278 lines
9.5 KiB
Ruby
278 lines
9.5 KiB
Ruby
|
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 StandardError => 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
|