cartodb/spec/models/carto/visualization_export_spec.rb
2020-06-15 10:58:47 +08:00

229 lines
8.3 KiB
Ruby

require 'spec_helper'
require 'support/factories/users'
require 'helpers/named_maps_helper'
describe Carto::DataExporter do
include CartoDB::Factories
include NamedMapsHelper
describe '#export_tables' do
include_context 'user helper'
# INFO: this needs SQL API configured for testing
it 'exports a table in requested format' do
table_name = 'table1'
table = create_table(name: table_name, user_id: @user.id)
user_table = Carto::UserTable.find_by_table_id(table.get_table_id)
table.insert_row!(id: 666, description: 'desc', name: 'a row')
format = 'shp'
tmp_dir = "/tmp/export_test_#{String.random(15)}"
FileUtils.mkdir_p tmp_dir
begin
Carto::Http::Request.any_instance.stubs(:run)
file = File.new(Carto::DataExporter.new.export_table(user_table, tmp_dir, format))
file.path.should match(/.#{format}$/)
file.close
ensure
File.delete file if file
FileUtils.rm_rf tmp_dir
table.destroy
end
end
end
end
describe Carto::VisualizationExport do
include Carto::ExporterConfig
include_context 'users helper'
include Carto::Factories::Visualizations
class FakeCartoHttpClientFileToucher
attr_reader :touched_files
def initialize
@touched_files = []
end
# Mock needs not url nor Typhoeus options
def get_file(_, exported_file, _)
@touched_files << exported_file
touch(exported_file)
end
private
def random_filename(dir, extension: 'shp')
"#{dir}/test_#{String.random(12)}.#{extension}".downcase
end
def touch_random_filename(dir, extension: 'shp')
touch(random_filename(dir, extension: extension))
end
def touch(path)
FileUtils.touch(path).first
end
end
let(:base_dir) { ensure_clean_folder('/tmp/exporter_test') }
describe '#export' do
it 'exports a .carto file including the carto.json and the files' do
map = FactoryGirl.create(:carto_map, user: @carto_user1)
table1 = FactoryGirl.create(:private_user_table, user: @carto_user1)
table2 = FactoryGirl.create(:private_user_table, user: @carto_user1)
layer1 = FactoryGirl.create(:carto_layer, options: { table_name: table1.name }, maps: [map])
FactoryGirl.create(:carto_layer, options: { table_name: table2.name }, maps: [map])
map, table, table_visualization, visualization = create_full_visualization(@carto_user1,
map: map,
table: table1,
data_layer: layer1)
fake_carto_http_client_toucher = FakeCartoHttpClientFileToucher.new
exported_file = Carto::VisualizationExport.new.export(
visualization,
@carto_user1,
base_dir: base_dir,
data_exporter: Carto::DataExporter.new(fake_carto_http_client_toucher))
touched_files = fake_carto_http_client_toucher.touched_files
CartoDB::Importer2::Unp.new.open(exported_file) do |files|
files.length.should eq (map.layers.count + 1)
names = files.map(&:path)
names.count { |f| f =~ /\.carto\.json$/ }.should eq 1
names.should include(touched_files[0].split('/').last)
names.should include(touched_files[1].split('/').last)
end
([exported_file] + touched_files).map { |f| File.delete(f) if File.exists?(f) }
destroy_full_visualization(map, table, table_visualization, visualization)
end
it 'excludes data not accessible by the user' do
map = FactoryGirl.create(:carto_map, user: @carto_user1)
table1 = FactoryGirl.create(:private_user_table, user: @carto_user1)
layer1 = FactoryGirl.create(:carto_layer, options: { table_name: table1.name }, maps: [map])
map, table, table_visualization, visualization = create_full_visualization(@carto_user1,
map: map,
table: table1,
data_layer: layer1)
fake_carto_http_client_toucher = FakeCartoHttpClientFileToucher.new
exported_file = Carto::VisualizationExport.new.export(
visualization,
@carto_user2,
base_dir: base_dir,
data_exporter: Carto::DataExporter.new(fake_carto_http_client_toucher))
touched_files = fake_carto_http_client_toucher.touched_files
CartoDB::Importer2::Unp.new.open(exported_file) do |files|
files.length.should eq 1 # visualization export
names = files.map(&:path)
names.count { |f| f =~ /\.carto\.json$/ }.should eq 1
end
([exported_file] + touched_files).map { |f| File.delete(f) if File.exists?(f) }
destroy_full_visualization(map, table, table_visualization, visualization)
end
it 'excludes layers and user_tables with user_tables_ids parameter' do
map = FactoryGirl.create(:carto_map, user: @carto_user1)
table1 = FactoryGirl.create(:private_user_table, user: @carto_user1)
table2 = FactoryGirl.create(:private_user_table, user: @carto_user1)
layer1 = FactoryGirl.create(:carto_layer, options: { table_name: table1.name }, maps: [map])
FactoryGirl.create(:carto_layer, options: { table_name: table2.name }, maps: [map])
map, table, table_visualization, visualization = create_full_visualization(@carto_user1,
map: map,
table: table1,
data_layer: layer1)
fake_carto_http_client_toucher = FakeCartoHttpClientFileToucher.new
exported_file = Carto::VisualizationExport.new.export(
visualization,
@carto_user1,
user_tables_ids: [table1.id],
base_dir: base_dir,
data_exporter: Carto::DataExporter.new(fake_carto_http_client_toucher))
touched_files = fake_carto_http_client_toucher.touched_files
CartoDB::Importer2::Unp.new.open(exported_file) do |files|
files.length.should eq (1 + 1) # selected user_table + metadata
names = files.map(&:path)
names.count { |f| f =~ /\.carto\.json$/ }.should eq 1
names.should include(touched_files[0].split('/').last)
touched_files.length.should eq 1
end
([exported_file] + touched_files).map { |f| File.delete(f) if File.exists?(f) }
destroy_full_visualization(map, table, table_visualization, visualization)
end
end
describe '#run_export!' do
# run_export! is called from the job, but the core of the logic is in `#export`, this makes sure its usage
it 'calls #export' do
visualization = FactoryGirl.create(:carto_visualization, user: @carto_user1)
ve = FactoryGirl.create(:visualization_export, user: @carto_user1, visualization: visualization)
fake_path = "/tmp/fakepath"
touch(fake_path)
ve.expects(:export).returns(fake_path)
file_upload_helper_mock = mock
file_upload_helper_mock.expects(:upload_file_to_storage)
ve.run_export!(file_upload_helper: file_upload_helper_mock)
visualization.destroy
File.delete(fake_path) if File.exists?(fake_path)
end
describe 'with S3' do
before(:each) do
@visualization = FactoryGirl.create(:carto_visualization, user: @carto_user1)
end
after(:each) do
@visualization.destroy
end
let(:test_dir) { '/tmp/exports_test/' }
let(:fake_path) { "#{test_dir}/fake_export.carto" }
it 'runs export creating a log trace' do
ve = Carto::VisualizationExport.new(visualization: @visualization, user: @carto_user1)
FileUtils.mkdir_p test_dir
FileUtils.touch(fake_path).first
ve.expects(:export).returns(fake_path)
file_upload_helper_mock = mock
file_upload_helper_mock.expects(:upload_file_to_storage).returns(file_url: fake_path)
ve.run_export!(file_upload_helper: file_upload_helper_mock)
ve.reload
ve.log.should_not be_nil
ve.destroy
end
end
end
end