canvas-lms/spec/lib/user_search_spec.rb

228 lines
8.6 KiB
Ruby

# encoding: utf-8
require File.expand_path( '../sharding_spec_helper' , File.dirname(__FILE__))
describe UserSearch do
describe '.for_user_in_context' do
let(:search_names) { ['Rose Tyler', 'Martha Jones', 'Rosemary Giver', 'Martha Stewart', 'Tyler Pickett', 'Jon Stewart', 'Stewart Little', 'Ĭńşŧřůćƭǜȑȩ Person'] }
let(:course) { Course.create! }
let(:users) { UserSearch.for_user_in_context('Stewart', course, user).to_a }
let(:names) { users.map(&:name) }
let(:user) { User.last }
let(:student) { User.find_by_name(search_names.last) }
before do
teacher = User.create!(:name => 'Tyler Teacher')
TeacherEnrollment.create!(:user => teacher, :course => course, :workflow_state => 'active')
search_names.each do |name|
student = User.create!(:name => name)
StudentEnrollment.create!(:user => student, :course => course, :workflow_state => 'active')
end
User.create!(:name => "admin")
TeacherEnrollment.create!(:user => user, :course => course, :workflow_state => 'active')
end
describe 'with complex search enabled' do
before { Setting.set('user_search_with_full_complexity', 'true') }
describe 'with gist setting enabled' do
before { Setting.set('user_search_with_gist', 'true') }
it "searches case-insensitively" do
UserSearch.for_user_in_context("steWArt", course, user).size.should == 3
end
it "uses postgres lower(), not ruby downcase()" do
# ruby 1.9 downcase doesn't handle the downcasing of many multi-byte characters correctly
UserSearch.for_user_in_context('Ĭńşŧřůćƭǜȑȩ', course, user).size.should == 1
end
it 'returns an enumerable' do
users.size.should == 3
end
it 'contains the matching users' do
names.should include('Martha Stewart')
names.should include('Stewart Little')
names.should include('Jon Stewart')
end
it 'does not contain users I am not allowed to see' do
unenrolled_user = User.create!(:name => 'Unenrolled User')
search_results = UserSearch.for_user_in_context('Stewart', course, unenrolled_user).map(&:name)
search_results.should == []
end
it 'will not pickup students outside the course' do
out_of_course_student = User.create!(:name => 'Stewart Stewart')
# names is evaluated lazily from the 'let' block so ^ user is still being
# created before the query executes
names.should_not include('Stewart Stewart')
end
it 'will find teachers' do
results = UserSearch.for_user_in_context('Tyler', course, user)
results.map(&:name).should include('Tyler Teacher')
end
describe 'filtering by role' do
subject { names }
describe 'to a single role' do
let(:users) { UserSearch.for_user_in_context('Tyler', course, user, nil, :enrollment_type => 'student' ).to_a }
it { should include('Rose Tyler') }
it { should include('Tyler Pickett') }
it { should_not include('Tyler Teacher') }
end
describe 'to multiple roles' do
let(:users) { UserSearch.for_user_in_context('Tyler', course, student, nil, :enrollment_type => ['ta', 'teacher'] ).to_a }
before do
ta = User.create!(:name => 'Tyler TA')
TaEnrollment.create!(:user => ta, :course => course, :workflow_state => 'active')
end
it { should include('Tyler TA') }
it { should include('Tyler Teacher') }
it { should_not include('Rose Tyler') }
end
describe 'with the broader role parameter' do
let(:users) { UserSearch.for_user_in_context('Tyler', course, student, nil, :enrollment_role => 'ObserverEnrollment' ).to_a }
before do
ta = User.create!(:name => 'Tyler Observer')
ObserverEnrollment.create!(:user => ta, :course => course, :workflow_state => 'active')
ta2 = User.create!(:name => 'Tyler Observer 2')
ObserverEnrollment.create!(:user => ta2, :course => course, :workflow_state => 'active')
student.observers << ta2
end
it { should_not include('Tyler Observer 2') }
it { should_not include('Tyler Observer') }
it { should_not include('Tyler Teacher') }
it { should_not include('Rose Tyler') }
end
end
describe 'searching on sis ids' do
let(:pseudonym) { user.pseudonyms.build }
before do
pseudonym.sis_user_id = "SOME_SIS_ID"
pseudonym.unique_id = "SOME_UNIQUE_ID@example.com"
pseudonym.save!
end
it 'will match against an sis id' do
UserSearch.for_user_in_context("SOME_SIS", course, user).should == [user]
end
it 'can match an SIS id and a user name in the same query' do
pseudonym.sis_user_id = "MARTHA_SIS_ID"
pseudonym.save!
other_user = User.find_by_name('Martha Stewart')
results = UserSearch.for_user_in_context("martha", course, user)
results.should include(user)
results.should include(other_user)
end
end
describe 'searching on emails' do
before { user.communication_channels.create!(:path => 'the.giver@example.com', :path_type => CommunicationChannel::TYPE_EMAIL) }
it 'matches against an email' do
UserSearch.for_user_in_context("the.giver", course, user).should == [user]
end
it 'can match an email and a name in the same query' do
results = UserSearch.for_user_in_context("giver", course, user)
results.should include(user)
results.should include(User.find_by_name('Rosemary Giver'))
end
it 'will not match channels where the type is not email' do
user.communication_channels.last.update_attributes!(:path_type => CommunicationChannel::TYPE_TWITTER)
UserSearch.for_user_in_context("the.giver", course, user).should == []
end
end
describe 'searching by a DB ID' do
it 'matches against the database id' do
UserSearch.for_user_in_context(user.id, course, user).should == [user]
end
describe "cross-shard users" do
specs_require_sharding
it 'matches against the database id of a cross-shard user' do
user = @shard1.activate { user_model }
course.enroll_student(user)
UserSearch.for_user_in_context(user.global_id, course, user).should == [user]
UserSearch.for_user_in_context(user.global_id, course.account, user).should == [user]
end
end
end
end
describe 'with gist setting disabled' do
before { Setting.set('user_search_with_gist', 'false') }
it 'returns a list of matching users using a prefix search' do
names.should == ['Stewart Little']
end
end
end
describe 'with complex search disabled' do
before do
Setting.set('user_search_with_full_complexity', 'false')
Setting.set('user_search_with_gist', 'true')
end
it 'matches against the display name' do
users.size.should == 3
end
it 'does not match against sis ids' do
pseudonym = user.pseudonyms.build
pseudonym.sis_user_id = "SOME_SIS_ID"
pseudonym.unique_id = "SOME_UNIQUE_ID@example.com"
pseudonym.save!
UserSearch.for_user_in_context("SOME_SIS", course, user).should == []
end
it 'does not match against emails' do
user.communication_channels.create!(:path => 'the.giver@example.com', :path_type => CommunicationChannel::TYPE_EMAIL)
UserSearch.for_user_in_context("the.giver", course, user).should == []
end
end
end
describe '.like_string_for' do
it 'uses a prefix if gist is not configured' do
Setting.set('user_search_with_gist', 'false')
UserSearch.like_string_for("word").should == 'word%'
end
it 'modulos both sides if gist is configured' do
Setting.set('user_search_with_gist', 'true')
UserSearch.like_string_for("word").should == '%word%'
end
end
describe '.scope_for' do
it 'raises an error if there is a bad enrollment type' do
course = Course.create!
student = User.create!
bad_scope = lambda { UserSearch.scope_for(course, student, :enrollment_type => 'all') }
bad_scope.should raise_error(ArgumentError, 'Invalid Enrollment Type')
end
end
end