263 lines
8.9 KiB
Perl
263 lines
8.9 KiB
Perl
|
|
# t/directorysearch.t
|
||
|
|
#
|
||
|
|
# Test directory search.
|
||
|
|
#
|
||
|
|
# This code was forked from the LiveJournal project owned and operated
|
||
|
|
# by Live Journal, Inc. The code has been modified and expanded by
|
||
|
|
# Dreamwidth Studios, LLC. These files were originally licensed under
|
||
|
|
# the terms of the license supplied by Live Journal, Inc, which can
|
||
|
|
# currently be found at:
|
||
|
|
#
|
||
|
|
# http://code.livejournal.org/trac/livejournal/browser/trunk/LICENSE-LiveJournal.txt
|
||
|
|
#
|
||
|
|
# In accordance with the original license, this code and all its
|
||
|
|
# modifications are provided under the GNU General Public License.
|
||
|
|
# A copy of that license can be found in the LICENSE file included as
|
||
|
|
# part of this distribution.
|
||
|
|
|
||
|
|
use strict;
|
||
|
|
use warnings;
|
||
|
|
|
||
|
|
use Test::More;
|
||
|
|
|
||
|
|
BEGIN { $LJ::_T_CONFIG = 1; require "$ENV{LJHOME}/cgi-bin/ljlib.pl"; }
|
||
|
|
use LJ::Test;
|
||
|
|
use LJ::Directory::Search;
|
||
|
|
use LJ::ModuleCheck;
|
||
|
|
if ( LJ::ModuleCheck->have("LJ::UserSearch") ) {
|
||
|
|
|
||
|
|
# plan tests => 71;
|
||
|
|
plan skip_all => "User search without workers currently bitrotted";
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
plan 'skip_all' => "Need LJ::UserSearch module.";
|
||
|
|
exit 0;
|
||
|
|
}
|
||
|
|
use LJ::Directory::MajorRegion;
|
||
|
|
use LJ::Directory::PackedUserRecord;
|
||
|
|
|
||
|
|
local @LJ::GEARMAN_SERVERS = (); # don't dispatch set requests. all in-process.
|
||
|
|
|
||
|
|
my @args;
|
||
|
|
|
||
|
|
my $is = sub {
|
||
|
|
local $Test::Builder::Level = $Test::Builder::Level + 1;
|
||
|
|
|
||
|
|
my ( $name, $str, @good_cons ) = @_;
|
||
|
|
my %args = map { LJ::durl($_) } split( /[=&]/, $str );
|
||
|
|
my @cons =
|
||
|
|
sort { ref($a) cmp ref($b) } LJ::Directory::Constraint->constraints_from_formargs( \%args );
|
||
|
|
is_deeply( \@cons, \@good_cons, $name );
|
||
|
|
};
|
||
|
|
|
||
|
|
$is->(
|
||
|
|
"US/Oregon",
|
||
|
|
"loc_cn=US&loc_st=OR&opt_sort=ut",
|
||
|
|
LJ::Directory::Constraint::Location->new( country => 'US', state => 'OR' )
|
||
|
|
);
|
||
|
|
|
||
|
|
$is->(
|
||
|
|
"OR (without US)",
|
||
|
|
"loc_cn=&loc_st=OR&opt_sort=ut",
|
||
|
|
LJ::Directory::Constraint::Location->new( country => 'US', state => 'OR' )
|
||
|
|
);
|
||
|
|
|
||
|
|
$is->(
|
||
|
|
"Oregon (without US)",
|
||
|
|
"loc_cn=&loc_st=Oregon&opt_sort=ut",
|
||
|
|
LJ::Directory::Constraint::Location->new( country => 'US', state => 'OR' )
|
||
|
|
);
|
||
|
|
|
||
|
|
$is->(
|
||
|
|
"Russia", "loc_cn=RU&opt_sort=ut", LJ::Directory::Constraint::Location->new( country => 'RU' )
|
||
|
|
);
|
||
|
|
|
||
|
|
$is->(
|
||
|
|
"Interest",
|
||
|
|
"int_like=lindenz&opt_sort=ut",
|
||
|
|
LJ::Directory::Constraint::Interest->new( interest => 'lindenz' )
|
||
|
|
);
|
||
|
|
|
||
|
|
$is->(
|
||
|
|
"Has friend", "fr_user=system&opt_sort=ut",
|
||
|
|
LJ::Directory::Constraint::HasFriend->new( user => 'system' )
|
||
|
|
);
|
||
|
|
|
||
|
|
$is->(
|
||
|
|
"Is friend of", "fro_user=system&opt_sort=ut",
|
||
|
|
LJ::Directory::Constraint::FriendOf->new( user => 'system' )
|
||
|
|
);
|
||
|
|
|
||
|
|
$is->(
|
||
|
|
"Is a community",
|
||
|
|
"journaltype=C&opt_sort=ut", LJ::Directory::Constraint::JournalType->new( journaltype => 'C' )
|
||
|
|
);
|
||
|
|
|
||
|
|
# serializing tests
|
||
|
|
{
|
||
|
|
my ( $con, $back, $str );
|
||
|
|
$con = LJ::Directory::Constraint::Location->new( country => 'US', state => 'OR' );
|
||
|
|
is( $con->serialize, "Location:country=US&state=OR", "serializes" );
|
||
|
|
$con = LJ::Directory::Constraint::Location->new( country => 'US', state => '' );
|
||
|
|
$str = $con->serialize;
|
||
|
|
is( $str, "Location:country=US", "serializes" );
|
||
|
|
$back = LJ::Directory::Constraint->deserialize($str);
|
||
|
|
ok( $back, "went back" );
|
||
|
|
is( ref $back, ref $con, "same type" );
|
||
|
|
}
|
||
|
|
|
||
|
|
my $usercount = 100;
|
||
|
|
|
||
|
|
# init the search system
|
||
|
|
my $inittime = time();
|
||
|
|
{
|
||
|
|
LJ::UserSearch::reset_usermeta( 8 * ( $usercount + 1 ) );
|
||
|
|
for my $uid ( 0 .. $usercount ) {
|
||
|
|
my $lastupdate = $inittime - $usercount + $uid;
|
||
|
|
my $buf = LJ::Directory::PackedUserRecord->new(
|
||
|
|
updatetime => $lastupdate,
|
||
|
|
age => $uid,
|
||
|
|
|
||
|
|
# scatter around USA:
|
||
|
|
regionid => 1 + int( $uid % 60 ),
|
||
|
|
|
||
|
|
# even amount of all:
|
||
|
|
journaltype => ( ( "P", "I", "C", "Y" )[ $uid % 4 ] ),
|
||
|
|
)->packed;
|
||
|
|
LJ::UserSearch::add_usermeta( $buf, 8 );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Major Region stuff (location canonicalization as well, for some major regions)
|
||
|
|
{
|
||
|
|
local $LJ::_T_DEFAULT_MAJREGIONS = 1;
|
||
|
|
my ( $regid, $regname );
|
||
|
|
$regid = LJ::Directory::MajorRegion->region_id( "RU", "Somewhere", "Msk" );
|
||
|
|
is( $regid, 64, "found matching region id for Msk" );
|
||
|
|
$regid = LJ::Directory::MajorRegion->region_id( "RU", "Somewhere", "Blahblahblah" );
|
||
|
|
ok( !$regid, "didn't find blahblahblah" );
|
||
|
|
|
||
|
|
$regid = LJ::Directory::MajorRegion->region_id( "RU", "", "" );
|
||
|
|
is( $regid, 63, "found Russia" );
|
||
|
|
|
||
|
|
$regid = LJ::Directory::MajorRegion->most_specific_matching_region_id( "RU", "Somewhere",
|
||
|
|
"Blahblahblah" );
|
||
|
|
is( $regid, 63, "found that blahblahblah is in Russia" );
|
||
|
|
|
||
|
|
$regid = LJ::Directory::MajorRegion->region_id( "US", "CA", "" );
|
||
|
|
is( $regid, 10, "found California" );
|
||
|
|
|
||
|
|
is_deeply(
|
||
|
|
[ sort LJ::Directory::MajorRegion->region_ids("RU") ],
|
||
|
|
[ 63, 64, 65 ],
|
||
|
|
"found all russia regions"
|
||
|
|
);
|
||
|
|
|
||
|
|
my $us_ids = [ LJ::Directory::MajorRegion->region_ids("US") ];
|
||
|
|
is( scalar(@$us_ids), 62, "found all US regions" );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
# doing actual searches
|
||
|
|
memcache_stress(
|
||
|
|
sub {
|
||
|
|
{
|
||
|
|
my ( $search, $res );
|
||
|
|
|
||
|
|
$search = LJ::Directory::Search->new;
|
||
|
|
ok( $search, "made a search" );
|
||
|
|
|
||
|
|
$search->add_constraint( LJ::Directory::Constraint::Test->new( uids => "1,2,3,4,5" ) );
|
||
|
|
$search->add_constraint(
|
||
|
|
LJ::Directory::Constraint::Test->new( uids => "2,3,4,5,6,2,2,2,2,2,2,2" ) );
|
||
|
|
|
||
|
|
$res = $search->search_no_dispatch;
|
||
|
|
ok( $res, "got a result" );
|
||
|
|
|
||
|
|
is( $res->pages, 1, "just one page" );
|
||
|
|
is_deeply( [ $res->userids ], [ 5, 4, 3, 2 ], "got the right results back" );
|
||
|
|
|
||
|
|
# test paging
|
||
|
|
$search = LJ::Directory::Search->new( page_size => 2, page => 2 );
|
||
|
|
is( $search->page, 2, "requested page 2" );
|
||
|
|
$search->add_constraint(
|
||
|
|
LJ::Directory::Constraint::Test->new( uids => "1,2,3,4,5,6,7,8,9,10" ) );
|
||
|
|
$search->add_constraint(
|
||
|
|
LJ::Directory::Constraint::Test->new(
|
||
|
|
uids => "1,2,3,4,5,6,7,8,9,10,11,12,14,15,888888888"
|
||
|
|
)
|
||
|
|
);
|
||
|
|
$res = $search->search_no_dispatch;
|
||
|
|
is( $res->pages, 5, "five pages" );
|
||
|
|
is_deeply( [ $res->userids ], [ 8, 7 ], "got the right results back" );
|
||
|
|
|
||
|
|
# test paging, not even page size
|
||
|
|
$search = LJ::Directory::Search->new( page_size => 2, page => 3 );
|
||
|
|
is( $search->page, 3, "requested page 3" );
|
||
|
|
$search->add_constraint(
|
||
|
|
LJ::Directory::Constraint::Test->new( uids => "1,2,3,4,5,6,7,8,9" ) );
|
||
|
|
$search->add_constraint(
|
||
|
|
LJ::Directory::Constraint::Test->new(
|
||
|
|
uids => "1,2,3,4,5,6,7,8,9,10,11,12,14,15,888888888"
|
||
|
|
)
|
||
|
|
);
|
||
|
|
$res = $search->search_no_dispatch;
|
||
|
|
is( $res->pages, 5, "five pages" );
|
||
|
|
is_deeply( [ $res->userids ], [ 5, 4 ], "got the right results back" );
|
||
|
|
|
||
|
|
# test update times
|
||
|
|
$search = LJ::Directory::Search->new;
|
||
|
|
$search->add_constraint(
|
||
|
|
LJ::Directory::Constraint::UpdateTime->new( since => ( $inittime - 4 ) ) );
|
||
|
|
$res = $search->search_no_dispatch;
|
||
|
|
is_deeply(
|
||
|
|
[ $res->userids ],
|
||
|
|
[ $usercount, $usercount - 1, $usercount - 2, $usercount - 3, $usercount - 4 ],
|
||
|
|
"got recent posters"
|
||
|
|
);
|
||
|
|
|
||
|
|
# test update times, after an initial et
|
||
|
|
$search = LJ::Directory::Search->new;
|
||
|
|
$search->add_constraint(
|
||
|
|
LJ::Directory::Constraint::Test->new( uids => "90,95,98,23,25,23" ) );
|
||
|
|
$search->add_constraint(
|
||
|
|
LJ::Directory::Constraint::UpdateTime->new(
|
||
|
|
since => ( $inittime - $usercount + 50 )
|
||
|
|
)
|
||
|
|
);
|
||
|
|
$res = $search->search_no_dispatch;
|
||
|
|
is_deeply(
|
||
|
|
[ $res->userids ],
|
||
|
|
[ 98, 95, 90 ],
|
||
|
|
"got correct answer (explicit set + first 50)"
|
||
|
|
);
|
||
|
|
|
||
|
|
# test sub major regions
|
||
|
|
$search = LJ::Directory::Search->new;
|
||
|
|
$search->add_constraint(
|
||
|
|
LJ::Directory::Constraint::Location->new( country => "US", state => "CA" ) );
|
||
|
|
$res = $search->search_no_dispatch;
|
||
|
|
ok( scalar( $res->userids ) > 0, "found a user or so in california" );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
# search with a huge number of ids (force it to use blobstore for set handles)
|
||
|
|
SKIP: {
|
||
|
|
my ( $search, $res );
|
||
|
|
|
||
|
|
memcache_stress(
|
||
|
|
sub {
|
||
|
|
# test paging
|
||
|
|
$search = LJ::Directory::Search->new( page_size => 100, page => 1 );
|
||
|
|
$search->add_constraint(
|
||
|
|
LJ::Directory::Constraint::Test->new( uids => join( ",", 1 .. 5000 ) ) );
|
||
|
|
$search->add_constraint(
|
||
|
|
LJ::Directory::Constraint::Test->new( uids => join( ",", 51 .. 6000 ) ) );
|
||
|
|
$res = $search->search_no_dispatch;
|
||
|
|
is( $res->pages, 1, "50 pages" );
|
||
|
|
is_deeply( [ $res->userids ], [ reverse( 51 .. 100 ) ], "got the right results back" );
|
||
|
|
}
|
||
|
|
);
|
||
|
|
}
|