229 lines
8.3 KiB
Ruby
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
|