435 lines
17 KiB
Ruby
435 lines
17 KiB
Ruby
|
require_relative '../../../spec_helper'
|
||
|
require_relative '../../api/json/imports_controller_shared_examples'
|
||
|
require_relative '../../../../app/controllers/carto/api/imports_controller'
|
||
|
require 'helpers/unique_names_helper'
|
||
|
|
||
|
describe Carto::Api::ImportsController do
|
||
|
include UniqueNamesHelper
|
||
|
it_behaves_like 'imports controllers' do
|
||
|
end
|
||
|
|
||
|
@headers = { 'CONTENT_TYPE' => 'application/json' }
|
||
|
|
||
|
before(:all) do
|
||
|
@user = FactoryGirl.create(:valid_user)
|
||
|
host! "#{@user.username}.localhost.lan"
|
||
|
end
|
||
|
|
||
|
after(:all) do
|
||
|
@user.destroy
|
||
|
end
|
||
|
|
||
|
before(:each) do
|
||
|
bypass_named_maps
|
||
|
delete_user_data @user
|
||
|
end
|
||
|
|
||
|
let(:params) { { api_key: @user.api_key } }
|
||
|
|
||
|
it 'gets a list of all pending imports' do
|
||
|
Resque.inline = false
|
||
|
serve_file(Rails.root.join('spec/support/data/ESP_adm.zip')) do |url|
|
||
|
post api_v1_imports_create_url, params.merge(url: url, table_name: 'wadus')
|
||
|
end
|
||
|
|
||
|
get api_v1_imports_index_url, params
|
||
|
|
||
|
response.code.should be == '200'
|
||
|
|
||
|
response_json = JSON.parse(response.body)
|
||
|
response_json.should_not be_nil
|
||
|
imports = response_json['imports']
|
||
|
imports.should have(1).items
|
||
|
Resque.inline = true
|
||
|
end
|
||
|
|
||
|
it "doesn't return old pending imports" do
|
||
|
Resque.inline = false
|
||
|
serve_file(Rails.root.join('spec/support/data/ESP_adm.zip')) do |url|
|
||
|
post api_v1_imports_create_url, params.merge(url: url, table_name: 'wadus')
|
||
|
end
|
||
|
|
||
|
Delorean.jump(7.hours)
|
||
|
get api_v1_imports_index_url, params
|
||
|
|
||
|
response.code.should be == '200'
|
||
|
|
||
|
response_json = JSON.parse(response.body)
|
||
|
response_json.should_not be_nil
|
||
|
imports = response_json['imports']
|
||
|
imports.should have(0).items
|
||
|
Resque.inline = true
|
||
|
Delorean.back_to_the_present
|
||
|
end
|
||
|
|
||
|
it 'gets the detail of an import' do
|
||
|
post api_v1_imports_create_url(api_key: @user.api_key, table_name: 'wadus'),
|
||
|
filename: upload_file('db/fake_data/column_number_to_boolean.csv', 'text/csv')
|
||
|
|
||
|
item_queue_id = JSON.parse(response.body)['item_queue_id']
|
||
|
|
||
|
get api_v1_imports_show_url(:id => item_queue_id), params
|
||
|
|
||
|
response.code.should be == '200'
|
||
|
|
||
|
import = JSON.parse(response.body)
|
||
|
import['state'].should be == 'complete'
|
||
|
import['display_name'].should be == 'column_number_to_boolean.csv'
|
||
|
end
|
||
|
|
||
|
it 'gets the detail of an import stuck unpacking' do
|
||
|
post api_v1_imports_create_url(api_key: @user.api_key, table_name: 'wadus'),
|
||
|
filename: upload_file('db/fake_data/column_number_to_boolean.csv', 'text/csv')
|
||
|
|
||
|
response_json = JSON.parse(response.body)
|
||
|
last_import = DataImport[response_json['item_queue_id']]
|
||
|
last_import.state = DataImport::STATE_UNPACKING
|
||
|
last_import.created_at -= 5.years
|
||
|
last_import.save
|
||
|
|
||
|
get api_v1_imports_show_url(:id => last_import.id), params
|
||
|
|
||
|
response.code.should be == '200'
|
||
|
|
||
|
import = JSON.parse(response.body)
|
||
|
import['state'].should be == 'failure'
|
||
|
import['error_code'].should be 6671
|
||
|
end
|
||
|
|
||
|
it 'tries to import a tgz' do
|
||
|
|
||
|
post api_v1_imports_create_url,
|
||
|
params.merge(filename: upload_file('spec/support/data/Weird Filename (2).tgz', 'application/octet-stream'))
|
||
|
|
||
|
item_queue_id = JSON.parse(response.body)['item_queue_id']
|
||
|
|
||
|
get api_v1_imports_show_url(:id => item_queue_id), params
|
||
|
|
||
|
response.code.should be == '200'
|
||
|
import = JSON.parse(response.body)
|
||
|
import['state'].should be == 'complete'
|
||
|
import['display_name'].should be == 'Weird_Filename_(2).tgz'
|
||
|
end
|
||
|
|
||
|
it 'fails with password protected files' do
|
||
|
post api_v1_imports_create_url,
|
||
|
params.merge(filename: upload_file('spec/support/data/alldata-pass.zip', 'application/octet-stream'))
|
||
|
|
||
|
item_queue_id = JSON.parse(response.body)['item_queue_id']
|
||
|
|
||
|
get api_v1_imports_show_url(:id => item_queue_id), params
|
||
|
|
||
|
response.code.should be == '200'
|
||
|
import = JSON.parse(response.body)
|
||
|
import['state'].should be == 'failure'
|
||
|
end
|
||
|
|
||
|
it 'imports files with weird filenames' do
|
||
|
post api_v1_imports_create_url,
|
||
|
params.merge(filename: upload_file('spec/support/data/Weird Filename (2).csv', 'application/octet-stream'))
|
||
|
|
||
|
item_queue_id = JSON.parse(response.body)['item_queue_id']
|
||
|
|
||
|
get api_v1_imports_show_url(:id => item_queue_id), params
|
||
|
|
||
|
response.code.should be == '200'
|
||
|
import = JSON.parse(response.body)
|
||
|
import['state'].should be == 'complete'
|
||
|
end
|
||
|
|
||
|
it 'creates a table from a sql query' do
|
||
|
post api_v1_imports_create_url(params.merge(table_name: 'wadus_2')),
|
||
|
filename: upload_file('spec/support/data/_penguins_below_80.zip', 'application/octet-stream')
|
||
|
|
||
|
response.code.should be == '200'
|
||
|
|
||
|
@table_from_import = UserTable.all.last.service
|
||
|
post api_v1_imports_create_url(:api_key => @user.api_key,
|
||
|
table_name: 'wadus_2',
|
||
|
:sql => "SELECT * FROM #{@table_from_import.name}")
|
||
|
|
||
|
|
||
|
response.code.should be == '200'
|
||
|
|
||
|
response_json = JSON.parse(response.body)
|
||
|
|
||
|
last_import = DataImport[response_json['item_queue_id']]
|
||
|
last_import.state.should be == 'complete'
|
||
|
|
||
|
import_table = UserTable.all.last.service
|
||
|
import_table.rows_counted.should be == @table_from_import.rows_counted
|
||
|
import_table.should have_required_indexes_and_triggers
|
||
|
end
|
||
|
|
||
|
it 'returns derived visualization id if created with create_vis flag' do
|
||
|
@user.update private_tables_enabled: false
|
||
|
post api_v1_imports_create_url,
|
||
|
params.merge({filename: upload_file('spec/support/data/csv_with_lat_lon.csv', 'application/octet-stream'),
|
||
|
create_vis: true})
|
||
|
response.code.should be == '200'
|
||
|
|
||
|
item_queue_id = ::JSON.parse(response.body)['item_queue_id']
|
||
|
|
||
|
get api_v1_imports_show_url(id: item_queue_id), params
|
||
|
|
||
|
import = DataImport[item_queue_id]
|
||
|
|
||
|
import.state.should be == 'complete'
|
||
|
import.visualization_id.nil?.should eq false
|
||
|
import.create_visualization.should eq true
|
||
|
|
||
|
vis = CartoDB::Visualization::Member.new(id: import.visualization_id).fetch
|
||
|
vis.nil?.should eq false
|
||
|
vis.name =~ /csv_with_lat_lon/ # just in case we change the prefix
|
||
|
|
||
|
@user.update private_tables_enabled: true
|
||
|
end
|
||
|
|
||
|
describe 'service_token_valid?' do
|
||
|
it 'returns oauth_valid false for unknown service tokens' do
|
||
|
get api_v1_imports_service_token_valid_url(id: 'kk'), params
|
||
|
response.code.should == '200'
|
||
|
response_json = JSON.parse(response.body)
|
||
|
response_json['oauth_valid'].should == false
|
||
|
response_json['success'].should == true
|
||
|
end
|
||
|
|
||
|
it 'returns 400 for known service token without known service datasource' do
|
||
|
synchronization_oauth = Carto::SynchronizationOauth.new(user_id: @user.id, service: 'kk-s', token: 'kk-t')
|
||
|
synchronization_oauth.save
|
||
|
get api_v1_imports_service_token_valid_url(id: synchronization_oauth.service), params
|
||
|
response.code.should == '400'
|
||
|
synchronization_oauth.destroy
|
||
|
end
|
||
|
|
||
|
it 'returns 400 for known service token for a service datasource which is not BaseOAuth' do
|
||
|
synchronization_oauth = Carto::SynchronizationOauth.new(user_id: @user.id, service: 'arcgis', token: 'kk-t')
|
||
|
synchronization_oauth.save
|
||
|
get api_v1_imports_service_token_valid_url(id: synchronization_oauth.service), params
|
||
|
response.code.should == '400'
|
||
|
synchronization_oauth.destroy
|
||
|
end
|
||
|
|
||
|
it 'returns oauth_valid false for not valid tokens and deletes them' do
|
||
|
CartoDB::Datasources::Url::MailChimp.any_instance.stubs(:token_valid?).returns(false)
|
||
|
synchronization_oauth = Carto::SynchronizationOauth.new(user_id: @user.id, service: 'mailchimp', token: 'kk-t')
|
||
|
synchronization_oauth.save
|
||
|
get api_v1_imports_service_token_valid_url(id: synchronization_oauth.service), params
|
||
|
response.code.should == '200'
|
||
|
response_json = JSON.parse(response.body)
|
||
|
response_json['oauth_valid'].should == false
|
||
|
response_json['success'].should == true
|
||
|
|
||
|
SynchronizationOauth.where(id: synchronization_oauth.id).first.should eq nil
|
||
|
synchronization_oauth.destroy
|
||
|
end
|
||
|
|
||
|
it 'returns 401 for expired tokens on assignment and deletes them' do
|
||
|
CartoDB::Datasources::Url::MailChimp.any_instance.stubs(:token=).raises(CartoDB::Datasources::TokenExpiredOrInvalidError.new('kk', 'mailchimp'))
|
||
|
synchronization_oauth = Carto::SynchronizationOauth.new(user_id: @user.id, service: 'mailchimp', token: 'kk-t')
|
||
|
synchronization_oauth.save
|
||
|
|
||
|
get api_v1_imports_service_token_valid_url(id: synchronization_oauth.service), params, @headers
|
||
|
response.code.should == '401'
|
||
|
|
||
|
SynchronizationOauth.where(id: synchronization_oauth.id).first.should eq nil
|
||
|
synchronization_oauth.destroy
|
||
|
end
|
||
|
|
||
|
it 'returns 401 for expired tokens on validation and deletes them' do
|
||
|
CartoDB::Datasources::Url::MailChimp.any_instance.stubs(:token_valid?).raises(CartoDB::Datasources::TokenExpiredOrInvalidError.new('kk', 'mailchimp'))
|
||
|
synchronization_oauth = Carto::SynchronizationOauth.new(user_id: @user.id, service: 'mailchimp', token: 'kk-t')
|
||
|
synchronization_oauth.save
|
||
|
|
||
|
get api_v1_imports_service_token_valid_url(id: synchronization_oauth.service), params, @headers
|
||
|
response.code.should == '401'
|
||
|
|
||
|
SynchronizationOauth.where(id: synchronization_oauth.id).first.should eq nil
|
||
|
synchronization_oauth.destroy
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
describe 'list_files_for_service' do
|
||
|
|
||
|
def fake_item_data(datasource_name = 'fake_datasource')
|
||
|
id = unique_integer
|
||
|
{
|
||
|
id: id,
|
||
|
title: "title_#{id}",
|
||
|
filename: "filename_#{id}",
|
||
|
service: datasource_name,
|
||
|
checksum: id,
|
||
|
size: rand(50)
|
||
|
}
|
||
|
end
|
||
|
|
||
|
def fake_resource_list(datasource_name = 'fake_datasource')
|
||
|
[ fake_item_data(datasource_name), fake_item_data(datasource_name) ]
|
||
|
end
|
||
|
|
||
|
it 'returns datasource resources list for known, valid tokens' do
|
||
|
service = 'mailchimp'
|
||
|
fake_files = fake_resource_list(service)
|
||
|
CartoDB::Datasources::Url::MailChimp.any_instance.stubs(:get_resources_list).returns(fake_files)
|
||
|
synchronization_oauth = Carto::SynchronizationOauth.new(user_id: @user.id, service: service, token: 'kk-t')
|
||
|
synchronization_oauth.save
|
||
|
get api_v1_imports_service_list_files_url(id: service), params
|
||
|
response.code.should == '200'
|
||
|
response_json = JSON.parse(response.body)
|
||
|
response_json['success'].should == true
|
||
|
response_json['files'].map(&:symbolize_keys).should == fake_files
|
||
|
synchronization_oauth.destroy
|
||
|
end
|
||
|
|
||
|
it 'returns 401 for expired tokens on resource listing and deletes them' do
|
||
|
CartoDB::Datasources::Url::MailChimp.any_instance.stubs(:get_resources_list).raises(CartoDB::Datasources::TokenExpiredOrInvalidError.new('kk', 'mailchimp'))
|
||
|
synchronization_oauth = Carto::SynchronizationOauth.new(user_id: @user.id, service: 'mailchimp', token: 'kk-t')
|
||
|
synchronization_oauth.save
|
||
|
|
||
|
get api_v1_imports_service_list_files_url(id: 'mailchimp'), params
|
||
|
response.code.should == '401'
|
||
|
|
||
|
SynchronizationOauth.where(id: synchronization_oauth.id).first.should eq nil
|
||
|
synchronization_oauth.destroy
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
describe 'auth_url' do
|
||
|
|
||
|
it 'returns 400 for existing tokens services' do
|
||
|
service = 'mailchimp'
|
||
|
synchronization_oauth = Carto::SynchronizationOauth.new(user_id: @user.id, service: service, token: 'kk-t')
|
||
|
synchronization_oauth.save
|
||
|
get api_v1_imports_service_auth_url_url(id: service), params
|
||
|
response.code.should == '400'
|
||
|
synchronization_oauth.destroy
|
||
|
end
|
||
|
|
||
|
it 'returns auth url for known, valid tokens' do
|
||
|
service = 'mailchimp'
|
||
|
fake_url = 'http://www.fakeurl.com'
|
||
|
CartoDB::Datasources::Url::MailChimp.any_instance.stubs(:get_auth_url).returns(fake_url)
|
||
|
get api_v1_imports_service_auth_url_url(id: service), params
|
||
|
response.code.should == '200'
|
||
|
response_json = JSON.parse(response.body)
|
||
|
response_json['success'].should == true
|
||
|
response_json['url'].should == fake_url
|
||
|
end
|
||
|
|
||
|
it 'returns 401 for expired tokens on url and deletes them' do
|
||
|
CartoDB::Datasources::Url::MailChimp.any_instance.stubs(:get_auth_url).raises(CartoDB::Datasources::TokenExpiredOrInvalidError.new('kk', 'mailchimp'))
|
||
|
|
||
|
get api_v1_imports_service_auth_url_url(id: 'mailchimp'), params
|
||
|
response.code.should == '401'
|
||
|
|
||
|
# INFO: this can never happen with the current implementation of get_service_auth_url, since it first checks there's no previous SynchronizationOauth
|
||
|
SynchronizationOauth.where(service: 'mailchimp').first.should eq nil
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe 'validate_service_oauth_code' do
|
||
|
|
||
|
it 'returns 400 for existing tokens services' do
|
||
|
service = 'mailchimp'
|
||
|
synchronization_oauth = Carto::SynchronizationOauth.new(user_id: @user.id, service: service, token: 'kk-t')
|
||
|
synchronization_oauth.save
|
||
|
get api_v1_imports_service_validate_code_url(id: service, code: 'kk'), params
|
||
|
response.code.should == '400'
|
||
|
synchronization_oauth.destroy
|
||
|
end
|
||
|
|
||
|
it 'returns 400 if it does not find datasource' do
|
||
|
CartoDB::Datasources::DatasourcesFactory.stubs(:get_datasource).returns(nil)
|
||
|
get api_v1_imports_service_validate_code_url(id: 'kk', code: 'kk'), params
|
||
|
response.code.should == '400'
|
||
|
end
|
||
|
|
||
|
it 'returns 401 for expired tokens on url and deletes them' do
|
||
|
CartoDB::Datasources::DatasourcesFactory.stubs(:get_datasource).raises(CartoDB::Datasources::TokenExpiredOrInvalidError.new('kk', 'mailchimp'))
|
||
|
|
||
|
get api_v1_imports_service_validate_code_url(id: 'mailchimp', code: 'kk'), params
|
||
|
response.code.should == '401'
|
||
|
|
||
|
# INFO: this can never happen with the current implementation since it first checks there's no previous SynchronizationOauth
|
||
|
SynchronizationOauth.where(service: 'mailchimp').first.should eq nil
|
||
|
end
|
||
|
|
||
|
it 'returns not success 200 and does not store oauth for not valid codes' do
|
||
|
CartoDB::Datasources::Url::MailChimp.any_instance.stubs(:validate_auth_code).raises(CartoDB::Datasources::AuthError.new)
|
||
|
|
||
|
get api_v1_imports_service_validate_code_url(id: 'mailchimp', code: 'kk'), params
|
||
|
response.code.should == '200'
|
||
|
response_json = JSON.parse(response.body)
|
||
|
response_json['success'].should == false
|
||
|
|
||
|
SynchronizationOauth.where(service: 'mailchimp').first.should eq nil
|
||
|
end
|
||
|
|
||
|
it 'returns 400 if validation fails catastrophically' do
|
||
|
CartoDB::Datasources::Url::MailChimp.any_instance.stubs(:validate_auth_code).raises(StandardError.new)
|
||
|
|
||
|
get api_v1_imports_service_validate_code_url(id: 'mailchimp', code: 'kk'), params
|
||
|
response.code.should == '400'
|
||
|
|
||
|
# INFO: this can never happen with the current implementation since it first checks there's no previous SynchronizationOauth
|
||
|
SynchronizationOauth.where(service: 'mailchimp').first.should eq nil
|
||
|
end
|
||
|
|
||
|
it 'returns success 200 and stores oauth for valid codes' do
|
||
|
token = 'kk'
|
||
|
CartoDB::Datasources::Url::MailChimp.any_instance.stubs(:validate_auth_code).returns(token)
|
||
|
|
||
|
get api_v1_imports_service_validate_code_url(id: 'mailchimp', code: 'kk'), params
|
||
|
response.code.should == '200'
|
||
|
response_json = JSON.parse(response.body)
|
||
|
response_json['success'].should == true
|
||
|
|
||
|
synchronization_oauth = SynchronizationOauth.where(service: 'mailchimp').first
|
||
|
synchronization_oauth.token.should eq token
|
||
|
synchronization_oauth.user_id.should eq @user.id
|
||
|
synchronization_oauth.destroy
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
describe 'service_oauth_callback' do
|
||
|
|
||
|
it 'returns 400 for existing tokens services' do
|
||
|
service = 'mailchimp'
|
||
|
synchronization_oauth = Carto::SynchronizationOauth.new(user_id: @user.id, service: service, token: 'kk-t')
|
||
|
synchronization_oauth.save
|
||
|
get api_v1_imports_service_oauth_callback_url(id: service), params
|
||
|
response.code.should == '400'
|
||
|
synchronization_oauth.destroy
|
||
|
end
|
||
|
|
||
|
it 'returns 401 for expired tokens and deletes them' do
|
||
|
CartoDB::Datasources::DatasourcesFactory.stubs(:get_datasource).raises(CartoDB::Datasources::TokenExpiredOrInvalidError.new('kk', 'mailchimp'))
|
||
|
|
||
|
get api_v1_imports_service_oauth_callback_url(id: 'mailchimp'), params
|
||
|
response.code.should == '401'
|
||
|
|
||
|
# INFO: this can never happen with the current implementation since it first checks there's no previous SynchronizationOauth
|
||
|
SynchronizationOauth.where(service: 'mailchimp').first.should eq nil
|
||
|
end
|
||
|
|
||
|
it 'returns success 200 and stores oauth for valid params' do
|
||
|
token = 'kk'
|
||
|
CartoDB::Datasources::Url::MailChimp.any_instance.stubs(:validate_callback).returns(token)
|
||
|
|
||
|
get api_v1_imports_service_oauth_callback_url(id: 'mailchimp'), params
|
||
|
response.code.should == '200'
|
||
|
response.body.should == '<script>window.close();</script>'
|
||
|
|
||
|
synchronization_oauth = SynchronizationOauth.where(service: 'mailchimp').first
|
||
|
synchronization_oauth.token.should eq token
|
||
|
synchronization_oauth.user_id.should eq @user.id
|
||
|
synchronization_oauth.destroy
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
end
|