Initial commit

This commit is contained in:
zhongjin
2020-06-15 10:58:47 +08:00
commit 4f1dfe7564
8590 changed files with 1516878 additions and 0 deletions
@@ -0,0 +1,478 @@
require_relative '../../spec_helper'
require_relative '../../../services/data-repository/backend/sequel'
require_relative '../../../services/data-repository/repository'
require_relative '../../../app/models/visualization/collection'
require_relative '../../../app/models/visualization/member'
require_relative '../../doubles/support_tables.rb'
require 'helpers/unique_names_helper'
include UniqueNamesHelper
include CartoDB
describe Visualization::Collection do
include Carto::Factories::Visualizations
before(:all) do
@user_1 = FactoryGirl.create(:valid_user, quota_in_bytes: 524288000, table_quota: 500, private_tables_enabled: true)
@user_2 = FactoryGirl.create(:valid_user, private_tables_enabled: true)
end
before(:each) do
bypass_named_maps
delete_user_data @user_1
delete_user_data @user_2
end
after(:all) do
@user_1.destroy
@user_2.destroy
end
describe '#fetch' do
it 'filters by tag if the backend supports array columns' do
attributes1 = random_attributes_for_vis_member(tags: ['tag 1', 'tag 11'], user_id: @user_1.id)
attributes2 = random_attributes_for_vis_member(tags: ['tag 2', 'tag 22'], user_id: @user_1.id)
Visualization::Member.new(attributes1).store
Visualization::Member.new(attributes2).store
collection = Visualization::Collection.new
collection.fetch(user_id: @user_1.id, tags: 'tag 1').count.should == 1
end
it 'filters by partial name / description match' do
attributes1 =
random_attributes_for_vis_member(name: 'viz_1', description: 'description_11', user_id: @user_1.id)
attributes2 =
random_attributes_for_vis_member(name: 'viz_2', description: 'description_22', user_id: @user_1.id)
Visualization::Member.new(attributes1).store
Visualization::Member.new(attributes2).store
collection = Visualization::Collection.new
collection.fetch(user_id: @user_1.id, q: 'viz').count.should == 2
collection.fetch(user_id: @user_1.id, q: 'viz_1').count.should == 1
collection = Visualization::Collection.new
collection.fetch(user_id: @user_1.id, q: 'description').count.should == 2
collection.fetch(user_id: @user_1.id, q: 'ion_11').count.should == 1
collection.fetch(user_id: @user_1.id, q: 'ion_22').count.should == 1
end
it 'orders the collection by the passed criteria' do
Visualization::Member.new(random_attributes_for_vis_member(user_id: @user_1.id, name: 'viz_1')).store
Visualization::Member.new(random_attributes_for_vis_member(user_id: @user_1.id, name: 'viz_2')).store
collection = Visualization::Collection.new
records = collection.fetch(user_id: @user_1.id, order: :name)
records.first.name.should == 'viz_2'
end
it 'checks fetching with, without and only shared entities' do
vis_1_name = unique_name('viz')
vis_2_name = unique_name('viz')
vis_3_name = unique_name('viz')
Visualization::Member.new(random_attributes_for_vis_member(name: vis_1_name, user_id: @user_1.id)).store
vis2 = Visualization::Member.new(random_attributes_for_vis_member(name: vis_2_name, user_id: @user_2.id)).store
vis3 = Visualization::Member.new(random_attributes_for_vis_member(name: vis_3_name, user_id: @user_2.id)).store
shared_entity = CartoDB::SharedEntity.new(
recipient_id: @user_1.id,
recipient_type: CartoDB::SharedEntity::RECIPIENT_TYPE_USER,
entity_id: vis2.id,
entity_type: CartoDB::SharedEntity::ENTITY_TYPE_VISUALIZATION
)
shared_entity.save
shared_entity.reload
collection = Visualization::Collection.new
collection.stubs(:user_shared_vis).with(@user_1.id).returns([vis2.id])
# Filter by user_id and non-owned id (excluding shared)
records = collection.fetch(user_id: @user_1.id, id: vis3.id, exclude_shared: true)
records.count.should eq 0
# Filter by user_id and non-owned id (not excluding shared)
records = collection.fetch(user_id: @user_1.id, id: vis3.id)
records.count.should eq 0
# Filter by name (not present user_id)
records = collection.fetch(name: vis_1_name)
records.count.should eq 1
records.first.name.should eq vis_1_name
# Filter by user_id (includes shared)
records = collection.fetch(user_id: @user_1.id).map { |item| item }
records.count.should eq 2
((records[0].name == vis_1_name || records[0].name == vis_2_name) &&
(records[1].name == vis_1_name || records[1].name == vis_2_name)).should eq true
# Filter by user_id excluding shared
records = collection.fetch(user_id: @user_1.id, exclude_shared: true)
records.count.should eq 1
records.first.name.should eq vis_1_name
# Filter by user_id and only shared
records = collection.fetch(user_id: @user_1.id, only_shared: true)
records.count.should eq 1
records.first.name.should eq vis_2_name
end
it 'checks that filtering collection by locked works' do
collection = Visualization::Collection.new
vis1 = Visualization::Member.new(random_attributes_for_vis_member(user_id: @user_1.id,
name: 'viz_1',
locked: true)).store
vis2 = Visualization::Member.new(random_attributes_for_vis_member(user_id: @user_1.id,
name: 'viz_2',
locked: false)).store
records = collection.fetch(user_id: @user_1.id, locked: false)
records.count.should eq 1
records.first.name.should eq vis2.name
records = collection.fetch(user_id: @user_1.id, locked: true)
records.count.should eq 1
records.first.name.should eq vis1.name
end
it "checks that shared entities appear no matter if they're locked or not" do
vis_1_name = 'viz_1'
vis_2_name = 'viz_2'
vis_3_name = 'viz_3'
vis_4_name = 'viz_4'
Visualization::Member.new(random_attributes_for_vis_member(name: vis_1_name,
user_id: @user_1.id,
locked: true)).store
vis2 = Visualization::Member.new(random_attributes_for_vis_member(name: vis_2_name,
user_id: @user_2.id,
locked: true)).store
vis3 = Visualization::Member.new(random_attributes_for_vis_member(name: vis_3_name,
user_id: @user_2.id,
locked: false)).store
Visualization::Member.new(random_attributes_for_vis_member(name: vis_4_name,
user_id: @user_1.id,
locked: false)).store
shared_entity = CartoDB::SharedEntity.new(
recipient_id: @user_1.id,
recipient_type: CartoDB::SharedEntity::RECIPIENT_TYPE_USER,
entity_id: vis2.id,
entity_type: CartoDB::SharedEntity::ENTITY_TYPE_VISUALIZATION
)
shared_entity.save
shared_entity = CartoDB::SharedEntity.new(
recipient_id: @user_1.id,
recipient_type: CartoDB::SharedEntity::RECIPIENT_TYPE_USER,
entity_id: vis3.id,
entity_type: CartoDB::SharedEntity::ENTITY_TYPE_VISUALIZATION
)
shared_entity.save
collection = Visualization::Collection.new
collection.stubs(:user_shared_vis).with(@user_1.id).returns([vis2.id, vis3.id])
# Non-locked vis, all shared vis
records = collection.fetch(user_id: @user_1.id)
records.count.should eq 4
# Same behaviour, non-locked, all shared
records = collection.fetch(user_id: @user_1.id, locked: false)
records.count.should eq 3
# Only user vis, no shared vis at all
records = collection.fetch(user_id: @user_1.id, locked: true)
records.count.should eq 1
records.map(&:name).first.should eq vis_1_name
end
it 'Checks all supported sorting methods work' do
# Supported: updated_at, likes, mapviews, row_count, size
# TODO: Add mapviews test. As it uses redis requires more work
vis1 = full_visualization_table(@user_1, nil).visualization
vis2 = full_visualization_table(@user_1, nil).visualization
vis3 = full_visualization_table(@user_1, nil).visualization
# Biggest row count
vis3.table.add_column!(name: "test_col", type: "text")
vis3.table.insert_row!(test_col: "333")
vis3.table.insert_row!(test_col: "333")
vis3.table.insert_row!(test_col: "333")
vis3.table.insert_row!(test_col: "333")
vis3.table.insert_row!(test_col: "333")
vis3.table.insert_row!(test_col: "333")
# pg_class.reltuples only get updated after VACUUMs, etc.
@user_1.in_database.run("VACUUM #{vis3.table.name}")
vis3.updated_at = Time.now - 3.minute
vis3.save
# Biggest in size and likes
long_string = ""
2000.times do
long_string << rand(999).to_s
end
vis2.table.add_column!(name: "test_col", type: "text")
vis2.table.add_column!(name: "test_col2", type: "text")
vis2.table.add_column!(name: "test_col3", type: "text")
vis2.table.insert_row!(test_col: long_string, test_col2: long_string, test_col3: long_string)
vis2.table.insert_row!(test_col: long_string, test_col2: long_string, test_col3: long_string)
vis2.table.insert_row!(test_col: long_string, test_col2: long_string, test_col3: long_string)
vis2.table.insert_row!(test_col: long_string, test_col2: long_string, test_col3: long_string)
@user_1.in_database.run("VACUUM #{vis2.table.name}")
vis2.updated_at = Time.now - 2.minute
vis2.save
# Latest edited
vis1.table.add_column!(name: "test_col", type: "text")
@user_1.in_database.run("VACUUM #{vis1.table.name}")
vis1.updated_at = Time.now - 1.minute
vis1.save
# Actual tests start here
collection = Visualization::Collection.new.fetch(user_id: @user_1.id,
order: 'updated_at',
exclude_shared: true)
collection.count.should eq 3
ids = collection.map(&:id)
expected_updated_ats = [vis1.id, vis2.id, vis3.id]
ids.should eq expected_updated_ats
collection = Visualization::Collection.new.fetch(user_id: @user_1.id,
order: :row_count,
exclude_shared: true)
collection.count.should eq 3
ids = collection.map(&:id)
expected_row_count = [vis3.id, vis2.id, vis1.id]
ids.should eq expected_row_count
collection = Visualization::Collection.new.fetch(user_id: @user_1.id,
order: :size,
exclude_shared: true)
collection.count.should eq 3
ids = collection.map(&:id)
expected_size = [vis2.id, vis3.id, vis1.id]
ids.should eq expected_size
# Cleanup
vis1.delete
vis2.delete
vis3.delete
end
def liked(user)
Visualization::Collection.new.fetch(user_id: user.id, only_liked: true)
end
it "checks filtering by 'liked' " do
user3 = create_user(quota_in_bytes: 524288000, table_quota: 500, private_tables_enabled: true)
full_visualization_table(@user_1, nil).visualization
vis2 = full_visualization_table(@user_1, nil).visualization
vis2.privacy = Visualization::Member::PRIVACY_PUBLIC
vis2.save
vis3 = full_visualization_table(@user_1, nil).visualization
vis3.privacy = Visualization::Member::PRIVACY_PUBLIC
vis3.save
vis4 = full_visualization_table(@user_1, nil).visualization
vis4.privacy.should eq Visualization::Member::PRIVACY_PRIVATE
vis_link = full_visualization_table(@user_1, nil).visualization
vis_link.privacy = Visualization::Member::PRIVACY_LINK
vis_link.save
vis_private = full_visualization_table(@user_1, nil).visualization
vis_private.privacy = Visualization::Member::PRIVACY_PRIVATE
vis_private.save
# vis1 0 likes
vis2.add_like_from(@user_1)
expect {
vis2.add_like_from(@user_2)
}.to raise_exception Carto::Visualization::UnauthorizedLikeError
vis3.add_like_from(@user_1)
# since vis4 is not public it won't count for users 2 and 3
vis4.add_like_from(@user_1)
vis_link.add_like_from(@user_1)
vis_private.add_like_from(@user_1)
collection = Visualization::Collection.new.fetch(user_id: @user_1.id)
collection.count.should eq 6
collection = Visualization::Collection.new.fetch(user_id: @user_1.id, only_liked: true)
collection.count.should eq 5
ids = collection.map(&:id)
collection = Visualization::Collection.new.fetch(user_id: @user_1.id,
type: Visualization::Member::TYPE_CANONICAL,
only_liked: true)
collection.count.should eq 5
ids = collection.map(&:id)
collection = Visualization::Collection.new.fetch(user_id: @user_1.id,
only_liked: true,
unauthenticated: true)
collection.count.should eq 2
ids = collection.map(&:id)
collection = Visualization::Collection.new.fetch(user_id: @user_1.id,
only_liked: true,
privacy: Visualization::Member::PRIVACY_PRIVATE)
collection.count.should eq 2
ids = collection.map(&:id)
collection = Visualization::Collection.new.fetch(only_liked: true)
collection.count.should eq 0
collection = Visualization::Collection.new.fetch(user_id: @user_2.id, only_liked: true)
collection.count.should eq 0
collection = Visualization::Collection.new.fetch(user_id: user3.id, only_liked: true)
collection.count.should eq 0 # Liked link privacy one
user3.destroy
end
end
describe 'single methods' do
it 'checks count_total method' do
vis_1_name = 'viz_1'
vis_2_name = 'viz_2'
vis_3_name = 'viz_3'
vis_4_name = 'viz_4'
Visualization::Member.new(random_attributes(name: vis_1_name, user_id: @user_1.id)).store
Visualization::Member.new(random_attributes(name: vis_2_name, privacy: 'private', user_id: @user_1.id)).store
vis_user2 = Visualization::Member.new(random_attributes(name: vis_3_name, user_id: @user_2.id)).store
vis2_user2 = Visualization::Member.new(random_attributes(name: vis_4_name, user_id: @user_2.id)).store
shared_entity = CartoDB::SharedEntity.new(
recipient_id: @user_1.id,
recipient_type: CartoDB::SharedEntity::RECIPIENT_TYPE_USER,
entity_id: vis_user2.id,
entity_type: CartoDB::SharedEntity::ENTITY_TYPE_VISUALIZATION
)
shared_entity.save
shared_entity.reload
collection = Visualization::Collection.new
collection.stubs(:user_shared_vis).with(@user_1.id).returns([vis_user2.id])
records = collection.fetch(user_id: @user_1.id)
records.count.should eq 3
collection.count_total(user_id: @user_1.id).should eq 2
# Other filters should be skipped
collection.count_total(user_id: @user_1.id, id: vis_user2.id).should eq 2
collection.count_total(user_id: @user_1.id, id: vis2_user2.id).should eq 2
collection.count_total(user_id: @user_1.id, name: 'test').should eq 2
collection.count_total(user_id: @user_1.id, description: 'test').should eq 2
collection.count_total(user_id: @user_1.id, privacy: CartoDB::Visualization::Member::PRIVACY_PRIVATE).should eq 2
collection.count_total(user_id: @user_1.id, locked: true).should eq 2
collection.count_total(user_id: @user_1.id, exclude_shared: false).should eq 2
collection.count_total(user_id: @user_1.id, only_shared: false).should eq 2
# If unauthenticated remove private ones
collection.count_total(user_id: @user_1.id, unauthenticated: true).should eq 1
# Type filters are allowed
collection.count_total(user_id: @user_1.id, type: CartoDB::Visualization::Member::TYPE_CANONICAL).should eq 2
collection.count_total(user_id: @user_1.id, type: CartoDB::Visualization::Member::TYPE_DERIVED).should eq 0
# And filtering by user_id
collection.count_total(user_id: @user_2.id).should eq 2
end
end
# Slide visualization types specs
# This should be a member_spec test, but as those specs have no collection support...
it 'checks the .children method' do
parent = Visualization::Member.new(random_attributes_for_vis_member(
user_id: @user_1.id,
type: Visualization::Member::TYPE_DERIVED)).store
parent.children.count.should eq 0
child1 = Visualization::Member.new(random_attributes_for_vis_member(
user_id: @user_1.id,
type: Visualization::Member::TYPE_SLIDE,
parent_id: parent.id)).store.fetch
parent.children.count.should eq 1
child2 = Visualization::Member.new(random_attributes_for_vis_member(
user_id: @user_1.id,
type: Visualization::Member::TYPE_SLIDE,
parent_id: parent.id)).store.fetch
child2.set_prev_list_item!(child1)
parent.fetch
parent.children.count.should eq 2
canonical = Visualization::Member.new(random_attributes_for_vis_member(
user_id: @user_1.id,
type: Visualization::Member::TYPE_CANONICAL)).store
parent.children.count.should eq 2
canonical.children.count.should eq 0
child_2_1 = Visualization::Member.new(random_attributes_for_vis_member(
user_id: @user_1.id,
type: Visualization::Member::TYPE_DERIVED)).store
Visualization::Member.new(random_attributes_for_vis_member(
user_id: @user_1.id,
type: Visualization::Member::TYPE_SLIDE,
parent_id: child_2_1.id)).store
child_2_1.children.count.should eq 1
end
it 'checks retrieving slide type items' do
member = Visualization::Member.new(random_attributes_for_vis_member(
type: Visualization::Member::TYPE_DERIVED,
user_id: @user_1.id)).store
c1 = Visualization::Member.new(random_attributes_for_vis_member(
type: Visualization::Member::TYPE_SLIDE,
parent_id: member.id,
user_id: @user_1.id)).store
c2 = Visualization::Member.new(random_attributes_for_vis_member(
type: Visualization::Member::TYPE_SLIDE,
parent_id: member.id,
user_id: @user_1.id)).store
collection = Visualization::Collection.new.fetch(user_id: @user_1.id,
type: Visualization::Member::TYPE_SLIDE)
collection.count.should eq 2
c1.delete
c2.delete
member.delete
end
def random_attributes(attributes = {})
random = unique_name('viz')
{
name: attributes.fetch(:name, random),
description: attributes.fetch(:description, "description #{random}"),
privacy: attributes.fetch(:privacy, 'public'),
tags: attributes.fetch(:tags, ['tag 1']),
type: attributes.fetch(:type, CartoDB::Visualization::Member::TYPE_CANONICAL),
user_id: attributes.fetch(:user_id, UUIDTools::UUID.timestamp_create.to_s),
locked: attributes.fetch(:locked, false),
title: attributes.fetch(:title, ''),
source: attributes.fetch(:source, ''),
license: attributes.fetch(:license, ''),
attributions: attributes.fetch(:attributions, ''),
kind: attributes.fetch(:kind, CartoDB::Visualization::Member::KIND_GEOM),
map_id: attributes.fetch(:map_id, nil)
}
end # random_attributes
end # Visualization::Collection
+117
View File
@@ -0,0 +1,117 @@
require 'rspec/core'
require 'rspec/expectations'
require 'rspec/mocks'
require 'sequel'
require_relative '../../spec_helper'
require_relative '../../../app/models/visualization/locator'
require_relative '../../../app/models/visualization'
require_relative '../../../app/models/visualization/member'
require_relative '../../doubles/support_tables.rb'
include CartoDB
describe Visualization::Locator do
UUID = 'db0dfb0c-a944-11e3-a51e-30f9edfe5da6'
before(:each) do
support_tables_mock = Doubles::Visualization::SupportTables.new
Visualization::Relator.any_instance.stubs(:support_tables).returns(support_tables_mock)
end
before do
bypass_named_maps
@db = SequelRails.connection
Sequel.extension(:pagination)
Visualization.repository = DataRepository::Backend::Sequel.new(@db, :visualizations)
@user_id = UUIDTools::UUID.timestamp_create.to_s
@map_id = UUIDTools::UUID.timestamp_create.to_s
# For relator->permission
@user_mock = create_mocked_user
CartoDB::Visualization::Relator.any_instance.stubs(:user).returns(@user_mock)
@visualization = Visualization::Member.new(
{
name: 'Visualization 1',
description: 'A sample visualization',
privacy: 'public',
type: 'derived',
map_id: UUID,
id: @map_id,
user_id: @user_id
}
).store
user_fake = model_fake(@map_id, @user_id)
@subdomain = 'bogus'
@locator = Visualization::Locator.new(user_fake)
end
describe '#get' do
it 'fetches a Visualization::Member if passed an UUID' do
rehydrated = @locator.get(@visualization.id, @subdomain).first
rehydrated.name.should == @visualization.name
rehydrated.description.should_not be_nil
end
it 'fetches a Visualization::Member if passed a visualization name' do
Visualization::Collection.any_instance.stubs(:user_shared_vis).returns([])
rehydrated = @locator.get(@visualization.name, @subdomain).first
rehydrated.id.should == @visualization.id
rehydrated.description.should_not be_nil
end
it 'fetches a Table if passed a table id' do
user = create_user(quota_in_bytes: 1234567890, table_quota: 10)
user.stubs(:invalidate_varnish_cache).returns(nil)
table = Table.new
table.user_id = user.id
table.save
table.reload
table_vis = table.table_visualization
table = Visualization::Locator.new.get(table.id, user.username)
table[1].nil?.should eq false
table[1].id.should eq table_vis.table.id
user.destroy
end
it 'returns nil if no visualization or table found' do
Visualization::Collection.any_instance.stubs(:user_shared_vis).returns([])
@locator.get('220d2f46-b371-11e4-93f7-080027880ca6', @subdomain).should == [nil, nil]
end
end #get
def model_fake(map_id=nil, user_id=UUID)
model_klass = Object.new
class << model_klass
attr_accessor :id
end
model_klass.id = user_id
def model_klass.where(filter)
@called_filter = filter
[OpenStruct.new(
maps: [OpenStruct.new(id: UUID)],
id: id
)]
end
def model_klass.called_filter
@called_filter
end
model_klass
end #model_fake
end # Visualization::Locator
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,53 @@
require 'rspec/core'
require 'rspec/expectations'
require 'rspec/mocks'
require 'sequel'
require_relative '../../spec_helper'
require_relative '../../../app/models/visualization/name_checker'
include CartoDB
describe Visualization::NameChecker do
before :all do
bypass_named_maps
@user = FactoryGirl.create(:valid_user)
@user2 = FactoryGirl.create(:valid_user)
@vis1 = FactoryGirl.build(:derived_visualization, name: 'Visualization 1', user_id: @user.id).store
@vis2 = FactoryGirl.build(:derived_visualization, name: 'Visualization 2', user_id: @user.id).store
@vis3 = FactoryGirl.build(:derived_visualization, name: 'Visualization 4', user_id: @user2.id).store
@shared_entity = CartoDB::SharedEntity.new(
recipient_id: @user.id,
recipient_type: CartoDB::SharedEntity::RECIPIENT_TYPE_USER,
entity_id: @vis3.id,
entity_type: CartoDB::SharedEntity::ENTITY_TYPE_VISUALIZATION
).save
end
after :all do
@shared_entity.destroy
@vis3.destroy
@vis2.destroy
@vis1.destroy
@user.destroy
end
describe '#available?' do
it 'returns true if passed visualization name is available for the user' do
checker = Visualization::NameChecker.new(@user)
checker.available?('Visualization 3').should == true
end
it 'returns false if passed visualization name is in use by the user' do
checker = Visualization::NameChecker.new(@user)
checker.available?('Visualization 1').should == false
checker.available?('Visualization 2').should == false
end
it 'returns true if name is available but used in shared visualizations' do
checker = Visualization::NameChecker.new(@user)
checker.available?('Visualization 4').should == true
end
end # available?
end # Visualization::NameChecker
@@ -0,0 +1,83 @@
require 'ostruct'
require_relative '../../spec_helper'
require_relative '../../../app/models/visualization/name_generator'
include CartoDB
describe Visualization::NameGenerator do
describe '#generate' do
it 'returns the candidate name if available' do
user = Object.new
candidate = 'Non existing name'
checker = positive_checker
generator = Visualization::NameGenerator.new(user, checker)
generator.name(candidate).should == candidate
end
it 'returns an altered name if no available candidate' do
user = Object.new
existing = 'visualization 1'
checker = negative_checker
generator = Visualization::NameGenerator.new(user, checker)
generator.name(existing).should_not == existing
end
it 'returns a generated name if no candidate' do
user = Object.new
checker = negative_checker
generator = Visualization::NameGenerator.new(user, checker)
generator.name.should =~ /#{Visualization::NameGenerator::PATTERN}/
end
it 'accepts names with non-ASCII characters' do
user = Object.new
checker = positive_checker
candidate = 'Me gustan los ñúes'
generator = Visualization::NameGenerator.new(user, checker)
generator.name(candidate).should == candidate
end
it 'strips leading and trailing whitespace from candidates' do
user = Object.new
checker = positive_checker
candidate = ' viva la pepa '
generator = Visualization::NameGenerator.new(user, checker)
generator.name(candidate).should == 'viva la pepa'
end
it 'assigns a valid name if a explicit nil candidate is passed' do
user = Object.new
checker = positive_checker
candidate = ' viva la pepa '
generator = Visualization::NameGenerator.new(user, checker)
generator.name(nil).should == Visualization::NameGenerator::PATTERN
end
it 'assigns an incremental number' do
user = Object.new
candidate = 'Untitled map'
Visualization::NameGenerator.new(user, negative_checker([])).name(candidate).should == candidate
Visualization::NameGenerator.new(user, negative_checker([candidate])).name(candidate).should == "#{candidate} 1"
Visualization::NameGenerator.new(user, negative_checker([candidate, "#{candidate} 1"])).name(candidate).should == "#{candidate} 2"
Visualization::NameGenerator.new(user, negative_checker([candidate, "#{candidate} 1", "#{candidate} 2"])).name(candidate).should == "#{candidate} 3"
end
end
def positive_checker
checker = Object.new
def checker.available?(*args); true; end
checker
end
def negative_checker(existing = [ 'visualization 1', 'Untitled visualization', 'Untitled visualization 0', 'Untitled visualization 1'])
checker = OpenStruct.new
checker.existing = existing
def checker.available?(candidate)
!existing.include?(candidate)
end
checker
end
end
@@ -0,0 +1,196 @@
require_relative '../../spec_helper'
require_relative '../../../services/data-repository/backend/sequel'
require_relative '../../../app/models/visualization/member'
require_relative '../../../services/data-repository/repository'
require_relative '../../factories/organizations_contexts'
include CartoDB
describe Visualization::Member do
include_context 'organization with users helper'
before(:each) do
bypass_named_maps
end
describe 'sharing tables and visualizations' do
it 'should give read permission to table aka canonical visualization' do
owner_table = create_table(@org_user_owner)
carto_canonical_vis = owner_table.table_visualization
canonical_vis = CartoDB::Visualization::Member.new(id: carto_canonical_vis.id).fetch
canonical_vis.has_permission?(@org_user_owner, CartoDB::Visualization::Member::PERMISSION_READONLY).should eq true
canonical_vis.has_permission?(@org_user_1, CartoDB::Visualization::Member::PERMISSION_READONLY).should eq false
give_permission(canonical_vis, @org_user_1, CartoDB::Permission::ACCESS_READONLY)
canonical_vis.has_permission?(@org_user_1, CartoDB::Visualization::Member::PERMISSION_READONLY).should eq true
end
it 'other user should not have permission until given' do
owner_table = create_table(@org_user_owner)
carto_vis = create_vis_from_table(owner_table.table_visualization.user, owner_table)
vis = CartoDB::Visualization::Member.new(id: carto_vis.id).fetch
vis.has_permission?(@org_user_owner, CartoDB::Visualization::Member::PERMISSION_READONLY).should eq true
vis.has_permission?(@org_user_1, CartoDB::Visualization::Member::PERMISSION_READONLY).should eq false
give_permission(vis, @org_user_1, CartoDB::Visualization::Member::PERMISSION_READONLY)
vis.has_permission?(@org_user_1, CartoDB::Visualization::Member::PERMISSION_READONLY).should eq true
end
it 'other user will not get permission in private table when the table owners adds it to the visualization' do
owner_table = create_table(@org_user_owner)
carto_vis = create_vis_from_table(owner_table.table_visualization.user, owner_table)
vis = CartoDB::Visualization::Member.new(id: carto_vis.id).fetch
give_permission(vis, @org_user_1, CartoDB::Visualization::Member::PERMISSION_READONLY)
vis.has_permission?(@org_user_1, CartoDB::Visualization::Member::PERMISSION_READONLY).should eq true
other_table = create_table(@org_user_owner)
other_vis = CartoDB::Visualization::Member.new(id: other_table.table_visualization.id).fetch
add_layer_from_table(vis, other_table)
vis.has_permission?(@org_user_1, CartoDB::Visualization::Member::PERMISSION_READONLY).should eq true
other_vis.has_permission?(@org_user_1, CartoDB::Visualization::Member::PERMISSION_READONLY).should eq false
end
it 'should not remove access to visualization if table privacy is changed to private' do
owner_table = create_table(@org_user_owner)
carto_canonical_vis = owner_table.table_visualization
canonical_vis = CartoDB::Visualization::Member.new(id: carto_canonical_vis.id).fetch
carto_vis = create_vis_from_table(owner_table.table_visualization.user, owner_table)
vis = CartoDB::Visualization::Member.new(id: carto_vis.id).fetch
give_permission(vis, @org_user_1, CartoDB::Visualization::Member::PERMISSION_READONLY)
# removes access to table
canonical_vis.permission.clear
canonical_vis.has_permission?(@org_user_1, CartoDB::Visualization::Member::PERMISSION_READONLY).should eq false
vis.has_permission?(@org_user_1, CartoDB::Visualization::Member::PERMISSION_READONLY).should eq true
end
end
private
def add_layer_from_table(vis, table)
layer = Layer.create(layer_params(table).slice(:kind, :options, :infowindow, :tooltip, :order))
vis.map.add_layer(layer)
layer.register_table_dependencies
vis.map.process_privacy_in(layer)
end
def create_vis_from_table(user, table)
blender = Visualization::TableBlender.new(user, [table])
map = blender.blend
vis = Visualization::Member.new(
name: 'wadus_vis',
map_id: map.id,
type: Visualization::Member::TYPE_DERIVED,
privacy: blender.blended_privacy,
user_id: user.id
)
vis.store
vis
end
def give_permission(vis, user, access)
per = vis.permission
per.set_user_permission(user, access)
per.save
per.reload
end
# @return [CartoDB::Visualization::Member]
def create_table(user)
table = Table.new
table.user_id = user.id
table.name = 'wadus_table_' + UUIDTools::UUID.timestamp_create.to_s
table.save
table.reload
# table = create_table(user_id: user.id, name: 'wadus_table')
table.table_visualization.type.should eq Visualization::Member::TYPE_CANONICAL
table
end
def layer_params(table)
{
:kind => "carto",
:options => {
:attribution => 'CartoDB',
:type => 'CartoDB',
:active => true,
:query => '',
:opacity => 0.99,
:interactivity => 'cartodb_id',
:interaction => true,
:debug => false,
:tiler_domain => 'localhost.lan',
:tiler_port => '8181',
:tiler_protocol => 'http',
:sql_api_domain => 'localhost.lan',
:sql_api_port => 8080,
:sql_api_protocol => 'http',
:extra_params => {
:cache_policy => 'persist',
:cache_buster => 1404930437358
},
:maxZoom => 28,
:auto_bound => false,
:visible => true,
:sql_domain => 'localhost.lan',
:sql_port => '80',
:sql_protocol => 'http',
:tile_style_history => ["##{table.name}{ line-color: #FF6600; line-width: 2; line-opacity: 0.7; }"],
:style_version => '2.1.1',
:table_name => table.name,
:user_name => 'foo',
:tile_style => "##{table.name}{ line-color: #FF6600; line-width: 2; line-opacity: 0.7; }",
:use_server_style => true,
:query_history => [],
:wizard_properties => {
:type => 'polygon',
:properties => {
'line-width' => 2,
'line-color' => '#FF6600',
'line-opacity' => 0.7,
'line-comp-op' => 'none',
'text-name' => 'None',
'text-face-name' => 'DejaVu Sans Book',
'text-size' => 10,
'text-fill' => '#000',
'text-halo-fill' => '#FFF',
'text-halo-radius' => 1,
'text-dy' => -10,
'text-allow-overlap' => true,
'text-placement-type' => 'dummy',
'text-label-position-tolerance' => 0,
'text-placement' => 'point',
'geometry_type' => 'line'
}
},
:tile_style_custom => false,
:query_wrapper => nil,
:query_generated => false,
:order => 2,
:stat_tag => table.id,
:sql_api_endpoint => '/api/v1/sql',
:no_cdn => true,
:force_cors => true
},
:infowindow => {
:template_name => 'table/views/infowindow_light',
:fields => []
},
:tooltip => {
:fields => []
},
:order => 2
}
end
end
@@ -0,0 +1,52 @@
require 'ostruct'
require 'sequel'
require_relative '../../spec_helper'
require_relative '../../../services/data-repository/backend/sequel'
require_relative '../../../app/models/visualization/member'
require_relative '../../../app/models/visualization/overlays'
require_relative '../../../services/data-repository/repository'
include CartoDB
describe Visualization::Overlays do
before(:each) do
@db = SequelRails.connection
Visualization.repository = DataRepository::Backend::Sequel.new(@db, :visualizations)
member = Visualization::Member.new
map_mock = mock
map_mock.stubs(:scrollwheel=)
map_mock.stubs(:legends=)
map_mock.stubs(:legends)
map_mock.stubs(:scrollwheel)
map_mock.stubs(:id)
map_mock.stubs(:save)
Visualization::Member.any_instance.stubs(:map).returns(map_mock)
@visualization = member
Visualization.repository = DataRepository::Backend::Sequel.new(@db, :visualizations)
end
describe 'default' do
it 'should create all overlays' do
Visualization::Overlays.new(@visualization).create_default_overlays
@visualization.overlays.count.should eq 5
@visualization.overlays.select { |o| o.options['display'] }.count.should eq 5
@visualization.overlays.select { |o| o.type == 'logo' }.count.should eq 1
end
it 'should not create logo if user has disabled_cartodb_logo feature_flag' do
user_mock = mock
user_mock.stubs(:has_feature_flag?).with('disabled_cartodb_logo').returns(true)
@visualization.stubs(:user).returns(user_mock)
Visualization::Overlays.new(@visualization).create_default_overlays
@visualization.overlays.select { |o| o.type == 'logo' }.count.should eq 0
@visualization.overlays.count.should eq 4
end
end
end
+198
View File
@@ -0,0 +1,198 @@
require_relative '../../spec_helper'
require_relative '../../../app/models/visualization/presenter'
require_relative '../../doubles/support_tables.rb'
include CartoDB
describe Visualization::Member do
before do
@db = SequelRails.connection
Sequel.extension(:pagination)
Visualization.repository = DataRepository::Backend::Sequel.new(@db, :visualizations)
end
before(:each) do
bypass_named_maps
user_name = 'whatever'
@user_mock = FactoryGirl.build(:user, username: user_name)
CartoDB::Visualization::Relator.any_instance.stubs(:user).returns(@user_mock)
support_tables_mock = Doubles::Visualization::SupportTables.new
Visualization::Relator.any_instance.stubs(:support_tables).returns(support_tables_mock)
end
describe '#privacy_for_vizjson' do
it 'checks expected privacy values for the vizjson' do
visualization = Visualization::Member.new(
privacy: Visualization::Member::PRIVACY_PUBLIC,
name: 'test',
type: Visualization::Member::TYPE_CANONICAL
)
# Careful, do a user mock after touching user_data as it does some checks about user too
user_mock = mock
user_mock.stubs(:private_tables_enabled).returns(true)
user_mock.stubs(:id).returns(@user_mock.id)
Visualization::Member.any_instance.stubs(:user).returns(user_mock)
presenter = Visualization::Presenter.new(visualization)
presenter.send(:privacy_for_vizjson).should eq Visualization::Member::PRIVACY_PUBLIC
visualization.privacy = Visualization::Member::PRIVACY_PRIVATE
presenter.send(:privacy_for_vizjson).should eq Visualization::Member::PRIVACY_PRIVATE
visualization.privacy = Visualization::Member::PRIVACY_PROTECTED
presenter.send(:privacy_for_vizjson).should eq Visualization::Member::PRIVACY_PROTECTED
visualization.privacy = Visualization::Member::PRIVACY_LINK
presenter.send(:privacy_for_vizjson).should eq Visualization::Member::PRIVACY_PUBLIC
end
end
describe 'to_poro fields' do
it 'basic fields expected at the to_poro method' do
perm_mock = FactoryGirl.build(:carto_permission)
vis_mock = mock
vis_mock.stubs(:id).returns(UUIDTools::UUID.timestamp_create.to_s)
vis_mock.stubs(:name).returns('vis1')
vis_mock.stubs(:display_name).returns('vis1')
vis_mock.stubs(:map_id).returns(UUIDTools::UUID.timestamp_create.to_s)
vis_mock.stubs(:active_layer_id).returns(1)
vis_mock.stubs(:type).returns(Visualization::Member::TYPE_CANONICAL)
vis_mock.stubs(:tags).returns(['tag1'])
vis_mock.stubs(:description).returns('desc')
vis_mock.stubs(:privacy).returns(Visualization::Member::PRIVACY_PUBLIC)
vis_mock.stubs(:stats).returns('123')
vis_mock.stubs(:created_at).returns(Time.now)
vis_mock.stubs(:updated_at).returns(Time.now)
vis_mock.stubs(:permission).returns(perm_mock)
vis_mock.stubs(:locked).returns(true)
vis_mock.stubs(:source).returns('')
vis_mock.stubs(:license).returns('')
vis_mock.stubs(:attributions).returns('')
vis_mock.stubs(:title).returns('')
vis_mock.stubs(:parent_id).returns(nil)
vis_mock.stubs(:children).returns([])
vis_mock.stubs(:kind).returns(Visualization::Member::KIND_GEOM)
vis_mock.stubs(:table).returns(nil)
vis_mock.stubs(:related_tables).returns([])
vis_mock.stubs(:prev_id).returns(nil)
vis_mock.stubs(:next_id).returns(nil)
vis_mock.stubs(:transition_options).returns({})
vis_mock.stubs(:active_child).returns(nil)
vis_mock.stubs(:likes).returns([])
vis_mock.stubs(:synchronization).returns(nil)
presenter = Visualization::Presenter.new(vis_mock)
data = presenter.to_poro
data[:id].present?.should eq true
data[:name].present?.should eq true
data[:display_name].present?.should eq true
data[:map_id].present?.should eq true
data[:active_layer_id].present?.should eq true
data[:type].present?.should eq true
data[:tags].present?.should eq true
data[:description].present?.should eq true
data[:privacy].present?.should eq true
data[:stats].present?.should eq true
data[:created_at].present?.should eq true
data[:updated_at].present?.should eq true
data[:permission].present?.should eq true
data[:locked].present?.should eq true
data[:related_tables].should eq Array.new
data[:table].should eq Hash.new
data[:parent_id].should eq nil
data[:children].should eq Array.new
data[:kind].should eq Visualization::Member::KIND_GEOM
data[:prev_id].should eq nil
data[:next_id].should eq nil
data[:transition_options].should eq Hash.new
data[:active_child].should eq nil
end
end
describe '#children' do
it 'tests .children and its sorting' do
Visualization::Member.any_instance.stubs(:supports_private_maps?).returns(true)
::Permission.any_instance.stubs(:owner).returns(@user_mock)
parent = Visualization::Member.new(random_attributes_for_vis_member({
name:'PARENT',
user_id: @user_mock.id,
type: Visualization::Member::TYPE_DERIVED
}))
parent = parent.store.fetch
# Create unsorted on purpose
member_d = Visualization::Member.new(random_attributes_for_vis_member({
name:'D',
user_id: @user_mock.id,
type: Visualization::Member::TYPE_SLIDE,
parent_id: parent.id
}))
member_d = member_d.store.fetch
member_c = Visualization::Member.new(random_attributes_for_vis_member({
name:'C',
user_id: @user_mock.id,
type: Visualization::Member::TYPE_SLIDE,
parent_id: parent.id
}))
member_c = member_c.store.fetch
member_b = Visualization::Member.new(random_attributes_for_vis_member({
name:'B',
user_id: @user_mock.id,
type: Visualization::Member::TYPE_SLIDE,
parent_id: parent.id
}))
member_b = member_b.store.fetch
member_e = Visualization::Member.new(random_attributes_for_vis_member({
name:'E',
user_id: @user_mock.id,
type: Visualization::Member::TYPE_SLIDE,
parent_id: parent.id
}))
member_e = member_e.store.fetch
member_a = Visualization::Member.new(random_attributes_for_vis_member({
name:'A',
user_id: @user_mock.id,
type: Visualization::Member::TYPE_SLIDE,
parent_id: parent.id
}))
member_a = member_a.store.fetch
# A -> B -> C -> D -> E
member_a.set_next_list_item! member_b
member_b.set_next_list_item! member_c
member_c.set_next_list_item! member_d
member_d.set_next_list_item! member_e
member_a.fetch
member_b.fetch
member_c.fetch
member_d.fetch
member_e.fetch
parent.fetch
@request_mock = mock
@request_mock.stubs(:host).returns("#{@user_mock.username}#{CartoDB.session_domain}")
@request_mock.stubs(:fullpath).returns('')
data = Visualization::Presenter.new(parent,{request:@request_mock}).to_poro
data[:children].length.should eq 5
data[:children][0][:id].should eq member_a.id
data[:children][1][:id].should eq member_b.id
data[:children][2][:id].should eq member_c.id
data[:children][3][:id].should eq member_d.id
data[:children][4][:id].should eq member_e.id
end
end
end
+149
View File
@@ -0,0 +1,149 @@
require_relative '../../spec_helper'
require_relative '../../../app/models/visualization/relator'
require_relative '../../../app/models/visualization/member'
require_relative '../../../app/models/visualization/collection'
require_relative '../../doubles/support_tables.rb'
include CartoDB
describe Visualization::Relator do
before do
@db = SequelRails.connection
Sequel.extension(:pagination)
Visualization.repository = DataRepository::Backend::Sequel.new(@db, :visualizations)
end
before(:all) do
@user = create_user({
email: 'admin@cartotest.com',
username: 'admin',
password: '000123456'
})
@carto_user = Carto::User.find(@user.id)
end
before(:each) do
bypass_named_maps
delete_user_data(@user)
end
after(:all) do
bypass_named_maps
@user.destroy
end
describe '#estimated_row_count and #actual_row_count' do
it 'should query Table estimated an actual row count methods' do
::Table.any_instance.stubs(:row_count_and_size).returns(row_count: 999)
::Table.any_instance.stubs(:actual_row_count).returns(1000)
table = create_table(name: 'table1', user_id: @user.id)
vis = table.table_visualization
vis.estimated_row_count.should == 999
vis.actual_row_count.should == 1000
end
end
before(:each) do
# For relator->permission
@user_mock = create_mocked_user
CartoDB::Visualization::Relator.any_instance.stubs(:user).returns(@user_mock)
support_tables_mock = Doubles::Visualization::SupportTables.new
Visualization::Relator.any_instance.stubs(:support_tables).returns(support_tables_mock)
end
describe '#related_canonical_visualizations' do
it 'should return the canonical visualizations associated to a derived visualization' do
table1 = create_table({:name => 'table1', :user_id => @user.id})
table2 = create_table({:name => 'table2', :user_id => @user.id})
vis_table1 = create_vis_from_table(@carto_user, table1)
create_vis_from_table(@carto_user, table2)
vis_table1.related_canonical_visualizations.map(&:id).should == [table1.table_visualization.id]
end
end
describe '#children' do
it 'tests .children and its sorting' do
Visualization::Member.any_instance.stubs(:supports_private_maps?).returns(true)
parent = Visualization::Member.new(random_attributes_for_vis_member({
name:'PARENT',
user_id: @user_mock.id,
type: Visualization::Member::TYPE_DERIVED }))
parent = parent.store.fetch
# Create unsorted on purpose
member_d = Visualization::Member.new(random_attributes_for_vis_member({
name:'D', type: Visualization::Member::TYPE_SLIDE,
user_id: @user_mock.id,
parent_id: parent.id }))
member_d = member_d.store.fetch
member_c = Visualization::Member.new(random_attributes_for_vis_member({
name:'C', type: Visualization::Member::TYPE_SLIDE,
user_id: @user_mock.id,
parent_id: parent.id }))
member_c = member_c.store.fetch
member_b = Visualization::Member.new(random_attributes_for_vis_member({
name:'B', type: Visualization::Member::TYPE_SLIDE,
user_id: @user_mock.id,
parent_id: parent.id }))
member_b = member_b.store.fetch
member_e = Visualization::Member.new(random_attributes_for_vis_member({
name:'E', type: Visualization::Member::TYPE_SLIDE,
user_id: @user_mock.id,
parent_id: parent.id }))
member_e = member_e.store.fetch
member_a = Visualization::Member.new(random_attributes_for_vis_member({
name:'A', type: Visualization::Member::TYPE_SLIDE,
user_id: @user_mock.id,
parent_id: parent.id }))
member_a = member_a.store.fetch
# A -> B -> C -> D -> E
member_a.set_next_list_item! member_b
member_b.set_next_list_item! member_c
member_c.set_next_list_item! member_d
member_d.set_next_list_item! member_e
member_a.fetch
member_b.fetch
member_c.fetch
member_d.fetch
member_e.fetch
parent.fetch
children = parent.children
children.length.should eq 5
children[0].id.should eq member_a.id
children[1].id.should eq member_b.id
children[2].id.should eq member_c.id
children[3].id.should eq member_d.id
children[4].id.should eq member_e.id
end
end
private
def create_vis_from_table(user, table)
blender = Visualization::TableBlender.new(user, [table])
map = blender.blend
vis = Visualization::Member.new(
name: 'wadus_vis',
map_id: map.id,
type: Visualization::Member::TYPE_DERIVED,
privacy: blender.blended_privacy,
user_id: user.id
)
vis.store
vis
end
end
@@ -0,0 +1,125 @@
require_relative '../../spec_helper'
require_relative '../../../app/models/visualization/table_blender'
include CartoDB::Visualization
# TODO this file cannot be executed in isolation
describe TableBlender do
let(:user) do
FactoryGirl.create(:valid_user, private_tables_enabled: true, viewer: true)
end
let(:map_mock) do
map = mock
map.stubs(:to_hash).returns({})
map.stubs(:user).returns(user)
map.stubs(:user_layers).returns([])
map.stubs(:data_layers).returns([])
map
end
describe '#blend' do
include Carto::Factories::Visualizations
include_context 'users helper'
it 'raises an error for viewer users' do
tables = [fake_public_table, fake_private_table]
expect {
TableBlender.new(user, tables).blend
}.to raise_error(/Viewer users can't blend tables/)
user.destroy
end
describe 'multiple tables' do
it 'sets increasing order for data layers and keep tiled first and last' do
map1 = FactoryGirl.create(:carto_map_with_2_tiled_layers, user_id: @carto_user1.id)
map2 = FactoryGirl.create(:carto_map_with_2_tiled_layers, user_id: @carto_user1.id)
map1, table1, table_visualization1, visualization1 = create_full_visualization(@carto_user1, canonical_map: map1)
map2, table2, table_visualization2, visualization2 = create_full_visualization(@carto_user1, canonical_map: map2)
blender = CartoDB::Visualization::TableBlender.new(@carto_user1, [table1, table2])
map = blender.blend
map.layers.count.should eq 4
orders_and_kind = map.layers.map { |l| [l.order, l.kind] }.sort { |x, y| x[0] <=> y[0] }
orders_and_kind.should eq [[0, 'tiled'], [1, 'carto'], [2, 'carto'], [3, 'tiled']]
destroy_full_visualization(map2, table2, table_visualization2, visualization2)
destroy_full_visualization(map1, table1, table_visualization1, visualization1)
end
end
describe 'default basemap' do
before(:each) do
@map, @table, @table_visualization, @visualization = create_full_visualization(@carto_user1)
end
after(:each) do
destroy_full_visualization(@map, @table, @table_visualization, @visualization)
end
it 'is chosen from table map basemap for editor users' do
@carto_user1.builder_enabled = false
# Let's force a name change in order to be sure that it's taken from the table map and it's not a default one
fake_name = 'fake_basemap_name'
@table.map.user_layers.first.options['name'] = fake_name
@table.save
blender = CartoDB::Visualization::TableBlender.new(@carto_user1, [@table])
map = blender.blend
map.user_layers.first.options['name'].should eq fake_name
end
it 'is chosen from the default basemap for builder users' do
@carto_user1.builder_enabled = true
# Let's force a name change in order to be sure that it's not taken from the table map
fake_name = 'fake_basemap_name'
@table.map.user_layers.first.options['name'] = fake_name
@table.save
blender = CartoDB::Visualization::TableBlender.new(@carto_user1, [@table])
map = blender.blend
map.user_layers.first.options['name'].should_not eq fake_name
map.user_layers.first.options['name'].should eq Cartodb.default_basemap['name']
end
end
end
# TODO test too coupled with implementation outside blender
# refactor once Privacy is extracted
describe '#blended_privacy' do
it 'returns private if any of all tables is private' do
user = Object.new
tables = [fake_public_table, fake_private_table]
TableBlender.new(user, tables).blended_privacy.should == 'private'
tables = [fake_private_table, fake_public_table]
TableBlender.new(user, tables).blended_privacy.should == 'private'
end
it 'returns public if all tables are public' do
user = Object.new
tables = [fake_public_table, fake_public_table]
TableBlender.new(user, tables).blended_privacy.should == 'public'
end
end
def fake_public_table
table = mock
table.stubs(:private?).returns(false)
table.stubs(:public_with_link_only?).returns(false)
table.stubs(:map).returns(map_mock)
table
end
def fake_private_table
table = mock
table.stubs(:private?).returns(true)
table.stubs(:public_with_link_only?).returns(false)
table.stubs(:map).returns(map_mock)
table
end
end
+97
View File
@@ -0,0 +1,97 @@
require_relative '../../spec_helper'
require_relative '../../../services/data-repository/backend/sequel'
require_relative '../../../services/data-repository/repository'
require_relative '../../../app/models/visualization/tags'
require_relative '../../../app/models/visualization/collection'
require 'helpers/unique_names_helper'
include UniqueNamesHelper
include CartoDB
describe Visualization::Tags do
include CartoDB::Factories
before(:each) do
Varnish.any_instance.stubs(:send_command).returns(true)
@db = SequelRails.connection
Visualization.repository = DataRepository::Backend::Sequel.new(@db, :visualizations)
bypass_named_maps
# For relator->permission
user_id = UUIDTools::UUID.timestamp_create.to_s
user_name = 'whatever'
user_apikey = '123'
@user_mock = create_mocked_user(user_id: user_id, user_name: user_name, user_apikey: user_apikey)
Visualization::Relator.any_instance.stubs(:user).returns(@user_mock)
end
describe '#filters' do
it 'checks that filtering by locked works' do
vis_1_tag = 'v1tag'
vis_2_tag = 'v2tag'
Visualization::Member.new(random_attributes(user_id: @user_mock.id, name: 'viz_1', locked:true, \
tags: [vis_1_tag])).store
Visualization::Member.new(random_attributes(user_id: @user_mock.id, name: 'viz_2', locked:false, \
tags: [vis_2_tag])).store
tags = Visualization::Tags.new(@user_mock)
records = tags.names()
records.length.should eq 2
records = tags.names(locked: false)
records.length.should eq 1
records.first.should eq vis_2_tag
records = tags.names(locked: true)
records.length.should eq 1
records.first.should eq vis_1_tag
end
end
describe 'searching' do
it 'should search for tags correctly' do
manolo_tag = 'manolo'
manoloescobar_tag = 'manoloescobar'
manolo_escobar_tag = 'Manolo Escobar'
v1 = Visualization::Member.new(random_attributes(user_id: @user_mock.id, name: 'v1', locked:true, tags: [manolo_tag, manoloescobar_tag, manolo_escobar_tag])).store
v2 = Visualization::Member.new(random_attributes(user_id: @user_mock.id, name: 'v2', locked:false, tags: [manolo_tag])).store
v3 = Visualization::Member.new(random_attributes(user_id: @user_mock.id, name: 'v3', locked:false, tags: [manolo_escobar_tag, manoloescobar_tag])).store
vqb1 = Carto::VisualizationQueryBuilder.new.with_tags([manolo_tag.upcase]).build.map(&:id)
vqb1.should include v1.id
vqb1.should include v2.id # Searching for 'manolo' should bring up 'manoloescobar' as well
vqb1.should include v3.id
vqb2 = Carto::VisualizationQueryBuilder.new.with_tags([manoloescobar_tag.upcase]).build.map(&:id)
vqb2.should include v1.id
vqb2.should_not include v2.id # 'manoloescobar' is not a substring of 'manolo'
vqb2.should include v3.id
vqb3 = Carto::VisualizationQueryBuilder.new.with_tags([manolo_escobar_tag.upcase]).build.map(&:id)
vqb3.should include v1.id
vqb3.should_not include v2.id
vqb3.should include v3.id
end
end
def random_attributes(attributes={})
random = unique_name('viz')
{
name: attributes.fetch(:name, random),
description: attributes.fetch(:description, "description #{random}"),
privacy: attributes.fetch(:privacy, 'public'),
tags: attributes.fetch(:tags, ['tag 1']),
type: attributes.fetch(:type, CartoDB::Visualization::Member::TYPE_CANONICAL),
user_id: attributes.fetch(:user_id, UUIDTools::UUID.timestamp_create.to_s),
locked: attributes.fetch(:locked, false)
}
end
end