4 use RT::Test tests => undef,
5 config => 'Set( %FullTextSearch, Enable => 1, Indexed => 0 );';
6 my ($baseurl, $m) = RT::Test->started_ok;
7 my $url = $m->rt_base_url;
9 my $queue = RT::Queue->new($RT::SystemUser);
10 $queue->Create( Name => 'other' );
11 ok( $queue->id, 'created queue other');
13 my $two_words_queue = RT::Test->load_or_create_queue(
16 ok $two_words_queue && $two_words_queue->id, 'loaded or created a queue';
20 my $tickets = RT::Tickets->new( RT->SystemUser );
21 my $active = "( ".join( " OR ", map "Status = '$_'", RT::Queue->ActiveStatusArray())." )";
22 my $inactive = "( ".join( " OR ", map "Status = '$_'", RT::Queue->InactiveStatusArray())." )";
24 require RT::Search::Googleish;
25 my $parser = RT::Search::Googleish->new(
26 TicketsObj => $tickets,
29 is $parser->QueryToSQL("foo"), "$active AND ( Subject LIKE 'foo' )", "correct parsing";
30 is $parser->QueryToSQL("1"), "( Id = 1 )", "correct parsing";
31 is $parser->QueryToSQL("#1"), "( Id = 1 )", "correct parsing";
32 is $parser->QueryToSQL("'1'"), "$active AND ( Subject LIKE '1' )", "correct parsing";
34 is $parser->QueryToSQL("foo bar"),
35 "$active AND ( Subject LIKE 'foo' AND Subject LIKE 'bar' )",
37 is $parser->QueryToSQL("'foo bar'"),
38 "$active AND ( Subject LIKE 'foo bar' )",
41 is $parser->QueryToSQL("'foo \\' bar'"),
42 "$active AND ( Subject LIKE 'foo \\' bar' )",
44 is $parser->QueryToSQL('"foo \' bar"'),
45 "$active AND ( Subject LIKE 'foo \\' bar' )",
47 is $parser->QueryToSQL('"\f\o\o"'),
48 "$active AND ( Subject LIKE '\\\\f\\\\o\\\\o' )",
51 is $parser->QueryToSQL("General"), "( Queue = 'General' ) AND $active", "correct parsing";
52 is $parser->QueryToSQL("'Two Words'"), "$active AND ( Subject LIKE 'Two Words' )", "correct parsing";
53 is $parser->QueryToSQL("queue:'Two Words'"), "( Queue = 'Two Words' ) AND $active", "correct parsing";
54 is $parser->QueryToSQL("subject:'Two Words'"), "$active AND ( Subject LIKE 'Two Words' )", "correct parsing";
56 is $parser->QueryToSQL("me"), "( Owner.id = '__CurrentUser__' ) AND $active", "correct parsing";
57 is $parser->QueryToSQL("'me'"), "$active AND ( Subject LIKE 'me' )", "correct parsing";
58 is $parser->QueryToSQL("owner:me"), "( Owner.id = '__CurrentUser__' ) AND $active", "correct parsing";
59 is $parser->QueryToSQL("owner:'me'"), "( Owner = 'me' ) AND $active", "correct parsing";
60 is $parser->QueryToSQL('owner:root@localhost'), "( Owner.EmailAddress = 'root\@localhost' ) AND $active", "Email address as owner";
62 is $parser->QueryToSQL("resolved me"), "( Owner.id = '__CurrentUser__' ) AND ( Status = 'resolved' )", "correct parsing";
63 is $parser->QueryToSQL("resolved active me"), "( Owner.id = '__CurrentUser__' ) AND ( Status = 'resolved' OR Status = 'new' OR Status = 'open' OR Status = 'stalled' )", "correct parsing";
64 is $parser->QueryToSQL("status:active"), $active, "Explicit active search";
65 is $parser->QueryToSQL("status:'active'"), "( Status = 'active' )", "Quoting active makes it the actual word";
66 is $parser->QueryToSQL("inactive me"), "( Owner.id = '__CurrentUser__' ) AND $inactive", "correct parsing";
68 is $parser->QueryToSQL("cf.Foo:bar"), "( 'CF.{Foo}' LIKE 'bar' ) AND $active", "correct parsing of CFs";
69 is $parser->QueryToSQL(q{cf."don't foo?":'bar n\\' baz'}), qq/( 'CF.{don\\'t foo?}' LIKE 'bar n\\' baz' ) AND $active/, "correct parsing of CFs with quotes";
72 my $ticket_found_1 = RT::Ticket->new($RT::SystemUser);
73 my $ticket_found_2 = RT::Ticket->new($RT::SystemUser);
74 my $ticket_not_found = RT::Ticket->new($RT::SystemUser);
76 $ticket_found_1->Create(
77 Subject => 'base ticket 1'.$$,
80 Requestor => 'customsearch@localhost',
81 Content => 'this is base ticket 1',
83 ok( $ticket_found_1->id, 'created ticket for custom search');
86 $ticket_found_2->Create(
87 Subject => 'base ticket 2'.$$,
90 Requestor => 'customsearch@localhost',
91 Content => 'this is base ticket 2',
93 ok( $ticket_found_2->id, 'created ticket for custom search');
95 $ticket_not_found = RT::Ticket->new($RT::SystemUser);
96 $ticket_not_found->Create(
97 Subject => 'not found subject' . $$,
100 Requestor => 'notfound@localhost',
101 Content => 'this is not found content',
103 ok( $ticket_not_found->id, 'created ticket for custom search');
105 ok($m->login, 'logged in');
108 'base ticket', 'root',
109 'customsearch@localhost', 'requestor:customsearch',
110 'subject:base', 'subject:"base ticket"',
111 'queue:general', 'owner:root',
114 for my $q (@queries) {
115 $m->form_with_fields('q');
116 $m->field( q => $q );
118 $m->content_contains( 'base ticket 1', 'base ticket 1 is found' );
119 $m->content_contains( 'base ticket 2', 'base ticket 2 is found' );
120 $m->content_lacks( 'not found subject', 'not found ticket is not found' );
123 $ticket_not_found->SetStatus('open');
124 is( $ticket_not_found->Status, 'open', 'status of not found ticket is open' );
125 @queries = qw/new status:new/;
126 for my $q (@queries) {
127 $m->form_with_fields('q');
128 $m->field( q => $q );
130 $m->content_contains( 'base ticket 1', 'base ticket 1 is found' );
131 $m->content_contains( 'base ticket 2', 'base ticket 2 is found' );
132 $m->content_lacks( 'not found subject', 'not found ticket is not found' );
135 @queries = ( 'fulltext:"base ticket 1"', "'base ticket 1'" );
136 for my $q (@queries) {
137 $m->form_with_fields('q');
138 $m->field( q => $q );
140 $m->content_contains( 'base ticket 1', 'base ticket 1 is found' );
141 $m->content_lacks( 'base ticket 2', 'base ticket 2 is not found' );
142 $m->content_lacks( 'not found subject', 'not found ticket is not found' );
145 # now let's test with ' or "
146 for my $quote ( q{'}, q{"} ) {
147 my $user = RT::User->new($RT::SystemUser);
148 is( ref($user), 'RT::User' );
149 my ( $id, $msg ) = $user->Create(
150 Name => qq!foo${quote}bar!,
151 EmailAddress => qq!foo${quote}bar$$\@example.com !,
154 ok ($id, "Creating user - " . $msg );
156 my ( $grantid, $grantmsg ) =
157 $user->PrincipalObj->GrantRight( Right => 'OwnTicket' );
158 ok( $grantid, $grantmsg );
162 my $ticket_quote = RT::Ticket->new($RT::SystemUser);
163 $ticket_quote->Create(
164 Subject => qq!base${quote}ticket $$!,
166 Owner => $user->Name,
167 Requestor => qq!custom${quote}search\@localhost!,
168 Content => qq!this is base${quote}ticket with quote inside!,
170 ok( $ticket_quote->id, 'created ticket with quote for custom search' );
173 qq!fulltext:base${quote}ticket!,
174 "base${quote}ticket",
175 "owner:foo${quote}bar",
178 # email doesn't allow " character
181 "requestor:custom${quote}search\@localhost",
182 "custom${quote}search\@localhost",
186 for my $q (@queries) {
187 $m->form_with_fields('q');
188 $m->field( q => $q );
190 my $escape_quote = $quote;
191 RT::Interface::Web::EscapeUTF8(\$escape_quote);
192 $m->content_contains( "base${escape_quote}ticket",
193 "base${quote}ticket is found" );
199 my $cf = RT::CustomField->new(RT->SystemUser);
200 ok( $cf->Create(Name => 'Foo', Type => 'Freeform', MaxValues => '1', Queue => 0) );
203 $ticket_found_1->AddCustomFieldValue( Field => 'Foo', Value => 'bar' );
204 $ticket_found_2->AddCustomFieldValue( Field => 'Foo', Value => 'bar' );
205 $ticket_not_found->AddCustomFieldValue( Field => 'Foo', Value => 'baz' );
206 is( $ticket_found_1->FirstCustomFieldValue('Foo'), 'bar', 'cf value is ok' );
207 is( $ticket_found_2->FirstCustomFieldValue('Foo'), 'bar', 'cf value is ok' );
208 is( $ticket_not_found->FirstCustomFieldValue('Foo'), 'baz', 'cf value is ok' );
210 @queries = qw/cf.Foo:bar/;
211 for my $q (@queries) {
212 $m->form_with_fields('q');
213 $m->field( q => $q );
215 $m->content_contains( 'base ticket 1', 'base ticket 1 is found' );
216 $m->content_contains( 'base ticket 2', 'base ticket 2 is found' );
217 $m->content_lacks( 'not found subject', 'not found ticket is not found' );