Initial commit
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe "Assets API" do
|
||||
|
||||
before(:each) do
|
||||
@user = FactoryGirl.create(:valid_user)
|
||||
|
||||
delete_user_data @user
|
||||
host! "#{@user.username}.localhost.lan"
|
||||
end
|
||||
|
||||
after(:each) do
|
||||
@user.destroy
|
||||
end
|
||||
|
||||
let(:params) { { :api_key => @user.api_key } }
|
||||
|
||||
it 'creates a new asset' do
|
||||
Asset.any_instance.stubs('use_s3?').returns(false)
|
||||
|
||||
file_path = Rails.root.join('spec', 'support', 'data', 'cartofante_blue.png')
|
||||
if File.exist?(file_path) && File.file?(file_path)
|
||||
uploaded_file = Rack::Test::UploadedFile.new(file_path, 'image/png')
|
||||
|
||||
post_json(
|
||||
api_v1_users_assets_create_url(user_id: @user),
|
||||
params.merge(kind: 'wadus', filename: uploaded_file.path)
|
||||
) do |response|
|
||||
response.status.should be_success
|
||||
response.body[:public_url].should =~ /\/test\/#{@user.username}\/assets\/\d+cartofante_blue/
|
||||
URI(response.body[:public_url]).should be_absolute
|
||||
response.body[:kind].should == 'wadus'
|
||||
@user.reload
|
||||
@user.assets.count.should == 1
|
||||
asset = @user.assets.first
|
||||
asset.public_url.should =~ /\/test\/#{@user.username}\/assets\/\d+cartofante_blue/
|
||||
asset.kind.should == 'wadus'
|
||||
end
|
||||
else
|
||||
pending("Required spec asset '#{file_path}' not found, test can't properly execute")
|
||||
end
|
||||
end
|
||||
|
||||
it 'creates a new asset with spaces in name' do
|
||||
Asset.any_instance.stubs('use_s3?').returns(false)
|
||||
|
||||
file_path = Rails.root.join('spec', 'support', 'data', 'cartofante blue.png')
|
||||
if File.exist?(file_path) && File.file?(file_path)
|
||||
uploaded_file = Rack::Test::UploadedFile.new(file_path, 'image/png')
|
||||
|
||||
post_json(
|
||||
api_v1_users_assets_create_url(user_id: @user),
|
||||
params.merge(kind: 'wadus', filename: uploaded_file.path)
|
||||
) do |response|
|
||||
response.status.should be_success
|
||||
response.body[:public_url].should =~ /\/test\/#{@user.username}\/assets\/\d+cartofante%20blue/
|
||||
URI(response.body[:public_url]).should be_absolute
|
||||
response.body[:kind].should == 'wadus'
|
||||
@user.reload
|
||||
@user.assets.count.should == 1
|
||||
asset = @user.assets.first
|
||||
asset.public_url.should =~ /\/test\/#{@user.username}\/assets\/\d+cartofante%20blue/
|
||||
asset.kind.should == 'wadus'
|
||||
end
|
||||
else
|
||||
pending("Required spec asset '#{file_path}' not found, test can't properly execute")
|
||||
end
|
||||
end
|
||||
|
||||
it "returns some error message when the asset creation fails" do
|
||||
pending "Fix this test, sometimes fails"
|
||||
Asset.any_instance.stubs(:s3_bucket).raises("AWS exception")
|
||||
post_json(api_v1_users_assets_create_url(user_id: @user), params.merge(
|
||||
:filename => Rack::Test::UploadedFile.new(Rails.root.join('spec/support/data/cartofante_blue.png'), 'image/png').path)
|
||||
) do |response|
|
||||
response.status.should == 400
|
||||
response.body[:error].should == ["AWS exception"]
|
||||
end
|
||||
end
|
||||
|
||||
it "finds image file extension" do
|
||||
asset = FactoryGirl.create(:asset, user_id: @user.id)
|
||||
|
||||
Asset::VALID_EXTENSIONS.each do |extension|
|
||||
asset_name = "cartofante" + extension
|
||||
asset.stubs(:asset_file).returns(asset_name)
|
||||
asset.asset_file_extension.should == extension
|
||||
end
|
||||
end
|
||||
|
||||
it "detects incorrect image file extension" do
|
||||
asset = FactoryGirl.create(:asset, user_id: @user.id)
|
||||
asset.stubs(:asset_file).returns("cartofante.gifv")
|
||||
asset.asset_file_extension.should == nil
|
||||
end
|
||||
|
||||
it "deletes an asset" do
|
||||
Asset.any_instance.stubs('use_s3?').returns(false)
|
||||
|
||||
FactoryGirl.create(:asset, user_id: @user.id)
|
||||
@user.reload
|
||||
delete_json(api_v1_users_assets_destroy_url(user_id: @user.id, id: @user.assets.first.id), params) do |response|
|
||||
response.body.should == {}
|
||||
response.status.should be_success
|
||||
@user.reload
|
||||
@user.assets.count.should == 0
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,162 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe "Geocodings API" do
|
||||
before(:all) do
|
||||
@user = FactoryGirl.create(:valid_user, table_quota: 50)
|
||||
|
||||
delete_user_data @user
|
||||
host! "#{@user.username}.localhost.lan"
|
||||
end
|
||||
|
||||
after(:all) do
|
||||
@user.destroy
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
bypass_named_maps
|
||||
end
|
||||
|
||||
let(:params) { { :api_key => @user.api_key } }
|
||||
|
||||
describe 'POST /api/v1/geocodings' do
|
||||
let(:table) { create_table(user_id: @user.id) }
|
||||
|
||||
it 'creates a new geocoding' do
|
||||
Geocoding.any_instance.stubs("run!").returns(true)
|
||||
payload = params.merge table_name: table.name, formatter: 'name, description', kind: 'high-resolution'
|
||||
post_json api_v1_geocodings_create_url(payload) do |response|
|
||||
response.status.should eq 200
|
||||
response.body[:id].should_not be_nil
|
||||
response.body[:user_id].should eq @user.id
|
||||
response.body[:table_id].should eq table.id
|
||||
response.body[:formatter].should eq 'name, description'
|
||||
response.body[:created_at].should_not be_nil
|
||||
response.body[:updated_at].should_not be_nil
|
||||
end
|
||||
end
|
||||
|
||||
it 'uses column_name instead of formatter if present' do
|
||||
Geocoding.any_instance.stubs("run!").returns(true)
|
||||
payload = params.merge table_name: table.name, column_name: 'name', kind: 'high-resolution'
|
||||
post_json api_v1_geocodings_create_url(payload) do |response|
|
||||
response.status.should eq 200
|
||||
response.body[:id].should_not be_nil
|
||||
response.body[:formatter].should eq '{name}'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'namedplace geocodings' do
|
||||
it "should set the country_code when the name of the country is present" do
|
||||
Geocoding.any_instance.stubs("run!").returns(true)
|
||||
payload = params.merge \
|
||||
table_name: table.name,
|
||||
column_name: 'name',
|
||||
text: true,
|
||||
location: 'spain',
|
||||
kind: 'namedplace'
|
||||
post_json api_v1_geocodings_create_url(payload) do |response|
|
||||
response.status.should eq 200
|
||||
response.body[:id].should_not be_nil
|
||||
response.body[:country_code].should eq "'spain'"
|
||||
response.body[:country_column].should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
it "should set country_code and country_column when a country column has been selected" do
|
||||
table.add_column!(name: "country", type: "text")
|
||||
table.insert_row!(country: "spain")
|
||||
table.insert_row!(country: "spain")
|
||||
table.insert_row!(country: "us")
|
||||
table.reload
|
||||
|
||||
Geocoding.any_instance.stubs("run!").returns(true)
|
||||
payload = params.merge \
|
||||
table_name: table.name,
|
||||
column_name: 'name',
|
||||
text: false,
|
||||
location: 'country',
|
||||
kind: 'namedplace'
|
||||
post_json api_v1_geocodings_create_url, payload do |response|
|
||||
response.status.should eq 200
|
||||
response.body[:id].should_not be_nil
|
||||
response.body[:country_code].split(',').sort.should eq ["'spain'", "'us'"]
|
||||
response.body[:country_column].should eq "country"
|
||||
end
|
||||
end
|
||||
|
||||
it "should set the region_code when the name of the region is present" do
|
||||
Geocoding.any_instance.stubs("run!").returns(true)
|
||||
payload = params.merge \
|
||||
table_name: table.name,
|
||||
column_name: 'name',
|
||||
text: true,
|
||||
location: 'spain',
|
||||
region_text: true,
|
||||
region: 'madrid',
|
||||
kind: 'namedplace'
|
||||
post_json api_v1_geocodings_create_url(payload) do |response|
|
||||
response.status.should eq 200
|
||||
response.body[:id].should_not be_nil
|
||||
response.body[:region_code].should eq "'madrid'"
|
||||
response.body[:region_column].should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
it "should set region_code and region_column when a region column has been selected" do
|
||||
table.add_column!(name: "country", type: "text")
|
||||
table.add_column!(name: "region", type: "text")
|
||||
table.insert_row!(country: "spain", region: "madrid")
|
||||
table.insert_row!(country: "spain", region: "madrid")
|
||||
table.insert_row!(country: "us", region: "minnesota")
|
||||
table.reload
|
||||
|
||||
Geocoding.any_instance.stubs("run!").returns(true)
|
||||
payload = params.merge \
|
||||
table_name: table.name,
|
||||
column_name: 'name',
|
||||
text: false,
|
||||
location: 'country',
|
||||
region_text: false,
|
||||
region: 'region',
|
||||
|
||||
kind: 'namedplace'
|
||||
post_json api_v1_geocodings_create_url, payload do |response|
|
||||
response.status.should eq 200
|
||||
response.body[:id].should_not be_nil
|
||||
response.body[:region_code].split(',').sort.should eq ["'madrid'", "'minnesota'"]
|
||||
response.body[:region_column].should eq "region"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'responds with 422 on bad payload' do
|
||||
payload = params.merge(table_name: '', formatter: '', kind: 'high-resolution')
|
||||
post_json api_v1_geocodings_create_url(payload) do |response|
|
||||
response.status.should eq 422
|
||||
response.body[:description].should eq "formatter is not present"
|
||||
end
|
||||
end
|
||||
|
||||
it 'responds with 500 on failure' do
|
||||
payload = params.merge(table_name: '', formatter: '', kind: 'high-resolution')
|
||||
Geocoding.any_instance.stubs(:save).raises(RuntimeError.new)
|
||||
post_json api_v1_geocodings_create_url(payload) do |response|
|
||||
response.status.should eq 500
|
||||
response.body[:description].should eq "RuntimeError"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT /api/v1/geocodings/:id' do
|
||||
it 'fails gracefully on job cancel failure' do
|
||||
geocoding = FactoryGirl.create(:geocoding, table_id: UUIDTools::UUID.timestamp_create.to_s, formatter: 'b', user: @user)
|
||||
Geocoding.any_instance.stubs(:cancel).raises('wadus')
|
||||
|
||||
put_json api_v1_geocodings_update_url(params.merge(id: geocoding.id)), { state: 'cancelled' } do |response|
|
||||
response.status.should eq 400
|
||||
response.body.should eq errors: "wadus"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,247 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe "Imports API" do
|
||||
|
||||
before(:all) do
|
||||
@user = FactoryGirl.create(:valid_user)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
bypass_named_maps
|
||||
delete_user_data @user
|
||||
host! "#{@user.username}.localhost.lan"
|
||||
end
|
||||
|
||||
after(:all) do
|
||||
@user.destroy
|
||||
end
|
||||
|
||||
let(:params) { { :api_key => @user.api_key } }
|
||||
|
||||
it 'performs asynchronous imports' do
|
||||
f = upload_file('db/fake_data/column_number_to_boolean.csv', 'text/csv')
|
||||
post api_v1_imports_create_url(params.merge(table_name: "wadus")), filename: f
|
||||
|
||||
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'
|
||||
table = UserTable[last_import.table_id]
|
||||
table.name.should == "column_number_to_boolean"
|
||||
table.map.data_layers.first.options["table_name"].should == "column_number_to_boolean"
|
||||
end
|
||||
|
||||
it 'performs asynchronous imports (file parameter, used in API docs)' do
|
||||
f = upload_file('db/fake_data/column_number_to_boolean.csv', 'text/csv')
|
||||
post api_v1_imports_create_url(params.merge(table_name: "wadus")), file: f
|
||||
|
||||
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'
|
||||
table = UserTable[last_import.table_id]
|
||||
table.name.should == "column_number_to_boolean"
|
||||
table.map.data_layers.first.options["table_name"].should == "column_number_to_boolean"
|
||||
end
|
||||
|
||||
it 'performs asynchronous url imports' do
|
||||
CartoDB::Importer2::Downloader.any_instance.stubs(:validate_url!).returns(true)
|
||||
serve_file Rails.root.join('db/fake_data/clubbing.csv') do |url|
|
||||
post api_v1_imports_create_url(params.merge(:url => url,
|
||||
:table_name => "wadus"))
|
||||
end
|
||||
|
||||
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'
|
||||
end
|
||||
|
||||
pending 'appends data to an existing table' do
|
||||
@table = FactoryGirl.create(:table, :user_id => @user.id)
|
||||
|
||||
f = upload_file('db/fake_data/column_number_to_boolean.csv', 'text/csv')
|
||||
post api_v1_imports_create_url(params.merge(table_id: @table.id, append: true)),
|
||||
f.read.force_encoding('UTF-8'),
|
||||
filename: f
|
||||
|
||||
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'
|
||||
|
||||
@table.reload.rows_counted.should be == 4
|
||||
end
|
||||
|
||||
it 'duplicates a table' do
|
||||
post api_v1_imports_create_url,
|
||||
params.merge(:filename => upload_file('spec/support/data/csv_with_lat_lon.csv', 'application/octet-stream'))
|
||||
|
||||
@table_from_import = UserTable.all.last.service
|
||||
|
||||
post api_v1_imports_create_url(params.merge(:table_name => 'wadus_copy__copy',
|
||||
:table_copy => @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 'detects lat/long columns and produces a the_geom column from them' do
|
||||
post api_v1_imports_create_url,
|
||||
params.merge(:filename => upload_file('spec/support/data/csv_with_lat_lon.csv', 'application/octet-stream'))
|
||||
@table_from_import = UserTable.all.last.service
|
||||
|
||||
@table_from_import.geometry_types.should == ["ST_Point"]
|
||||
@table_from_import.record(1)[:the_geom].should == '{"type":"Point","coordinates":[16.5607329,48.1199611]}'
|
||||
end
|
||||
|
||||
it 'duplicates a table without geometries' do
|
||||
post api_v1_imports_create_url,
|
||||
params.merge(:filename => upload_file('spec/support/data/csv_with_number_columns.csv', 'application/octet-stream'))
|
||||
|
||||
@table_from_import = UserTable.all.last.service
|
||||
|
||||
post api_v1_imports_create_url(params.merge(:table_name => 'wadus_copy__copy',
|
||||
:table_copy => @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 'imports all the sample data' do
|
||||
@user.update table_quota: 10
|
||||
|
||||
CartoDB::Importer2::Downloader.any_instance.stubs(:validate_url!).returns(true)
|
||||
serve_file(Rails.root.join('spec/support/data/TM_WORLD_BORDERS_SIMPL-0.3.zip')) do |url|
|
||||
post api_v1_imports_create_url(params.merge(url: url, table_name: "wadus"))
|
||||
|
||||
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'
|
||||
table = UserTable[last_import.table_id].service
|
||||
|
||||
table.should have_required_indexes_and_triggers
|
||||
table.should have_no_invalid_the_geom
|
||||
table.geometry_types.should_not be_blank
|
||||
|
||||
table.map.should be
|
||||
end
|
||||
end
|
||||
|
||||
it 'raises an error if the user attempts to import tables when being over quota' do
|
||||
@user.update table_quota: 1
|
||||
|
||||
# This file contains 6 data sources
|
||||
CartoDB::Importer2::Downloader.any_instance.stubs(:validate_url!).returns(true)
|
||||
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
|
||||
response.code.should be == '200'
|
||||
last_import = DataImport.order(Sequel.desc(:updated_at)).first
|
||||
last_import.tables_created_count.should be_nil
|
||||
last_import.state.should be == 'failure'
|
||||
last_import.error_code.should be == 8002
|
||||
last_import.log.entries.should include('Results would set overquota')
|
||||
@user.reload.tables.count.should == 0
|
||||
end
|
||||
|
||||
it 'raises an error if the user attempts to import tables when being over disk quota' do
|
||||
@user.update quota_in_bytes: 1000, table_quota: 200
|
||||
CartoDB::Importer2::Downloader.any_instance.stubs(:validate_url!).returns(true)
|
||||
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
|
||||
response.code.should be == '200'
|
||||
last_import = DataImport.order(Sequel.desc(:updated_at)).first
|
||||
last_import.state.should be == 'failure'
|
||||
last_import.error_code.should be == 8001
|
||||
@user.reload.tables.count.should == 0
|
||||
end
|
||||
|
||||
it 'raises an error if the user attempts to duplicate a table when being over quota' do
|
||||
@user.update table_quota: 1, quota_in_bytes: 100.megabytes
|
||||
|
||||
post api_v1_imports_create_url,
|
||||
params.merge(:filename => upload_file('spec/support/data/_penguins_below_80.zip', 'application/octet-stream'))
|
||||
|
||||
@table_from_import = UserTable.all.last.service
|
||||
last_import = DataImport.order(Sequel.desc(:updated_at)).first
|
||||
last_import.state.should be == 'complete', "Import failure: #{last_import.log}"
|
||||
|
||||
post api_v1_imports_create_url, params.merge(:table_name => 'wadus_copy__copy',
|
||||
:table_copy => @table_from_import.name)
|
||||
|
||||
response.code.should be == '200'
|
||||
last_import = DataImport.order(Sequel.desc(:updated_at)).first
|
||||
last_import.state.should be == 'failure'
|
||||
last_import.error_code.should be == 8002
|
||||
@user.reload.tables.count.should == 1
|
||||
end
|
||||
|
||||
it 'imports data when the user has infinite tables' do
|
||||
@user.update table_quota: nil
|
||||
|
||||
post api_v1_imports_create_url,
|
||||
params.merge(:filename => upload_file('spec/support/data/csv_with_lat_lon.csv', 'application/octet-stream'))
|
||||
|
||||
@table_from_import = UserTable.all.last.service
|
||||
|
||||
response.code.should be == '200'
|
||||
last_import = DataImport.order(Sequel.desc(:updated_at)).first
|
||||
last_import.state.should be == 'complete'
|
||||
@user.reload.tables.count.should == 1
|
||||
end
|
||||
|
||||
it 'updates tables_created_count upon finished import' do
|
||||
post api_v1_imports_create_url,
|
||||
params.merge(:filename => upload_file('spec/support/data/zipped_ab.zip', 'application/octet-stream'))
|
||||
|
||||
response.code.should be == '200'
|
||||
last_import = DataImport.order(Sequel.desc(:updated_at)).first
|
||||
last_import.state.should be == 'complete'
|
||||
last_import.tables_created_count.should eq 2
|
||||
last_import.table_names.should eq 'zipped_a zipped_b'
|
||||
end
|
||||
|
||||
it 'properly reports table row count limit' do
|
||||
old_max_import_row_count = @user.max_import_table_row_count
|
||||
@user.update max_import_table_row_count: 2
|
||||
|
||||
# Internally uses reltuples from pg_class which is an estimation and non-deterministic so...
|
||||
CartoDB::PlatformLimits::Importer::TableRowCount.any_instance.expects(:get).returns(5)
|
||||
|
||||
post api_v1_imports_create_url,
|
||||
params.merge(:filename => upload_file('spec/support/data/csv_with_lat_lon.csv', 'application/octet-stream'))
|
||||
|
||||
response.code.should be == '200'
|
||||
last_import = DataImport.order(Sequel.desc(:updated_at)).first
|
||||
last_import.state.should be == 'failure'
|
||||
last_import.error_code.should be == 6668
|
||||
|
||||
@user.update max_import_table_row_count: old_max_import_row_count
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,7 @@
|
||||
require 'spec_helper'
|
||||
|
||||
shared_examples_for "geocoding controllers" do
|
||||
|
||||
# Left for when writes migration happens
|
||||
|
||||
end
|
||||
@@ -0,0 +1,69 @@
|
||||
require_relative '../../../spec_helper'
|
||||
require_relative 'geocodings_controller_shared_examples'
|
||||
require_relative '../../../../app/controllers/api/json/geocodings_controller'
|
||||
|
||||
describe Api::Json::GeocodingsController do
|
||||
it_behaves_like 'geocoding controllers' do
|
||||
end
|
||||
|
||||
include Rack::Test::Methods
|
||||
include Warden::Test::Helpers
|
||||
include CacheHelper
|
||||
|
||||
describe 'POST api/v1/geocodings' do
|
||||
|
||||
before(:all) do
|
||||
@user = create_user
|
||||
end
|
||||
|
||||
after(:all) do
|
||||
bypass_named_maps
|
||||
@user.destroy
|
||||
end
|
||||
|
||||
let(:params) { { api_key: @user.api_key, kind: 'ipaddress', formatter: '{some_column}' } }
|
||||
|
||||
before(:each) do
|
||||
bypass_named_maps
|
||||
delete_user_data @user
|
||||
host! "#{@user.username}.localhost.lan"
|
||||
login_as(@user, scope: @user.username)
|
||||
end
|
||||
|
||||
it 'takes an optional argument force_all_rows and stores it in the model' do
|
||||
table = create_table(user_id: @user.id)
|
||||
Resque.expects(:enqueue).once
|
||||
|
||||
geocoding_id = nil
|
||||
|
||||
post_json api_v1_geocodings_create_url(params.merge({
|
||||
table_name: table.name,
|
||||
force_all_rows: true
|
||||
})) do |response|
|
||||
response.status.should be_success
|
||||
response.body[:force_all_rows].should == true
|
||||
geocoding_id = response.body[:id]
|
||||
end
|
||||
|
||||
Geocoding[geocoding_id].force_all_rows == true
|
||||
end
|
||||
|
||||
it 'sets force_all_rows to nil if not present' do
|
||||
table = create_table(user_id: @user.id)
|
||||
Resque.expects(:enqueue).once
|
||||
|
||||
geocoding_id = nil
|
||||
|
||||
post_json api_v1_geocodings_create_url(params.merge({
|
||||
table_name: table.name,
|
||||
})) do |response|
|
||||
response.status.should be_success
|
||||
response.body[:force_all_rows].should == false
|
||||
geocoding_id = response.body[:id]
|
||||
end
|
||||
|
||||
Geocoding[geocoding_id].force_all_rows == false
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
require 'spec_helper'
|
||||
|
||||
shared_examples_for "imports controllers" do
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,8 @@
|
||||
require_relative '../../../spec_helper'
|
||||
require_relative 'imports_controller_shared_examples'
|
||||
require_relative '../../../../app/controllers/api/json/imports_controller'
|
||||
|
||||
describe Api::Json::ImportsController do
|
||||
it_behaves_like 'imports controllers' do
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,743 @@
|
||||
shared_examples_for "layer presenters" do |tested_klass, model_klass|
|
||||
describe '#show legacy tests' do
|
||||
def set_tested_classes(tested_class, model_class)
|
||||
@tested_class = tested_class
|
||||
@model_class = model_class
|
||||
end
|
||||
|
||||
def instance_of_tested_class(*args)
|
||||
@tested_class.new(*args)
|
||||
end
|
||||
|
||||
# Always uses old models to created data, then battery set one for instantiation
|
||||
def instance_of_tested_model(creation_model)
|
||||
@model_class.where(id: creation_model.id).first
|
||||
end
|
||||
|
||||
before(:all) do
|
||||
set_tested_classes(tested_klass, model_klass)
|
||||
puts "Testing class #{tested_klass.to_s} with model #{model_klass.to_s}"
|
||||
|
||||
@user_1 = FactoryGirl.create(:valid_user)
|
||||
@user_2 = FactoryGirl.create(:valid_user)
|
||||
end
|
||||
|
||||
after(:all) do
|
||||
@user_1.destroy
|
||||
@user_2.destroy
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
CartoDB::UserModule::DBService.any_instance.stubs(:enable_remote_db_user).returns(true)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
bypass_named_maps
|
||||
delete_user_data @user_1
|
||||
delete_user_data @user_2
|
||||
end
|
||||
|
||||
it "Tests to_json()" do
|
||||
layer_1 = Layer.create({
|
||||
kind: 'tiled'
|
||||
})
|
||||
layer_2 = Layer.create({
|
||||
kind: 'carto',
|
||||
order: 13,
|
||||
options: {
|
||||
'fake' => 'value',
|
||||
'table_name' => 'test_table'
|
||||
},
|
||||
infowindow: { 'fake2' => 'val2' },
|
||||
tooltip: { 'fake3' => 'val3' }
|
||||
})
|
||||
|
||||
layer_2 = instance_of_tested_model(layer_2)
|
||||
presenter = instance_of_tested_class(layer_2)
|
||||
json_data = JSON.parse(presenter.to_json)
|
||||
|
||||
json_data['id'].should == layer_2.id
|
||||
json_data['kind'].should == layer_2.kind
|
||||
json_data['order'].should == layer_2.order
|
||||
json_data['options'].should == layer_2.options
|
||||
json_data['infowindow'].should == layer_2.infowindow
|
||||
json_data['tooltip'].should == layer_2.tooltip
|
||||
|
||||
presenter_options = {
|
||||
viewer_user: @user_2,
|
||||
user: @user_1
|
||||
}
|
||||
|
||||
#no changes to layer_2
|
||||
presenter = instance_of_tested_class(layer_2, presenter_options)
|
||||
json_data = JSON.parse(presenter.to_json)
|
||||
# to_json shouldn't change table_name even if viewer/user sent at presenter options
|
||||
json_data['options'].should == layer_2.options
|
||||
end
|
||||
|
||||
it 'Tests to_poro()' do
|
||||
table_name = 'test_table'
|
||||
|
||||
layer_2 = Layer.create(
|
||||
kind: 'carto',
|
||||
order: 13,
|
||||
options: {
|
||||
'fake' => 'value',
|
||||
'table_name' => table_name
|
||||
},
|
||||
infowindow: { 'fake2' => 'val2' },
|
||||
tooltip: { 'fake3' => 'val3' }
|
||||
)
|
||||
layer_2 = instance_of_tested_model(layer_2)
|
||||
|
||||
expected_poro = {
|
||||
'id' => layer_2.id,
|
||||
'kind' => 'carto',
|
||||
'order' => 13,
|
||||
'options' => {
|
||||
'fake' => 'value',
|
||||
'table_name' => table_name
|
||||
},
|
||||
'infowindow' => {
|
||||
'fake2' => 'val2'
|
||||
},
|
||||
'tooltip' => {
|
||||
'fake3' => 'val3'
|
||||
}
|
||||
}
|
||||
expected_options = expected_poro.delete('options')
|
||||
|
||||
poro = instance_of_tested_class(layer_2).to_poro
|
||||
poro_options = poro.delete('options')
|
||||
|
||||
expect(poro).to include(expected_poro)
|
||||
expect(poro_options).to include(expected_options)
|
||||
|
||||
# Now add presenter options to change table_name (new way)
|
||||
expected_options['table_name'] = "#{@user_1.database_schema}.#{table_name}"
|
||||
|
||||
presenter_options = {
|
||||
viewer_user: @user_2,
|
||||
# New presenter way of sending a viewer that's different from the owner
|
||||
user: @user_1
|
||||
}
|
||||
|
||||
poro = instance_of_tested_class(layer_2, presenter_options).to_poro
|
||||
poro_options = poro.delete('options')
|
||||
|
||||
expect(poro).to include(expected_poro)
|
||||
expect(poro_options).to include(expected_options)
|
||||
|
||||
# old way
|
||||
|
||||
# change state always with old model to be sure
|
||||
layer_2 = ::Layer.where(id: layer_2.id).first
|
||||
layer_2.options = {
|
||||
'fake' => 'value',
|
||||
'table_name' => table_name,
|
||||
# Old presenter way of sending a viewer
|
||||
'user_name' => @user_1.username
|
||||
}
|
||||
layer_2.save
|
||||
layer_2 = instance_of_tested_model(layer_2)
|
||||
|
||||
expected_poro = {
|
||||
'id' => layer_2.id,
|
||||
'kind' => 'carto',
|
||||
'order' => 13,
|
||||
'options' => {
|
||||
'fake' => 'value',
|
||||
'table_name' => "#{@user_1.username}.#{table_name}",
|
||||
'user_name' => @user_1.username
|
||||
},
|
||||
'infowindow' => {
|
||||
'fake2' => 'val2'
|
||||
},
|
||||
'tooltip' => {
|
||||
'fake3' => 'val3'
|
||||
}
|
||||
}
|
||||
|
||||
presenter_options = {
|
||||
viewer_user: @user_2
|
||||
}
|
||||
|
||||
poro = instance_of_tested_class(layer_2, presenter_options).to_poro
|
||||
# Already changed to fully qualified expected table name, so no need to do it again
|
||||
poro_options = poro.delete('options')
|
||||
expected_options = expected_poro.delete('options')
|
||||
expect(poro).to include(expected_poro)
|
||||
expect(poro_options).to include(expected_options)
|
||||
|
||||
# Finally, don't change if already has a fully qualified table_name
|
||||
|
||||
layer_2 = ::Layer.where(id: layer_2.id).first
|
||||
layer_2.options = {
|
||||
'fake' => 'value',
|
||||
'table_name' => "fake.#{table_name}",
|
||||
# Old presenter way of sending a viewer
|
||||
'user_name' => @user_1.username
|
||||
}
|
||||
layer_2.save
|
||||
layer_2 = instance_of_tested_model(layer_2)
|
||||
|
||||
expected_options['table_name'] = "fake.#{table_name}"
|
||||
|
||||
poro = instance_of_tested_class(layer_2, presenter_options).to_poro
|
||||
poro_options = poro.delete('options')
|
||||
expect(poro).to include(expected_poro)
|
||||
expect(poro_options).to include(expected_options)
|
||||
end
|
||||
|
||||
it 'Tests to_poro() with uuid table name' do
|
||||
table_name = '000cd294-b124-4f82-b569-0f7fe41d2db8'
|
||||
|
||||
layer_2 = Layer.create(
|
||||
kind: 'carto',
|
||||
order: 13,
|
||||
options: {
|
||||
'fake' => 'value',
|
||||
'table_name' => table_name
|
||||
},
|
||||
infowindow: { 'fake2' => 'val2' },
|
||||
tooltip: { 'fake3' => 'val3' }
|
||||
)
|
||||
layer_2 = instance_of_tested_model(layer_2)
|
||||
|
||||
expected_poro = {
|
||||
'id' => layer_2.id,
|
||||
'kind' => 'carto',
|
||||
'order' => 13,
|
||||
'options' => {
|
||||
'fake' => 'value',
|
||||
'table_name' => table_name
|
||||
},
|
||||
'infowindow' => {
|
||||
'fake2' => 'val2'
|
||||
},
|
||||
'tooltip' => {
|
||||
'fake3' => 'val3'
|
||||
}
|
||||
}
|
||||
expected_options = expected_poro.delete('options')
|
||||
|
||||
poro = instance_of_tested_class(layer_2).to_poro
|
||||
poro_options = poro.delete('options')
|
||||
|
||||
expect(poro).to include(expected_poro)
|
||||
expect(poro_options).to include(expected_options)
|
||||
|
||||
# Now add presenter options to change table_name (new way)
|
||||
expected_options['table_name'] = "#{@user_1.database_schema}.\"#{table_name}\""
|
||||
|
||||
presenter_options = {
|
||||
viewer_user: @user_2,
|
||||
# New presenter way of sending a viewer that's different from the owner
|
||||
user: @user_1
|
||||
}
|
||||
|
||||
poro = instance_of_tested_class(layer_2, presenter_options).to_poro
|
||||
poro_options = poro.delete('options')
|
||||
|
||||
expect(poro).to include(expected_poro)
|
||||
expect(poro_options).to include(expected_options)
|
||||
|
||||
# old way
|
||||
|
||||
# change state always with old model to be sure
|
||||
layer_2 = ::Layer.where(id: layer_2.id).first
|
||||
layer_2.options = {
|
||||
'fake' => 'value',
|
||||
'table_name' => table_name,
|
||||
# Old presenter way of sending a viewer
|
||||
'user_name' => @user_1.username
|
||||
}
|
||||
layer_2.save
|
||||
layer_2 = instance_of_tested_model(layer_2)
|
||||
|
||||
expected_poro = {
|
||||
'id' => layer_2.id,
|
||||
'kind' => 'carto',
|
||||
'order' => 13,
|
||||
'options' => {
|
||||
'fake' => 'value',
|
||||
'table_name' => "#{@user_1.username}.\"#{table_name}\"",
|
||||
'user_name' => @user_1.username
|
||||
},
|
||||
'infowindow' => {
|
||||
'fake2' => 'val2'
|
||||
},
|
||||
'tooltip' => {
|
||||
'fake3' => 'val3'
|
||||
}
|
||||
}
|
||||
|
||||
presenter_options = {
|
||||
viewer_user: @user_2
|
||||
}
|
||||
|
||||
poro = instance_of_tested_class(layer_2, presenter_options).to_poro
|
||||
# Already changed to fully qualified expected table name, so no need to do it again
|
||||
poro_options = poro.delete('options')
|
||||
expected_options = expected_poro.delete('options')
|
||||
expect(poro).to include(expected_poro)
|
||||
expect(poro_options).to include(expected_options)
|
||||
|
||||
# Finally, don't change if already has a fully qualified table_name
|
||||
|
||||
layer_2 = ::Layer.where(id: layer_2.id).first
|
||||
layer_2.options = {
|
||||
'fake' => 'value',
|
||||
'table_name' => "fake.\"#{table_name}\"",
|
||||
# Old presenter way of sending a viewer
|
||||
'user_name' => @user_1.username
|
||||
}
|
||||
layer_2.save
|
||||
layer_2 = instance_of_tested_model(layer_2)
|
||||
|
||||
expected_options['table_name'] = "fake.\"#{table_name}\""
|
||||
|
||||
poro = instance_of_tested_class(layer_2, presenter_options).to_poro
|
||||
poro_options = poro.delete('options')
|
||||
expect(poro).to include(expected_poro)
|
||||
expect(poro_options).to include(expected_options)
|
||||
end
|
||||
|
||||
it 'Tests to_vizjson_v1()' do
|
||||
layer_parent = Layer.create({
|
||||
kind: 'tiled'
|
||||
})
|
||||
layer_parent = instance_of_tested_model(layer_parent)
|
||||
|
||||
layer = Layer.create({
|
||||
kind: 'carto',
|
||||
order: 5,
|
||||
options: {
|
||||
'fake' => 'value',
|
||||
'table_name' => 'my_test_table',
|
||||
'opt1' => 'val1',
|
||||
},
|
||||
infowindow: {
|
||||
'template' => nil,
|
||||
'fake2' => 'val2'
|
||||
},
|
||||
tooltip: { 'fake3' => 'val3' }
|
||||
})
|
||||
layer = instance_of_tested_model(layer)
|
||||
|
||||
expected_vizjson = {
|
||||
id: layer.id,
|
||||
kind: 'CartoDB',
|
||||
order: layer.order,
|
||||
infowindow: {
|
||||
'template' => nil,
|
||||
'fake2' => 'val2'
|
||||
},
|
||||
options: {
|
||||
'opt1' => 'val1'
|
||||
}
|
||||
}
|
||||
|
||||
presenter_options = { }
|
||||
|
||||
presenter_configuration = {
|
||||
layer_opts: {
|
||||
'public_opts' => {
|
||||
'whatever' => true,
|
||||
'opt1' => true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vizjson = instance_of_tested_class(layer, presenter_options, presenter_configuration).to_vizjson_v1
|
||||
vizjson.should == expected_vizjson
|
||||
|
||||
# Now full options
|
||||
|
||||
presenter_options = {
|
||||
# Full options
|
||||
full: true
|
||||
}
|
||||
|
||||
expected_vizjson[:options] = {
|
||||
'fake' => 'value',
|
||||
'table_name' => 'my_test_table',
|
||||
'opt1' => 'val1',
|
||||
}
|
||||
|
||||
vizjson = instance_of_tested_class(layer, presenter_options, presenter_configuration).to_vizjson_v1
|
||||
vizjson.should == expected_vizjson
|
||||
|
||||
# Now a base layer, which should be a poro with symbolized keys
|
||||
|
||||
vizjson = instance_of_tested_class(layer_parent).to_vizjson_v1
|
||||
vizjson[:id].should == layer_parent.id
|
||||
vizjson[:kind].should == layer_parent.kind
|
||||
end
|
||||
|
||||
it 'Tests to_vizjson_v2()' do
|
||||
maps_api_template = "http://{user}.localhost.lan:8181"
|
||||
sql_api_template = "http://{user}.localhost.lan:8080"
|
||||
|
||||
# Modules do not use '.any_instance' for stubbing
|
||||
ApplicationHelper.stubs(:maps_api_template).returns(maps_api_template)
|
||||
ApplicationHelper.stubs(:sql_api_template).returns(sql_api_template)
|
||||
|
||||
|
||||
stat_tag = '00000000-0000-0000-0000-000000000000'
|
||||
|
||||
layer_parent = Layer.create({
|
||||
kind: 'tiled'
|
||||
})
|
||||
layer_parent = instance_of_tested_model(layer_parent)
|
||||
|
||||
# Base, which should be a poro but with symbols
|
||||
|
||||
vizjson = instance_of_tested_class(layer_parent).to_vizjson_v2
|
||||
vizjson[:id].should == layer_parent.id
|
||||
vizjson[:kind].should == nil
|
||||
vizjson[:type].should == layer_parent.kind
|
||||
|
||||
presenter_options = {
|
||||
visualization_id: stat_tag
|
||||
}
|
||||
|
||||
|
||||
# torque layer with very basic options
|
||||
layer = Layer.create({
|
||||
kind: 'torque',
|
||||
options: {
|
||||
'table_name' => 'my_test_table',
|
||||
},
|
||||
})
|
||||
layer = instance_of_tested_model(layer)
|
||||
|
||||
expected_vizjson = {
|
||||
id: layer.id,
|
||||
type: layer.kind,
|
||||
order: layer.order,
|
||||
legend: nil,
|
||||
options: {
|
||||
stat_tag: stat_tag,
|
||||
maps_api_template: maps_api_template,
|
||||
sql_api_template: sql_api_template,
|
||||
tiler_protocol: nil,
|
||||
tiler_domain: nil,
|
||||
tiler_port: nil,
|
||||
sql_api_protocol: nil,
|
||||
sql_api_domain: nil,
|
||||
sql_api_endpoint: nil,
|
||||
sql_api_port: nil,
|
||||
layer_name: layer.options['table_name'],
|
||||
'table_name' => layer.options['table_name'],
|
||||
'query' => "select * from #{layer.options['table_name']}"
|
||||
}
|
||||
}
|
||||
|
||||
vizjson = instance_of_tested_class(layer, presenter_options).to_vizjson_v2
|
||||
vizjson.should == expected_vizjson
|
||||
|
||||
# torque layer, different viewer
|
||||
layer = Layer.create({
|
||||
kind: 'torque',
|
||||
options: {
|
||||
'table_name' => 'my_test_table',
|
||||
# This is only for compatibility with old LayerModule::Presenter, new one checkes in the presenter options
|
||||
'user_name' => @user_1.database_schema
|
||||
},
|
||||
})
|
||||
layer = instance_of_tested_model(layer)
|
||||
|
||||
expected_vizjson[:id] = layer.id
|
||||
# No special quoting
|
||||
expected_vizjson[:options]['query'] = "select * from public.#{layer.options['table_name']}"
|
||||
expected_vizjson[:options]['user_name'] = @user_1.database_schema
|
||||
|
||||
presenter_options = {
|
||||
visualization_id: stat_tag,
|
||||
viewer_user: @user_2,
|
||||
# New presenter way of sending a viewer that's different from the owner
|
||||
user: @user_1
|
||||
}
|
||||
|
||||
vizjson = instance_of_tested_class(layer, presenter_options).to_vizjson_v2
|
||||
vizjson.should == expected_vizjson
|
||||
|
||||
# torque layer, different viewer, UUID table name
|
||||
layer = Layer.create(
|
||||
kind: 'torque',
|
||||
options: {
|
||||
'table_name' => '000cd294-b124-4f82-b569-0f7fe41d2db8',
|
||||
# This is only for compatibility with old LayerModule::Presenter, new one checkes in the presenter options
|
||||
'user_name' => @user_1.database_schema
|
||||
}
|
||||
)
|
||||
layer = instance_of_tested_model(layer)
|
||||
|
||||
expected_vizjson[:id] = layer.id
|
||||
# No special quoting
|
||||
expected_vizjson[:options][:layer_name] = layer.options['table_name']
|
||||
expected_vizjson[:options]['table_name'] = layer.options['table_name']
|
||||
expected_vizjson[:options]['query'] = "select * from public.\"#{layer.options['table_name']}\""
|
||||
expected_vizjson[:options]['user_name'] = @user_1.database_schema
|
||||
|
||||
presenter_options = {
|
||||
visualization_id: stat_tag,
|
||||
viewer_user: @user_2,
|
||||
# New presenter way of sending a viewer that's different from the owner
|
||||
user: @user_1
|
||||
}
|
||||
|
||||
vizjson = instance_of_tested_class(layer, presenter_options).to_vizjson_v2
|
||||
vizjson.should == expected_vizjson
|
||||
|
||||
# torque layer, custom query
|
||||
layer = Layer.create({
|
||||
kind: 'torque',
|
||||
options: {
|
||||
'query' => 'SELECT * FROM my_test_table LIMIT 5',
|
||||
'table_name' => 'my_test_table',
|
||||
},
|
||||
})
|
||||
layer = instance_of_tested_model(layer)
|
||||
|
||||
presenter_options = {
|
||||
visualization_id: stat_tag
|
||||
}
|
||||
|
||||
expected_vizjson[:id] = layer.id
|
||||
expected_vizjson[:options][:layer_name] = layer.options['table_name']
|
||||
expected_vizjson[:options]['table_name'] = layer.options['table_name']
|
||||
expected_vizjson[:options]['query'] = layer.options['query']
|
||||
expected_vizjson[:options].delete('user_name')
|
||||
|
||||
vizjson = instance_of_tested_class(layer, presenter_options).to_vizjson_v2
|
||||
vizjson.should == expected_vizjson
|
||||
|
||||
# torque layer, with wrapping
|
||||
layer = Layer.create({
|
||||
kind: 'torque',
|
||||
options: {
|
||||
'query' => 'SELECT * FROM my_test_table LIMIT 5',
|
||||
'table_name' => 'my_test_table',
|
||||
'query_wrapper' => "select * from (<%= sql %>)",
|
||||
# This options shouldn't appear as is not listed at presnter TORQUE_ATTRS
|
||||
'wadus' => 'whatever'
|
||||
}
|
||||
})
|
||||
layer = instance_of_tested_model(layer)
|
||||
|
||||
presenter_options = {
|
||||
visualization_id: stat_tag
|
||||
}
|
||||
|
||||
expected_vizjson[:id] = layer.id
|
||||
expected_vizjson[:options]['query'] = "select * from (#{layer.options['query']})"
|
||||
|
||||
vizjson = instance_of_tested_class(layer, presenter_options).to_vizjson_v2
|
||||
vizjson.should == expected_vizjson
|
||||
|
||||
|
||||
# CartoDB layer, minimal options
|
||||
layer = Layer.create({
|
||||
kind: 'carto',
|
||||
options: {
|
||||
'table_name' => 'my_test_table',
|
||||
'style_version' => '2.1.1',
|
||||
'interactivity' => 'something'
|
||||
},
|
||||
})
|
||||
layer = instance_of_tested_model(layer)
|
||||
|
||||
presenter_options = {
|
||||
visualization_id: stat_tag
|
||||
}
|
||||
|
||||
expected_vizjson = {
|
||||
id: layer.id,
|
||||
type: 'CartoDB',
|
||||
order: layer.order,
|
||||
infowindow: nil,
|
||||
tooltip: nil,
|
||||
legend: nil,
|
||||
visible: nil,
|
||||
options: {
|
||||
sql: "select * from #{layer.options['table_name']}",
|
||||
layer_name: layer.options['table_name'],
|
||||
cartocss: @tested_class::EMPTY_CSS,
|
||||
cartocss_version: layer.options['style_version'],
|
||||
interactivity: layer.options['interactivity']
|
||||
}
|
||||
}
|
||||
|
||||
vizjson = instance_of_tested_class(layer, presenter_options).to_vizjson_v2
|
||||
vizjson.should == expected_vizjson
|
||||
|
||||
# CartoDB layer, non default fields filled. table_name UUID to check quoting
|
||||
layer = Layer.create(
|
||||
kind: 'carto',
|
||||
options: {
|
||||
'table_name' => '000cd294-b124-4f82-b569-0f7fe41d2db8',
|
||||
'style_version' => '2.1.1',
|
||||
'interactivity' => 'something',
|
||||
'tile_style' => '/* aaa */ #bbb{ marker-width: 12; } ',
|
||||
'legend' => {
|
||||
'type' => "custom",
|
||||
'show_title' => true,
|
||||
'title' => "xxx",
|
||||
'template' => "",
|
||||
'items' => [
|
||||
{
|
||||
'name' => "yyy",
|
||||
'visible' => true,
|
||||
'value' => "#ccc",
|
||||
'sync' => true
|
||||
}
|
||||
]
|
||||
},
|
||||
'visible' => true,
|
||||
# Shouldn't appear
|
||||
'wadus' => 'whatever'
|
||||
},
|
||||
infowindow: {
|
||||
'fields' => nil,
|
||||
'template_name' => "infowindow_light",
|
||||
'template' => "<div></div>",
|
||||
'alternative_names' => {},
|
||||
'width' => 200,
|
||||
'maxHeight' => 100
|
||||
},
|
||||
tooltip: {
|
||||
'fields' => nil,
|
||||
'template_name' => "tooltip_light",
|
||||
'template' => "<div></div>",
|
||||
'alternative_names' => {},
|
||||
'maxHeight' => 180
|
||||
}
|
||||
)
|
||||
layer = instance_of_tested_model(layer)
|
||||
|
||||
expected_vizjson = {
|
||||
id: layer.id,
|
||||
type: 'CartoDB',
|
||||
order: layer.order,
|
||||
infowindow: layer.infowindow,
|
||||
tooltip: layer.tooltip,
|
||||
legend: layer.legend,
|
||||
visible: true,
|
||||
options: {
|
||||
# yes... this ones come as symbols and not strings as the others (sigh)
|
||||
sql: "select * from \"#{layer.options['table_name']}\"",
|
||||
layer_name: layer.options['table_name'],
|
||||
cartocss: layer.options['tile_style'],
|
||||
cartocss_version: layer.options['style_version'],
|
||||
interactivity: layer.options['interactivity']
|
||||
}
|
||||
}
|
||||
|
||||
vizjson = instance_of_tested_class(layer, presenter_options).to_vizjson_v2
|
||||
vizjson.should == expected_vizjson
|
||||
|
||||
# CartoDB layer, non default fields filled
|
||||
layer = Layer.create({
|
||||
kind: 'carto',
|
||||
options: {
|
||||
'table_name' => 'my_test_table',
|
||||
'style_version' => '2.1.1',
|
||||
'interactivity' => 'something',
|
||||
'tile_style' => '/* aaa */ #bbb{ marker-width: 12; } ',
|
||||
'legend' => {
|
||||
'type' => "custom",
|
||||
'show_title' => true,
|
||||
'title' => "xxx",
|
||||
'template' => "",
|
||||
'items' => [
|
||||
{
|
||||
'name' => "yyy",
|
||||
'visible' => true,
|
||||
'value' => "#ccc",
|
||||
'sync' => true
|
||||
}
|
||||
]
|
||||
},
|
||||
'visible' => true,
|
||||
# Shouldn't appear
|
||||
'wadus' => 'whatever'
|
||||
},
|
||||
infowindow: {
|
||||
'fields' => nil,
|
||||
'template_name' => "infowindow_light",
|
||||
'template' => "<div></div>",
|
||||
'alternative_names' => { },
|
||||
'width' => 200,
|
||||
'maxHeight' => 100
|
||||
},
|
||||
tooltip: {
|
||||
'fields' => nil,
|
||||
'template_name' => "tooltip_light",
|
||||
'template' => "<div></div>",
|
||||
'alternative_names' => { },
|
||||
'maxHeight' => 180
|
||||
}
|
||||
})
|
||||
layer = instance_of_tested_model(layer)
|
||||
|
||||
expected_vizjson = {
|
||||
id: layer.id,
|
||||
type: 'CartoDB',
|
||||
order: layer.order,
|
||||
infowindow: layer.infowindow,
|
||||
tooltip: layer.tooltip,
|
||||
legend: layer.legend,
|
||||
visible: true,
|
||||
options: {
|
||||
# yes... this ones come as symbols and not strings as the others (sigh)
|
||||
sql: "select * from #{layer.options['table_name']}",
|
||||
layer_name: layer.options['table_name'],
|
||||
cartocss: layer.options['tile_style'],
|
||||
cartocss_version: layer.options['style_version'],
|
||||
interactivity: layer.options['interactivity']
|
||||
}
|
||||
}
|
||||
|
||||
vizjson = instance_of_tested_class(layer, presenter_options).to_vizjson_v2
|
||||
vizjson.should == expected_vizjson
|
||||
|
||||
# CartoDB layer with `Full` options flag
|
||||
layer = Layer.create({
|
||||
kind: 'carto',
|
||||
options: {
|
||||
'table_name' => 'my_test_table',
|
||||
'interactivity' => 'something',
|
||||
'wadus' => 'whatever'
|
||||
}
|
||||
})
|
||||
layer = instance_of_tested_model(layer)
|
||||
|
||||
presenter_options = {
|
||||
visualization_id: stat_tag,
|
||||
full: true
|
||||
}
|
||||
|
||||
expected_vizjson = {
|
||||
id: layer.id,
|
||||
type: 'CartoDB',
|
||||
order: layer.order,
|
||||
infowindow: nil,
|
||||
tooltip: nil,
|
||||
legend: nil,
|
||||
visible: nil,
|
||||
options: {
|
||||
'table_name' => layer.options['table_name'],
|
||||
'interactivity' => layer.options['interactivity'],
|
||||
'wadus' => 'whatever'
|
||||
}
|
||||
}
|
||||
|
||||
vizjson = instance_of_tested_class(layer, presenter_options).to_vizjson_v2
|
||||
puts vizjson.inspect
|
||||
vizjson.should == expected_vizjson
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,8 @@
|
||||
require_relative '../../../spec_helper'
|
||||
require_relative '../../../../app/models/layer/presenter'
|
||||
require_relative 'layer_presenter_shared_examples'
|
||||
|
||||
describe CartoDB::LayerModule::Presenter do
|
||||
# Old presenter, old model
|
||||
it_behaves_like 'layer presenters', CartoDB::LayerModule::Presenter, ::Layer
|
||||
end
|
||||
@@ -0,0 +1,3 @@
|
||||
shared_examples_for "overlays controllers" do
|
||||
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
require 'sequel'
|
||||
require 'rack/test'
|
||||
|
||||
shared_examples_for 'synchronization controllers' do
|
||||
include Rack::Test::Methods
|
||||
include Warden::Test::Helpers
|
||||
include CacheHelper
|
||||
|
||||
end
|
||||
@@ -0,0 +1,108 @@
|
||||
require_relative '../../../spec_helper'
|
||||
require_relative 'synchronizations_controller_shared_examples'
|
||||
require_relative '../../../../app/controllers/api/json/synchronizations_controller'
|
||||
|
||||
describe Api::Json::SynchronizationsController do
|
||||
include_context 'users helper'
|
||||
|
||||
it_behaves_like 'synchronization controllers' do
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
login(@user1)
|
||||
@user1.sync_tables_enabled = true
|
||||
@user1.save
|
||||
end
|
||||
|
||||
describe '#create' do
|
||||
let(:params) do
|
||||
{
|
||||
url: "fake_url",
|
||||
interval: 3600,
|
||||
content_guessing: true,
|
||||
type_guessing: true,
|
||||
create_vis: false
|
||||
}
|
||||
end
|
||||
|
||||
describe 'for users without sync tables' do
|
||||
before(:each) do
|
||||
@user1.sync_tables_enabled = false
|
||||
@user1.save
|
||||
end
|
||||
|
||||
it 'returns 401' do
|
||||
post_json api_v1_synchronizations_create_url(params) do |r|
|
||||
r.status.should eq 401
|
||||
end
|
||||
end
|
||||
|
||||
it 'creates a synchronization and enqueues a import job for external sources' do
|
||||
begin
|
||||
Resque::ImporterJobs.expects(:perform).once
|
||||
carto_visualization = FactoryGirl.create(:carto_visualization, user_id: @user1.id)
|
||||
external_source = FactoryGirl.create(:external_source, visualization: carto_visualization)
|
||||
remote_id = external_source.visualization_id
|
||||
|
||||
expect {
|
||||
post_json api_v1_synchronizations_create_url(params.merge(remote_visualization_id: remote_id)) do |r|
|
||||
r.status.should eq 200
|
||||
Carto::Synchronization.find(r.body[:id]).state.should eq Carto::Synchronization::STATE_QUEUED
|
||||
end
|
||||
}.to change { Carto::Synchronization.count }.by 1
|
||||
ensure
|
||||
external_source.external_data_imports.each(&:destroy)
|
||||
external_source.destroy
|
||||
carto_visualization.destroy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'creates a synchronization and enqueues a import job' do
|
||||
Resque::ImporterJobs.expects(:perform).once
|
||||
expect {
|
||||
post_json api_v1_synchronizations_create_url(params) do |r|
|
||||
r.status.should eq 200
|
||||
Carto::Synchronization.find(r.body[:id]).state.should eq Carto::Synchronization::STATE_QUEUED
|
||||
end
|
||||
}.to change { Carto::Synchronization.count }.by 1
|
||||
end
|
||||
end
|
||||
|
||||
describe '#sync_now' do
|
||||
it 'syncs... now :D' do
|
||||
sync = FactoryGirl.create(:carto_synchronization, user_id: @user1.id)
|
||||
sync.state.should eq Carto::Synchronization::STATE_SUCCESS
|
||||
Resque::SynchronizationJobs.expects(:perform).once
|
||||
put_json api_v1_synchronizations_sync_now_url(id: sync.id) do |r|
|
||||
r.status.should eq 200
|
||||
sync.reload
|
||||
sync.state.should eq Carto::Synchronization::STATE_QUEUED
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update' do
|
||||
it 'updates the interval' do
|
||||
sync = FactoryGirl.create(:carto_synchronization, user_id: @user1.id)
|
||||
new_interval = sync.interval * 2
|
||||
put_json api_v1_synchronizations_update_url(id: sync.id), interval: new_interval do |r|
|
||||
r.status.should eq 200
|
||||
sync.reload
|
||||
sync.interval.should eq new_interval
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#destroy' do
|
||||
it 'destroys a sync' do
|
||||
sync = FactoryGirl.create(:carto_synchronization, user_id: @user1.id)
|
||||
Carto::Synchronization.exists?(sync.id).should be_true
|
||||
delete_json api_v1_synchronizations_update_url(id: sync.id) do |r|
|
||||
r.status.should eq 204
|
||||
Carto::Synchronization.exists?(sync.id).should be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
require_relative '../../acceptance_helper'
|
||||
|
||||
feature "API 1.0 maps management" do
|
||||
|
||||
before(:all) do
|
||||
Capybara.current_driver = :rack_test
|
||||
@user = create_user({:username => 'test'})
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
bypass_named_maps
|
||||
delete_user_data @user
|
||||
end
|
||||
|
||||
after(:all) do
|
||||
bypass_named_maps
|
||||
@user.destroy
|
||||
end
|
||||
|
||||
scenario "Create a new map" do
|
||||
table = create_table(:user_id => @user.id)
|
||||
post_json v1_maps_url(:host => CartoDB.hostname.sub('http://', ''), :api_key => api_key), { :table_id => table.id } do |response|
|
||||
response.status.should be_success
|
||||
table.refresh
|
||||
table.map.should == Map[response.body[:id]]
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Create a new google map" do
|
||||
table = create_table(:user_id => @user.id)
|
||||
data = { table_id: table.id, center: "[41.68932225997044,-13.4912109375]", zoom: 5, minZoom: 0, maxZoom: 20, provider: "googlemaps", id: 24, user_id: 2,bounding_box_sw: "[0,0]", bounding_box_ne: "[0,0]" }
|
||||
|
||||
post_json v1_maps_url(:host => CartoDB.hostname.sub('http://', ''), :api_key => api_key), data do |response|
|
||||
response.status.should be_success
|
||||
table.refresh
|
||||
table.map.should == Map[response.body[:id]]
|
||||
response.body[:center].should == "[41.68932225997044,-13.4912109375]"
|
||||
response.body[:zoom].should == 5
|
||||
response.body[:bounding_box_sw].should == "[0,0]"
|
||||
response.body[:bounding_box_ne].should == "[0,0]"
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Can't create a map associated to another user's table" do
|
||||
another_user = create_user({:username => 'waldo'})
|
||||
table = create_table(:user_id => another_user.id)
|
||||
data = { table_id: table.id }
|
||||
|
||||
post_json v1_maps_url(:host => CartoDB.hostname.sub('http://', ''), :api_key => api_key), data do |response|
|
||||
response.status.should_not be_success
|
||||
end
|
||||
|
||||
another_user.destroy
|
||||
end
|
||||
|
||||
scenario "Update a map" do
|
||||
table = create_table(:user_id => @user.id)
|
||||
map = create_map(:user_id => @user.id, :table_id => table.id)
|
||||
|
||||
put_json v1_map_url(:host => CartoDB.hostname.sub('http://', ''), :api_key => api_key, :id => map.id), {:center => "center_value"} do |response|
|
||||
response.status.should be_success
|
||||
response.body[:id].should == map.id
|
||||
response.body[:center].should == "center_value"
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Drop a map" do
|
||||
table = create_table(:user_id => @user.id)
|
||||
map = create_map(:user_id => @user.id, :table_id => table.id)
|
||||
|
||||
delete_json v1_map_url(:host => CartoDB.hostname.sub('http://', ''), :api_key => api_key, :id => map.id) do |response|
|
||||
response.status.should eql(204)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,64 @@
|
||||
require_relative '../../acceptance_helper'
|
||||
|
||||
feature "API 1.0 queries management" do
|
||||
before(:all) do
|
||||
Capybara.current_driver = :rack_test
|
||||
@user = create_user({:username => 'test'})
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
bypass_named_maps
|
||||
delete_user_data @user
|
||||
@table = create_table :user_id => @user.id
|
||||
end
|
||||
|
||||
after(:all) do
|
||||
bypass_named_maps
|
||||
@user.destroy
|
||||
end
|
||||
|
||||
scenario "Get the results of a SELECT query" do
|
||||
50.times do |i|
|
||||
@table.insert_row!({:name => "Row number #{i}", :description => String.random(50), :the_geom => %Q{\{"type":"Point","coordinates":[40.392949,-3.69084]\}}})
|
||||
end
|
||||
|
||||
get_json api_queries_url(:sql => "SELECT * FROM #{@table.name} ORDER BY cartodb_id ASC LIMIT 10", :rows_per_page => 2) do |response|
|
||||
response.status.should be_success
|
||||
response.body[:rows].size.should == 2
|
||||
response.body[:rows][0]["name"].should == "Row number 0"
|
||||
response.body[:rows][1]["name"].should == "Row number 1"
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Get the results of a UPDATE query" do
|
||||
50.times do |i|
|
||||
@table.insert_row!({:name => "Row number #{i}", :description => String.random(50), :the_geom => %Q{\{"type":"Point","coordinates":[40.392949,-3.69084]\}}})
|
||||
end
|
||||
|
||||
get_json api_queries_url(:sql => "UPDATE #{@table.name} SET description = NULL WHERE cartodb_id < 13", :rows_per_page => 2) do |response|
|
||||
response.status.should be_success
|
||||
response.body[:rows].size.should == 0
|
||||
response.body[:affected_rows].should == 12
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Get the results of a DELETE query" do
|
||||
50.times do |i|
|
||||
@table.insert_row!({:name => "Row number #{i}", :description => String.random(50), :the_geom => %Q{\{"type":"Point","coordinates":[40.392949,-3.69084]\}}})
|
||||
end
|
||||
|
||||
get_json api_queries_url(:sql => "DELETE FROM #{@table.name} WHERE cartodb_id < 13", :rows_per_page => 2) do |response|
|
||||
response.status.should be_success
|
||||
response.body[:rows].size.should == 0
|
||||
response.body[:affected_rows].should == 12
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
scenario "Get the results of a query involving system tables" do
|
||||
get_json api_queries_url(:sql => "SELECT datname FROM pg_database;", :rows_per_page => 2) do |response|
|
||||
response.status.should == 400
|
||||
response.body[:errors].should == ["System tables are forbidden"]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,90 @@
|
||||
require 'sequel'
|
||||
require 'rack/test'
|
||||
require 'json'
|
||||
require 'uri'
|
||||
|
||||
require_relative '../../spec_helper'
|
||||
require_relative '../../../app/controllers/api/json/synchronizations_controller'
|
||||
require_relative '../../../services/data-repository/backend/sequel'
|
||||
|
||||
include CartoDB
|
||||
|
||||
def app
|
||||
CartoDB::Application.new
|
||||
end
|
||||
|
||||
describe Api::Json::SynchronizationsController do
|
||||
include Rack::Test::Methods
|
||||
|
||||
before(:all) do
|
||||
|
||||
@user = create_user(
|
||||
sync_tables_enabled: true
|
||||
)
|
||||
@api_key = @user.api_key
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
@db = SequelRails.connection
|
||||
Sequel.extension(:pagination)
|
||||
|
||||
CartoDB::Synchronization.repository = DataRepository::Backend::Sequel.new(@db, :synchronizations)
|
||||
|
||||
bypass_named_maps
|
||||
delete_user_data @user
|
||||
@headers = {
|
||||
'CONTENT_TYPE' => 'application/json'
|
||||
}
|
||||
host! "#{@user.username}.localhost.lan"
|
||||
end
|
||||
|
||||
after(:all) do
|
||||
bypass_named_maps
|
||||
@user.destroy
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/synchronizations' do
|
||||
it 'creates a synchronization' do
|
||||
payload = {
|
||||
table_name: 'table_1',
|
||||
interval: 3600,
|
||||
url: 'http://www.foo.com'
|
||||
}
|
||||
|
||||
post "/api/v1/synchronizations?api_key=#{@api_key}", payload.to_json, @headers
|
||||
last_response.status.should == 200
|
||||
|
||||
response = JSON.parse(last_response.body)
|
||||
response.fetch('id').should_not be_empty
|
||||
response.fetch('name').should_not be_empty
|
||||
end
|
||||
|
||||
it 'respond error 400 if interval is beneath 15 minutes' do
|
||||
payload = {
|
||||
table_name: 'table_1',
|
||||
interval: 60,
|
||||
url: 'http://www.foo.com'
|
||||
}
|
||||
|
||||
post "/api/v1/synchronizations?api_key=#{@api_key}", payload.to_json, @headers
|
||||
last_response.status.should eq 400
|
||||
last_response.body.to_str.should match /15 minutes/
|
||||
end
|
||||
|
||||
it 'schedules an import' do
|
||||
payload = {
|
||||
table_name: 'table_1',
|
||||
interval: 3600,
|
||||
url: 'http://www.foo.com'
|
||||
}
|
||||
|
||||
post "/api/v1/synchronizations?api_key=#{@api_key}", payload.to_json, @headers
|
||||
last_response.status.should == 200
|
||||
|
||||
response = JSON.parse(last_response.body)
|
||||
response.fetch('data_import').should_not be_empty
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,277 @@
|
||||
require 'sequel'
|
||||
require 'rack/test'
|
||||
require 'json'
|
||||
require 'uri'
|
||||
require_relative '../../spec_helper'
|
||||
require_relative '../../../services/data-repository/backend/sequel'
|
||||
require 'helpers/unique_names_helper'
|
||||
|
||||
describe Carto::Api::VisualizationsController do
|
||||
include UniqueNamesHelper
|
||||
include Rack::Test::Methods
|
||||
include DataRepository
|
||||
|
||||
before(:all) do
|
||||
CartoDB::Varnish.any_instance.stubs(:send_command).returns(true)
|
||||
@user = create_user(
|
||||
private_tables_enabled: true,
|
||||
private_maps_enabled: true
|
||||
)
|
||||
@api_key = @user.api_key
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
CartoDB::Varnish.any_instance.stubs(:send_command).returns(true)
|
||||
bypass_named_maps_requests
|
||||
|
||||
begin
|
||||
delete_user_data @user
|
||||
rescue => exception
|
||||
# Silence named maps problems only here upon data cleaning, not in specs
|
||||
raise unless exception.class.to_s == 'CartoDB::NamedMapsWrapper::HTTPResponseError'
|
||||
end
|
||||
|
||||
@headers = {
|
||||
'CONTENT_TYPE' => 'application/json'
|
||||
}
|
||||
host! "#{@user.username}.localhost.lan"
|
||||
end
|
||||
|
||||
after(:all) do
|
||||
bypass_named_maps
|
||||
@user.destroy
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/viz' do
|
||||
it 'creates a visualization' do
|
||||
payload = factory.merge(type: 'table')
|
||||
|
||||
post "/api/v1/viz?api_key=#{@api_key}", payload.to_json, @headers
|
||||
|
||||
last_response.status.should == 200
|
||||
response = JSON.parse(last_response.body)
|
||||
response.fetch('tags') .should == payload.fetch(:tags)
|
||||
response.fetch('map_id') .should == payload.fetch(:map_id)
|
||||
response.fetch('description') .should == payload.fetch(:description)
|
||||
|
||||
id = response.fetch('id')
|
||||
|
||||
get "/api/v1/viz/#{id}?api_key=#{@api_key}", {}, @headers
|
||||
last_response.status.should == 200
|
||||
|
||||
response = JSON.parse(last_response.body)
|
||||
response.fetch('name') .should_not == nil
|
||||
response.fetch('tags') .should_not == payload.fetch(:tags).to_json
|
||||
response.keys.should_not include 'related'
|
||||
end
|
||||
|
||||
it 'creates a visualization from a source_visualization_id' do
|
||||
table = table_factory
|
||||
source_visualization = table.fetch('table_visualization')
|
||||
|
||||
payload = { source_visualization_id: source_visualization.fetch('id') }
|
||||
|
||||
post "/api/v1/viz?api_key=#{@api_key}", payload.to_json, @headers
|
||||
last_response.status.should == 200
|
||||
response = JSON.parse(last_response.body)
|
||||
id = response.fetch('id')
|
||||
|
||||
CartoDB::Visualization::Member.new(id: id).fetch.derived?.should be_true
|
||||
end
|
||||
|
||||
it 'creates a private visualization from a private table' do
|
||||
table1 = table_factory(privacy: 0)
|
||||
source_visualization_id = table1.fetch('table_visualization').fetch('id')
|
||||
payload = { source_visualization_id: source_visualization_id }
|
||||
|
||||
post "/api/v1/viz?api_key=#{@api_key}", payload.to_json, @headers
|
||||
last_response.status.should == 200
|
||||
|
||||
visualization = JSON.parse(last_response.body)
|
||||
visualization.fetch('privacy').should == 'PRIVATE'
|
||||
end
|
||||
|
||||
it 'creates a private visualization if any table in the list is private' do
|
||||
table3 = table_factory(privacy: 0)
|
||||
|
||||
payload = {
|
||||
name: 'new visualization',
|
||||
tables: [table3.fetch('name')]
|
||||
}
|
||||
|
||||
post "/api/v1/viz?api_key=#{@api_key}", payload.to_json, @headers
|
||||
last_response.status.should == 200
|
||||
|
||||
visualization = JSON.parse(last_response.body)
|
||||
visualization.fetch('privacy').should == 'PRIVATE'
|
||||
end
|
||||
|
||||
it 'creates a private visualization if any table in the list is private' do
|
||||
table1 = table_factory
|
||||
table2 = table_factory
|
||||
table3 = table_factory(privacy: 0)
|
||||
|
||||
payload = {
|
||||
name: 'new visualization',
|
||||
tables: [
|
||||
table1.fetch('name'),
|
||||
table2.fetch('name'),
|
||||
table3.fetch('name')
|
||||
],
|
||||
privacy: 'public'
|
||||
}
|
||||
|
||||
post "/api/v1/viz?api_key=#{@api_key}", payload.to_json, @headers
|
||||
last_response.status.should == 200
|
||||
|
||||
visualization = JSON.parse(last_response.body)
|
||||
visualization.fetch('privacy').should == 'PRIVATE'
|
||||
end
|
||||
|
||||
it 'assigns a generated name if name taken' do
|
||||
table = table_factory
|
||||
visualization = table.fetch('table_visualization')
|
||||
visualization_name = visualization.fetch('name')
|
||||
|
||||
payload = {
|
||||
source_visualization_id: visualization.fetch('id'),
|
||||
name: visualization_name
|
||||
}
|
||||
|
||||
post "/api/v1/viz?api_key=#{@api_key}", payload.to_json, @headers
|
||||
last_response.status.should == 200
|
||||
|
||||
response = JSON.parse(last_response.body)
|
||||
response.fetch('name').should =~ /#{visualization_name} 1/
|
||||
end
|
||||
end # POST /api/v1/viz
|
||||
|
||||
describe 'PUT /api/v1/viz/:id' do
|
||||
it 'updates an existing visualization' do
|
||||
payload = factory
|
||||
post "/api/v1/viz?api_key=#{@api_key}", payload.to_json, @headers
|
||||
|
||||
response = JSON.parse(last_response.body)
|
||||
id = response.fetch('id')
|
||||
|
||||
response.fetch('tags').should == ['foo', 'bar']
|
||||
|
||||
put "/api/v1/viz/#{id}?api_key=#{@api_key}", { name: 'changed', tags: [], id: id }.to_json, @headers
|
||||
last_response.status.should == 200
|
||||
response = JSON.parse(last_response.body)
|
||||
response.fetch('name').should == 'changed'
|
||||
response.fetch('tags').should == []
|
||||
end
|
||||
|
||||
it 'updates the table in a table visualization', now: true do
|
||||
table_attributes = table_factory
|
||||
id = table_attributes.fetch('table_visualization').fetch('id')
|
||||
|
||||
Delorean.jump(1.minute)
|
||||
put "/api/v1/viz/#{id}?api_key=#{@api_key}", { name: 'changed name', id: id }.to_json, @headers
|
||||
Delorean.back_to_the_present
|
||||
last_response.status.should == 200
|
||||
response = JSON.parse(last_response.body)
|
||||
|
||||
response.fetch('table').fetch('updated_at').should_not == table_attributes.fetch('updated_at')
|
||||
end
|
||||
|
||||
it 'returns a downcased name' do
|
||||
table_attributes = table_factory
|
||||
id = table_attributes.fetch('table_visualization').fetch('id')
|
||||
|
||||
put "/api/v1/viz/#{id}?api_key=#{@api_key}", { name: 'CHANGED_NAME', id: id }.to_json, @headers
|
||||
last_response.status.should == 200
|
||||
response = JSON.parse(last_response.body)
|
||||
response.fetch('name').should == 'changed_name'
|
||||
|
||||
get "/api/v1/viz/#{id}?api_key=#{@api_key}", {}, @headers
|
||||
response = JSON.parse(last_response.body)
|
||||
response.fetch('name').should == 'changed_name'
|
||||
end
|
||||
|
||||
it 'returns a sanitized name' do
|
||||
table_attributes = table_factory
|
||||
id = table_attributes.fetch('table_visualization').fetch('id')
|
||||
|
||||
put "/api/v1/viz/#{id}?api_key=#{@api_key}", { name: 'changed name', id: id }.to_json, @headers
|
||||
last_response.status.should == 200
|
||||
response = JSON.parse(last_response.body)
|
||||
response.fetch('name').should == 'changed_name'
|
||||
|
||||
get "/api/v1/viz/#{id}?api_key=#{@api_key}", {}, @headers
|
||||
response = JSON.parse(last_response.body)
|
||||
response.fetch('name').should == 'changed_name'
|
||||
end
|
||||
end # PUT /api/v1/viz/:id
|
||||
|
||||
describe 'DELETE /api/v1/viz/:id' do
|
||||
it 'deletes the visualization' do
|
||||
payload = factory
|
||||
post "/api/v1/viz?api_key=#{@api_key}",
|
||||
payload.to_json, @headers
|
||||
|
||||
id = JSON.parse(last_response.body).fetch('id')
|
||||
get "/api/v1/viz/#{id}?api_key=#{@api_key}", {}, @headers
|
||||
last_response.status.should == 200
|
||||
|
||||
delete "/api/v1/viz/#{id}?api_key=#{@api_key}", {}, @headers
|
||||
last_response.status.should == 204
|
||||
last_response.body.should be_empty
|
||||
|
||||
get "/api/v1/viz/#{id}?api_key=#{@api_key}", {}, @headers
|
||||
last_response.status.should == 404
|
||||
end
|
||||
|
||||
it 'deletes the associated table' do
|
||||
table_attributes = table_factory
|
||||
table_id = table_attributes.fetch('id')
|
||||
|
||||
get "/api/v1/tables/#{table_id}?api_key=#{@api_key}", {}, @headers
|
||||
last_response.status.should == 200
|
||||
table = JSON.parse(last_response.body)
|
||||
visualization_id = table.fetch('table_visualization').fetch('id')
|
||||
|
||||
delete "/api/v1/viz/#{visualization_id}?api_key=#{@api_key}", {}, @headers
|
||||
last_response.status.should == 204
|
||||
|
||||
get "/api/v1/tables/#{table_id}?api_key=#{@api_key}", {}, @headers
|
||||
last_response.status.should == 404
|
||||
end
|
||||
end # DELETE /api/v1/viz/:id
|
||||
|
||||
# Visualizations are always created with default_privacy
|
||||
def factory(attributes={})
|
||||
{
|
||||
name: attributes.fetch(:name, unique_name('viz')),
|
||||
tags: attributes.fetch(:tags, ['foo', 'bar']),
|
||||
map_id: attributes.fetch(:map_id, ::Map.create(user_id: @user.id).id),
|
||||
description: attributes.fetch(:description, 'bogus'),
|
||||
type: attributes.fetch(:type, 'derived'),
|
||||
privacy: attributes.fetch(:privacy, 'public'),
|
||||
source_visualization_id: attributes.fetch(:source_visualization_id, nil),
|
||||
parent_id: attributes.fetch(:parent_id, nil),
|
||||
locked: attributes.fetch(:locked, false),
|
||||
prev_id: attributes.fetch(:prev_id, nil),
|
||||
next_id: attributes.fetch(:next_id, nil)
|
||||
}
|
||||
end
|
||||
|
||||
def table_factory(options={})
|
||||
privacy = options.fetch(:privacy, 1)
|
||||
|
||||
name = unique_name('table')
|
||||
payload = {
|
||||
name: name,
|
||||
description: "#{name} description"
|
||||
}
|
||||
post "/api/v1/tables?api_key=#{@api_key}", payload.to_json, @headers
|
||||
|
||||
table_attributes = JSON.parse(last_response.body)
|
||||
table_id = table_attributes.fetch('table_visualization').fetch("id")
|
||||
|
||||
put "/api/v1/viz/#{table_id}?api_key=#{@api_key}", { privacy: privacy }.to_json, @headers
|
||||
|
||||
table_attributes
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user