311 lines
13 KiB
Ruby
311 lines
13 KiB
Ruby
|
require_relative '../../../spec_helper'
|
||
|
require_relative '../../api/json/geocodings_controller_shared_examples'
|
||
|
require_relative '../../../../app/controllers/carto/api/geocodings_controller'
|
||
|
require 'mock_redis'
|
||
|
|
||
|
describe Carto::Api::GeocodingsController do
|
||
|
it_behaves_like 'geocoding controllers' do
|
||
|
end
|
||
|
|
||
|
describe 'legacy behaviour tests' do
|
||
|
let(:params) { { :api_key => @user.api_key } }
|
||
|
|
||
|
before(:all) do
|
||
|
@user = create_user
|
||
|
end
|
||
|
|
||
|
before(:each) do
|
||
|
bypass_named_maps
|
||
|
delete_user_data @user
|
||
|
host! "#{@user.username}.localhost.lan"
|
||
|
login_as(@user, scope: @user.username)
|
||
|
end
|
||
|
|
||
|
after(:all) do
|
||
|
bypass_named_maps
|
||
|
@user.destroy
|
||
|
end
|
||
|
|
||
|
describe 'GET /api/v1/geocodings' do
|
||
|
|
||
|
it 'returns every geocoding belonging to current_user' do
|
||
|
FactoryGirl.create(:geocoding, table_name: 'a', formatter: 'b', user: @user, state: 'wadus')
|
||
|
FactoryGirl.create(:geocoding, table_name: 'a', formatter: 'b', user_id: Carto::UUIDHelper.random_uuid)
|
||
|
get_json api_v1_geocodings_index_url(params) do |response|
|
||
|
response.status.should be_success
|
||
|
response.body[:geocodings].size.should == 1
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe 'GET /api/v1/geocodings/:id' do
|
||
|
|
||
|
it 'returns a geocoding' do
|
||
|
@user.geocoder_provider = 'heremaps'
|
||
|
@user.save.reload
|
||
|
redis_mock = MockRedis.new
|
||
|
user_geocoder_metrics = CartoDB::GeocoderUsageMetrics.new(@user.username, _orgname = nil, _redis = redis_mock)
|
||
|
CartoDB::GeocoderUsageMetrics.stubs(:new).returns(user_geocoder_metrics)
|
||
|
user_geocoder_metrics.incr(:geocoder_here, :success_responses, 100)
|
||
|
geocoding = FactoryGirl.create(:geocoding, table_id: Carto::UUIDHelper.random_uuid, formatter: 'b', user: @user, used_credits: 100, processed_rows: 100, kind: 'high-resolution')
|
||
|
|
||
|
get_json api_v1_geocodings_show_url(params.merge(id: geocoding.id)) do |response|
|
||
|
response.status.should be_success
|
||
|
response.body[:id].should eq geocoding.id
|
||
|
response.body[:used_credits].should eq 100
|
||
|
response.body[:price].should eq 150
|
||
|
response.body[:remaining_quota].should eq 900
|
||
|
end
|
||
|
end
|
||
|
|
||
|
it 'does not return a geocoding owned by another user' do
|
||
|
geocoding = FactoryGirl.create(:geocoding, table_id: Carto::UUIDHelper.random_uuid, formatter: 'b', user_id: Carto::UUIDHelper.random_uuid)
|
||
|
|
||
|
get_json api_v1_geocodings_show_url(params.merge(id: geocoding.id)) do |response|
|
||
|
response.status.should eq 404
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe 'GET /api/v1/geocodings/estimation_for' do
|
||
|
|
||
|
it 'returns the estimated geocoding cost for the specified table' do
|
||
|
table = create_table(user_id: @user.id)
|
||
|
Geocoding.stubs(:processable_rows).returns(2)
|
||
|
Carto::Geocoding.stubs(:processable_rows).returns(2)
|
||
|
get_json api_v1_geocodings_estimation_url(params.merge(table_name: table.name)) do |response|
|
||
|
response.status.should be_success
|
||
|
response.body.should == {:rows=>2, :estimation=>0}
|
||
|
end
|
||
|
Geocoding.stubs(:processable_rows).returns(1400)
|
||
|
Carto::Geocoding.stubs(:processable_rows).returns(1400)
|
||
|
get_json api_v1_geocodings_estimation_url(params.merge(table_name: table.name)) do |response|
|
||
|
response.status.should be_success
|
||
|
response.body.should == {:rows=>1400, :estimation=>600}
|
||
|
end
|
||
|
Geocoding.stubs(:processable_rows).returns(1001)
|
||
|
Carto::Geocoding.stubs(:processable_rows).returns(1001)
|
||
|
get_json api_v1_geocodings_estimation_url(params.merge(table_name: table.name)) do |response|
|
||
|
response.status.should be_success
|
||
|
response.body.should == {:rows=>1001, :estimation=>1.5}
|
||
|
end
|
||
|
end
|
||
|
|
||
|
it 'returns 500 if the table does not exist' do
|
||
|
get_json api_v1_geocodings_estimation_url(params.merge(table_name: 'me_not_exist')) do |response|
|
||
|
response.status.should eq 500
|
||
|
response.body[:description].should_not be_blank
|
||
|
end
|
||
|
end
|
||
|
|
||
|
it 'takes the parameter force_all_rows into consideration' do
|
||
|
@user.geocoding_quota = 0
|
||
|
@user.save
|
||
|
table = create_table(user_id: @user.id)
|
||
|
table.add_column!(name: 'cartodb_georef_status', type: 'bool')
|
||
|
table.insert_row!(cartodb_georef_status: nil)
|
||
|
table.insert_row!(cartodb_georef_status: true)
|
||
|
table.insert_row!(cartodb_georef_status: false)
|
||
|
|
||
|
expected_rows = 2
|
||
|
expected_estimation = expected_rows * @user.geocoding_block_price / Carto::Geocoding::GEOCODING_BLOCK_SIZE
|
||
|
get_json api_v1_geocodings_estimation_url(params.merge(table_name: table.name, force_all_rows: false)) do |response|
|
||
|
response.status.should be_success
|
||
|
response.body.should == {rows: expected_rows, estimation: expected_estimation}
|
||
|
end
|
||
|
|
||
|
expected_rows = 3
|
||
|
expected_estimation = expected_rows * @user.geocoding_block_price / Carto::Geocoding::GEOCODING_BLOCK_SIZE
|
||
|
get_json api_v1_geocodings_estimation_url(params.merge(table_name: table.name, force_all_rows: true)) do |response|
|
||
|
response.status.should be_success
|
||
|
response.body.should == {rows: expected_rows, estimation: expected_estimation}
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
describe 'available_geometries' do
|
||
|
include_context 'users helper'
|
||
|
include_context 'visualization creation helpers'
|
||
|
|
||
|
before(:each) do
|
||
|
login(@user1)
|
||
|
end
|
||
|
|
||
|
it 'returns 400 if kind is not admin1, namedplace or postalcode' do
|
||
|
get api_v1_geocodings_available_geometries_url, { kind: 'kk'}
|
||
|
last_response.status.should == 400
|
||
|
end
|
||
|
|
||
|
it 'returns "polygon" for "admin1" kind' do
|
||
|
get api_v1_geocodings_available_geometries_url, { kind: 'admin1'}
|
||
|
last_response.status.should == 200
|
||
|
JSON.parse(last_response.body).should eq ['polygon']
|
||
|
end
|
||
|
|
||
|
it 'returns "point" for "namedplace" kind' do
|
||
|
get api_v1_geocodings_available_geometries_url, { kind: 'namedplace'}
|
||
|
last_response.status.should == 200
|
||
|
JSON.parse(last_response.body).should eq ['point']
|
||
|
end
|
||
|
|
||
|
it 'returns 400 for postal code if "free_text" or "column_name" and "table_name" are not set' do
|
||
|
get api_v1_geocodings_available_geometries_url, { kind: 'postalcode'}
|
||
|
last_response.status.should == 400
|
||
|
end
|
||
|
|
||
|
it 'returns empty json for postalcode if free text is empty or has non alphanumeric characters' do
|
||
|
get api_v1_geocodings_available_geometries_url, { kind: 'postalcode', free_text: ''}
|
||
|
last_response.status.should == 200
|
||
|
JSON.parse(last_response.body).should eq []
|
||
|
|
||
|
get api_v1_geocodings_available_geometries_url, { kind: 'postalcode', free_text: ' '}
|
||
|
last_response.status.should == 200
|
||
|
JSON.parse(last_response.body).should eq []
|
||
|
|
||
|
get api_v1_geocodings_available_geometries_url, { kind: 'postalcode', free_text: '--%'}
|
||
|
last_response.status.should == 200
|
||
|
JSON.parse(last_response.body).should eq []
|
||
|
end
|
||
|
|
||
|
it 'returns point and polygon if SQLApi says there are the same amount of points and polygons services, or the one with more data if they are not equal' do
|
||
|
# INFO: this expectation is bound to implementation because it's used in a refactor
|
||
|
CartoDB::SQLApi.any_instance.expects(:fetch).with("SELECT (admin0_available_services(Array['myfreetext'])).*").returns([ { 'postal_code_points' => 1, 'postal_code_polygons' => 1 }])
|
||
|
get api_v1_geocodings_available_geometries_url, { kind: 'postalcode', free_text: 'my free text'}
|
||
|
JSON.parse(last_response.body).should eq ['point', 'polygon']
|
||
|
|
||
|
CartoDB::SQLApi.any_instance.stubs(:fetch).returns([ { 'postal_code_points' => 1, 'postal_code_polygons' => 1 }, { 'postal_code_points' => 1 }])
|
||
|
get api_v1_geocodings_available_geometries_url, { kind: 'postalcode', free_text: 'my free text'}
|
||
|
JSON.parse(last_response.body).should eq ['point']
|
||
|
|
||
|
CartoDB::SQLApi.any_instance.stubs(:fetch).returns([ { 'postal_code_points' => 1, 'postal_code_polygons' => 1 }, { 'postal_code_polygons' => 1 }])
|
||
|
get api_v1_geocodings_available_geometries_url, { kind: 'postalcode', free_text: 'my free text'}
|
||
|
JSON.parse(last_response.body).should eq ['polygon']
|
||
|
end
|
||
|
|
||
|
it 'returns point from an input column if SQLApi says there is a point service for it' do
|
||
|
table = create_table(user_id: @user1.id)
|
||
|
table.add_column!(name: 'country', type: 'string')
|
||
|
table.insert_row!(country: 'Cote d\'Ivore')
|
||
|
|
||
|
CartoDB::SQLApi.any_instance.expects(:fetch).
|
||
|
with("SELECT (admin0_available_services(Array['Cote d''Ivore'])).*").
|
||
|
returns([{ 'postal_code_points' => 1, 'postal_code_polygons' => 0 }])
|
||
|
get api_v1_geocodings_available_geometries_url,
|
||
|
{ kind: 'postalcode', column_name: 'country', table_name: table.name }
|
||
|
last_response.status.should == 200
|
||
|
end
|
||
|
|
||
|
it 'returns 400 if table name does not exist' do
|
||
|
get api_v1_geocodings_available_geometries_url, { kind: 'postalcode', column_name: 'my_column', table_name: 'my_table'}
|
||
|
last_response.status.should eq 400
|
||
|
end
|
||
|
|
||
|
it 'Queries SQL API with table columns' do
|
||
|
cp = 12345
|
||
|
table = create_random_table(@user1)
|
||
|
table.insert_row!({name: cp})
|
||
|
|
||
|
# INFO: this expectation is bound to implementation because it's used in a refactor
|
||
|
CartoDB::SQLApi.any_instance.expects(:fetch).with("SELECT (admin0_available_services(Array['#{cp}'])).*").returns([ { 'postal_code_points' => 1, 'postal_code_polygons' => 1 }, { 'postal_code_polygons' => 1 }])
|
||
|
get api_v1_geocodings_available_geometries_url, { kind: 'postalcode', column_name: 'name', table_name: table.name}
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
describe 'estimation_for' do
|
||
|
include_context 'users helper'
|
||
|
include_context 'visualization creation helpers'
|
||
|
|
||
|
before(:each) do
|
||
|
login(@user1)
|
||
|
end
|
||
|
|
||
|
it 'returns estimation and price' do
|
||
|
table = create_random_table(@user1)
|
||
|
table.insert_row!({name: 'estimation'})
|
||
|
|
||
|
get api_v1_geocodings_estimation_url(table_name: table.name)
|
||
|
last_response.status.should eq 200
|
||
|
body = JSON.parse(last_response.body)
|
||
|
body.should == { 'rows' => 1, 'estimation' => 0 }
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
def remove_dates(geocoding_hash)
|
||
|
geocoding_hash.except('created_at', 'updated_at')
|
||
|
end
|
||
|
|
||
|
describe 'index' do
|
||
|
include_context 'users helper'
|
||
|
|
||
|
before(:each) do
|
||
|
login(@user1)
|
||
|
end
|
||
|
|
||
|
it 'returns started geocodings but not finished' do
|
||
|
geocoding1 = FactoryGirl.create(:geocoding, user: @user1, kind: 'high-resolution', created_at: Time.now,
|
||
|
processed_rows: 1, state: 'started', formatter: 'foo')
|
||
|
FactoryGirl.create(:geocoding, user: @user1, kind: 'high-resolution', created_at: Time.now,
|
||
|
processed_rows: 1, state: 'finished', formatter: 'foo')
|
||
|
|
||
|
get api_v1_geocodings_index_url
|
||
|
last_response.status.should eq 200
|
||
|
|
||
|
expected = {"geocodings"=>[{"table_name" => nil, "processed_rows" => 1, "remote_id" => nil, "formatter" => 'foo',
|
||
|
"geocoder_type" => nil, "state" => "started", "cache_hits" => 0,
|
||
|
"id" => geocoding1.id, "user_id" => @user1.id,"table_id" => nil,
|
||
|
"kind" => "high-resolution", "country_code" => nil,
|
||
|
"geometry_type" => nil, "processable_rows" => nil, "real_rows" => nil,
|
||
|
"used_credits" => nil, "country_column" => nil, "data_import_id" => nil,
|
||
|
"region_code" => nil, "region_column" => nil, "batched" => nil, "error_code" => nil,
|
||
|
"force_all_rows" => false, "log_id" => nil, "pid" => nil}]}
|
||
|
received_without_dates = {
|
||
|
'geocodings' => JSON.parse(last_response.body)['geocodings'].map { |g| remove_dates(g) }
|
||
|
}
|
||
|
received_without_dates.should == expected
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
describe 'show' do
|
||
|
include_context 'users helper'
|
||
|
|
||
|
before(:each) do
|
||
|
login(@user1)
|
||
|
end
|
||
|
|
||
|
it 'returns requested geocoding' do
|
||
|
geocoding = FactoryGirl.create(
|
||
|
:geocoding,
|
||
|
user: @user1,
|
||
|
kind: 'high-resolution',
|
||
|
created_at: Time.now,
|
||
|
processed_rows: 1,
|
||
|
state: 'started',
|
||
|
formatter: 'foo'
|
||
|
)
|
||
|
|
||
|
get api_v1_geocodings_show_url(id: geocoding.id)
|
||
|
last_response.status.should eq 200
|
||
|
|
||
|
expected = {"id" => geocoding.id, "table_id" => nil, "table_name" => nil, "state" => "started",
|
||
|
"kind" => "high-resolution", "country_code" => nil, "region_code" => nil, "formatter" => 'foo',
|
||
|
"geocoder_type" => nil, "geometry_type" => nil, "error" => {"title" => "Geocoding error",
|
||
|
"description" => ""}, "processed_rows" => 1, "cache_hits" => 0, "processable_rows" => nil,
|
||
|
"real_rows" => nil, "price" => 0, "used_credits" => nil, "remaining_quota" => 0,
|
||
|
"country_column" => nil, "region_column" => nil, "data_import_id" => nil, "error_code" => nil}
|
||
|
received_without_dates = remove_dates(JSON.parse(last_response.body))
|
||
|
received_without_dates.should == expected
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
include Rack::Test::Methods
|
||
|
include Warden::Test::Helpers
|
||
|
end
|