summaryrefslogtreecommitdiff
path: root/rt/t/web
diff options
context:
space:
mode:
authorIvan Kohler <ivan@freeside.biz>2012-06-07 16:58:33 -0700
committerIvan Kohler <ivan@freeside.biz>2012-06-07 16:58:33 -0700
commit21a232b78413718d8a68867ba7eb4f52a287f9b6 (patch)
tree988115f9363144a2afdac9e3d9914964a7725105 /rt/t/web
parentc24d6e2242ae0e026684b8f95decf156aba6e75e (diff)
rt 4.0.6
Diffstat (limited to 'rt/t/web')
-rw-r--r--rt/t/web/command_line_link_to_articles.t48
-rw-r--r--rt/t/web/csrf-rest.t77
-rw-r--r--rt/t/web/csrf.t181
-rw-r--r--rt/t/web/installer.t95
-rw-r--r--rt/t/web/owner_disabled_group_19221.t190
-rw-r--r--rt/t/web/query_builder_queue_limits.t180
-rw-r--r--rt/t/web/rest_cfs_with_same_name.t88
7 files changed, 859 insertions, 0 deletions
diff --git a/rt/t/web/command_line_link_to_articles.t b/rt/t/web/command_line_link_to_articles.t
new file mode 100644
index 000000000..9a49145fd
--- /dev/null
+++ b/rt/t/web/command_line_link_to_articles.t
@@ -0,0 +1,48 @@
+use strict;
+use warnings;
+use Test::Expect;
+use RT::Test tests => 12, actual_server => 1;
+
+my $class = RT::Class->new( RT->SystemUser );
+my ( $class_id, $msg ) = $class->Create( Name => 'foo' );
+ok( $class_id, $msg );
+
+my $article = RT::Article->new( RT->SystemUser );
+( my $article_id, $msg ) =
+ $article->Create( Class => 'foo', Summary => 'article summary' );
+ok( $article_id, $msg );
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+my $rt_tool_path = "$RT::BinPath/rt";
+
+$ENV{'RTUSER'} = 'root';
+$ENV{'RTPASSWD'} = 'password';
+$RT::Logger->debug(
+ "Connecting to server at " . RT->Config->Get('WebBaseURL') );
+$ENV{'RTSERVER'} = RT->Config->Get('WebBaseURL');
+$ENV{'RTDEBUG'} = '1';
+$ENV{'RTCONFIG'} = '/dev/null';
+
+expect_run(
+ command => "$rt_tool_path shell",
+ prompt => 'rt> ',
+ quit => 'quit',
+);
+expect_send( q{create -t ticket set subject='new ticket'},
+ "creating a ticket..." );
+
+expect_like( qr/Ticket \d+ created/, "created the ticket" );
+expect_handle->before() =~ /Ticket (\d+) created/;
+my $ticket_id = $1;
+expect_send(
+ "link $ticket_id RefersTo a:$article_id",
+ "link $ticket_id RefersTo a:$article_id"
+);
+expect_like( qr/Created link $ticket_id RefersTo a:$article_id/,
+ 'created link' );
+expect_send( "show -s ticket/$ticket_id/links", "show ticket links" );
+expect_like( qr|RefersTo: fsck\.com-article://example\.com/article/$article_id|,
+ "found new created link" );
+
+expect_quit();
+
diff --git a/rt/t/web/csrf-rest.t b/rt/t/web/csrf-rest.t
new file mode 100644
index 000000000..5bb908165
--- /dev/null
+++ b/rt/t/web/csrf-rest.t
@@ -0,0 +1,77 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use RT::Test tests => undef;
+
+my ($baseurl, $m) = RT::Test->started_ok;
+
+# Get a non-REST session
+diag "Standard web session";
+ok $m->login, 'logged in';
+$m->content_contains("RT at a glance", "Get full UI content");
+
+# Requesting a REST page should be fine, as we have a Referer
+$m->post("$baseurl/REST/1.0/ticket/new", [
+ format => 'l',
+]);
+$m->content_like(qr{^id: ticket/new}m, "REST request with referrer");
+
+# Removing the Referer header gets us an interstitial
+$m->add_header(Referer => undef);
+$m->post("$baseurl/REST/1.0/ticket/new", [
+ format => 'l',
+ foo => 'bar',
+]);
+$m->content_contains("Possible cross-site request forgery",
+ "REST request without referrer is blocked");
+
+# But passing username and password lets us though
+$m->post("$baseurl/REST/1.0/ticket/new", [
+ user => 'root',
+ pass => 'password',
+ format => 'l',
+]);
+$m->content_like(qr{^id: ticket/new}m, "REST request without referrer, but username/password supplied, is OK");
+
+# And we can still access non-REST urls
+$m->get("$baseurl");
+$m->content_contains("RT at a glance", "Full UI is still available");
+
+
+# Now go get a REST session
+diag "REST session";
+$m = RT::Test::Web->new;
+$m->post("$baseurl/REST/1.0/ticket/new", [
+ user => 'root',
+ pass => 'password',
+ format => 'l',
+]);
+$m->content_like(qr{^id: ticket/new}m, "REST request to log in");
+
+# Requesting that page again, with a username/password but no referrer,
+# is fine
+$m->add_header(Referer => undef);
+$m->post("$baseurl/REST/1.0/ticket/new", [
+ user => 'root',
+ pass => 'password',
+ format => 'l',
+]);
+$m->content_like(qr{^id: ticket/new}m, "REST request with no referrer, but username/pass");
+
+# And it's still fine without both referer and username and password,
+# because REST is special-cased
+$m->post("$baseurl/REST/1.0/ticket/new", [
+ format => 'l',
+]);
+$m->content_like(qr{^id: ticket/new}m, "REST request with no referrer or username/pass is special-cased for REST sessions");
+
+# But the REST page can't request normal pages
+$m->get("$baseurl");
+$m->content_lacks("RT at a glance", "Full UI is denied for REST sessions");
+$m->content_contains("This login session belongs to a REST client", "Tells you why");
+$m->warning_like(qr/This login session belongs to a REST client/, "Logs a warning");
+
+undef $m;
+done_testing;
+
diff --git a/rt/t/web/csrf.t b/rt/t/web/csrf.t
new file mode 100644
index 000000000..d99b4ce22
--- /dev/null
+++ b/rt/t/web/csrf.t
@@ -0,0 +1,181 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use RT::Test tests => undef;
+
+my $ticket = RT::Ticket->new(RT::CurrentUser->new('root'));
+my ($ok, $msg) = $ticket->Create(Queue => 1, Owner => 'nobody', Subject => 'bad music');
+ok($ok);
+my $other = RT::Test->load_or_create_queue(Name => "Other queue", Disabled => 0);
+my $other_queue_id = $other->id;
+
+my ($baseurl, $m) = RT::Test->started_ok;
+
+my $test_page = "/Ticket/Create.html?Queue=1";
+my $test_path = "/Ticket/Create.html";
+
+ok $m->login, 'logged in';
+
+# valid referer
+$m->add_header(Referer => $baseurl);
+$m->get_ok($test_page);
+$m->content_lacks("Possible cross-site request forgery");
+$m->title_is('Create a new ticket');
+
+# off-site referer BUT provides auth
+$m->add_header(Referer => 'http://example.net');
+$m->get_ok("$test_page&user=root&pass=password");
+$m->content_lacks("Possible cross-site request forgery");
+$m->title_is('Create a new ticket');
+
+# explicitly no referer BUT provides auth
+$m->add_header(Referer => undef);
+$m->get_ok("$test_page&user=root&pass=password");
+$m->content_lacks("Possible cross-site request forgery");
+$m->title_is('Create a new ticket');
+
+# now send a referer from an attacker
+$m->add_header(Referer => 'http://example.net');
+$m->get_ok($test_page);
+$m->content_contains("Possible cross-site request forgery");
+$m->content_contains("If you really intended to visit <tt>/Ticket/Create.html</tt>");
+$m->content_contains("the Referrer header supplied by your browser (example.net:80) is not allowed");
+$m->title_is('Possible cross-site request forgery');
+
+# reinstate mech's usual header policy
+$m->delete_header('Referer');
+
+# clicking the resume request button gets us to the test page
+$m->follow_link(text_regex => qr{resume your request});
+$m->content_lacks("Possible cross-site request forgery");
+like($m->response->request->uri, qr{^http://[^/]+\Q$test_path\E\?CSRF_Token=\w+$});
+$m->title_is('Create a new ticket');
+
+# try a whitelisted argument from an attacker
+$m->add_header(Referer => 'http://example.net');
+$m->get_ok("/Ticket/Display.html?id=1");
+$m->content_lacks("Possible cross-site request forgery");
+$m->title_is('#1: bad music');
+
+# now a non-whitelisted argument
+$m->get_ok("/Ticket/Display.html?id=1&Action=Take");
+$m->content_contains("Possible cross-site request forgery");
+$m->content_contains("If you really intended to visit <tt>/Ticket/Display.html</tt>");
+$m->content_contains("the Referrer header supplied by your browser (example.net:80) is not allowed");
+$m->title_is('Possible cross-site request forgery');
+
+$m->delete_header('Referer');
+$m->follow_link(text_regex => qr{resume your request});
+$m->content_lacks("Possible cross-site request forgery");
+like($m->response->request->uri, qr{^http://[^/]+\Q/Ticket/Display.html});
+$m->title_is('#1: bad music');
+$m->content_contains('Owner changed from Nobody to root');
+
+# force mech to never set referer
+$m->add_header(Referer => undef);
+$m->get_ok($test_page);
+$m->content_contains("Possible cross-site request forgery");
+$m->content_contains("If you really intended to visit <tt>/Ticket/Create.html</tt>");
+$m->content_contains("your browser did not supply a Referrer header");
+$m->title_is('Possible cross-site request forgery');
+
+$m->follow_link(text_regex => qr{resume your request});
+$m->content_lacks("Possible cross-site request forgery");
+is($m->response->redirects, 0, "no redirection");
+like($m->response->request->uri, qr{^http://[^/]+\Q$test_path\E\?CSRF_Token=\w+$});
+$m->title_is('Create a new ticket');
+
+# try sending the wrong csrf token, then the right one
+$m->add_header(Referer => undef);
+$m->get_ok($test_page);
+$m->content_contains("Possible cross-site request forgery");
+$m->content_contains("If you really intended to visit <tt>/Ticket/Create.html</tt>");
+$m->content_contains("your browser did not supply a Referrer header");
+$m->title_is('Possible cross-site request forgery');
+
+# Sending a wrong CSRF is just a normal request. We'll make a request
+# with just an invalid token, which means no Queue=, which means
+# Create.html errors out.
+my $link = $m->find_link(text_regex => qr{resume your request});
+(my $broken_url = $link->url) =~ s/(CSRF_Token)=\w+/$1=crud/;
+$m->get_ok($broken_url);
+$m->content_contains("Queue could not be loaded");
+$m->title_is('RT Error');
+$m->warning_like(qr/Queue could not be loaded/);
+
+# The token doesn't work for other pages, or other arguments to the same page.
+$m->add_header(Referer => undef);
+$m->get_ok($test_page);
+$m->content_contains("Possible cross-site request forgery");
+my ($token) = $m->content =~ m{CSRF_Token=(\w+)};
+
+$m->add_header(Referer => undef);
+$m->get_ok("/Admin/Queues/Modify.html?id=new&Name=test&CSRF_Token=$token");
+$m->content_contains("Possible cross-site request forgery");
+$m->content_contains("If you really intended to visit <tt>/Admin/Queues/Modify.html</tt>");
+$m->content_contains("your browser did not supply a Referrer header");
+$m->title_is('Possible cross-site request forgery');
+
+$m->follow_link(text_regex => qr{resume your request});
+$m->content_lacks("Possible cross-site request forgery");
+$m->title_is('Configuration for queue test');
+
+# Try the same page, but different query parameters, which are blatted by the token
+$m->get_ok("/Ticket/Create.html?Queue=$other_queue_id&CSRF_Token=$token");
+$m->content_lacks("Possible cross-site request forgery");
+$m->title_is('Create a new ticket');
+$m->text_unlike(qr/Queue:\s*Other queue/);
+$m->text_like(qr/Queue:\s*General/);
+
+# Ensure that file uploads work across the interstitial
+$m->delete_header('Referer');
+$m->get_ok($test_page);
+$m->content_contains("Create a new ticket", 'ticket create page');
+$m->form_name('TicketCreate');
+$m->field('Subject', 'Attachments test');
+
+my $logofile = "$RT::MasonComponentRoot/NoAuth/images/bpslogo.png";
+open LOGO, "<", $logofile or die "Can't open logo file: $!";
+binmode LOGO;
+my $logo_contents = do {local $/; <LOGO>};
+close LOGO;
+$m->field('Attach', $logofile);
+
+# Lose the referer before the POST
+$m->add_header(Referer => undef);
+$m->submit;
+$m->content_contains("Possible cross-site request forgery");
+$m->content_contains("If you really intended to visit <tt>/Ticket/Create.html</tt>");
+$m->follow_link(text_regex => qr{resume your request});
+$m->content_contains('Download bpslogo.png', 'page has file name');
+$m->follow_link_ok({text => "Download bpslogo.png"});
+is($m->content, $logo_contents, "Binary content matches");
+
+
+# now try self-service with CSRF
+my $user = RT::User->new(RT->SystemUser);
+$user->Create(Name => "SelfService", Password => "chops", Privileged => 0);
+
+$m = RT::Test::Web->new;
+$m->get_ok("$baseurl/index.html?user=SelfService&pass=chops");
+$m->title_is("Open tickets", "got self-service interface");
+$m->content_contains("My open tickets", "got self-service interface");
+
+# post without referer
+$m->add_header(Referer => undef);
+$m->get_ok("/SelfService/Create.html?Queue=1");
+$m->content_contains("Possible cross-site request forgery");
+$m->content_contains("If you really intended to visit <tt>/SelfService/Create.html</tt>");
+$m->content_contains("your browser did not supply a Referrer header");
+$m->title_is('Possible cross-site request forgery');
+
+$m->follow_link(text_regex => qr{resume your request});
+$m->content_lacks("Possible cross-site request forgery");
+is($m->response->redirects, 0, "no redirection");
+like($m->response->request->uri, qr{^http://[^/]+\Q/SelfService/Create.html\E\?CSRF_Token=\w+$});
+$m->title_is('Create a ticket');
+$m->content_contains('Describe the issue below:');
+
+undef $m;
+done_testing;
diff --git a/rt/t/web/installer.t b/rt/t/web/installer.t
new file mode 100644
index 000000000..4dc82df47
--- /dev/null
+++ b/rt/t/web/installer.t
@@ -0,0 +1,95 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+$ENV{RT_TEST_WEB_HANDLER} = 'plack+rt-server';
+use RT::Test
+ tests => undef,
+ nodb => 1,
+ server_ok => 1;
+
+my ($base, $m) = RT::Test->started_ok;
+
+$m->warning_like(qr/If this is a new installation of RT/,
+ "Got startup warning");
+
+$m->get_ok($base);
+like $m->uri, qr/Install/, 'at installer';
+
+diag "Testing language change";
+{
+ $m->submit_form_ok(
+ {
+ with_fields => {
+ Lang => 'fr',
+ },
+ button => 'ChangeLang',
+ },
+ 'change language to french'
+ );
+ $m->content_like(qr/RT\s+pour\s+example\.com/i);
+ $m->submit_form_ok(
+ {
+ with_fields => {
+ Lang => 'en',
+ },
+ button => 'ChangeLang',
+ },
+ 'change language to english'
+ );
+ $m->content_like(qr/RT\s+for\s+example\.com/i);
+}
+
+diag "Walking through install screens setting defaults";
+{
+ $m->click_ok('Run');
+
+ # Database type
+ $m->content_contains('DatabaseType');
+ $m->content_contains($_, "found database $_")
+ for qw(MySQL PostgreSQL Oracle SQLite);
+ $m->submit();
+
+ # Database details
+ $m->content_contains('DatabaseName');
+ $m->submit();
+ $m->content_contains('Connection succeeded');
+ $m->submit_form_ok({ button => 'Next' });
+
+ # Basic options
+ $m->submit_form_ok({
+ with_fields => {
+ Password => 'password',
+ }
+ }, 'set root password');
+
+ # Mail options
+ $m->submit_form_ok({
+ with_fields => {
+ OwnerEmail => 'admin@example.com',
+ },
+ }, 'set admin email');
+
+ # Mail addresses
+ $m->submit_form_ok({
+ with_fields => {
+ CorrespondAddress => 'rt@example.com',
+ CommentAddress => 'rt-comment@example.com',
+ },
+ }, 'set addresses');
+
+ # Initialize database
+ $m->content_contains('database');
+ $m->submit();
+
+ # Finish
+ $m->content_contains('/RT_SiteConfig.pm');
+ $m->content_contains('Finish');
+ $m->submit();
+
+ $m->content_contains('Login');
+ ok $m->login(), 'logged in';
+}
+
+undef $m;
+done_testing;
diff --git a/rt/t/web/owner_disabled_group_19221.t b/rt/t/web/owner_disabled_group_19221.t
new file mode 100644
index 000000000..2664c5bc2
--- /dev/null
+++ b/rt/t/web/owner_disabled_group_19221.t
@@ -0,0 +1,190 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+
+use RT::Test tests => undef;
+
+my $queue = RT::Test->load_or_create_queue( Name => 'Test' );
+ok $queue && $queue->id, 'loaded or created queue';
+
+my $user = RT::Test->load_or_create_user(
+ Name => 'ausername',
+ Privileged => 1,
+);
+ok $user && $user->id, 'loaded or created user';
+
+my $group = RT::Group->new(RT->SystemUser);
+my ($ok, $msg) = $group->CreateUserDefinedGroup(Name => 'Disabled Group');
+ok($ok, $msg);
+
+($ok, $msg) = $group->AddMember( $user->PrincipalId );
+ok($ok, $msg);
+
+ok( RT::Test->set_rights({
+ Principal => $group,
+ Object => $queue,
+ Right => [qw(OwnTicket)]
+}), 'set rights');
+
+RT->Config->Set( AutocompleteOwners => 0 );
+my ($base, $m) = RT::Test->started_ok;
+ok $m->login, 'logged in';
+
+diag "user from group shows up in create form";
+{
+ $m->get_ok('/', 'open home page');
+ $m->form_name('CreateTicketInQueue');
+ $m->select( 'Queue', $queue->id );
+ $m->submit;
+
+ $m->content_contains('Create a new ticket', 'opened create ticket page');
+ my $form = $m->form_name('TicketCreate');
+ my $input = $form->find_input('Owner');
+ is $input->value, RT->Nobody->Id, 'correct owner selected';
+ ok((scalar grep { $_ == $user->Id } $input->possible_values), 'user from group is in dropdown');
+}
+
+diag "user from disabled group DOESN'T shows up in create form";
+{
+ ($ok, $msg) = $group->SetDisabled(1);
+ ok($ok, $msg);
+
+ $m->get_ok('/', 'open home page');
+ $m->form_name('CreateTicketInQueue');
+ $m->select( 'Queue', $queue->id );
+ $m->submit;
+
+ $m->content_contains('Create a new ticket', 'opened create ticket page');
+ my $form = $m->form_name('TicketCreate');
+ my $input = $form->find_input('Owner');
+ is $input->value, RT->Nobody->Id, 'correct owner selected';
+ ok((not scalar grep { $_ == $user->Id } $input->possible_values), 'user from disabled group is NOT in dropdown');
+ ($ok, $msg) = $group->SetDisabled(0);
+ ok($ok, $msg);
+}
+
+
+
+diag "Put us in a nested group";
+my $super = RT::Group->new(RT->SystemUser);
+($ok, $msg) = $super->CreateUserDefinedGroup(Name => 'Supergroup');
+ok($ok, $msg);
+
+($ok, $msg) = $super->AddMember( $group->PrincipalId );
+ok($ok, $msg);
+
+ok( RT::Test->set_rights({
+ Principal => $super,
+ Object => $queue,
+ Right => [qw(OwnTicket)]
+}), 'set rights');
+
+
+diag "Disable the middle group";
+{
+ ($ok, $msg) = $group->SetDisabled(1);
+ ok($ok, "Disabled group: $msg");
+
+ $m->get_ok('/', 'open home page');
+ $m->form_name('CreateTicketInQueue');
+ $m->select( 'Queue', $queue->id );
+ $m->submit;
+
+ $m->content_contains('Create a new ticket', 'opened create ticket page');
+ my $form = $m->form_name('TicketCreate');
+ my $input = $form->find_input('Owner');
+ is $input->value, RT->Nobody->Id, 'correct owner selected';
+ ok((not scalar grep { $_ == $user->Id } $input->possible_values), 'user from disabled group is NOT in dropdown');
+ ($ok, $msg) = $group->SetDisabled(0);
+ ok($ok, "Re-enabled group: $msg");
+}
+
+diag "Disable the top group";
+{
+ ($ok, $msg) = $super->SetDisabled(1);
+ ok($ok, "Disabled supergroup: $msg");
+
+ $m->get_ok('/', 'open home page');
+ $m->form_name('CreateTicketInQueue');
+ $m->select( 'Queue', $queue->id );
+ $m->submit;
+
+ $m->content_contains('Create a new ticket', 'opened create ticket page');
+ my $form = $m->form_name('TicketCreate');
+ my $input = $form->find_input('Owner');
+ is $input->value, RT->Nobody->Id, 'correct owner selected';
+ ok((not scalar grep { $_ == $user->Id } $input->possible_values), 'user from disabled group is NOT in dropdown');
+ ($ok, $msg) = $super->SetDisabled(0);
+ ok($ok, "Re-enabled supergroup: $msg");
+}
+
+
+diag "Check WithMember and WithoutMember recursively";
+{
+ my $with = RT::Groups->new( RT->SystemUser );
+ $with->WithMember( PrincipalId => $user->PrincipalObj->Id, Recursively => 1 );
+ $with->Limit( FIELD => 'domain', OPERATOR => '=', VALUE => 'UserDefined' );
+ is_deeply(
+ [map {$_->Name} @{$with->ItemsArrayRef}],
+ ['Disabled Group','Supergroup'],
+ "Get expected recursive memberships",
+ );
+
+ my $without = RT::Groups->new( RT->SystemUser );
+ $without->WithoutMember( PrincipalId => $user->PrincipalObj->Id, Recursively => 1 );
+ $without->Limit( FIELD => 'domain', OPERATOR => '=', VALUE => 'UserDefined' );
+ is_deeply(
+ [map {$_->Name} @{$without->ItemsArrayRef}],
+ [],
+ "And not a member of no groups",
+ );
+
+ ($ok, $msg) = $super->SetDisabled(1);
+ ok($ok, "Disabled supergroup: $msg");
+ $with->RedoSearch;
+ $without->RedoSearch;
+ is_deeply(
+ [map {$_->Name} @{$with->ItemsArrayRef}],
+ ['Disabled Group'],
+ "Recursive check only contains subgroup",
+ );
+ is_deeply(
+ [map {$_->Name} @{$without->ItemsArrayRef}],
+ [],
+ "Doesn't find the currently disabled group",
+ );
+ ($ok, $msg) = $super->SetDisabled(0);
+ ok($ok, "Re-enabled supergroup: $msg");
+
+ ($ok, $msg) = $group->SetDisabled(1);
+ ok($ok, "Disabled intermediate group: $msg");
+ $with->RedoSearch;
+ $without->RedoSearch;
+ is_deeply(
+ [map {$_->Name} @{$with->ItemsArrayRef}],
+ [],
+ "Recursive check finds no groups",
+ );
+ is_deeply(
+ [map {$_->Name} @{$without->ItemsArrayRef}],
+ ['Supergroup'],
+ "Now not a member of the supergroup",
+ );
+ ($ok, $msg) = $group->SetDisabled(0);
+ ok($ok, "Re-enabled intermediate group: $msg");
+}
+
+diag "Check MemberOfGroup";
+{
+ ($ok, $msg) = $group->SetDisabled(1);
+ ok($ok, "Disabled intermediate group: $msg");
+ my $users = RT::Users->new(RT->SystemUser);
+ $users->MemberOfGroup($super->PrincipalObj->id);
+ is($users->Count, 0, "Supergroup claims no members");
+ ($ok, $msg) = $group->SetDisabled(0);
+ ok($ok, "Re-enabled intermediate group: $msg");
+}
+
+
+undef $m;
+done_testing;
diff --git a/rt/t/web/query_builder_queue_limits.t b/rt/t/web/query_builder_queue_limits.t
new file mode 100644
index 000000000..a3b976524
--- /dev/null
+++ b/rt/t/web/query_builder_queue_limits.t
@@ -0,0 +1,180 @@
+use strict;
+use warnings;
+
+use RT::Test tests => 34;
+
+my $lifecycles = RT->Config->Get('Lifecycles');
+$lifecycles->{foo} = {
+ initial => ['initial'],
+ active => ['open'],
+ inactive => ['resolved'],
+
+};
+
+RT::Lifecycle->FillCache();
+
+my $general = RT::Test->load_or_create_queue( Name => 'General' );
+my $foo = RT::Test->load_or_create_queue( Name => 'foo', Lifecycle => 'foo' );
+
+my $global_cf = RT::Test->load_or_create_custom_field(
+ Name => 'global_cf',
+ Queue => 0,
+ Type => 'FreeformSingle',
+);
+
+my $general_cf = RT::Test->load_or_create_custom_field(
+ Name => 'general_cf',
+ Queue => 'General',
+ Type => 'FreeformSingle',
+);
+
+my $foo_cf = RT::Test->load_or_create_custom_field(
+ Name => 'foo_cf',
+ Queue => 'foo',
+ Type => 'FreeformSingle'
+);
+
+my $root = RT::Test->load_or_create_user( Name => 'root', );
+my $user_a = RT::Test->load_or_create_user(
+ Name => 'user_a',
+ Password => 'password',
+);
+my $user_b = RT::Test->load_or_create_user(
+ Name => 'user_b',
+ Password => 'password',
+);
+
+ok(
+ RT::Test->set_rights(
+ {
+ Principal => $user_a,
+ Object => $general,
+ Right => ['OwnTicket'],
+ },
+ {
+ Principal => $user_b,
+ Object => $foo,
+ Right => ['OwnTicket'],
+ },
+ ),
+ 'granted OwnTicket right for user_a and user_b'
+);
+
+my ( $url, $m ) = RT::Test->started_ok;
+ok( $m->login, 'logged in' );
+
+$m->get_ok( $url . '/Search/Build.html' );
+
+diag "check default statuses, cf and owners";
+my $form = $m->form_name('BuildQuery');
+ok( $form, 'found BuildQuery form' );
+ok( $form->find_input("ValueOf'CF.{global_cf}'"), 'found global_cf by default' );
+ok( !$form->find_input("ValueOf'CF.{general_cf}'"), 'no general_cf by default' );
+ok( !$form->find_input("ValueOf'CF.{foo_cf}'"), 'no foo_cf by default' );
+
+my $status_input = $form->find_input('ValueOfStatus');
+my @statuses = sort $status_input->possible_values;
+is_deeply(
+ \@statuses, [ '', qw/initial new open rejected resolved stalled/], 'found all statuses'
+);
+
+my $owner_input = $form->find_input('ValueOfActor');
+my @owners = sort $owner_input->possible_values;
+is_deeply(
+ \@owners, [ '', qw/Nobody root user_a user_b/], 'found all users'
+);
+
+diag "limit queue to foo";
+$m->submit_form(
+ fields => { ValueOfQueue => 'foo' },
+ button => 'AddClause',
+);
+
+$form = $m->form_name('BuildQuery');
+ok( $form->find_input("ValueOf'CF.{foo_cf}'"), 'found foo_cf' );
+ok( $form->find_input("ValueOf'CF.{global_cf}'"), 'found global_cf' );
+ok( !$form->find_input("ValueOf'CF.{general_cf}'"), 'still no general_cf' );
+$status_input = $form->find_input('ValueOfStatus');
+@statuses = sort $status_input->possible_values;
+is_deeply(
+ \@statuses,
+ [ '', qw/initial open resolved/ ],
+ 'found statuses from foo only'
+);
+
+$owner_input = $form->find_input('ValueOfActor');
+@owners = sort $owner_input->possible_values;
+is_deeply(
+ \@owners, [ '', qw/Nobody root user_b/], 'no user_a'
+);
+
+diag "limit queue to general too";
+
+$m->submit_form(
+ fields => { ValueOfQueue => 'General' },
+ button => 'AddClause',
+);
+
+$form = $m->form_name('BuildQuery');
+ok( $form->find_input("ValueOf'CF.{general_cf}'"), 'found general_cf' );
+ok( $form->find_input("ValueOf'CF.{foo_cf}'"), 'found foo_cf' );
+ok( $form->find_input("ValueOf'CF.{global_cf}'"), 'found global_cf' );
+$status_input = $form->find_input('ValueOfStatus');
+@statuses = sort $status_input->possible_values;
+is_deeply(
+ \@statuses,
+ [ '', qw/initial new open rejected resolved stalled/ ],
+ 'found all statuses again'
+);
+$owner_input = $form->find_input('ValueOfActor');
+@owners = sort $owner_input->possible_values;
+is_deeply(
+ \@owners, [ '', qw/Nobody root user_a user_b/], 'found all users again'
+);
+
+diag "limit queue to != foo";
+$m->get_ok( $url . '/Search/Build.html?NewQuery=1' );
+$m->submit_form(
+ form_name => 'BuildQuery',
+ fields => { ValueOfQueue => 'foo', QueueOp => '!=' },
+ button => 'AddClause',
+);
+
+$form = $m->form_name('BuildQuery');
+ok( $form->find_input("ValueOf'CF.{global_cf}'"), 'found global_cf' );
+ok( !$form->find_input("ValueOf'CF.{foo_cf}'"), 'no foo_cf' );
+ok( !$form->find_input("ValueOf'CF.{general_cf}'"), 'no general_cf' );
+$status_input = $form->find_input('ValueOfStatus');
+@statuses = sort $status_input->possible_values;
+is_deeply(
+ \@statuses, [ '', qw/initial new open rejected resolved stalled/],
+ 'found all statuses'
+);
+$owner_input = $form->find_input('ValueOfActor');
+@owners = sort $owner_input->possible_values;
+is_deeply(
+ \@owners, [ '', qw/Nobody root user_a user_b/], 'found all users'
+);
+
+diag "limit queue to General OR foo";
+$m->get_ok( $url . '/Search/Edit.html' );
+$m->submit_form(
+ form_name => 'BuildQueryAdvanced',
+ fields => { Query => q{Queue = 'General' OR Queue = 'foo'} },
+);
+$form = $m->form_name('BuildQuery');
+ok( $form->find_input("ValueOf'CF.{general_cf}'"), 'found general_cf' );
+ok( $form->find_input("ValueOf'CF.{foo_cf}'"), 'found foo_cf' );
+ok( $form->find_input("ValueOf'CF.{global_cf}'"), 'found global_cf' );
+$status_input = $form->find_input('ValueOfStatus');
+@statuses = sort $status_input->possible_values;
+is_deeply(
+ \@statuses,
+ [ '', qw/initial new open rejected resolved stalled/ ],
+ 'found all statuses'
+);
+$owner_input = $form->find_input('ValueOfActor');
+@owners = sort $owner_input->possible_values;
+is_deeply(
+ \@owners, [ '', qw/Nobody root user_a user_b/], 'found all users'
+);
diff --git a/rt/t/web/rest_cfs_with_same_name.t b/rt/t/web/rest_cfs_with_same_name.t
new file mode 100644
index 000000000..958f67177
--- /dev/null
+++ b/rt/t/web/rest_cfs_with_same_name.t
@@ -0,0 +1,88 @@
+use strict;
+use warnings;
+use RT::Interface::REST;
+
+use RT::Test tests => 25;
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+for my $queue_name (qw/foo bar/) {
+
+ my $queue = RT::Test->load_or_create_queue( Name => $queue_name );
+ ok( $queue, "created queue $queue_name" );
+ my $cf = RT::Test->load_or_create_custom_field(
+ Name => 'test',
+ Type => 'Freeform',
+ Queue => $queue_name,
+ );
+ ok( $cf->id, "created cf test for queue $queue_name " . $cf->id );
+
+ $m->post(
+ "$baseurl/REST/1.0/ticket/new",
+ [
+ user => 'root',
+ pass => 'password',
+ format => 'l',
+ ]
+ );
+
+ my $text = $m->content;
+ my @lines = $text =~ m{.*}g;
+ shift @lines; # header
+
+ # cfs aren't in the default ticket form
+ push @lines, "CF.{test}: baz";
+
+ $text = join "\n", @lines;
+
+ ok( $text =~ s/Subject:\s*$/Subject: test cf/m,
+ "successfully replaced subject" );
+ ok( $text =~ s/Queue: General\s*$/Queue: $queue_name/m,
+ "successfully replaced Queue" );
+
+ $m->post(
+ "$baseurl/REST/1.0/ticket/edit",
+ [
+ user => 'root',
+ pass => 'password',
+ content => $text,
+ ],
+ Content_Type => 'form-data'
+ );
+
+ my ($id) = $m->content =~ /Ticket (\d+) created/;
+ ok( $id, "got ticket #$id" );
+
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ $ticket->Load($id);
+ is( $ticket->id, $id, "loaded the REST-created ticket" );
+ is( $ticket->Subject, "test cf", "subject successfully set" );
+ is( $ticket->Queue, $queue->id, "queue successfully set" );
+ is( $ticket->FirstCustomFieldValue("test"), "baz", "cf successfully set" );
+
+ $m->post(
+ "$baseurl/REST/1.0/ticket/show",
+ [
+ user => 'root',
+ pass => 'password',
+ format => 'l',
+ id => "ticket/$id",
+ ]
+ );
+ $text = $m->content;
+ like( $text, qr/^CF\.{test}: baz\s*$/m, 'cf value in rest show' );
+
+ $text =~ s{.*}{}; # remove header
+ $text =~ s!CF\.{test}: baz!CF.{test}: newbaz!;
+ $m->post(
+ "$baseurl/REST/1.0/ticket/edit",
+ [
+ user => 'root',
+ pass => 'password',
+ content => $text,
+ ],
+ Content_Type => 'form-data'
+ );
+ $m->content =~ /Ticket ($id) updated/;
+ is( $ticket->FirstCustomFieldValue("test"), "newbaz", "cf successfully updated" );
+}
+