diff options
Diffstat (limited to 'rt/t/web')
35 files changed, 5043 insertions, 0 deletions
diff --git a/rt/t/web/attachments.t b/rt/t/web/attachments.t new file mode 100644 index 000000000..e827b2f02 --- /dev/null +++ b/rt/t/web/attachments.t @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w +use strict; + +use RT::Test tests => 14; + +use constant LogoFile => $RT::MasonComponentRoot .'/NoAuth/images/bplogo.gif'; +use constant FaviconFile => $RT::MasonComponentRoot .'/NoAuth/images/favicon.png'; + +my ($baseurl, $m) = RT::Test->started_ok; +ok $m->login, 'logged in'; + +my $queue = RT::Queue->new($RT::Nobody); +my $qid = $queue->Load('General'); +ok( $qid, "Loaded General queue" ); + +$m->form_name('CreateTicketInQueue'); +$m->field('Queue', $qid); +$m->submit; +is($m->status, 200, "request successful"); +$m->content_like(qr/Create a new ticket/, 'ticket create page'); + +$m->form_name('TicketCreate'); +$m->field('Subject', 'Attachments test'); +$m->field('Attach', LogoFile); +$m->field('Content', 'Some content'); +$m->submit; +is($m->status, 200, "request successful"); + +$m->content_like(qr/Attachments test/, 'we have subject on the page'); +$m->content_like(qr/Some content/, 'and content'); +$m->content_like(qr/Download bplogo\.gif/, 'page has file name'); + +$m->follow_link_ok({text => 'Reply'}, "reply to the ticket"); +$m->form_name('TicketUpdate'); +$m->field('Attach', LogoFile); +$m->click('AddMoreAttach'); +is($m->status, 200, "request successful"); + +$m->form_name('TicketUpdate'); +$m->field('Attach', FaviconFile); +$m->field('UpdateContent', 'Message'); +$m->click('SubmitTicket'); +is($m->status, 200, "request successful"); + +$m->content_like(qr/Download bplogo\.gif/, 'page has file name'); +$m->content_like(qr/Download favicon\.png/, 'page has file name'); + diff --git a/rt/t/web/basic.t b/rt/t/web/basic.t new file mode 100644 index 000000000..bc4d65587 --- /dev/null +++ b/rt/t/web/basic.t @@ -0,0 +1,146 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Encode; + +use RT::Test tests => 24; +$RT::Test::SKIP_REQUEST_WORK_AROUND = 1; + +my ($baseurl, $agent) = RT::Test->started_ok; + +my $url = $agent->rt_base_url; +diag $url if $ENV{TEST_VERBOSE}; + +# get the top page +{ + $agent->get($url); + is ($agent->{'status'}, 200, "Loaded a page"); +} + +# test a login +{ + ok($agent->{form}->find_input('user')); + ok($agent->{form}->find_input('pass')); + + ok($agent->{'content'} =~ /username:/i); + $agent->field( 'user' => 'root' ); + $agent->field( 'pass' => 'password' ); + + # the field isn't named, so we have to click link 0 + $agent->click(0); + is( $agent->{'status'}, 200, "Fetched the page ok"); + ok( $agent->{'content'} =~ /Logout/i, "Found a logout link"); +} + +{ + $agent->get($url."Ticket/Create.html?Queue=1"); + is ($agent->{'status'}, 200, "Loaded Create.html"); + $agent->form_number(3); + my $string = Encode::decode_utf8("I18N Web Testing æøå"); + $agent->field('Subject' => "Ticket with utf8 body"); + $agent->field('Content' => $string); + ok($agent->submit, "Created new ticket with $string as Content"); + $agent->content_like( qr{$string} , "Found the content"); + ok($agent->{redirected_uri}, "Did redirection"); + + { + my $ticket = RT::Test->last_ticket; + my $content = $ticket->Transactions->First->Content; + like( + $content, qr{$string}, + 'content is there, API check' + ); + } +} + +{ + $agent->get($url."Ticket/Create.html?Queue=1"); + is ($agent->{'status'}, 200, "Loaded Create.html"); + $agent->form_number(3); + + my $string = Encode::decode_utf8("I18N Web Testing æøå"); + $agent->field('Subject' => $string); + $agent->field('Content' => "Ticket with utf8 subject"); + ok($agent->submit, "Created new ticket with $string as Content"); + $agent->content_like( qr{$string} , "Found the content"); + ok($agent->{redirected_uri}, "Did redirection"); + + { + my $ticket = RT::Test->last_ticket; + is( + $ticket->Subject, $string, + 'subject is correct, API check' + ); + } +} + +# Update time worked in hours +{ + $agent->follow_link( text_regex => qr/Basics/ ); + $agent->submit_form( form_number => 3, + fields => { TimeWorked => 5, 'TimeWorked-TimeUnits' => "hours" } + ); + + like ($agent->{'content'}, qr/to '300'/, "5 hours is 300 minutes"); +} + +# {{{ test an image + +TODO: { + todo_skip("Need to handle mason trying to compile images",1); +$agent->get( $url."NoAuth/images/test.png" ); +my $file = RT::Test::get_relocatable_file( + File::Spec->catfile( + qw(.. .. share html NoAuth images test.png) + ) +); +is( + length($agent->content), + -s $file, + "got a file of the correct size ($file)", +); +} +# }}} + +# {{{ Query Builder tests +# +# XXX: hey-ho, we have these tests in t/web/query-builder +# TODO: move everything about QB there + +my $response = $agent->get($url."Search/Build.html"); +ok( $response->is_success, "Fetched " . $url."Search/Build.html" ); + +# Parsing TicketSQL +# +# Adding items + +# set the first value +ok($agent->form_name('BuildQuery')); +$agent->field("AttachmentField", "Subject"); +$agent->field("AttachmentOp", "LIKE"); +$agent->field("ValueOfAttachment", "aaa"); +$agent->submit("AddClause"); + +# set the next value +ok($agent->form_name('BuildQuery')); +$agent->field("AttachmentField", "Subject"); +$agent->field("AttachmentOp", "LIKE"); +$agent->field("ValueOfAttachment", "bbb"); +$agent->submit("AddClause"); + +ok($agent->form_name('BuildQuery')); + +# get the query +my $query = $agent->current_form->find_input("Query")->value; +# strip whitespace from ends +$query =~ s/^\s*//g; +$query =~ s/\s*$//g; + +# collapse other whitespace +$query =~ s/\s+/ /g; + +is ($query, "Subject LIKE 'aaa' AND Subject LIKE 'bbb'"); + + +1; diff --git a/rt/t/web/cf_access.t b/rt/t/web/cf_access.t new file mode 100644 index 000000000..1022c6da6 --- /dev/null +++ b/rt/t/web/cf_access.t @@ -0,0 +1,191 @@ +#!/usr/bin/perl -w +use strict; + +use RT::Test tests => 26; +$RT::Test::SKIP_REQUEST_WORK_AROUND = 1; + +my ($baseurl, $m) = RT::Test->started_ok; + +use constant ImageFile => $RT::MasonComponentRoot .'/NoAuth/images/bplogo.gif'; +use constant ImageFileContent => RT::Test->file_content(ImageFile); + +ok $m->login, 'logged in'; + +diag "Create a CF" if $ENV{'TEST_VERBOSE'}; +{ + $m->follow_link( text => 'Configuration' ); + $m->title_is(q/RT Administration/, 'admin screen'); + $m->follow_link( text => 'Custom Fields' ); + $m->title_is(q/Select a Custom Field/, 'admin-cf screen'); + $m->follow_link( text => 'Create' ); + $m->submit_form( + form_name => "ModifyCustomField", + fields => { + TypeComposite => 'Image-0', + LookupType => 'RT::Queue-RT::Ticket', + Name => 'img', + Description => 'img', + }, + ); +} + +diag "apply the CF to General queue" if $ENV{'TEST_VERBOSE'}; +my ( $cf, $cfid, $tid ); +{ + $m->title_is(q/Created CustomField img/, 'admin-cf created'); + $m->follow_link( text => 'Queues' ); + $m->title_is(q/Admin queues/, 'admin-queues screen'); + $m->follow_link( text => 'General' ); + $m->title_is(q/Editing Configuration for queue General/, 'admin-queue: general'); + $m->follow_link( text => 'Ticket Custom Fields' ); + + $m->title_is(q/Edit Custom Fields for General/, 'admin-queue: general cfid'); + $m->form_name('EditCustomFields'); + + # Sort by numeric IDs in names + my @names = map { $_->[1] } + sort { $a->[0] <=> $b->[0] } + map { /Object-1-CF-(\d+)/ ? [ $1 => $_ ] : () } + grep defined, map $_->name, $m->current_form->inputs; + $cf = pop(@names); + $cf =~ /(\d+)$/ or die "Hey this is impossible dude"; + $cfid = $1; + $m->field( $cf => 1 ); # Associate the new CF with this queue + $m->field( $_ => undef ) for @names; # ...and not any other. ;-) + $m->submit; + + $m->content_like( qr/Object created/, 'TCF added to the queue' ); +} + +my $tester = RT::Test->load_or_create_user( Name => 'tester', Password => '123456' ); +RT::Test->set_rights( + { Principal => $tester->PrincipalObj, + Right => [qw(SeeQueue ShowTicket CreateTicket)], + }, +); +ok $m->login( $tester->Name, 123456), 'logged in'; + +diag "check that we have no the CF on the create" + ." ticket page when user has no SeeCustomField right" + if $ENV{'TEST_VERBOSE'}; +{ + $m->submit_form( + form_name => "CreateTicketInQueue", + fields => { Queue => 'General' }, + ); + $m->content_unlike(qr/Upload multiple images/, 'has no upload image field'); + + my $form = $m->form_name("TicketCreate"); + my $upload_field = "Object-RT::Ticket--CustomField-$cfid-Upload"; + ok !$form->find_input( $upload_field ), 'no form field on the page'; + + $m->submit_form( + form_name => "TicketCreate", + fields => { Subject => 'test' }, + ); + $m->content_like(qr/Ticket \d+ created/, "a ticket is created succesfully"); + + $m->content_unlike(qr/img:/, 'has no img field on the page'); + $m->follow_link( text => 'Custom Fields'); + $m->content_unlike(qr/Upload multiple images/, 'has no upload image field'); +} + +RT::Test->set_rights( + { Principal => $tester->PrincipalObj, + Right => [qw(SeeQueue ShowTicket CreateTicket SeeCustomField)], + }, +); + +diag "check that we have no the CF on the create" + ." ticket page when user has no ModifyCustomField right" + if $ENV{'TEST_VERBOSE'}; +{ + $m->submit_form( + form_name => "CreateTicketInQueue", + fields => { Queue => 'General' }, + ); + $m->content_unlike(qr/Upload multiple images/, 'has no upload image field'); + + my $form = $m->form_name("TicketCreate"); + my $upload_field = "Object-RT::Ticket--CustomField-$cfid-Upload"; + ok !$form->find_input( $upload_field ), 'no form field on the page'; + + $m->submit_form( + form_name => "TicketCreate", + fields => { Subject => 'test' }, + ); + $tid = $1 if $m->content =~ /Ticket (\d+) created/i; + ok $tid, "a ticket is created succesfully"; + + $m->follow_link( text => 'Custom Fields' ); + $m->content_unlike(qr/Upload multiple images/, 'has no upload image field'); + $form = $m->form_number(3); + $upload_field = "Object-RT::Ticket-$tid-CustomField-$cfid-Upload"; + ok !$form->find_input( $upload_field ), 'no form field on the page'; +} + +RT::Test->set_rights( + { Principal => $tester->PrincipalObj, + Right => [qw(SeeQueue ShowTicket CreateTicket SeeCustomField ModifyCustomField)], + }, +); + +diag "create a ticket with an image" if $ENV{'TEST_VERBOSE'}; +{ + $m->submit_form( + form_name => "CreateTicketInQueue", + fields => { Queue => 'General' }, + ); + $m->content_like(qr/Upload multiple images/, 'has a upload image field'); + + $cf =~ /(\d+)$/ or die "Hey this is impossible dude"; + my $upload_field = "Object-RT::Ticket--CustomField-$1-Upload"; + + $m->submit_form( + form_name => "TicketCreate", + fields => { + $upload_field => ImageFile, + Subject => 'testing img cf creation', + }, + ); + + $m->content_like(qr/Ticket \d+ created/, "a ticket is created succesfully"); + + $tid = $1 if $m->content =~ /Ticket (\d+) created/; + + $m->title_like(qr/testing img cf creation/, "its title is the Subject"); + + $m->follow_link( text => 'bplogo.gif' ); + $m->content_is(ImageFileContent, "it links to the uploaded image"); +} + +$m->get( $m->rt_base_url ); +$m->follow_link( text => 'Tickets' ); +$m->follow_link( text => 'New Query' ); + +$m->title_is(q/Query Builder/, 'Query building'); +$m->submit_form( + form_name => "BuildQuery", + fields => { + idOp => '=', + ValueOfid => $tid, + ValueOfQueue => 'General', + }, + button => 'AddClause', +); + +$m->form_name('BuildQuery'); + +my $col = ($m->current_form->find_input('SelectDisplayColumns'))[-1]; +$col->value( ($col->possible_values)[-1] ); + +$m->click('AddCol'); + +$m->form_name('BuildQuery'); +$m->click('DoSearch'); + +$m->follow_link( text_regex => qr/bplogo\.gif/ ); +$m->content_is(ImageFileContent, "it links to the uploaded image"); + +__END__ +[FC] Bulk Update does not have custom fields. diff --git a/rt/t/web/cf_onqueue.t b/rt/t/web/cf_onqueue.t new file mode 100644 index 000000000..dcd585277 --- /dev/null +++ b/rt/t/web/cf_onqueue.t @@ -0,0 +1,66 @@ +#!/usr/bin/perl -w +use strict; + +use RT::Test tests => 14; +my ($baseurl, $m) = RT::Test->started_ok; + +ok $m->login, 'logged in'; + +diag "Create a queue CF" if $ENV{'TEST_VERBOSE'}; +{ + $m->follow_link( text => 'Configuration' ); + $m->title_is(q/RT Administration/, 'admin screen'); + $m->follow_link( text => 'Custom Fields' ); + $m->title_is(q/Select a Custom Field/, 'admin-cf screen'); + $m->follow_link( text => 'Create' ); + $m->submit_form( + form_name => "ModifyCustomField", + fields => { + TypeComposite => 'Freeform-1', + LookupType => 'RT::Queue', + Name => 'QueueCFTest', + Description => 'QueueCFTest', + }, + ); + $m->content_like( qr/Object created/, 'CF QueueCFTest created' ); +} + +diag "Apply the new CF globally" if $ENV{'TEST_VERBOSE'}; +{ + $m->follow_link( text => 'Global' ); + $m->title_is(q!Admin/Global configuration!, 'global configuration screen'); + $m->follow_link( url_regex => qr!Admin/Global/CustomFields/index! ); + $m->title_is(q/Global custom field configuration/, 'global custom field configuration screen'); + $m->follow_link( url => 'Queues.html' ); + $m->title_is(q/Edit Custom Fields for all queues/, 'global custom field for all queues configuration screen'); + $m->content_like( qr/QueueCFTest/, 'CF QueueCFTest displayed on page' ); + $m->submit_form( + form_name => "EditCustomFields", + fields => { + 'Object--CF-1' => '1', + }, + ); + $m->content_like( qr/Object created/, 'CF QueueCFTest enabled globally' ); +} + +diag "Edit the CF value for default queue" if $ENV{'TEST_VERBOSE'}; +{ + $m->follow_link( url => '/Admin/Queues/' ); + $m->title_is(q/Admin queues/, 'queues configuration screen'); + $m->follow_link( text => "1" ); + $m->title_is(q/Editing Configuration for queue General/, 'default queue configuration screen'); + $m->content_like( qr/QueueCFTest/, 'CF QueueCFTest displayed on default queue' ); + $m->submit_form( + form_number => 3, + # The following doesn't want to works :( + #with_fields => { 'Object-RT::Queue-1-CustomField-1-Value' }, + fields => { + 'Object-RT::Queue-1-CustomField-1-Value' => 'QueueCFTest content', + }, + ); + $m->content_like( qr/QueueCFTest QueueCFTest content added/, 'Content filed in CF QueueCFTest for default queue' ); + +} + + +__END__ diff --git a/rt/t/web/cf_select_one.t b/rt/t/web/cf_select_one.t new file mode 100644 index 000000000..e009af7cf --- /dev/null +++ b/rt/t/web/cf_select_one.t @@ -0,0 +1,159 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use RT::Test tests => 41; + +my ($baseurl, $m) = RT::Test->started_ok; +ok $m->login, 'logged in as root'; + +my $cf_name = 'test select one value'; + +my $cfid; +diag "Create a CF" if $ENV{'TEST_VERBOSE'}; +{ + $m->follow_link( text => 'Configuration' ); + $m->title_is(q/RT Administration/, 'admin screen'); + $m->follow_link( text => 'Custom Fields' ); + $m->title_is(q/Select a Custom Field/, 'admin-cf screen'); + $m->follow_link( text => 'Create' ); + $m->submit_form( + form_name => "ModifyCustomField", + fields => { + Name => $cf_name, + TypeComposite => 'Select-1', + LookupType => 'RT::Queue-RT::Ticket', + }, + ); + $m->content_like( qr/Object created/, 'created CF sucessfully' ); + $cfid = $m->form_name('ModifyCustomField')->value('id'); + ok $cfid, "found id of the CF in the form, it's #$cfid"; +} + +diag "add 'qwe', 'ASD' and '0' as values to the CF" if $ENV{'TEST_VERBOSE'}; +{ + foreach my $value(qw(qwe ASD 0)) { + $m->submit_form( + form_name => "ModifyCustomField", + fields => { + "CustomField-". $cfid ."-Value-new-Name" => $value, + }, + button => 'Update', + ); + $m->content_like( qr/Object created/, 'added a value to the CF' ); # or diag $m->content; + } +} + +my $queue = RT::Test->load_or_create_queue( Name => 'General' ); +ok $queue && $queue->id, 'loaded or created queue'; + +diag "apply the CF to General queue" if $ENV{'TEST_VERBOSE'}; +{ + $m->follow_link( text => 'Queues' ); + $m->title_is(q/Admin queues/, 'admin-queues screen'); + $m->follow_link( text => 'General' ); + $m->title_is(q/Editing Configuration for queue General/, 'admin-queue: general'); + $m->follow_link( text => 'Ticket Custom Fields' ); + $m->title_is(q/Edit Custom Fields for General/, 'admin-queue: general cfid'); + + $m->form_name('EditCustomFields'); + $m->field( "Object-". $queue->id ."-CF-$cfid" => 1 ); + $m->submit; + + $m->content_like( qr/Object created/, 'TCF added to the queue' ); +} + +my $tid; +diag "create a ticket using API with 'asd'(not 'ASD') as value of the CF" + if $ENV{'TEST_VERBOSE'}; +{ + my $ticket = RT::Ticket->new( $RT::SystemUser ); + my ($txnid, $msg); + ($tid, $txnid, $msg) = $ticket->Create( + Subject => 'test', + Queue => $queue->id, + "CustomField-$cfid" => 'asd', + ); + ok $tid, "created ticket"; + diag $msg if $msg && $ENV{'TEST_VERBOSE'}; + + # we use lc as we really don't care about case + # so if later we'll add canonicalization of value + # test should work + is lc $ticket->FirstCustomFieldValue( $cf_name ), + 'asd', 'assigned value of the CF'; +} + +diag "check that values of the CF are case insensetive(asd vs. ASD)" + if $ENV{'TEST_VERBOSE'}; +{ + ok $m->goto_ticket( $tid ), "opened ticket's page"; + $m->follow_link( text => 'Custom Fields' ); + $m->title_like(qr/Modify ticket/i, 'modify ticket'); + $m->content_like(qr/\Q$cf_name/, 'CF on the page'); + + my $value = $m->form_number(3)->value("Object-RT::Ticket-$tid-CustomField-$cfid-Values"); + is lc $value, 'asd', 'correct value is selected'; + $m->submit; + $m->content_unlike(qr/\Q$cf_name\E.*?changed/mi, 'field is not changed'); + + $value = $m->form_number(3)->value("Object-RT::Ticket-$tid-CustomField-$cfid-Values"); + is lc $value, 'asd', 'the same value is still selected'; + + my $ticket = RT::Ticket->new( $RT::SystemUser ); + $ticket->Load( $tid ); + ok $ticket->id, 'loaded the ticket'; + is lc $ticket->FirstCustomFieldValue( $cf_name ), + 'asd', 'value is still the same'; +} + +diag "check that 0 is ok value of the CF" + if $ENV{'TEST_VERBOSE'}; +{ + ok $m->goto_ticket( $tid ), "opened ticket's page"; + $m->follow_link( text => 'Custom Fields' ); + $m->title_like(qr/Modify ticket/i, 'modify ticket'); + $m->content_like(qr/\Q$cf_name/, 'CF on the page'); + + my $value = $m->form_number(3)->value("Object-RT::Ticket-$tid-CustomField-$cfid-Values"); + is lc $value, 'asd', 'correct value is selected'; + $m->select("Object-RT::Ticket-$tid-CustomField-$cfid-Values" => 0 ); + $m->submit; + $m->content_like(qr/\Q$cf_name\E.*?changed/mi, 'field is changed'); + $m->content_unlike(qr/0 is no longer a value for custom field/mi, 'no bad message in results'); + + $value = $m->form_number(3)->value("Object-RT::Ticket-$tid-CustomField-$cfid-Values"); + is lc $value, '0', 'new value is selected'; + + my $ticket = RT::Ticket->new( $RT::SystemUser ); + $ticket->Load( $tid ); + ok $ticket->id, 'loaded the ticket'; + is lc $ticket->FirstCustomFieldValue( $cf_name ), + '0', 'API returns correct value'; +} + +diag "check that we can set empty value when the current is 0" + if $ENV{'TEST_VERBOSE'}; +{ + ok $m->goto_ticket( $tid ), "opened ticket's page"; + $m->follow_link( text => 'Custom Fields' ); + $m->title_like(qr/Modify ticket/i, 'modify ticket'); + $m->content_like(qr/\Q$cf_name/, 'CF on the page'); + + my $value = $m->form_number(3)->value("Object-RT::Ticket-$tid-CustomField-$cfid-Values"); + is lc $value, '0', 'correct value is selected'; + $m->select("Object-RT::Ticket-$tid-CustomField-$cfid-Values" => '' ); + $m->submit; + $m->content_like(qr/0 is no longer a value for custom field/mi, '0 is no longer a value'); + + $value = $m->form_number(3)->value("Object-RT::Ticket-$tid-CustomField-$cfid-Values"); + is $value, '', '(no value) is selected'; + + my $ticket = RT::Ticket->new( $RT::SystemUser ); + $ticket->Load( $tid ); + ok $ticket->id, 'loaded the ticket'; + is $ticket->FirstCustomFieldValue( $cf_name ), + undef, 'API returns correct value'; +} + diff --git a/rt/t/web/command_line.t b/rt/t/web/command_line.t new file mode 100644 index 000000000..3fc279bf3 --- /dev/null +++ b/rt/t/web/command_line.t @@ -0,0 +1,544 @@ +#!/usr/bin/perl -w + +use strict; +use File::Spec (); +use Test::Expect; +use RT::Test tests => 295; +my ($baseurl, $m) = RT::Test->started_ok; + +use RT::User; +use RT::Queue; + +my $rt_tool_path = "$RT::BinPath/rt"; + +# {{{ test configuration options + +# config directives: +# (in $CWD/.rtrc) +# - server <URL> URL to RT server. +# - user <username> RT username. +# - passwd <passwd> RT user's password. +# - query <RT Query> Default RT Query for list action +# - orderby <order> Default RT order for list action +# +# Blank and #-commented lines are ignored. + +# environment variables +# The following environment variables override any corresponding +# values defined in configuration files: +# +# - RTUSER +$ENV{'RTUSER'} = 'root'; +# - RTPASSWD +$ENV{'RTPASSWD'} = 'password'; +# - RTSERVER +$RT::Logger->debug("Connecting to server at ".RT->Config->Get('WebBaseURL')); +$ENV{'RTSERVER'} =RT->Config->Get('WebBaseURL') ; +# - RTDEBUG Numeric debug level. (Set to 3 for full logs.) +$ENV{'RTDEBUG'} = '1'; +# - RTCONFIG Specifies a name other than ".rtrc" for the +# configuration file. +# +# - RTQUERY Default RT Query for rt list +# - RTORDERBY Default order for rt list + + +# }}} + +# {{{ test ticket manipulation + +# create a ticket +expect_run( + command => "$rt_tool_path shell", + prompt => 'rt> ', + quit => 'quit', +); +expect_send(q{create -t ticket set subject='new ticket' add cc=foo@example.com}, "Creating a ticket..."); +expect_like(qr/Ticket \d+ created/, "Created the ticket"); +expect_handle->before() =~ /Ticket (\d+) created/; +my $ticket_id = $1; +ok($ticket_id, "Got ticket id=$ticket_id"); +expect_send(q{create -t ticket set subject='new ticket'}, "Creating a ticket as just a subject..."); +expect_like(qr/Ticket \d+ created/, "Created the ticket"); + +# make sure we can request things as 'rt foo' +expect_send(q{rt create -t ticket set subject='rt ticket'}, "Creating a ticket with 'rt create'..."); +expect_like(qr/Ticket \d+ created/, "Created the ticket"); + +# {{{ test queue manipulation + +# creating queues +expect_send("create -t queue set Name='NewQueue$$'", 'Creating a queue...'); +expect_like(qr/Queue \d+ created/, 'Created the queue'); +expect_handle->before() =~ /Queue (\d+) created/; +my $queue_id = $1; +ok($queue_id, "Got queue id=$queue_id"); +# updating users +expect_send("edit queue/$queue_id set Name='EditedQueue$$'", 'Editing the queue'); +expect_like(qr/Queue $queue_id updated/, 'Edited the queue'); +expect_send("show queue/$queue_id", 'Showing the queue...'); +expect_like(qr/id: queue\/$queue_id/, 'Saw the queue'); +expect_like(qr/Name: EditedQueue$$/, 'Saw the modification'); +TODO: { + todo_skip "Listing non-ticket items doesn't work", 2; + expect_send("list -t queue 'id > 0'", 'Listing the queues...'); + expect_like(qr/$queue_id: EditedQueue$$/, 'Found the queue'); +} + +# }}} + + +# Set up a custom field for editing tests +my $cf = RT::CustomField->new($RT::SystemUser); +my ($val,$msg) = $cf->Create(Name => 'MyCF'.$$, Type => 'FreeformSingle', Queue => $queue_id); +ok($val,$msg); + +my $othercf = RT::CustomField->new($RT::SystemUser); +($val,$msg) = $othercf->Create(Name => 'My CF'.$$, Type => 'FreeformSingle', Queue => $queue_id); +ok($val,$msg); + +my $multiple_cf = RT::CustomField->new($RT::SystemUser); +($val,$msg) = $multiple_cf->Create(Name => 'MultipleCF'.$$, Type => + 'FreeformMultiple', Queue => $queue_id); +ok($val,$msg); + + +# add a comment to ticket + expect_send("comment -m 'comment-$$' $ticket_id", "Adding a comment..."); + expect_like(qr/Message recorded/, "Added the comment"); + ### should test to make sure it actually got added + # add correspondance to ticket (?) + expect_send("correspond -m 'correspond-$$' $ticket_id", "Adding correspondence..."); + expect_like(qr/Message recorded/, "Added the correspondence"); + ### should test to make sure it actually got added + + my $test_email = RT::Test::get_relocatable_file('lorem-ipsum', + (File::Spec->updir(), 'data', 'emails')); + # add attachments to a ticket + # text attachment + check_attachment($test_email); + # binary attachment + check_attachment($RT::MasonComponentRoot.'/NoAuth/images/bplogo.gif'); + +# change a ticket's Owner +expect_send("edit ticket/$ticket_id set owner=root", 'Changing owner...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed owner'); +expect_send("show ticket/$ticket_id -f owner", 'Verifying change...'); +expect_like(qr/Owner: root/, 'Verified change'); +# change a ticket's Requestor +expect_send("edit ticket/$ticket_id set requestors=foo\@example.com", 'Changing Requestor...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed Requestor'); +expect_send("show ticket/$ticket_id -f requestors", 'Verifying change...'); +expect_like(qr/Requestors: foo\@example.com/, 'Verified change'); +# change a ticket's Cc +expect_send("edit ticket/$ticket_id set cc=bar\@example.com", 'Changing Cc...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed Cc'); +expect_send("show ticket/$ticket_id -f cc", 'Verifying change...'); +expect_like(qr/Cc: bar\@example.com/, 'Verified change'); +# change a ticket's priority +expect_send("edit ticket/$ticket_id set priority=10", 'Changing priority...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed priority'); +expect_send("show ticket/$ticket_id -f priority", 'Verifying change...'); +expect_like(qr/Priority: 10/, 'Verified change'); +# move a ticket to a different queue +expect_send("edit ticket/$ticket_id set queue=EditedQueue$$", 'Changing queue...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed queue'); +expect_send("show ticket/$ticket_id -f queue", 'Verifying change...'); +expect_like(qr/Queue: EditedQueue$$/, 'Verified change'); +# cannot move ticket to a nonexistent queue +expect_send("edit ticket/$ticket_id set queue=nonexistent-$$", 'Changing to nonexistent queue...'); +expect_like(qr/queue does not exist/i, 'Errored out'); +expect_send("show ticket/$ticket_id -f queue", 'Verifying lack of change...'); +expect_like(qr/Queue: EditedQueue$$/, 'Verified lack of change'); + +# Test reading and setting custom fields without spaces +expect_send("show ticket/$ticket_id -f CF-myCF$$", 'Checking initial value'); +expect_like(qr/CF\.{myCF$$}:/i, 'Verified initial empty value (CF-x syntax)'); +expect_send("show ticket/$ticket_id -f CF.{myCF$$}", 'Checking initial value'); +expect_like(qr/CF\.{myCF$$}:/i, 'Verified initial empty value (CF.{x} syntax)'); + +expect_send("edit ticket/$ticket_id set 'CF-myCF$$=VALUE' ", 'Changing CF...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed cf'); +expect_send("show ticket/$ticket_id -f CF-myCF$$", 'Checking new value'); +expect_like(qr/CF\.{myCF$$}: VALUE/i, 'Verified change'); +# Test setting 0 as value of the custom field +expect_send("edit ticket/$ticket_id set 'CF-myCF$$=0' ", 'Changing CF...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed cf'); +expect_send("show ticket/$ticket_id -f CF-myCF$$", 'Checking new value'); +expect_like(qr/CF\.{myCF$$}: 0/i, 'Verified change'); + +expect_send("edit ticket/$ticket_id set 'CF.{myCF$$}=VALUE' ",'Changing CF...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed cf'); +expect_send("show ticket/$ticket_id -f CF.{myCF$$}", 'Checking new value'); +expect_like(qr/CF\.{myCF$$}: VALUE/i, 'Verified change'); +# Test setting 0 as value of the custom field +expect_send("edit ticket/$ticket_id set 'CF.{myCF$$}=0' ", 'Changing CF...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed cf'); +expect_send("show ticket/$ticket_id -f CF.{myCF$$}", 'Checking new value'); +expect_like(qr/CF\.{myCF$$}: 0/i, 'Verified change'); + +# Test reading and setting custom fields with spaces +expect_send("show ticket/$ticket_id -f 'CF-my CF$$'", 'Checking initial value'); +expect_like(qr/CF\.{my CF$$}:/i, 'Verified change'); +expect_send("edit ticket/$ticket_id set 'CF-my CF$$=VALUE' ", 'Changing CF...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed cf'); +expect_send("show ticket/$ticket_id -f 'CF-my CF$$'", 'Checking new value'); +expect_like(qr/CF\.{my CF$$}: VALUE/i, 'Verified change'); +expect_send("ls -l 'id = $ticket_id' -f 'CF-my CF$$'", 'Checking new value'); +expect_like(qr/CF\.{my CF$$}: VALUE/i, 'Verified change'); + +expect_send("show ticket/$ticket_id -f 'CF.{my CF$$}'", 'Checking initial value'); +expect_like(qr/CF\.{my CF$$}: VALUE/i, 'Verified change'); +expect_send("edit ticket/$ticket_id set 'CF.{my CF$$}=NEW' ", 'Changing CF...'); +expect_send("show ticket/$ticket_id -f 'CF.{my CF$$}'", 'Checking new value'); +expect_like(qr/CF\.{my CF$$}: NEW/i, 'Verified change'); +expect_send("ls -l 'id = $ticket_id' -f 'CF.{my CF$$}'", 'Checking new value'); +expect_like(qr/CF\.{my CF$$}: NEW/i, 'Verified change'); + +# Test reading and setting single value custom field with commas or quotes +expect_send("show ticket/$ticket_id -f CF-myCF$$", 'Checking initial value'); +expect_like(qr/CF\.{myCF$$}:/i, 'Verified change'); +expect_send("edit ticket/$ticket_id set CF-myCF$$=1,2,3", 'Changing CF...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed cf'); +expect_send("show ticket/$ticket_id -f CF-myCF$$", 'Checking new value'); +expect_like(qr/CF\.{myCF$$}: 1,2,3/i, 'Verified change'); +expect_send("edit ticket/$ticket_id set CF-myCF$$=\"1's,2,3\"", 'Changing CF...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed cf'); +expect_send("show ticket/$ticket_id -f CF-myCF$$", 'Checking new value'); +expect_like(qr/CF\.{myCF$$}: 1's,2,3/i, 'Verified change'); + +# Test reading and setting custom fields with multiple values +expect_send("show ticket/$ticket_id -f CF-MultipleCF$$", 'Checking initial value'); +expect_like(qr/CF\.{MultipleCF$$}:/i, 'Verified multiple cf change'); +expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=1,2,3 ", 'Changing CF...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf'); +expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); +expect_like(qr/CF\.{MultipleCF$$}: 1,\s*2,\s*3/i, 'Verified multiple cf change'); +expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=a,b,c ", 'Changing CF...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf'); +expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); +expect_like(qr/CF\.{MultipleCF$$}: a,\s*b,\s*c/i, 'Verified change'); +expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=a", 'Changing CF...'); +expect_like(qr/Ticket $ticket_id updated/, 'del multiple cf'); +expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); +expect_like(qr/CF\.{MultipleCF$$}: b,\s*c/i, 'Verified multiple cf change'); +expect_send("edit ticket/$ticket_id add CF.{MultipleCF$$}=o", 'Changing CF...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf'); +expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); +expect_like(qr/CF\.{MultipleCF$$}: b,\s*c,\s*o/i, 'Verified multiple cf change'); + +expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"'a,b,c'\" ", 'Changing CF...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf'); +expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); +expect_like(qr/CF\.{MultipleCF$$}: 'a,b,c'/i, 'Verified change'); +expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=a", 'Changing CF...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf'); +expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); +expect_like(qr/CF\.{MultipleCF$$}: 'a,b,c'/i, 'Verified change'); + +expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=q{a,b,c}", 'Changing CF...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf'); +expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); +expect_like(qr/CF\.{MultipleCF$$}: 'a,b,c'/i, 'Verified change'); +expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=a", 'Changing CF...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf'); +expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); +expect_like(qr/CF\.{MultipleCF$$}: 'a,b,c'/i, 'Verified change'); +expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=\"'a,b,c'\"", 'Changing CF...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf'); +expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); +expect_like(qr/CF\.{MultipleCF$$}: \s*$/i, 'Verified change'); + +expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"q{1,2's,3}\"", 'Changing CF...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed multiple cf'); +expect_send("show ticket/$ticket_id -f CF.{MultipleCF$$}", 'Checking new value'); +expect_like(qr/CF\.{MultipleCF$$}: '1,2\\'s,3'/i, 'Verified change'); + +# ... +# change a ticket's ...[other properties]... +# ... +# stall a ticket +expect_send("edit ticket/$ticket_id set status=stalled", 'Changing status to "stalled"...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed status'); +expect_send("show ticket/$ticket_id -f status", 'Verifying change...'); +expect_like(qr/Status: stalled/, 'Verified change'); +# resolve a ticket +expect_send("edit ticket/$ticket_id set status=resolved", 'Changing status to "resolved"...'); +expect_like(qr/Ticket $ticket_id updated/, 'Changed status'); +expect_send("show ticket/$ticket_id -f status", 'Verifying change...'); +expect_like(qr/Status: resolved/, 'Verified change'); +# try to set status to an illegal value +expect_send("edit ticket/$ticket_id set status=quux", 'Changing status to an illegal value...'); +expect_like(qr/illegal value/i, 'Errored out'); +expect_send("show ticket/$ticket_id -f status", 'Verifying lack of change...'); +expect_like(qr/Status: resolved/, 'Verified change'); + +# }}} + +# {{{ display + +# show ticket list +expect_send("ls -s -t ticket -o +id \"Status='resolved'\"", 'Listing resolved tickets...'); +expect_like(qr/$ticket_id: new ticket/, 'Found our ticket'); +# show ticket list verbosely +expect_send("ls -l -t ticket -o +id \"Status='resolved'\"", 'Listing resolved tickets verbosely...'); +expect_like(qr/id: ticket\/$ticket_id/, 'Found our ticket'); +# show ticket +expect_send("show -s -t ticket $ticket_id", 'Showing our ticket...'); +expect_like(qr/id: ticket\/$ticket_id/, 'Got our ticket'); +# show ticket history +expect_send("show ticket/$ticket_id/history", 'Showing our ticket\'s history...'); +expect_like(qr/Ticket created by root/, 'Got our history'); + +expect_send("show -v ticket/$ticket_id/history", 'Showing our ticket\'s history verbosely...'); +TODO: { + local $TODO = "Cannot show verbose ticket history right now"; + # show ticket history verbosely + expect_like(qr/Ticket created by root/, 'Got our history'); +} +# get attachments from a ticket +expect_send("show -s ticket/$ticket_id/attachments", 'Showing ticket attachments...'); +expect_like(qr/id: ticket\/$ticket_id\/attachments/, 'Got our ticket\'s attachments'); +expect_like(qr/Attachments: \d+: \(Unnamed\) \(\S+ \/ \d+\w+\)/, 'Our ticket has an attachment'); +expect_handle->before() =~ /Attachments: (\d+): \(Unnamed\) \((\S+)/; +my $attachment_id = $1; +my $attachment_type = $2; +ok($attachment_id, "Got attachment id=$attachment_id $attachment_type"); +expect_send("show -s ticket/$ticket_id/attachments/$attachment_id", "Showing attachment $attachment_id..."); +expect_like(qr/ContentType: $attachment_type/, 'Got the attachment'); + +# }}} + +# {{{ test user manipulation + +# creating users +expect_send("create -t user set Name='NewUser$$' EmailAddress='fbar$$\@example.com'", 'Creating a user...'); +expect_like(qr/User \d+ created/, 'Created the user'); +expect_handle->before() =~ /User (\d+) created/; +my $user_id = $1; +ok($user_id, "Got user id=$user_id"); +# updating users +expect_send("edit user/$user_id set Name='EditedUser$$'", 'Editing the user'); +expect_like(qr/User $user_id updated/, 'Edited the user'); +expect_send("show user/$user_id", 'Showing the user...'); +expect_like(qr/id: user\/$user_id/, 'Saw the user'); +expect_like(qr/Name: EditedUser$$/, 'Saw the modification'); +TODO: { + todo_skip "Listing non-ticket items doesn't work", 2; + expect_send("list -t user 'id > 0'", 'Listing the users...'); + expect_like(qr/$user_id: EditedUser$$/, 'Found the user'); +} + +# }}} + +# {{{ test group manipulation + +TODO: { +todo_skip "Group manipulation doesn't work right now", 8; +# creating groups +expect_send("create -t group set Name='NewGroup$$'", 'Creating a group...'); +expect_like(qr/Group \d+ created/, 'Created the group'); +expect_handle->before() =~ /Group (\d+) created/; +my $group_id = $1; +ok($group_id, "Got group id=$group_id"); +# updating groups +expect_send("edit group/$group_id set Name='EditedGroup$$'", 'Editing the group'); +expect_like(qr/Group $group_id updated/, 'Edited the group'); +expect_send("show group/$group_id", 'Showing the group...'); +expect_like(qr/id: group\/$group_id/, 'Saw the group'); +expect_like(qr/Name: EditedGroup$$/, 'Saw the modification'); +TODO: { + local $TODO = "Listing non-ticket items doesn't work"; + expect_send("list -t group 'id > 0'", 'Listing the groups...'); + expect_like(qr/$group_id: EditedGroup$$/, 'Found the group'); +} +} + +# }}} + +TODO: { +todo_skip "Custom field manipulation not yet implemented", 8; +# {{{ test custom field manipulation + +# creating custom fields +expect_send("create -t custom_field set Name='NewCF$$'", 'Creating a custom field...'); +expect_like(qr/Custom Field \d+ created/, 'Created the custom field'); +expect_handle->before() =~ /Custom Field (\d+) created/; +my $cf_id = $1; +ok($cf_id, "Got custom field id=$cf_id"); +# updating custom fields +expect_send("edit cf/$cf_id set Name='EditedCF$$'", 'Editing the custom field'); +expect_like(qr/Custom field $cf_id updated/, 'Edited the custom field'); +expect_send("show cf/$cf_id", 'Showing the queue...'); +expect_like(qr/id: custom_field\/$cf_id/, 'Saw the custom field'); +expect_like(qr/Name: EditedCF$$/, 'Saw the modification'); +TODO: { + todo_skip "Listing non-ticket items doesn't work", 2; + expect_send("list -t custom_field 'id > 0'", 'Listing the CFs...'); + expect_like(qr/$cf_id: EditedCF$$/, 'Found the custom field'); +} +} + +# }}} + +# {{{ test merging tickets +expect_send("create -t ticket set subject='CLIMergeTest1-$$'", 'Creating first ticket to merge...'); +expect_like(qr/Ticket \d+ created/, 'Created first ticket'); +expect_handle->before() =~ /Ticket (\d+) created/; +my $merge_ticket_A = $1; +ok($merge_ticket_A, "Got first ticket to merge id=$merge_ticket_A"); +expect_send("create -t ticket set subject='CLIMergeTest2-$$'", 'Creating second ticket to merge...'); +expect_like(qr/Ticket \d+ created/, 'Created second ticket'); +expect_handle->before() =~ /Ticket (\d+) created/; +my $merge_ticket_B = $1; +ok($merge_ticket_B, "Got second ticket to merge id=$merge_ticket_B"); +expect_send("merge $merge_ticket_B $merge_ticket_A", 'Merging the tickets...'); +expect_like(qr/Merge completed/, 'Merged the tickets'); + +TODO: { + local $TODO = "we generate a spurious warning here"; + $m->no_warnings_ok; +} + +expect_send("show ticket/$merge_ticket_A/history", 'Checking merge on first ticket'); +expect_like(qr/Merged into ticket #$merge_ticket_A by root/, 'Merge recorded in first ticket'); +expect_send("show ticket/$merge_ticket_B/history", 'Checking merge on second ticket'); +expect_like(qr/Merged into ticket #$merge_ticket_A by root/, 'Merge recorded in second ticket'); +# }}} + +# {{{ test taking/stealing tickets +{ + # create a user; give them privileges to take and steal + ### TODO: implement 'grant' in the CLI tool; use that here instead. + ### this breaks the abstraction barrier, like, a lot. + my $steal_user = RT::User->new($RT::SystemUser); + my ($steal_user_id, $msg) = $steal_user->Create( Name => "fooser$$", + EmailAddress => "fooser$$\@localhost", + Privileged => 1, + Password => 'foobar', + ); + ok($steal_user_id, "Created the user? $msg"); + my $steal_queue = RT::Queue->new($RT::SystemUser); + my $steal_queue_id; + ($steal_queue_id, $msg) = $steal_queue->Create( Name => "Steal$$" ); + ok($steal_queue_id, "Got the queue? $msg"); + ok($steal_queue->id, "queue obj has id"); + my $status; + ($status, $msg) = $steal_user->PrincipalObj->GrantRight( Right => 'ShowTicket', Object => $steal_queue ); + ok($status, "Gave 'ShowTicket' to our user? $msg"); + ($status, $msg) = $steal_user->PrincipalObj->GrantRight( Right => 'OwnTicket', Object => $steal_queue ); + ok($status, "Gave 'OwnTicket' to our user? $msg"); + ($status, $msg) = $steal_user->PrincipalObj->GrantRight( Right => 'StealTicket', Object => $steal_queue ); + ok($status, "Gave 'StealTicket' to our user? $msg"); + ($status, $msg) = $steal_user->PrincipalObj->GrantRight( Right => 'TakeTicket', Object => $steal_queue ); + ok($status, "Gave 'TakeTicket' to our user? $msg"); + + # create a ticket to take/steal + expect_send("create -t ticket set queue=$steal_queue_id subject='CLIStealTest-$$'", 'Creating ticket to steal...'); + expect_like(qr/Ticket \d+ created/, 'Created ticket'); + expect_handle->before() =~ /Ticket (\d+) created/; + my $steal_ticket_id = $1; + ok($steal_ticket_id, "Got ticket to steal id=$steal_ticket_id"); + + # root takes the ticket + expect_send("take $steal_ticket_id", 'root takes the ticket...'); + expect_like(qr/Owner changed from Nobody to root/, 'root took the ticket'); + expect_quit(); + + # log in as the non-root user + $ENV{'RTUSER'} = "fooser$$"; + $ENV{'RTPASSWD'} = 'foobar'; + expect_run( command => "$rt_tool_path shell", prompt => 'rt> ', quit => 'quit',); + + # user tries to take the ticket, fails + # shouldn't be able to 'take' a ticket which someone else has taken out from + # under you; that should produce an error. should have to explicitly + # 'steal' it back from them. 'steal' can automatically 'take' a ticket, + # though. + expect_send("take $steal_ticket_id", 'user tries to take the ticket...'); + expect_like(qr/You can only take tickets that are unowned/, '...and fails.'); + expect_send("show ticket/$steal_ticket_id -f owner", 'Double-checking...'); + expect_like(qr/Owner: root/, '...no change.'); + + # user steals the ticket + expect_send("steal $steal_ticket_id", 'user tries to *steal* the ticket...'); + expect_like(qr/Owner changed from root to fooser$$/, '...and succeeds!'); + expect_send("show ticket/$steal_ticket_id -f owner", 'Double-checking...'); + expect_like(qr/Owner: fooser$$/, '...yup, it worked.'); + expect_quit(); + + # log back in as root + $ENV{'RTUSER'} = 'root'; + $ENV{'RTPASSWD'} = 'password'; + expect_run( command => "$rt_tool_path shell", prompt => 'rt> ', quit => 'quit',); + + # root steals the ticket back + expect_send("steal $steal_ticket_id", 'root steals the ticket back...'); + expect_like(qr/Owner changed from fooser$$ to root/, '...and succeeds.'); +} +# }}} + +# {{{ test ticket linking + my @link_relns = ( 'DependsOn', 'DependedOnBy', 'RefersTo', 'ReferredToBy', + 'MemberOf', 'HasMember', ); + my %display_relns = map { $_ => $_ } @link_relns; + $display_relns{HasMember} = 'Members'; + + my $link1_id = ok_create_ticket( "LinkTicket1-$$" ); + my $link2_id = ok_create_ticket( "LinkTicket2-$$" ); + + foreach my $reln (@link_relns) { + # create link + expect_send("link $link1_id $reln $link2_id", "Link by $reln..."); + expect_like(qr/Created link $link1_id $reln $link2_id/, 'Linked'); + expect_send("show -s ticket/$link1_id/links", "Checking creation of $reln..."); + expect_like(qr/$display_relns{$reln}: [\w\d\.\-]+:\/\/[\w\d\.]+\/ticket\/$link2_id/, "Created link $reln"); + + # delete link + expect_send("link -d $link1_id $reln $link2_id", "Delete $reln..."); + expect_like(qr/Deleted link $link1_id $reln $link2_id/, 'Deleted'); + expect_send("show ticket/$link1_id/links", "Checking removal of $reln..."); + ok( expect_handle->before() !~ /\Q$display_relns{$reln}: \E[\w\d\.\-]+:\/\/[w\d\.]+\/ticket\/$link2_id/, "Removed link $reln" ); + #expect_unlike(qr/\Q$reln: \E[\w\d\.]+\Q://\E[w\d\.]+\/ticket\/$link2_id/, "Removed link $reln"); + + } +# }}} + +expect_quit(); # We need to do this ourselves, so that we quit + # *before* we tear down the webserver. + +# helper function +sub ok_create_ticket { + my $subject = shift; + + expect_send("create -t ticket set subject='$subject'", 'Creating ticket...'); + expect_like(qr/Ticket \d+ created/, "Created ticket '$subject'"); + expect_handle->before() =~ /Ticket (\d+) created/; + my $id = $1; + ok($id, "Got ticket id=$id"); + + return $id; +} + +# wrap up all the file handling stuff for attachment testing +sub check_attachment { + my $attachment_path = shift; + (my $filename = $attachment_path) =~ s/.*\/(.*)$/$1/; + expect_send("comment -m 'attach file' -a $attachment_path $ticket_id", "Adding an attachment ($filename)"); + expect_like(qr/Message recorded/, "Added the attachment"); + expect_send("show ticket/$ticket_id/attachments","Finding Attachment"); + my $attachment_regex = qr/(\d+):\s+$filename/; + expect_like($attachment_regex,"Attachment Uploaded"); + expect_handle->before() =~ $attachment_regex; + my $attachment_id = $1; + expect_send("show ticket/$ticket_id/attachments/$attachment_id/content","Fetching Attachment"); + open (my $fh, $attachment_path) or die "Can't open $attachment_path: $!"; + my $attachment_content = do { local($/); <$fh> }; + close $fh; + chomp $attachment_content; + expect_is($attachment_content,"Attachment contains original text"); +} + + + +1; diff --git a/rt/t/web/command_line_with_unknown_field.t b/rt/t/web/command_line_with_unknown_field.t new file mode 100644 index 000000000..9a7ec7acd --- /dev/null +++ b/rt/t/web/command_line_with_unknown_field.t @@ -0,0 +1,34 @@ +#!/usr/bin/perl -w + +use strict; +use File::Spec (); +use Test::Expect; +use RT::Test tests => 10; +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'; + +expect_run( + command => "$rt_tool_path shell", + prompt => 'rt> ', + quit => 'quit', +); +expect_send(q{create -t ticket set subject='new ticket' add cc=foo@example.com}, "Creating a ticket..."); +expect_like(qr/Ticket \d+ created/, "Created the ticket"); +expect_handle->before() =~ /Ticket (\d+) created/; +my $ticket_id = $1; + +expect_send("edit ticket/$ticket_id set marge=simpson", 'set unknown field'); +expect_like(qr/marge: Unknown field/, 'marge is unknown field'); +expect_like(qr/marge: simpson/, 'the value we set for marge is shown too'); + +expect_send("edit ticket/$ticket_id set homer=simpson", 'set unknown field'); +expect_like(qr/homer: Unknown field/, 'homer is unknown field'); +expect_like(qr/homer: simpson/, 'the value we set for homer is shown too'); + +expect_quit(); diff --git a/rt/t/web/compilation_errors.t b/rt/t/web/compilation_errors.t new file mode 100644 index 000000000..46a862868 --- /dev/null +++ b/rt/t/web/compilation_errors.t @@ -0,0 +1,68 @@ +#!/usr/bin/perl + +use strict; +use Test::More; +use File::Find; +BEGIN { + sub wanted { + -f && /\.html$/ && $_ !~ /Logout.html$/; + } + my $tests = 7; + find( sub { wanted() and $tests += 4 }, 'share/html/' ); + plan tests => $tests; +} + + +use HTTP::Request::Common; +use HTTP::Cookies; +use LWP; +use Encode; + +my $cookie_jar = HTTP::Cookies->new; + +use RT::Test; +my ($baseurl, $agent) = RT::Test->started_ok; + +# give the agent a place to stash the cookies +$agent->cookie_jar($cookie_jar); + +# get the top page +my $url = $agent->rt_base_url; +diag "Base URL is '$url'" if $ENV{TEST_VERBOSE}; +$agent->get($url); + +is ($agent->{'status'}, 200, "Loaded a page"); + +# {{{ test a login + +# follow the link marked "Login" + +ok($agent->{form}->find_input('user')); + +ok($agent->{form}->find_input('pass')); +like ($agent->{'content'} , qr/username:/i); +$agent->field( 'user' => 'root' ); +$agent->field( 'pass' => 'password' ); +# the field isn't named, so we have to click link 0 +$agent->click(0); +is($agent->{'status'}, 200, "Fetched the page ok"); +like( $agent->{'content'} , qr/Logout/i, "Found a logout link"); + + +find ( sub { wanted() and test_get($File::Find::name) } , 'share/html/'); + +sub test_get { + my $file = shift; + + $file =~ s#^share/html/##; + diag( "testing $url/$file" ) if $ENV{TEST_VERBOSE}; + ok ($agent->get("$url/$file", "GET $url/$file"), "Can Get $url/$file"); + is ($agent->{'status'}, 200, "Loaded $file"); +# ok( $agent->{'content'} =~ /Logout/i, "Found a logout link on $file "); + ok( $agent->{'content'} !~ /Not logged in/i, "Still logged in for $file"); + ok( $agent->{'content'} !~ /raw error/i, "Didn't get a Mason compilation error on $file"); +} + +# }}} + +1; diff --git a/rt/t/web/config_tab_right.t b/rt/t/web/config_tab_right.t new file mode 100644 index 000000000..4dc9ec082 --- /dev/null +++ b/rt/t/web/config_tab_right.t @@ -0,0 +1,41 @@ +#!/usr/bin/perl -w +use strict; +use warnings; + +use RT::Test tests => 8; + +my ($uname, $upass, $user) = ('tester', 'tester'); +{ + $user = RT::User->new($RT::SystemUser); + my ($status, $msg) = $user->Create( + Name => $uname, + Password => $upass, + Disabled => 0, + Privileged => 1, + ); + ok($status, 'created a user'); +} + +my ($baseurl, $m) = RT::Test->started_ok; +ok $m->login($uname, $upass), "logged in"; + +{ + $m->content_unlike(qr/Configuration/, 'no configuration'); + $m->get('/Admin/'); + is $m->status, 403, 'no access to /Admin/'; +} + +RT::Test->set_rights( + { Principal => $user->PrincipalObj, + Right => [qw(ShowConfigTab)], + }, +); + +{ + $m->get('/'); + $m->content_like(qr/Configuration/, 'configuration is there'); + + $m->follow_link_ok({text => 'Configuration'}); + is $m->status, 200, 'user has access to /Admin/'; +} + diff --git a/rt/t/web/crypt-gnupg.t b/rt/t/web/crypt-gnupg.t new file mode 100644 index 000000000..fb28c887c --- /dev/null +++ b/rt/t/web/crypt-gnupg.t @@ -0,0 +1,446 @@ +#!/usr/bin/perl -w +use strict; + +use RT::Test tests => 94; + +plan skip_all => 'GnuPG required.' + unless eval 'use GnuPG::Interface; 1'; +plan skip_all => 'gpg executable is required.' + unless RT::Test->find_executable('gpg'); + + +use RT::Action::SendEmail; + +eval 'use GnuPG::Interface; 1' or plan skip_all => 'GnuPG required.'; + +RT::Test->set_mail_catcher; + +RT->Config->Set( CommentAddress => 'general@example.com'); +RT->Config->Set( CorrespondAddress => 'general@example.com'); +RT->Config->Set( DefaultSearchResultFormat => qq{ + '<B><A HREF="__WebPath__/Ticket/Display.html?id=__id__">__id__</a></B>/TITLE:#', + '<B><A HREF="__WebPath__/Ticket/Display.html?id=__id__">__Subject__</a></B>/TITLE:Subject', + 'OO-__OwnerName__-O', + 'OR-__Requestors__-O', + 'KO-__KeyOwnerName__-K', + 'KR-__KeyRequestors__-K', + Status}); + +use File::Spec (); +use Cwd; +use File::Temp qw(tempdir); +my $homedir = tempdir( CLEANUP => 1 ); + +use_ok('RT::Crypt::GnuPG'); + +RT->Config->Set( 'GnuPG', + Enable => 1, + OutgoingMessagesFormat => 'RFC' ); + +RT->Config->Set( 'GnuPGOptions', + homedir => $homedir, + passphrase => 'recipient', + 'no-permission-warning' => undef, + 'trust-model' => 'always'); +RT->Config->Set( 'MailPlugins' => 'Auth::MailFrom', 'Auth::GnuPG' ); + +RT::Test->import_gnupg_key('recipient@example.com', 'public'); +RT::Test->import_gnupg_key('recipient@example.com', 'secret'); +RT::Test->import_gnupg_key('general@example.com', 'public'); +RT::Test->import_gnupg_key('general@example.com', 'secret'); +RT::Test->import_gnupg_key('general@example.com.2', 'public'); +RT::Test->import_gnupg_key('general@example.com.2', 'secret'); + +ok(my $user = RT::User->new($RT::SystemUser)); +ok($user->Load('root'), "Loaded user 'root'"); +$user->SetEmailAddress('recipient@example.com'); + +my $queue = RT::Test->load_or_create_queue( + Name => 'General', + CorrespondAddress => 'general@example.com', +); +ok $queue && $queue->id, 'loaded or created queue'; +my $qid = $queue->id; + +RT::Test->set_rights( + Principal => 'Everyone', + Right => ['CreateTicket', 'ShowTicket', 'SeeQueue', 'ModifyTicket'], +); + +my ($baseurl, $m) = RT::Test->started_ok; +ok $m->login, 'logged in'; + +$m->get_ok("/Admin/Queues/Modify.html?id=$qid"); +$m->form_with_fields('Sign', 'Encrypt'); +$m->field(Encrypt => 1); +$m->submit; + +RT::Test->clean_caught_mails; + +$m->goto_create_ticket( $queue ); +$m->form_name('TicketCreate'); +$m->field('Subject', 'Encryption test'); +$m->field('Content', 'Some content'); +ok($m->value('Encrypt', 2), "encrypt tick box is checked"); +ok(!$m->value('Sign', 2), "sign tick box is unchecked"); +$m->submit; +is($m->status, 200, "request successful"); + +$m->get($baseurl); # ensure that the mail has been processed + +my @mail = RT::Test->fetch_caught_mails; +ok(@mail, "got some mail"); + +$user->SetEmailAddress('general@example.com'); +for my $mail (@mail) { + unlike $mail, qr/Some content/, "outgoing mail was encrypted"; + + my ($content_type) = $mail =~ /^(Content-Type: .*)/m; + my ($mime_version) = $mail =~ /^(MIME-Version: .*)/m; + my $body = strip_headers($mail); + + $mail = << "MAIL"; +Subject: RT mail sent back into RT +From: general\@example.com +To: recipient\@example.com +$mime_version +$content_type + +$body +MAIL + + my ($status, $id) = RT::Test->send_via_mailgate($mail); + is ($status >> 8, 0, "The mail gateway exited normally"); + ok ($id, "got id of a newly created ticket - $id"); + + my $tick = RT::Ticket->new( $RT::SystemUser ); + $tick->Load( $id ); + ok ($tick->id, "loaded ticket #$id"); + + is ($tick->Subject, + "RT mail sent back into RT", + "Correct subject" + ); + + my $txn = $tick->Transactions->First; + my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef}; + + is( $msg->GetHeader('X-RT-Privacy'), + 'PGP', + "RT's outgoing mail has crypto" + ); + is( $msg->GetHeader('X-RT-Incoming-Encryption'), + 'Success', + "RT's outgoing mail looks encrypted" + ); + + like($attachments[0]->Content, qr/Some content/, "RT's mail includes copy of ticket text"); + like($attachments[0]->Content, qr/$RT::rtname/, "RT's mail includes this instance's name"); +} + +$m->get("$baseurl/Admin/Queues/Modify.html?id=$qid"); +$m->form_with_fields('Sign', 'Encrypt'); +$m->field(Encrypt => undef); +$m->field(Sign => 1); +$m->submit; + +RT::Test->clean_caught_mails; + +$m->goto_create_ticket( $queue ); +$m->form_name('TicketCreate'); +$m->field('Subject', 'Signing test'); +$m->field('Content', 'Some other content'); +ok(!$m->value('Encrypt', 2), "encrypt tick box is unchecked"); +ok($m->value('Sign', 2), "sign tick box is checked"); +$m->submit; +is($m->status, 200, "request successful"); + +$m->get($baseurl); # ensure that the mail has been processed + +@mail = RT::Test->fetch_caught_mails; +ok(@mail, "got some mail"); +for my $mail (@mail) { + like $mail, qr/Some other content/, "outgoing mail was not encrypted"; + like $mail, qr/-----BEGIN PGP SIGNATURE-----[\s\S]+-----END PGP SIGNATURE-----/, "data has some kind of signature"; + + my ($content_type) = $mail =~ /^(Content-Type: .*)/m; + my ($mime_version) = $mail =~ /^(MIME-Version: .*)/m; + my $body = strip_headers($mail); + + $mail = << "MAIL"; +Subject: More RT mail sent back into RT +From: general\@example.com +To: recipient\@example.com +$mime_version +$content_type + +$body +MAIL + + my ($status, $id) = RT::Test->send_via_mailgate($mail); + is ($status >> 8, 0, "The mail gateway exited normally"); + ok ($id, "got id of a newly created ticket - $id"); + + my $tick = RT::Ticket->new( $RT::SystemUser ); + $tick->Load( $id ); + ok ($tick->id, "loaded ticket #$id"); + + is ($tick->Subject, + "More RT mail sent back into RT", + "Correct subject" + ); + + my $txn = $tick->Transactions->First; + my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef}; + + is( $msg->GetHeader('X-RT-Privacy'), + 'PGP', + "RT's outgoing mail has crypto" + ); + is( $msg->GetHeader('X-RT-Incoming-Encryption'), + 'Not encrypted', + "RT's outgoing mail looks unencrypted" + ); + is( $msg->GetHeader('X-RT-Incoming-Signature'), + 'general <general@example.com>', + "RT's outgoing mail looks signed" + ); + + like($attachments[0]->Content, qr/Some other content/, "RT's mail includes copy of ticket text"); + like($attachments[0]->Content, qr/$RT::rtname/, "RT's mail includes this instance's name"); +} + +$m->get("$baseurl/Admin/Queues/Modify.html?id=$qid"); +$m->form_with_fields('Sign', 'Encrypt'); +$m->field(Encrypt => 1); +$m->field(Sign => 1); +$m->submit; + +RT::Test->clean_caught_mails; + + +$m->goto_create_ticket( $queue ); +$m->form_name('TicketCreate'); +$m->field('Subject', 'Crypt+Sign test'); +$m->field('Content', 'Some final? content'); +ok($m->value('Encrypt', 2), "encrypt tick box is checked"); +ok($m->value('Sign', 2), "sign tick box is checked"); +$m->submit; +is($m->status, 200, "request successful"); + +$m->get($baseurl); # ensure that the mail has been processed + +@mail = RT::Test->fetch_caught_mails; +ok(@mail, "got some mail"); +for my $mail (@mail) { + unlike $mail, qr/Some other content/, "outgoing mail was encrypted"; + + my ($content_type) = $mail =~ /^(Content-Type: .*)/m; + my ($mime_version) = $mail =~ /^(MIME-Version: .*)/m; + my $body = strip_headers($mail); + + $mail = << "MAIL"; +Subject: Final RT mail sent back into RT +From: general\@example.com +To: recipient\@example.com +$mime_version +$content_type + +$body +MAIL + + my ($status, $id) = RT::Test->send_via_mailgate($mail); + is ($status >> 8, 0, "The mail gateway exited normally"); + ok ($id, "got id of a newly created ticket - $id"); + + my $tick = RT::Ticket->new( $RT::SystemUser ); + $tick->Load( $id ); + ok ($tick->id, "loaded ticket #$id"); + + is ($tick->Subject, + "Final RT mail sent back into RT", + "Correct subject" + ); + + my $txn = $tick->Transactions->First; + my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef}; + + is( $msg->GetHeader('X-RT-Privacy'), + 'PGP', + "RT's outgoing mail has crypto" + ); + is( $msg->GetHeader('X-RT-Incoming-Encryption'), + 'Success', + "RT's outgoing mail looks encrypted" + ); + is( $msg->GetHeader('X-RT-Incoming-Signature'), + 'general <general@example.com>', + "RT's outgoing mail looks signed" + ); + + like($attachments[0]->Content, qr/Some final\? content/, "RT's mail includes copy of ticket text"); + like($attachments[0]->Content, qr/$RT::rtname/, "RT's mail includes this instance's name"); +} + +RT::Test->clean_caught_mails; + +$m->goto_create_ticket( $queue ); +$m->form_name('TicketCreate'); +$m->field('Subject', 'Test crypt-off on encrypted queue'); +$m->field('Content', 'Thought you had me figured out didya'); +$m->field(Encrypt => undef, 2); # turn off encryption +ok(!$m->value('Encrypt', 2), "encrypt tick box is now unchecked"); +ok($m->value('Sign', 2), "sign tick box is still checked"); +$m->submit; +is($m->status, 200, "request successful"); + +$m->get($baseurl); # ensure that the mail has been processed + +@mail = RT::Test->fetch_caught_mails; +ok(@mail, "got some mail"); +for my $mail (@mail) { + like $mail, qr/Thought you had me figured out didya/, "outgoing mail was unencrypted"; + + my ($content_type) = $mail =~ /^(Content-Type: .*)/m; + my ($mime_version) = $mail =~ /^(MIME-Version: .*)/m; + my $body = strip_headers($mail); + + $mail = << "MAIL"; +Subject: Post-final! RT mail sent back into RT +From: general\@example.com +To: recipient\@example.com +$mime_version +$content_type + +$body +MAIL + + my ($status, $id) = RT::Test->send_via_mailgate($mail); + is ($status >> 8, 0, "The mail gateway exited normally"); + ok ($id, "got id of a newly created ticket - $id"); + + my $tick = RT::Ticket->new( $RT::SystemUser ); + $tick->Load( $id ); + ok ($tick->id, "loaded ticket #$id"); + + is ($tick->Subject, + "Post-final! RT mail sent back into RT", + "Correct subject" + ); + + my $txn = $tick->Transactions->First; + my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef}; + + is( $msg->GetHeader('X-RT-Privacy'), + 'PGP', + "RT's outgoing mail has crypto" + ); + is( $msg->GetHeader('X-RT-Incoming-Encryption'), + 'Not encrypted', + "RT's outgoing mail looks unencrypted" + ); + is( $msg->GetHeader('X-RT-Incoming-Signature'), + 'general <general@example.com>', + "RT's outgoing mail looks signed" + ); + + like($attachments[0]->Content, qr/Thought you had me figured out didya/, "RT's mail includes copy of ticket text"); + like($attachments[0]->Content, qr/$RT::rtname/, "RT's mail includes this instance's name"); +} + +sub strip_headers +{ + my $mail = shift; + $mail =~ s/.*?\n\n//s; + return $mail; +} + +# now test the OwnerNameKey and RequestorsKey fields + +my $nokey = RT::Test->load_or_create_user(Name => 'nokey', EmailAddress => 'nokey@example.com'); +$nokey->PrincipalObj->GrantRight(Right => 'CreateTicket'); +$nokey->PrincipalObj->GrantRight(Right => 'OwnTicket'); + +my $tick = RT::Ticket->new( $RT::SystemUser ); +$tick->Create(Subject => 'owner lacks pubkey', Queue => 'general', + Owner => $nokey); +ok(my $id = $tick->id, 'created ticket for owner-without-pubkey'); + +$tick = RT::Ticket->new( $RT::SystemUser ); +$tick->Create(Subject => 'owner has pubkey', Queue => 'general', + Owner => 'root'); +ok($id = $tick->id, 'created ticket for owner-with-pubkey'); + +my $mail = << "MAIL"; +Subject: Nokey requestor +From: nokey\@example.com +To: general\@example.com + +hello +MAIL + +((my $status), $id) = RT::Test->send_via_mailgate($mail); +is ($status >> 8, 0, "The mail gateway exited normally"); +ok ($id, "got id of a newly created ticket - $id"); + +$tick = RT::Ticket->new( $RT::SystemUser ); +$tick->Load( $id ); +ok ($tick->id, "loaded ticket #$id"); + +is ($tick->Subject, + "Nokey requestor", + "Correct subject" +); + +# test key selection +my $key1 = "EC1E81E7DC3DB42788FB0E4E9FA662C06DE22FC2"; +my $key2 = "75E156271DCCF02DDD4A7A8CDF651FA0632C4F50"; + +ok($user = RT::User->new($RT::SystemUser)); +ok($user->Load('root'), "Loaded user 'root'"); +is($user->PreferredKey, $key1, "preferred key is set correctly"); +$m->get("$baseurl/Prefs/Other.html"); +like($m->content, qr/Preferred key/, "preferred key option shows up in preference"); + +# XXX: mech doesn't let us see the current value of the select, apparently +like($m->content, qr/$key1/, "first key shows up in preferences"); +like($m->content, qr/$key2/, "second key shows up in preferences"); +like($m->content, qr/$key1.*?$key2/s, "first key shows up before the second"); + +$m->form_number(3); +$m->select("PreferredKey" => $key2); +$m->submit; + +ok($user = RT::User->new($RT::SystemUser)); +ok($user->Load('root'), "Loaded user 'root'"); +is($user->PreferredKey, $key2, "preferred key is set correctly to the new value"); + +$m->get("$baseurl/Prefs/Other.html"); +like($m->content, qr/Preferred key/, "preferred key option shows up in preference"); + +# XXX: mech doesn't let us see the current value of the select, apparently +like($m->content, qr/$key2/, "second key shows up in preferences"); +like($m->content, qr/$key1/, "first key shows up in preferences"); +like($m->content, qr/$key2.*?$key1/s, "second key (now preferred) shows up before the first"); + +# test that the new fields work +$m->get("$baseurl/Search/Simple.html?q=General"); +my $content = $m->content; +$content =~ s/(/(/g; +$content =~ s/)/)/g; + +like($content, qr/OO-Nobody-O/, "original OwnerName untouched"); +like($content, qr/OO-nokey-O/, "original OwnerName untouched"); +like($content, qr/OO-root-O/, "original OwnerName untouched"); + +like($content, qr/OR-recipient\@example.com-O/, "original Requestors untouched"); +like($content, qr/OR-nokey\@example.com-O/, "original Requestors untouched"); + +like($content, qr/KO-root-K/, "KeyOwnerName does not issue no-pubkey warning for recipient"); +like($content, qr/KO-nokey \(no pubkey!\)-K/, "KeyOwnerName issues no-pubkey warning for root"); +like($content, qr/KO-Nobody \(no pubkey!\)-K/, "KeyOwnerName issues no-pubkey warning for nobody"); + +like($content, qr/KR-recipient\@example.com-K/, "KeyRequestors does not issue no-pubkey warning for recipient\@example.com"); +like($content, qr/KR-general\@example.com-K/, "KeyRequestors does not issue no-pubkey warning for general\@example.com"); +like($content, qr/KR-nokey\@example.com \(no pubkey!\)-K/, "KeyRequestors DOES issue no-pubkey warning for nokey\@example.com"); + diff --git a/rt/t/web/custom_frontpage.t b/rt/t/web/custom_frontpage.t new file mode 100644 index 000000000..45a390ab0 --- /dev/null +++ b/rt/t/web/custom_frontpage.t @@ -0,0 +1,61 @@ +#!/usr/bin/perl -w +use strict; + +use RT::Test tests => 7; +my ($baseurl, $m) = RT::Test->started_ok; + +my $url = $m->rt_base_url; + +my $user_obj = RT::User->new($RT::SystemUser); +my ($ret, $msg) = $user_obj->LoadOrCreateByEmail('customer@example.com'); +ok($ret, 'ACL test user creation'); +$user_obj->SetName('customer'); +$user_obj->SetPrivileged(1); +($ret, $msg) = $user_obj->SetPassword('customer'); +$user_obj->PrincipalObj->GrantRight(Right => 'LoadSavedSearch'); +$user_obj->PrincipalObj->GrantRight(Right => 'EditSavedSearch'); +$user_obj->PrincipalObj->GrantRight(Right => 'CreateSavedSearch'); +$user_obj->PrincipalObj->GrantRight(Right => 'ModifySelf'); + +ok $m->login( customer => 'customer' ), "logged in"; + +$m->get ( $url."Search/Build.html"); + +#create a saved search +$m->form_name ('BuildQuery'); + +$m->field ( "ValueOfAttachment" => 'stupid'); +$m->field ( "SavedSearchDescription" => 'stupid tickets'); +$m->click_button (name => 'SavedSearchSave'); + +$m->get ( $url.'Prefs/MyRT.html' ); +$m->content_like (qr/stupid tickets/, 'saved search listed in rt at a glance items'); + +ok $m->login, 'we did log in as root'; + +$m->get ( $url.'Prefs/MyRT.html' ); +$m->form_name ('SelectionBox-body'); +# can't use submit form for mutli-valued select as it uses set_fields +$m->field ('body-Selected' => ['component-QuickCreate', 'system-Unowned Tickets', 'system-My Tickets']); +$m->click_button (name => 'remove'); +$m->form_name ('SelectionBox-body'); +#$m->click_button (name => 'body-Save'); +$m->get ( $url ); +$m->content_lacks ('highest priority tickets', 'remove everything from body pane'); + +$m->get ( $url.'Prefs/MyRT.html' ); +$m->form_name ('SelectionBox-body'); +$m->field ('body-Available' => ['component-QuickCreate', 'system-Unowned Tickets', 'system-My Tickets']); +$m->click_button (name => 'add'); + +$m->form_name ('SelectionBox-body'); +$m->field ('body-Selected' => ['component-QuickCreate']); +$m->click_button (name => 'movedown'); + +$m->form_name ('SelectionBox-body'); +$m->click_button (name => 'movedown'); + +$m->form_name ('SelectionBox-body'); +#$m->click_button (name => 'body-Save'); +$m->get ( $url ); +$m->content_like (qr'highest priority tickets', 'adds them back'); diff --git a/rt/t/web/custom_search.t b/rt/t/web/custom_search.t new file mode 100644 index 000000000..05cfdab60 --- /dev/null +++ b/rt/t/web/custom_search.t @@ -0,0 +1,84 @@ +#!/usr/bin/perl -w +use strict; + +use RT::Test tests => 11; +my ($baseurl, $m) = RT::Test->started_ok; +my $url = $m->rt_base_url; + +# reset preferences for easier test? + + + +my $t = RT::Ticket->new($RT::SystemUser); +$t->Create(Subject => 'for custom search'.$$, Queue => 'general', + Owner => 'root', Requestor => 'customsearch@localhost'); +ok(my $id = $t->id, 'created ticket for custom search'); + +ok $m->login, 'logged in'; + +my $t_link = $m->find_link( text => "for custom search".$$ ); +like ($t_link->url, qr/$id/, 'link to the ticket we created'); + +$m->content_lacks ('customsearch@localhost', 'requestor not displayed '); +$m->get ( $url.'Prefs/MyRT.html' ); +my $cus_hp = $m->find_link( text => "My Tickets" ); +my $cus_qs = $m->find_link( text => "Quick search" ); +$m->get ($cus_hp); +$m->content_like (qr'highest priority tickets'); + +# add Requestor to the fields +$m->form_name ('BuildQuery'); +# can't use submit form for mutli-valued select as it uses set_fields +$m->field (SelectDisplayColumns => ['Requestors']); +$m->click_button (name => 'AddCol') ; + +$m->form_name ('BuildQuery'); +$m->click_button (name => 'Save'); + +$m->get( $url ); +$m->content_contains ('customsearch@localhost', 'requestor now displayed '); + + +# now remove Requestor from the fields +$m->get ($cus_hp); + +$m->form_name ('BuildQuery'); + +my $cdc = $m->current_form->find_input('CurrentDisplayColumns'); +my ($requestor_value) = grep { /Requestor/ } $cdc->possible_values; +ok($requestor_value, "got the requestor value"); + +$m->field (CurrentDisplayColumns => $requestor_value); +$m->click_button (name => 'RemoveCol') ; + +$m->form_name ('BuildQuery'); +$m->click_button (name => 'Save'); + +$m->get( $url ); +$m->content_lacks ('customsearch@localhost', 'requestor not displayed '); + + +# try to disable General from quick search + +# Note that there's a small problem in the current implementation, +# since ticked quese are wanted, we do the invesrsion. So any +# queue added during the quicksearch setting will be unticked. +my $nlinks = $#{$m->find_all_links( text => "General" )}; +$m->get ($cus_qs); +$m->form_name ('Preferences'); +$m->untick('Want-General', '1'); +$m->click_button (name => 'Save'); + +$m->get( $url ); +is ($#{$m->find_all_links( text => "General" )}, $nlinks - 1, + 'General gone from quicksearch list'); + +# get it back +$m->get ($cus_qs); +$m->form_name ('Preferences'); +$m->tick('Want-General', '1'); +$m->click_button (name => 'Save'); + +$m->get( $url ); +is ($#{$m->find_all_links( text => "General" )}, $nlinks, + 'General back in quicksearch list'); diff --git a/rt/t/web/dashboard_with_deleted_saved_search.t b/rt/t/web/dashboard_with_deleted_saved_search.t new file mode 100644 index 000000000..328095aaf --- /dev/null +++ b/rt/t/web/dashboard_with_deleted_saved_search.t @@ -0,0 +1,89 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use RT::Test tests => 18; +my ( $url, $m ) = RT::Test->started_ok; +ok( $m->login, 'logged in' ); + +# create a saved search +$m->get_ok( $url . "/Search/Build.html?Query=" . 'id=1' ); + +$m->submit_form( + form_name => 'BuildQuery', + fields => { SavedSearchDescription => 'foo', }, + button => 'SavedSearchSave', +); + +my ( $search_uri, $user_id, $search_id ) = + $m->content =~ /value="(RT::User-(\d+)-SavedSearch-(\d+))"/; +$m->submit_form( + form_name => 'BuildQuery', + fields => { SavedSearchLoad => $search_uri }, + button => 'SavedSearchSave', +); + +$m->content_like( qr/name="SavedSearchDelete"\s+value="Delete"/, + 'found Delete button' ); +$m->content_like( + qr/name="SavedSearchDescription"\s+value="foo"/, + 'found Description input with the value filled' +); + +# create a dashboard with the created search + +$m->get_ok( $url . "/Dashboards/Modify.html?Create=1" ); +$m->submit_form( + form_name => 'ModifyDashboard', + fields => { Name => 'bar' }, +); + +$m->content_like( qr/Saved dashboard bar/i, 'dashboard saved' ); +my $dashboard_queries_link = $m->find_link( text_regex => qr/Queries/ ); +my ( $dashboard_id ) = $dashboard_queries_link->url =~ /id=(\d+)/; + +$m->get_ok( $url . "/Dashboards/Queries.html?id=$dashboard_id" ); + +$m->content_lacks( 'value="Update"', 'no update button' ); + +$m->submit_form( + form_name => 'Dashboard-Searches-body', + fields => + { 'Searches-body-Available' => "search-$search_id-RT::User-$user_id" }, + button => 'add', +); + +$m->content_like( qr/Dashboard updated/i, 'added search foo to dashboard bar' ); + +# delete the created search + +$m->get_ok( $url . "/Search/Build.html?Query=" . 'id=1' ); +$m->submit_form( + form_name => 'BuildQuery', + fields => { SavedSearchLoad => $search_uri }, +); +$m->submit_form( + form_name => 'BuildQuery', + button => 'SavedSearchDelete', +); + +$m->content_lacks( $search_uri, 'deleted search foo' ); + +# here is what we really want to test + +$m->get_ok( $url . "/Dashboards/Queries.html?id=$dashboard_id" ); +$m->content_like( qr/Deleted queries/i, 'found deleted message' ); + +# Update button shows so we can update the deleted search easily +$m->content_contains( 'value="Update"', 'found update button' ); + +$m->submit_form( + form_name => 'Dashboard-Searches-body', + button => 'update', +); + +$m->content_unlike( qr/Deleted queries/i, 'deleted message is gone' ); +$m->content_lacks( 'value="Update"', 'update button is gone too' ); + +$m->get_warnings; # we'll get a lot of warnings because the deleted search + diff --git a/rt/t/web/dashboards-groups.t b/rt/t/web/dashboards-groups.t new file mode 100644 index 000000000..cbf1d6a9f --- /dev/null +++ b/rt/t/web/dashboards-groups.t @@ -0,0 +1,102 @@ +#!/usr/bin/perl -w +use strict; + +use RT::Test tests => 40; +my ($baseurl, $m) = RT::Test->started_ok; + +my $url = $m->rt_base_url; + +# create user and queue {{{ +my $user_obj = RT::User->new($RT::SystemUser); +my ($ok, $msg) = $user_obj->LoadOrCreateByEmail('customer@example.com'); +ok($ok, 'ACL test user creation'); +$user_obj->SetName('customer'); +$user_obj->SetPrivileged(1); +($ok, $msg) = $user_obj->SetPassword('customer'); +$user_obj->PrincipalObj->GrantRight(Right => 'ModifySelf'); +my $currentuser = RT::CurrentUser->new($user_obj); + +my $queue = RT::Queue->new($RT::SystemUser); +$queue->Create(Name => 'SearchQueue'.$$); + +$user_obj->PrincipalObj->GrantRight(Right => $_, Object => $queue) + for qw/SeeQueue ShowTicket OwnTicket/; + +# grant the user all these rights so we can make sure that the group rights +# are checked and not these as well +$user_obj->PrincipalObj->GrantRight(Right => $_, Object => $RT::System) + for qw/SubscribeDashboard CreateOwnDashboard SeeOwnDashboard ModifyOwnDashboard DeleteOwnDashboard/; +# }}} +# create and test groups (outer < inner < user) {{{ +my $inner_group = RT::Group->new($RT::SystemUser); +($ok, $msg) = $inner_group->CreateUserDefinedGroup(Name => "inner", Description => "inner group"); +ok($ok, "created inner group: $msg"); + +my $outer_group = RT::Group->new($RT::SystemUser); +($ok, $msg) = $outer_group->CreateUserDefinedGroup(Name => "outer", Description => "outer group"); +ok($ok, "created outer group: $msg"); + +($ok, $msg) = $outer_group->AddMember($inner_group->PrincipalId); +ok($ok, "added inner as a member of outer: $msg"); + +($ok, $msg) = $inner_group->AddMember($user_obj->PrincipalId); +ok($ok, "added user as a member of member: $msg"); + +ok($outer_group->HasMember($inner_group->PrincipalId), "outer has inner"); +ok(!$outer_group->HasMember($user_obj->PrincipalId), "outer doesn't have user directly"); +ok($outer_group->HasMemberRecursively($inner_group->PrincipalId), "outer has inner recursively"); +ok($outer_group->HasMemberRecursively($user_obj->PrincipalId), "outer has user recursively"); + +ok(!$inner_group->HasMember($outer_group->PrincipalId), "inner doesn't have outer"); +ok($inner_group->HasMember($user_obj->PrincipalId), "inner has user"); +ok(!$inner_group->HasMemberRecursively($outer_group->PrincipalId), "inner doesn't have outer, even recursively"); +ok($inner_group->HasMemberRecursively($user_obj->PrincipalId), "inner has user recursively"); +# }}} + +ok $m->login(customer => 'customer'), "logged in"; + +$m->get_ok("$url/Dashboards"); + +$m->follow_link_ok({text => "New"}); +$m->form_name('ModifyDashboard'); +is_deeply([$m->current_form->find_input('Privacy')->possible_values], ["RT::User-" . $user_obj->Id], "the only selectable privacy is user"); +$m->content_lacks('Delete', "Delete button hidden because we are creating"); + +$user_obj->PrincipalObj->GrantRight(Right => 'CreateGroupDashboard', Object => $inner_group); + +$m->follow_link_ok({text => "New"}); +$m->form_name('ModifyDashboard'); +is_deeply([$m->current_form->find_input('Privacy')->possible_values], ["RT::User-" . $user_obj->Id, "RT::Group-" . $inner_group->Id], "the only selectable privacies are user and inner group (not outer group)"); +$m->field("Name" => 'inner dashboard'); +$m->field("Privacy" => "RT::Group-" . $inner_group->Id); +$m->content_lacks('Delete', "Delete button hidden because we are creating"); + +$m->click_button(value => 'Create'); +$m->content_lacks("No permission to create dashboards"); +$m->content_contains("Saved dashboard inner dashboard"); +$m->content_lacks('Delete', "Delete button hidden because we lack DeleteDashboard"); + +my $dashboard = RT::Dashboard->new($currentuser); +my ($id) = $m->content =~ /name="id" value="(\d+)"/; +ok($id, "got an ID, $id"); +$dashboard->LoadById($id); +is($dashboard->Name, "inner dashboard"); + +is($dashboard->Privacy, 'RT::Group-' . $inner_group->Id, "correct privacy"); +is($dashboard->PossibleHiddenSearches, 0, "all searches are visible"); + +$m->no_warnings_ok; + +$m->get_ok("/Dashboards/Modify.html?id=$id"); +$m->content_lacks("inner dashboard", "no SeeGroupDashboard right"); +$m->content_contains("Permission denied"); + +$m->warning_like(qr/Permission denied/, "got a permission denied warning"); + +$user_obj->PrincipalObj->GrantRight(Right => 'SeeGroupDashboard', Object => $inner_group); +$m->get_ok("/Dashboards/Modify.html?id=$id"); +$m->content_contains("inner dashboard", "we now have SeeGroupDashboard right"); +$m->content_lacks("Permission denied"); + +$m->content_contains('Subscription', "Subscription link not hidden because we have SubscribeDashboard"); + diff --git a/rt/t/web/dashboards-permissions.t b/rt/t/web/dashboards-permissions.t new file mode 100644 index 000000000..172404289 --- /dev/null +++ b/rt/t/web/dashboards-permissions.t @@ -0,0 +1,38 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use RT::Test tests => 7; +my ($baseurl, $m) = RT::Test->started_ok; + +my $url = $m->rt_base_url; + +# create user and queue {{{ +my $user_obj = RT::User->new($RT::SystemUser); +my ($ok, $msg) = $user_obj->LoadOrCreateByEmail('customer@example.com'); +ok($ok, 'ACL test user creation'); +$user_obj->SetName('customer'); +$user_obj->SetPrivileged(1); +($ok, $msg) = $user_obj->SetPassword('customer'); +$user_obj->PrincipalObj->GrantRight(Right => 'ModifySelf'); +my $currentuser = RT::CurrentUser->new($user_obj); + +my $queue = RT::Queue->new($RT::SystemUser); +$queue->Create(Name => 'SearchQueue'.$$); + +$user_obj->PrincipalObj->GrantRight(Right => $_, Object => $queue) + for qw/SeeQueue ShowTicket OwnTicket/; + +$user_obj->PrincipalObj->GrantRight(Right => $_, Object => $RT::System) + for qw/SubscribeDashboard CreateOwnDashboard SeeOwnDashboard ModifyOwnDashboard DeleteOwnDashboard/; +# }}} + +ok $m->login(customer => 'customer'), "logged in"; + +$m->get_ok("$url/Dashboards"); + +$m->follow_link_ok({text => "New"}); +$m->form_name('ModifyDashboard'); +is_deeply([$m->current_form->find_input('Privacy')->possible_values], ["RT::User-" . $user_obj->Id], "the only selectable privacy is user"); +$m->content_lacks('Delete', "Delete button hidden because we are creating"); + diff --git a/rt/t/web/dashboards.t b/rt/t/web/dashboards.t new file mode 100644 index 000000000..9d98ce6e4 --- /dev/null +++ b/rt/t/web/dashboards.t @@ -0,0 +1,250 @@ +#!/usr/bin/perl -w +use strict; + +use RT::Test tests => 109; +my ($baseurl, $m) = RT::Test->started_ok; + +my $url = $m->rt_base_url; + +my $user_obj = RT::User->new($RT::SystemUser); +my ($ret, $msg) = $user_obj->LoadOrCreateByEmail('customer@example.com'); +ok($ret, 'ACL test user creation'); +$user_obj->SetName('customer'); +$user_obj->SetPrivileged(1); +($ret, $msg) = $user_obj->SetPassword('customer'); +$user_obj->PrincipalObj->GrantRight(Right => 'ModifySelf'); +my $currentuser = RT::CurrentUser->new($user_obj); + +my $onlooker = RT::User->new($RT::SystemUser); +($ret, $msg) = $onlooker->LoadOrCreateByEmail('onlooker@example.com'); +ok($ret, 'ACL test user creation'); +$onlooker->SetName('onlooker'); +$onlooker->SetPrivileged(1); +($ret, $msg) = $onlooker->SetPassword('onlooker'); + +my $queue = RT::Queue->new($RT::SystemUser); +$queue->Create(Name => 'SearchQueue'.$$); + +for my $user ($user_obj, $onlooker) { + $user->PrincipalObj->GrantRight(Right => 'ModifySelf'); + for my $right (qw/SeeQueue ShowTicket OwnTicket/) { + $user->PrincipalObj->GrantRight(Right => $right, Object => $queue); + } +} + +ok $m->login(customer => 'customer'), "logged in"; + +$m->get_ok($url."Dashboards/index.html"); +$m->content_lacks('<a href="/Dashboards/Modify.html?Create=1">New</a>', + "No 'new dashboard' link because we have no CreateOwnDashboard"); + +$m->no_warnings_ok; + +$m->get_ok($url."Dashboards/Modify.html?Create=1"); +$m->content_contains("Permission denied"); +$m->content_lacks("Save Changes"); + +$m->warning_like(qr/Permission denied/, "got a permission denied warning"); + +$user_obj->PrincipalObj->GrantRight(Right => 'ModifyOwnDashboard', Object => $RT::System); + +# Modify itself is no longer good enough, you need Create +$m->get_ok($url."Dashboards/Modify.html?Create=1"); +$m->content_contains("Permission denied"); +$m->content_lacks("Save Changes"); + +$m->warning_like(qr/Permission denied/, "got a permission denied warning"); + +$user_obj->PrincipalObj->GrantRight(Right => 'CreateOwnDashboard', Object => $RT::System); + +$m->get_ok($url."Dashboards/Modify.html?Create=1"); +$m->content_lacks("Permission denied"); +$m->content_contains("Create"); + +$m->get_ok($url."Dashboards/index.html"); +$m->content_contains("New", "'New' link because we now have ModifyOwnDashboard"); + +$m->follow_link_ok({text => "New"}); +$m->form_name('ModifyDashboard'); +$m->field("Name" => 'different dashboard'); +$m->content_lacks('Delete', "Delete button hidden because we are creating"); +$m->click_button(value => 'Create'); +$m->content_lacks("No permission to create dashboards"); +$m->content_contains("Saved dashboard different dashboard"); +$m->content_lacks('Delete', "Delete button hidden because we lack DeleteOwnDashboard"); + +$m->get_ok($url."Dashboards/index.html"); +$m->content_lacks("different dashboard", "we lack SeeOwnDashboard"); + +$user_obj->PrincipalObj->GrantRight(Right => 'SeeOwnDashboard', Object => $RT::System); + +$m->get_ok($url."Dashboards/index.html"); +$m->content_contains("different dashboard", "we now have SeeOwnDashboard"); +$m->content_lacks("Permission denied"); + +$m->follow_link_ok({text => "different dashboard"}); +$m->content_contains("Basics"); +$m->content_contains("Queries"); +$m->content_lacks("Subscription", "we don't have the SubscribeDashboard right"); + +$m->follow_link_ok({text => "Basics"}); +$m->content_contains("Modify the dashboard different dashboard"); + +$m->follow_link_ok({text => "Queries"}); +$m->content_contains("Modify the queries of dashboard different dashboard"); +$m->form_name('Dashboard-Searches-body'); +$m->field('Searches-body-Available' => ["search-2-RT::System-1"]); +$m->click_button(name => 'add'); +$m->content_contains("Dashboard updated"); + +my $dashboard = RT::Dashboard->new($currentuser); +my ($id) = $m->content =~ /name="id" value="(\d+)"/; +ok($id, "got an ID, $id"); +$dashboard->LoadById($id); +is($dashboard->Name, "different dashboard"); + +is($dashboard->Privacy, 'RT::User-' . $user_obj->Id, "correct privacy"); +is($dashboard->PossibleHiddenSearches, 0, "all searches are visible"); + +my @searches = $dashboard->Searches; +is(@searches, 1, "one saved search in the dashboard"); +like($searches[0]->Name, qr/newest unowned tickets/, "correct search name"); + +$m->form_name('Dashboard-Searches-body'); +$m->field('Searches-body-Available' => ["search-1-RT::System-1"]); +$m->click_button(name => 'add'); +$m->content_contains("Dashboard updated"); + +RT::Record->FlushCache if RT::Record->can('FlushCache'); +$dashboard = RT::Dashboard->new($currentuser); +$dashboard->LoadById($id); + +@searches = $dashboard->Searches; +is(@searches, 2, "two saved searches in the dashboard"); +like($searches[0]->Name, qr/newest unowned tickets/, "correct existing search name"); +like($searches[1]->Name, qr/highest priority tickets I own/, "correct new search name"); + +my $ticket = RT::Ticket->new($RT::SystemUser); +$ticket->Create( + Queue => $queue->Id, + Requestor => [ $user_obj->Name ], + Owner => $user_obj, + Subject => 'dashboard test', +); + +$m->follow_link_ok({text => 'different dashboard'}); +$m->content_contains("20 highest priority tickets I own"); +$m->content_contains("20 newest unowned tickets"); +$m->content_lacks("Bookmarked Tickets"); +$m->content_contains("dashboard test", "ticket subject"); + +$m->get_ok("/Dashboards/$id/This fragment left intentionally blank"); +$m->content_contains("20 highest priority tickets I own"); +$m->content_contains("20 newest unowned tickets"); +$m->content_lacks("Bookmarked Tickets"); +$m->content_contains("dashboard test", "ticket subject"); + +$m->get_ok("/Dashboards/Subscription.html?DashboardId=$id"); +$m->form_name('SubscribeDashboard'); +$m->click_button(name => 'Save'); +$m->content_contains("Permission denied"); +$m->warning_like(qr/Unable to subscribe to dashboard.*Permission denied/, "got a permission denied warning when trying to subscribe to a dashboard"); + +RT::Record->FlushCache if RT::Record->can('FlushCache'); +is($user_obj->Attributes->Named('Subscription'), 0, "no subscriptions"); + +$user_obj->PrincipalObj->GrantRight(Right => 'SubscribeDashboard', Object => $RT::System); + +$m->get_ok("/Dashboards/Modify.html?id=$id"); +$m->follow_link_ok({text => "Subscription"}); +$m->content_contains("Subscribe to dashboard different dashboard"); +$m->content_contains("Unowned Tickets"); +$m->content_contains("My Tickets"); +$m->content_lacks("Bookmarked Tickets", "only dashboard queries show up"); + +$m->form_name('SubscribeDashboard'); +$m->click_button(name => 'Save'); +$m->content_lacks("Permission denied"); +$m->content_contains("Subscribed to dashboard different dashboard"); + +RT::Record->FlushCache if RT::Record->can('FlushCache'); +TODO: { + local $TODO = "some kind of caching is still happening (it works if I remove the check above)"; + is($user_obj->Attributes->Named('Subscription'), 1, "we have a subscription"); +}; + +$m->get_ok("/Dashboards/Modify.html?id=$id"); +$m->follow_link_ok({text => "Subscription"}); +$m->content_contains("Modify the subscription to dashboard different dashboard"); + +$m->get_ok("/Dashboards/Modify.html?id=$id&Delete=1"); +$m->content_contains("Permission denied", "unable to delete dashboard because we lack DeleteOwnDashboard"); + +$m->warning_like(qr/Couldn't delete dashboard.*Permission denied/, "got a permission denied warning when trying to delete the dashboard"); + +$user_obj->PrincipalObj->GrantRight(Right => 'DeleteOwnDashboard', Object => $RT::System); + +$m->get_ok("/Dashboards/Modify.html?id=$id"); +$m->content_contains('Delete', "Delete button shows because we have DeleteOwnDashboard"); + +$m->form_name('ModifyDashboard'); +$m->click_button(name => 'Delete'); +$m->content_contains("Deleted dashboard $id"); + +$m->get("/Dashboards/Modify.html?id=$id"); +$m->content_lacks("different dashboard", "dashboard was deleted"); +$m->content_contains("Failed to load dashboard $id"); + +$m->warning_like(qr/Failed to load dashboard.*Couldn't find row/, "the dashboard was deleted"); + +$user_obj->PrincipalObj->GrantRight(Right => "SuperUser", Object => $RT::System); + +# now test that we warn about searches others can't see +# first create a personal saved search... +$m->get_ok($url."Search/Build.html"); +$m->follow_link_ok({text => 'Advanced'}); +$m->form_with_fields('Query'); +$m->field(Query => "id > 0"); +$m->submit; + +$m->form_with_fields('SavedSearchDescription'); +$m->field(SavedSearchDescription => "personal search"); +$m->click_button(name => "SavedSearchSave"); + +# then the system-wide dashboard +$m->get_ok($url."Dashboards/Modify.html?Create=1"); + +$m->form_name('ModifyDashboard'); +$m->field("Name" => 'system dashboard'); +$m->field("Privacy" => 'RT::System-1'); +$m->content_lacks('Delete', "Delete button hidden because we are creating"); +$m->click_button(value => 'Create'); +$m->content_lacks("No permission to create dashboards"); +$m->content_contains("Saved dashboard system dashboard"); + +$m->follow_link_ok({text => 'Queries'}); + +$m->form_name('Dashboard-Searches-body'); +$m->field('Searches-body-Available' => ['search-7-RT::User-22']); # XXX: :( :( +$m->click_button(name => 'add'); +$m->content_contains("Dashboard updated"); + +$m->content_contains("The following queries may not be visible to all users who can see this dashboard."); + +$m->follow_link_ok({text => 'system dashboard'}); +$m->content_contains("personal search", "saved search shows up"); +$m->content_contains("dashboard test", "matched ticket shows up"); + +# make sure the onlooker can't see the search... +$onlooker->PrincipalObj->GrantRight(Right => 'SeeDashboard', Object => $RT::System); + +my $omech = RT::Test::Web->new; +ok $omech->login(onlooker => 'onlooker'), "logged in"; +$omech->get_ok("/Dashboards"); + +$omech->follow_link_ok({text => 'system dashboard'}); +$omech->content_lacks("personal search", "saved search doesn't show up"); +$omech->content_lacks("dashboard test", "matched ticket doesn't show up"); + +$m->warning_like(qr/User .* tried to load container user /, "can't see other users' personal searches"); + diff --git a/rt/t/web/gnupg-outgoing.t b/rt/t/web/gnupg-outgoing.t new file mode 100644 index 000000000..a46833c6c --- /dev/null +++ b/rt/t/web/gnupg-outgoing.t @@ -0,0 +1,363 @@ +#!/usr/bin/perl -w +use strict; +use warnings; + +use RT::Test tests => 492; + +plan skip_all => 'GnuPG required.' + unless eval 'use GnuPG::Interface; 1'; +plan skip_all => 'gpg executable is required.' + unless RT::Test->find_executable('gpg'); + + +use RT::Action::SendEmail; +use File::Temp qw(tempdir); + +RT::Test->set_mail_catcher; + +use_ok('RT::Crypt::GnuPG'); + +RT->Config->Set( GnuPG => + Enable => 1, + OutgoingMessagesFormat => 'RFC', +); + +RT->Config->Set( GnuPGOptions => + homedir => scalar tempdir( CLEANUP => 1 ), + passphrase => 'rt-test', + 'no-permission-warning' => undef, + 'trust-model' => 'always', +); +RT->Config->Set( 'MailPlugins' => 'Auth::MailFrom', 'Auth::GnuPG' ); + +RT::Test->import_gnupg_key('rt-recipient@example.com'); +RT::Test->import_gnupg_key('rt-test@example.com', 'public'); + +my $queue = RT::Test->load_or_create_queue( + Name => 'Regression', + CorrespondAddress => 'rt-recipient@example.com', + CommentAddress => 'rt-recipient@example.com', +); +ok $queue && $queue->id, 'loaded or created queue'; + +RT::Test->set_rights( + Principal => 'Everyone', + Right => ['CreateTicket', 'ShowTicket', 'SeeQueue', 'ReplyToTicket', 'ModifyTicket'], +); + +my ($baseurl, $m) = RT::Test->started_ok; +ok $m->login, 'logged in'; + +my @variants = ( + {}, + { Sign => 1 }, + { Encrypt => 1 }, + { Sign => 1, Encrypt => 1 }, +); + +# collect emails +my %mail = ( + plain => [], + signed => [], + encrypted => [], + signed_encrypted => [], +); + +diag "check in read-only mode that queue's props influence create/update ticket pages" if $ENV{TEST_VERBOSE}; +{ + foreach my $variant ( @variants ) { + set_queue_crypt_options( %$variant ); + $m->goto_create_ticket( $queue ); + $m->form_name('TicketCreate'); + if ( $variant->{'Encrypt'} ) { + ok $m->value('Encrypt', 2), "encrypt tick box is checked"; + } else { + ok !$m->value('Encrypt', 2), "encrypt tick box is unchecked"; + } + if ( $variant->{'Sign'} ) { + ok $m->value('Sign', 2), "sign tick box is checked"; + } else { + ok !$m->value('Sign', 2), "sign tick box is unchecked"; + } + } + + # to avoid encryption/signing during create + set_queue_crypt_options(); + + my $ticket = RT::Ticket->new( $RT::SystemUser ); + my ($id) = $ticket->Create( + Subject => 'test', + Queue => $queue->id, + Requestor => 'rt-test@example.com', + ); + ok $id, 'ticket created'; + + foreach my $variant ( @variants ) { + set_queue_crypt_options( %$variant ); + $m->goto_ticket( $id ); + $m->follow_link_ok({text => 'Reply'}, '-> reply'); + $m->form_number(3); + if ( $variant->{'Encrypt'} ) { + ok $m->value('Encrypt', 2), "encrypt tick box is checked"; + } else { + ok !$m->value('Encrypt', 2), "encrypt tick box is unchecked"; + } + if ( $variant->{'Sign'} ) { + ok $m->value('Sign', 2), "sign tick box is checked"; + } else { + ok !$m->value('Sign', 2), "sign tick box is unchecked"; + } + } +} + +# create a ticket for each combination +foreach my $queue_set ( @variants ) { + set_queue_crypt_options( %$queue_set ); + foreach my $ticket_set ( @variants ) { + create_a_ticket( %$ticket_set ); + } +} + +my $tid; +{ + my $ticket = RT::Ticket->new( $RT::SystemUser ); + ($tid) = $ticket->Create( + Subject => 'test', + Queue => $queue->id, + Requestor => 'rt-test@example.com', + ); + ok $tid, 'ticket created'; +} + +# again for each combination add a reply message +foreach my $queue_set ( @variants ) { + set_queue_crypt_options( %$queue_set ); + foreach my $ticket_set ( @variants ) { + update_ticket( $tid, %$ticket_set ); + } +} + + +# ------------------------------------------------------------------------------ +# now delete all keys from the keyring and put back secret/pub pair for rt-test@ +# and only public key for rt-recipient@ so we can verify signatures and decrypt +# like we are on another side recieve emails +# ------------------------------------------------------------------------------ + +unlink $_ foreach glob( RT->Config->Get('GnuPGOptions')->{'homedir'} ."/*" ); +RT::Test->import_gnupg_key('rt-recipient@example.com', 'public'); +RT::Test->import_gnupg_key('rt-test@example.com'); + +$queue = RT::Test->load_or_create_queue( + Name => 'Regression', + CorrespondAddress => 'rt-test@example.com', + CommentAddress => 'rt-test@example.com', +); +ok $queue && $queue->id, 'changed props of the queue'; + +foreach my $mail ( map cleanup_headers($_), @{ $mail{'plain'} } ) { + my ($status, $id) = RT::Test->send_via_mailgate($mail); + is ($status >> 8, 0, "The mail gateway exited normally"); + ok ($id, "got id of a newly created ticket - $id"); + + my $tick = RT::Ticket->new( $RT::SystemUser ); + $tick->Load( $id ); + ok ($tick->id, "loaded ticket #$id"); + + my $txn = $tick->Transactions->First; + my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef}; + + ok !$msg->GetHeader('X-RT-Privacy'), "RT's outgoing mail has no crypto"; + is $msg->GetHeader('X-RT-Incoming-Encryption'), 'Not encrypted', + "RT's outgoing mail looks not encrypted"; + ok !$msg->GetHeader('X-RT-Incoming-Signature'), + "RT's outgoing mail looks not signed"; + + like $msg->Content, qr/Some content/, "RT's mail includes copy of ticket text"; +} + +foreach my $mail ( map cleanup_headers($_), @{ $mail{'signed'} } ) { + my ($status, $id) = RT::Test->send_via_mailgate($mail); + is ($status >> 8, 0, "The mail gateway exited normally"); + ok ($id, "got id of a newly created ticket - $id"); + + my $tick = RT::Ticket->new( $RT::SystemUser ); + $tick->Load( $id ); + ok ($tick->id, "loaded ticket #$id"); + + my $txn = $tick->Transactions->First; + my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef}; + + is $msg->GetHeader('X-RT-Privacy'), 'PGP', + "RT's outgoing mail has crypto"; + is $msg->GetHeader('X-RT-Incoming-Encryption'), 'Not encrypted', + "RT's outgoing mail looks not encrypted"; + like $msg->GetHeader('X-RT-Incoming-Signature'), + qr/<rt-recipient\@example.com>/, + "RT's outgoing mail looks signed"; + + like $attachments[0]->Content, qr/Some content/, + "RT's mail includes copy of ticket text"; +} + +foreach my $mail ( map cleanup_headers($_), @{ $mail{'encrypted'} } ) { + my ($status, $id) = RT::Test->send_via_mailgate($mail); + is ($status >> 8, 0, "The mail gateway exited normally"); + ok ($id, "got id of a newly created ticket - $id"); + + my $tick = RT::Ticket->new( $RT::SystemUser ); + $tick->Load( $id ); + ok ($tick->id, "loaded ticket #$id"); + + my $txn = $tick->Transactions->First; + my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef}; + + is $msg->GetHeader('X-RT-Privacy'), 'PGP', + "RT's outgoing mail has crypto"; + is $msg->GetHeader('X-RT-Incoming-Encryption'), 'Success', + "RT's outgoing mail looks encrypted"; + ok !$msg->GetHeader('X-RT-Incoming-Signature'), + "RT's outgoing mail looks not signed"; + + like $attachments[0]->Content, qr/Some content/, + "RT's mail includes copy of ticket text"; +} + +foreach my $mail ( map cleanup_headers($_), @{ $mail{'signed_encrypted'} } ) { + my ($status, $id) = RT::Test->send_via_mailgate($mail); + is ($status >> 8, 0, "The mail gateway exited normally"); + ok ($id, "got id of a newly created ticket - $id"); + + my $tick = RT::Ticket->new( $RT::SystemUser ); + $tick->Load( $id ); + ok ($tick->id, "loaded ticket #$id"); + + my $txn = $tick->Transactions->First; + my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef}; + + is $msg->GetHeader('X-RT-Privacy'), 'PGP', + "RT's outgoing mail has crypto"; + is $msg->GetHeader('X-RT-Incoming-Encryption'), 'Success', + "RT's outgoing mail looks encrypted"; + like $msg->GetHeader('X-RT-Incoming-Signature'), + qr/<rt-recipient\@example.com>/, + "RT's outgoing mail looks signed"; + + like $attachments[0]->Content, qr/Some content/, + "RT's mail includes copy of ticket text"; +} + +sub create_a_ticket { + my %args = (@_); + + RT::Test->clean_caught_mails; + + $m->goto_create_ticket( $queue ); + $m->form_name('TicketCreate'); + $m->field( Subject => 'test' ); + $m->field( Requestors => 'rt-test@example.com' ); + $m->field( Content => 'Some content' ); + + foreach ( qw(Sign Encrypt) ) { + if ( $args{ $_ } ) { + $m->tick( $_ => 1 ); + } else { + $m->untick( $_ => 1 ); + } + } + + $m->submit; + is $m->status, 200, "request successful"; + + unlike($m->content, qr/unable to sign outgoing email messages/); + + $m->get_ok('/'); # ensure that the mail has been processed + + my @mail = RT::Test->fetch_caught_mails; + check_text_emails( \%args, @mail ); +} + +sub update_ticket { + my $tid = shift; + my %args = (@_); + + RT::Test->clean_caught_mails; + + ok $m->goto_ticket( $tid ), "UI -> ticket #$tid"; + $m->follow_link_ok( { text => 'Reply' }, 'ticket -> reply' ); + $m->form_number(3); + $m->field( UpdateContent => 'Some content' ); + + foreach ( qw(Sign Encrypt) ) { + if ( $args{ $_ } ) { + $m->tick( $_ => 1 ); + } else { + $m->untick( $_ => 1 ); + } + } + + $m->click('SubmitTicket'); + is $m->status, 200, "request successful"; + $m->content_like(qr/Message recorded/, 'Message recorded') or diag $m->content; + + $m->get_ok('/'); # ensure that the mail has been processed + + my @mail = RT::Test->fetch_caught_mails; + check_text_emails( \%args, @mail ); +} + +sub check_text_emails { + my %args = %{ shift @_ }; + my @mail = @_; + + ok scalar @mail, "got some mail"; + for my $mail (@mail) { + if ( $args{'Encrypt'} ) { + unlike $mail, qr/Some content/, "outgoing email was encrypted"; + } else { + like $mail, qr/Some content/, "outgoing email was not encrypted"; + } + if ( $args{'Sign'} && $args{'Encrypt'} ) { + like $mail, qr/BEGIN PGP MESSAGE/, 'outgoing email was signed'; + } elsif ( $args{'Sign'} ) { + like $mail, qr/SIGNATURE/, 'outgoing email was signed'; + } else { + unlike $mail, qr/SIGNATURE/, 'outgoing email was not signed'; + } + } + if ( $args{'Sign'} && $args{'Encrypt'} ) { + push @{ $mail{'signed_encrypted'} }, @mail; + } elsif ( $args{'Sign'} ) { + push @{ $mail{'signed'} }, @mail; + } elsif ( $args{'Encrypt'} ) { + push @{ $mail{'encrypted'} }, @mail; + } else { + push @{ $mail{'plain'} }, @mail; + } +} + +sub cleanup_headers { + my $mail = shift; + # strip id from subject to create new ticket + $mail =~ s/^(Subject:)\s*\[.*?\s+#\d+\]\s*/$1 /m; + # strip several headers + foreach my $field ( qw(Message-ID X-RT-Original-Encoding RT-Originator RT-Ticket X-RT-Loop-Prevention) ) { + $mail =~ s/^$field:.*?\n(?! |\t)//gmsi; + } + return $mail; +} + +sub set_queue_crypt_options { + my %args = @_; + $m->get_ok("/Admin/Queues/Modify.html?id=". $queue->id); + $m->form_with_fields('Sign', 'Encrypt'); + foreach my $opt ('Sign', 'Encrypt') { + if ( $args{$opt} ) { + $m->tick($opt => 1); + } else { + $m->untick($opt => 1); + } + } + $m->submit; +} + diff --git a/rt/t/web/gnupg-select-keys-on-create.t b/rt/t/web/gnupg-select-keys-on-create.t new file mode 100644 index 000000000..deee6b291 --- /dev/null +++ b/rt/t/web/gnupg-select-keys-on-create.t @@ -0,0 +1,325 @@ +#!/usr/bin/perl -w +use strict; +use warnings; + +use RT::Test tests => 60; + +plan skip_all => 'GnuPG required.' + unless eval 'use GnuPG::Interface; 1'; +plan skip_all => 'gpg executable is required.' + unless RT::Test->find_executable('gpg'); + + +use RT::Action::SendEmail; +use File::Temp qw(tempdir); + +RT::Test->set_mail_catcher; + +use_ok('RT::Crypt::GnuPG'); + +RT->Config->Set( GnuPG => + Enable => 1, + OutgoingMessagesFormat => 'RFC', +); + +RT->Config->Set( GnuPGOptions => + homedir => scalar tempdir( CLEANUP => 0 ), + passphrase => 'rt-test', + 'no-permission-warning' => undef, +); +diag "GnuPG --homedir ". RT->Config->Get('GnuPGOptions')->{'homedir'} if $ENV{TEST_VERBOSE}; + +RT->Config->Set( 'MailPlugins' => 'Auth::MailFrom', 'Auth::GnuPG' ); + +my $queue = RT::Test->load_or_create_queue( + Name => 'Regression', + CorrespondAddress => 'rt-recipient@example.com', + CommentAddress => 'rt-recipient@example.com', +); +ok $queue && $queue->id, 'loaded or created queue'; + +RT::Test->set_rights( + Principal => 'Everyone', + Right => ['CreateTicket', 'ShowTicket', 'SeeQueue', 'ReplyToTicket', 'ModifyTicket'], +); + +my ($baseurl, $m) = RT::Test->started_ok; +ok $m->login, 'logged in'; + +diag "check that signing doesn't work if there is no key" if $ENV{TEST_VERBOSE}; +{ + RT::Test->clean_caught_mails; + + ok $m->goto_create_ticket( $queue ), "UI -> create ticket"; + $m->form_number(3); + $m->tick( Sign => 1 ); + $m->field( Requestors => 'rt-test@example.com' ); + $m->field( Content => 'Some content' ); + $m->submit; + $m->content_like( + qr/unable to sign outgoing email messages/i, + 'problems with passphrase' + ); + + my @mail = RT::Test->fetch_caught_mails; + ok !@mail, 'there are no outgoing emails'; +} + +{ + RT::Test->import_gnupg_key('rt-recipient@example.com'); + RT::Test->trust_gnupg_key('rt-recipient@example.com'); + my %res = RT::Crypt::GnuPG::GetKeysInfo('rt-recipient@example.com'); + is $res{'info'}[0]{'TrustTerse'}, 'ultimate', 'ultimately trusted key'; +} + +diag "check that things don't work if there is no key" if $ENV{TEST_VERBOSE}; +{ + RT::Test->clean_caught_mails; + + ok $m->goto_create_ticket( $queue ), "UI -> create ticket"; + $m->form_number(3); + $m->tick( Encrypt => 1 ); + $m->field( Requestors => 'rt-test@example.com' ); + $m->field( Content => 'Some content' ); + $m->submit; + $m->content_like( + qr/You are going to encrypt outgoing email messages/i, + 'problems with keys' + ); + $m->content_like( + qr/There is no key suitable for encryption/i, + 'problems with keys' + ); + + my $form = $m->form_number(3); + ok !$form->find_input( 'UseKey-rt-test@example.com' ), 'no key selector'; + + my @mail = RT::Test->fetch_caught_mails; + ok !@mail, 'there are no outgoing emails'; +} + +diag "import first key of rt-test\@example.com" if $ENV{TEST_VERBOSE}; +my $fpr1 = ''; +{ + RT::Test->import_gnupg_key('rt-test@example.com', 'public'); + my %res = RT::Crypt::GnuPG::GetKeysInfo('rt-test@example.com'); + is $res{'info'}[0]{'TrustLevel'}, 0, 'is not trusted key'; + $fpr1 = $res{'info'}[0]{'Fingerprint'}; +} + +diag "check that things still doesn't work if key is not trusted" if $ENV{TEST_VERBOSE}; +{ + RT::Test->clean_caught_mails; + + ok $m->goto_create_ticket( $queue ), "UI -> create ticket"; + $m->form_number(3); + $m->tick( Encrypt => 1 ); + $m->field( Requestors => 'rt-test@example.com' ); + $m->field( Content => 'Some content' ); + $m->submit; + $m->content_like( + qr/You are going to encrypt outgoing email messages/i, + 'problems with keys' + ); + $m->content_like( + qr/There is one suitable key, but trust level is not set/i, + 'problems with keys' + ); + + my $form = $m->form_number(3); + ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector'; + is scalar $input->possible_values, 1, 'one option'; + + $m->select( 'UseKey-rt-test@example.com' => $fpr1 ); + $m->submit; + $m->content_like( + qr/You are going to encrypt outgoing email messages/i, + 'problems with keys' + ); + $m->content_like( + qr/Selected key either is not trusted/i, + 'problems with keys' + ); + + my @mail = RT::Test->fetch_caught_mails; + ok !@mail, 'there are no outgoing emails'; +} + +diag "import a second key of rt-test\@example.com" if $ENV{TEST_VERBOSE}; +my $fpr2 = ''; +{ + RT::Test->import_gnupg_key('rt-test@example.com.2', 'public'); + my %res = RT::Crypt::GnuPG::GetKeysInfo('rt-test@example.com'); + is $res{'info'}[1]{'TrustLevel'}, 0, 'is not trusted key'; + $fpr2 = $res{'info'}[2]{'Fingerprint'}; +} + +diag "check that things still doesn't work if two keys are not trusted" if $ENV{TEST_VERBOSE}; +{ + RT::Test->clean_caught_mails; + + ok $m->goto_create_ticket( $queue ), "UI -> create ticket"; + $m->form_number(3); + $m->tick( Encrypt => 1 ); + $m->field( Requestors => 'rt-test@example.com' ); + $m->field( Content => 'Some content' ); + $m->submit; + $m->content_like( + qr/You are going to encrypt outgoing email messages/i, + 'problems with keys' + ); + $m->content_like( + qr/There are several keys suitable for encryption/i, + 'problems with keys' + ); + + my $form = $m->form_number(3); + ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector'; + is scalar $input->possible_values, 2, 'two options'; + + $m->select( 'UseKey-rt-test@example.com' => $fpr1 ); + $m->submit; + $m->content_like( + qr/You are going to encrypt outgoing email messages/i, + 'problems with keys' + ); + $m->content_like( + qr/Selected key either is not trusted/i, + 'problems with keys' + ); + + my @mail = RT::Test->fetch_caught_mails; + ok !@mail, 'there are no outgoing emails'; +} + +{ + RT::Test->lsign_gnupg_key( $fpr1 ); + my %res = RT::Crypt::GnuPG::GetKeysInfo('rt-test@example.com'); + ok $res{'info'}[0]{'TrustLevel'} > 0, 'trusted key'; + is $res{'info'}[1]{'TrustLevel'}, 0, 'is not trusted key'; +} + +diag "check that we see key selector even if only one key is trusted but there are more keys"; +{ + RT::Test->clean_caught_mails; + + ok $m->goto_create_ticket( $queue ), "UI -> create ticket"; + $m->form_number(3); + $m->tick( Encrypt => 1 ); + $m->field( Requestors => 'rt-test@example.com' ); + $m->field( Content => 'Some content' ); + $m->submit; + $m->content_like( + qr/You are going to encrypt outgoing email messages/i, + 'problems with keys' + ); + $m->content_like( + qr/There are several keys suitable for encryption/i, + 'problems with keys' + ); + + my $form = $m->form_number(3); + ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector'; + is scalar $input->possible_values, 2, 'two options'; + + my @mail = RT::Test->fetch_caught_mails; + ok !@mail, 'there are no outgoing emails'; +} + +diag "check that key selector works and we can select trusted key"; +{ + RT::Test->clean_caught_mails; + + ok $m->goto_create_ticket( $queue ), "UI -> create ticket"; + $m->form_number(3); + $m->tick( Encrypt => 1 ); + $m->field( Requestors => 'rt-test@example.com' ); + $m->field( Content => 'Some content' ); + $m->submit; + $m->content_like( + qr/You are going to encrypt outgoing email messages/i, + 'problems with keys' + ); + $m->content_like( + qr/There are several keys suitable for encryption/i, + 'problems with keys' + ); + + my $form = $m->form_number(3); + ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector'; + is scalar $input->possible_values, 2, 'two options'; + + $m->select( 'UseKey-rt-test@example.com' => $fpr1 ); + $m->submit; + $m->content_like( qr/Ticket \d+ created in queue/i, 'ticket created' ); + + my @mail = RT::Test->fetch_caught_mails; + ok @mail, 'there are some emails'; + check_text_emails( { Encrypt => 1 }, @mail ); +} + +diag "check encrypting of attachments"; +{ + RT::Test->clean_caught_mails; + + ok $m->goto_create_ticket( $queue ), "UI -> create ticket"; + $m->form_number(3); + $m->tick( Encrypt => 1 ); + $m->field( Requestors => 'rt-test@example.com' ); + $m->field( Content => 'Some content' ); + $m->field( Attach => $0 ); + $m->submit; + $m->content_like( + qr/You are going to encrypt outgoing email messages/i, + 'problems with keys' + ); + $m->content_like( + qr/There are several keys suitable for encryption/i, + 'problems with keys' + ); + + my $form = $m->form_number(3); + ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector'; + is scalar $input->possible_values, 2, 'two options'; + + $m->select( 'UseKey-rt-test@example.com' => $fpr1 ); + $m->submit; + $m->content_like( qr/Ticket \d+ created in queue/i, 'ticket created' ); + + my @mail = RT::Test->fetch_caught_mails; + ok @mail, 'there are some emails'; + check_text_emails( { Encrypt => 1, Attachment => 1 }, @mail ); +} + +sub check_text_emails { + my %args = %{ shift @_ }; + my @mail = @_; + + ok scalar @mail, "got some mail"; + for my $mail (@mail) { + for my $type ('email', 'attachment') { + next if $type eq 'attachment' && !$args{'Attachment'}; + + my $content = $type eq 'email' + ? "Some content" + : "Attachment content"; + + if ( $args{'Encrypt'} ) { + unlike $mail, qr/$content/, "outgoing $type was encrypted"; + } else { + like $mail, qr/$content/, "outgoing $type was not encrypted"; + } + + next unless $type eq 'email'; + + if ( $args{'Sign'} && $args{'Encrypt'} ) { + like $mail, qr/BEGIN PGP MESSAGE/, 'outgoing email was signed'; + } elsif ( $args{'Sign'} ) { + like $mail, qr/SIGNATURE/, 'outgoing email was signed'; + } else { + unlike $mail, qr/SIGNATURE/, 'outgoing email was not signed'; + } + } + } +} + diff --git a/rt/t/web/gnupg-select-keys-on-update.t b/rt/t/web/gnupg-select-keys-on-update.t new file mode 100644 index 000000000..76817ddf2 --- /dev/null +++ b/rt/t/web/gnupg-select-keys-on-update.t @@ -0,0 +1,344 @@ +#!/usr/bin/perl -w +use strict; +use warnings; + +use RT::Test tests => 68; + +plan skip_all => 'GnuPG required.' + unless eval 'use GnuPG::Interface; 1'; +plan skip_all => 'gpg executable is required.' + unless RT::Test->find_executable('gpg'); + + +use RT::Action::SendEmail; +use File::Temp qw(tempdir); + +RT::Test->set_mail_catcher; + +use_ok('RT::Crypt::GnuPG'); + +RT->Config->Set( GnuPG => + Enable => 1, + OutgoingMessagesFormat => 'RFC', +); + +RT->Config->Set( GnuPGOptions => + homedir => scalar tempdir( CLEANUP => 0 ), + passphrase => 'rt-test', + 'no-permission-warning' => undef, +); +diag "GnuPG --homedir ". RT->Config->Get('GnuPGOptions')->{'homedir'} if $ENV{TEST_VERBOSE}; + +RT->Config->Set( 'MailPlugins' => 'Auth::MailFrom', 'Auth::GnuPG' ); + +my $queue = RT::Test->load_or_create_queue( + Name => 'Regression', + CorrespondAddress => 'rt-recipient@example.com', + CommentAddress => 'rt-recipient@example.com', +); +ok $queue && $queue->id, 'loaded or created queue'; + +RT::Test->set_rights( + Principal => 'Everyone', + Right => ['CreateTicket', 'ShowTicket', 'SeeQueue', 'ReplyToTicket', 'ModifyTicket'], +); + +my ($baseurl, $m) = RT::Test->started_ok; +ok $m->login, 'logged in'; + + +my $tid; +{ + my $ticket = RT::Ticket->new( $RT::SystemUser ); + ($tid) = $ticket->Create( + Subject => 'test', + Queue => $queue->id, + ); + ok $tid, 'ticket created'; +} + +diag "check that signing doesn't work if there is no key" if $ENV{TEST_VERBOSE}; +{ + RT::Test->clean_caught_mails; + + ok $m->goto_ticket( $tid ), "UI -> ticket #$tid"; + $m->follow_link_ok( { text => 'Reply' }, 'ticket -> reply' ); + $m->form_number(3); + $m->tick( Sign => 1 ); + $m->field( UpdateCc => 'rt-test@example.com' ); + $m->field( UpdateContent => 'Some content' ); + $m->click('SubmitTicket'); + $m->content_like( + qr/unable to sign outgoing email messages/i, + 'problems with passphrase' + ); + + my @mail = RT::Test->fetch_caught_mails; + ok !@mail, 'there are no outgoing emails'; +} + +{ + RT::Test->import_gnupg_key('rt-recipient@example.com'); + RT::Test->trust_gnupg_key('rt-recipient@example.com'); + my %res = RT::Crypt::GnuPG::GetKeysInfo('rt-recipient@example.com'); + is $res{'info'}[0]{'TrustTerse'}, 'ultimate', 'ultimately trusted key'; +} + +diag "check that things don't work if there is no key" if $ENV{TEST_VERBOSE}; +{ + RT::Test->clean_caught_mails; + + ok $m->goto_ticket( $tid ), "UI -> ticket #$tid"; + $m->follow_link_ok( { text => 'Reply' }, 'ticket -> reply' ); + $m->form_number(3); + $m->tick( Encrypt => 1 ); + $m->field( UpdateCc => 'rt-test@example.com' ); + $m->field( UpdateContent => 'Some content' ); + $m->click('SubmitTicket'); + $m->content_like( + qr/You are going to encrypt outgoing email messages/i, + 'problems with keys' + ); + $m->content_like( + qr/There is no key suitable for encryption/i, + 'problems with keys' + ); + + my $form = $m->form_number(3); + ok !$form->find_input( 'UseKey-rt-test@example.com' ), 'no key selector'; + + my @mail = RT::Test->fetch_caught_mails; + ok !@mail, 'there are no outgoing emails'; +} + + +diag "import first key of rt-test\@example.com" if $ENV{TEST_VERBOSE}; +my $fpr1 = ''; +{ + RT::Test->import_gnupg_key('rt-test@example.com', 'public'); + my %res = RT::Crypt::GnuPG::GetKeysInfo('rt-test@example.com'); + is $res{'info'}[0]{'TrustLevel'}, 0, 'is not trusted key'; + $fpr1 = $res{'info'}[0]{'Fingerprint'}; +} + +diag "check that things still doesn't work if key is not trusted" if $ENV{TEST_VERBOSE}; +{ + RT::Test->clean_caught_mails; + + ok $m->goto_ticket( $tid ), "UI -> ticket #$tid"; + $m->follow_link_ok( { text => 'Reply' }, 'ticket -> reply' ); + $m->form_number(3); + $m->tick( Encrypt => 1 ); + $m->field( UpdateCc => 'rt-test@example.com' ); + $m->field( UpdateContent => 'Some content' ); + $m->click('SubmitTicket'); + $m->content_like( + qr/You are going to encrypt outgoing email messages/i, + 'problems with keys' + ); + $m->content_like( + qr/There is one suitable key, but trust level is not set/i, + 'problems with keys' + ); + + my $form = $m->form_number(3); + ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector'; + is scalar $input->possible_values, 1, 'one option'; + + $m->select( 'UseKey-rt-test@example.com' => $fpr1 ); + $m->click('SubmitTicket'); + $m->content_like( + qr/You are going to encrypt outgoing email messages/i, + 'problems with keys' + ); + $m->content_like( + qr/Selected key either is not trusted/i, + 'problems with keys' + ); + + my @mail = RT::Test->fetch_caught_mails; + ok !@mail, 'there are no outgoing emails'; +} + +diag "import a second key of rt-test\@example.com" if $ENV{TEST_VERBOSE}; +my $fpr2 = ''; +{ + RT::Test->import_gnupg_key('rt-test@example.com.2', 'public'); + my %res = RT::Crypt::GnuPG::GetKeysInfo('rt-test@example.com'); + is $res{'info'}[1]{'TrustLevel'}, 0, 'is not trusted key'; + $fpr2 = $res{'info'}[2]{'Fingerprint'}; +} + +diag "check that things still doesn't work if two keys are not trusted" if $ENV{TEST_VERBOSE}; +{ + RT::Test->clean_caught_mails; + + ok $m->goto_ticket( $tid ), "UI -> ticket #$tid"; + $m->follow_link_ok( { text => 'Reply' }, 'ticket -> reply' ); + $m->form_number(3); + $m->tick( Encrypt => 1 ); + $m->field( UpdateCc => 'rt-test@example.com' ); + $m->field( UpdateContent => 'Some content' ); + $m->click('SubmitTicket'); + $m->content_like( + qr/You are going to encrypt outgoing email messages/i, + 'problems with keys' + ); + $m->content_like( + qr/There are several keys suitable for encryption/i, + 'problems with keys' + ); + + my $form = $m->form_number(3); + ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector'; + is scalar $input->possible_values, 2, 'two options'; + + $m->select( 'UseKey-rt-test@example.com' => $fpr1 ); + $m->click('SubmitTicket'); + $m->content_like( + qr/You are going to encrypt outgoing email messages/i, + 'problems with keys' + ); + $m->content_like( + qr/Selected key either is not trusted/i, + 'problems with keys' + ); + + my @mail = RT::Test->fetch_caught_mails; + ok !@mail, 'there are no outgoing emails'; +} + +{ + RT::Test->lsign_gnupg_key( $fpr1 ); + my %res = RT::Crypt::GnuPG::GetKeysInfo('rt-test@example.com'); + ok $res{'info'}[0]{'TrustLevel'} > 0, 'trusted key'; + is $res{'info'}[1]{'TrustLevel'}, 0, 'is not trusted key'; +} + +diag "check that we see key selector even if only one key is trusted but there are more keys" if $ENV{TEST_VERBOSE}; +{ + RT::Test->clean_caught_mails; + + ok $m->goto_ticket( $tid ), "UI -> ticket #$tid"; + $m->follow_link_ok( { text => 'Reply' }, 'ticket -> reply' ); + $m->form_number(3); + $m->tick( Encrypt => 1 ); + $m->field( UpdateCc => 'rt-test@example.com' ); + $m->field( UpdateContent => 'Some content' ); + $m->click('SubmitTicket'); + $m->content_like( + qr/You are going to encrypt outgoing email messages/i, + 'problems with keys' + ); + $m->content_like( + qr/There are several keys suitable for encryption/i, + 'problems with keys' + ); + + my $form = $m->form_number(3); + ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector'; + is scalar $input->possible_values, 2, 'two options'; + + my @mail = RT::Test->fetch_caught_mails; + ok !@mail, 'there are no outgoing emails'; +} + +diag "check that key selector works and we can select trusted key" if $ENV{TEST_VERBOSE}; +{ + RT::Test->clean_caught_mails; + + ok $m->goto_ticket( $tid ), "UI -> ticket #$tid"; + $m->follow_link_ok( { text => 'Reply' }, 'ticket -> reply' ); + $m->form_number(3); + $m->tick( Encrypt => 1 ); + $m->field( UpdateCc => 'rt-test@example.com' ); + $m->field( UpdateContent => 'Some content' ); + $m->click('SubmitTicket'); + $m->content_like( + qr/You are going to encrypt outgoing email messages/i, + 'problems with keys' + ); + $m->content_like( + qr/There are several keys suitable for encryption/i, + 'problems with keys' + ); + + my $form = $m->form_number(3); + ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector'; + is scalar $input->possible_values, 2, 'two options'; + + $m->select( 'UseKey-rt-test@example.com' => $fpr1 ); + $m->click('SubmitTicket'); + $m->content_like( qr/Message recorded/i, 'Message recorded' ); + + my @mail = RT::Test->fetch_caught_mails; + ok @mail, 'there are some emails'; + check_text_emails( { Encrypt => 1 }, @mail ); +} + +diag "check encrypting of attachments" if $ENV{TEST_VERBOSE}; +{ + RT::Test->clean_caught_mails; + + ok $m->goto_ticket( $tid ), "UI -> ticket #$tid"; + $m->follow_link_ok( { text => 'Reply' }, 'ticket -> reply' ); + $m->form_number(3); + $m->tick( Encrypt => 1 ); + $m->field( UpdateCc => 'rt-test@example.com' ); + $m->field( UpdateContent => 'Some content' ); + $m->field( Attach => $0 ); + $m->click('SubmitTicket'); + $m->content_like( + qr/You are going to encrypt outgoing email messages/i, + 'problems with keys' + ); + $m->content_like( + qr/There are several keys suitable for encryption/i, + 'problems with keys' + ); + + my $form = $m->form_number(3); + ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector'; + is scalar $input->possible_values, 2, 'two options'; + + $m->select( 'UseKey-rt-test@example.com' => $fpr1 ); + $m->click('SubmitTicket'); + $m->content_like( qr/Message recorded/i, 'Message recorded' ); + + my @mail = RT::Test->fetch_caught_mails; + ok @mail, 'there are some emails'; + check_text_emails( { Encrypt => 1, Attachment => 1 }, @mail ); +} + +sub check_text_emails { + my %args = %{ shift @_ }; + my @mail = @_; + + ok scalar @mail, "got some mail"; + for my $mail (@mail) { + for my $type ('email', 'attachment') { + next if $type eq 'attachment' && !$args{'Attachment'}; + + my $content = $type eq 'email' + ? "Some content" + : "Attachment content"; + + if ( $args{'Encrypt'} ) { + unlike $mail, qr/$content/, "outgoing $type was encrypted"; + } else { + like $mail, qr/$content/, "outgoing $type was not encrypted"; + } + + next unless $type eq 'email'; + + if ( $args{'Sign'} && $args{'Encrypt'} ) { + like $mail, qr/BEGIN PGP MESSAGE/, 'outgoing email was signed'; + } elsif ( $args{'Sign'} ) { + like $mail, qr/SIGNATURE/, 'outgoing email was signed'; + } else { + unlike $mail, qr/SIGNATURE/, 'outgoing email was not signed'; + } + } + } +} + diff --git a/rt/t/web/offline_messages_utf8.t b/rt/t/web/offline_messages_utf8.t new file mode 100644 index 000000000..c32e0bc27 --- /dev/null +++ b/rt/t/web/offline_messages_utf8.t @@ -0,0 +1,67 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use RT::Test tests => 6; +use File::Temp qw/tempfile/; +use Encode; +use RT::Ticket; + +my ( $url, $m ) = RT::Test->started_ok; +$m->default_header( 'Accept-Language' => "zh-cn" ); +ok( $m->login, 'logged in' ); + +my $ticket_id; +my $template; + +{ + + # test create message + $template = <<EOF; +===Create-Ticket: ticket1 +Queue: General +Subject: test message +Status: new +Content: +ENDOFCONTENT +Due: +TimeEstimated: 100 +TimeLeft: 100 +FinalPriority: 90 +EOF + + $m->get_ok( $url . '/Tools/Offline.html' ); + + $m->submit_form( + form_name => 'TicketUpdate', + fields => { string => $template, }, + button => 'UpdateTickets', + ); + my $content = encode 'utf8', $m->content; + ok( $content =~ qr/申请单 #(\d+) 成功新增于 'General' 表单/, 'message is shown right' ); + $ticket_id = $1; +} + +{ + + # test update message + $template = <<EOF; +===Update-Ticket: 1 +Subject: test message update +EOF + + $m->get_ok( $url . '/Tools/Offline.html' ); + $m->submit_form( + form_name => 'TicketUpdate', + fields => { string => $template, }, + button => 'UpdateTickets', + ); + + my $content = encode 'utf8', $m->content; + ok( + $content =~ +qr/主题\s*的值从\s*'test message'\s*改为\s*'test message update'/, + 'subject is updated' + ); +} + diff --git a/rt/t/web/offline_utf8.t b/rt/t/web/offline_utf8.t new file mode 100644 index 000000000..2a3e64d3c --- /dev/null +++ b/rt/t/web/offline_utf8.t @@ -0,0 +1,54 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use RT::Test tests => 8; +use File::Temp qw/tempfile/; +use Encode; +use RT::Ticket; +my ( $fh, $file ) = tempfile; +my $template = <<EOF; +===Create-Ticket: ticket1 +Queue: General +Subject: 标题 +Status: new +Content: +这是正文 +ENDOFCONTENT +EOF + +print $fh $template; +close $fh; + +my ( $url, $m ) = RT::Test->started_ok; +ok( $m->login, 'logged in' ); + +$m->get_ok( $url . '/Tools/Offline.html' ); + +$m->submit_form( + form_name => 'TicketUpdate', + fields => { Template => $file, }, + button => 'Parse', +); + +$m->content_contains( '这是正文', 'content is parsed right' ); + +$m->submit_form( + form_name => 'TicketUpdate', + button => 'UpdateTickets', + + # mimic what browsers do: they seems decoded $template + fields => { string => decode( 'utf8', $template ), }, +); + +$m->content_like( qr/Ticket \d+ created/, 'found ticket created message' ); +my ( $ticket_id ) = $m->content =~ /Ticket (\d+) created/; + +my $ticket = RT::Ticket->new( $RT::SystemUser ); +$ticket->Load( $ticket_id ); +is( $ticket->Subject, '标题', 'subject in $ticket is right' ); + +$m->get_ok( $url . "/Ticket/Display.html?id=$ticket_id" ); +$m->content_contains( '这是正文', + 'content is right in ticket display page' ); + diff --git a/rt/t/web/query_builder.t b/rt/t/web/query_builder.t new file mode 100644 index 000000000..02ed1297f --- /dev/null +++ b/rt/t/web/query_builder.t @@ -0,0 +1,249 @@ +#!/usr/bin/perl + +use strict; +use HTTP::Request::Common; +use HTTP::Cookies; +use LWP; +use Encode; +use RT::Test tests => 42; + +my $cookie_jar = HTTP::Cookies->new; +my ($baseurl, $agent) = RT::Test->started_ok; + + +# give the agent a place to stash the cookies + +$agent->cookie_jar($cookie_jar); + +# create a regression queue if it doesn't exist +my $queue = RT::Test->load_or_create_queue( Name => 'Regression' ); +ok $queue && $queue->id, 'loaded or created queue'; + +my $url = $agent->rt_base_url; +ok $agent->login, "logged in"; + +# {{{ Query Builder tests + +my $response = $agent->get($url."Search/Build.html"); +ok $response->is_success, "Fetched ". $url ."Search/Build.html"; + +sub getQueryFromForm { + $agent->form_name('BuildQuery'); + # This pulls out the "hidden input" query from the page + my $q = $agent->current_form->find_input("Query")->value; + $q =~ s/^\s+//g; + $q =~ s/\s+$//g; + $q =~ s/\s+/ /g; + return $q; +} + +sub selectedClauses { + my @clauses = grep { defined } map { $_->value } $agent->current_form->find_input("clauses"); + return [ @clauses ]; +} + + +diag "add the first condition" if $ENV{'TEST_VERBOSE'}; +{ + ok $agent->form_name('BuildQuery'), "found the form once"; + $agent->field("ActorField", "Owner"); + $agent->field("ActorOp", "="); + $agent->field("ValueOfActor", "Nobody"); + $agent->submit; + is getQueryFromForm, "Owner = 'Nobody'", 'correct query'; +} + +diag "set the next condition" if $ENV{'TEST_VERBOSE'}; +{ + ok($agent->form_name('BuildQuery'), "found the form again"); + $agent->field("QueueOp", "!="); + $agent->field("ValueOfQueue", "Regression"); + $agent->submit; + is getQueryFromForm, "Owner = 'Nobody' AND Queue != 'Regression'", + 'correct query'; +} + +diag "We're going to delete the owner" if $ENV{'TEST_VERBOSE'}; +{ + $agent->select("clauses", ["0"] ); + $agent->click("DeleteClause"); + ok $agent->form_name('BuildQuery'), "found the form"; + is getQueryFromForm, "Queue != 'Regression'", 'correct query'; +} + +diag "add a cond with OR and se number by the way" if $ENV{'TEST_VERBOSE'}; +{ + $agent->field("AndOr", "OR"); + $agent->select("idOp", ">"); + $agent->field("ValueOfid" => "1234"); + $agent->click("AddClause"); + ok $agent->form_name('BuildQuery'), "found the form again"; + is getQueryFromForm, "Queue != 'Regression' OR id > 1234", + "added something as OR, and number not quoted"; + is_deeply selectedClauses, ["1"], 'the id that we just entered is still selected'; + +} + +diag "Move the second one up a level" if $ENV{'TEST_VERBOSE'}; +{ + $agent->click("Up"); + ok $agent->form_name('BuildQuery'), "found the form again"; + is getQueryFromForm, "id > 1234 OR Queue != 'Regression'", "moved up one"; + is_deeply selectedClauses, ["0"], 'the one we moved up is selected'; +} + +diag "Move the second one right" if $ENV{'TEST_VERBOSE'}; +{ + $agent->click("Right"); + ok $agent->form_name('BuildQuery'), "found the form again"; + is getQueryFromForm, "Queue != 'Regression' OR ( id > 1234 )", + "moved over to the right (and down)"; + is_deeply selectedClauses, ["2"], 'the one we moved right is selected'; +} + +diag "Move the block up" if $ENV{'TEST_VERBOSE'}; +{ + $agent->select("clauses", ["1"]); + $agent->click("Up"); + ok $agent->form_name('BuildQuery'), "found the form again"; + is getQueryFromForm, "( id > 1234 ) OR Queue != 'Regression'", "moved up"; + is_deeply selectedClauses, ["0"], 'the one we moved up is selected'; +} + + +diag "Can not move up the top most clause" if $ENV{'TEST_VERBOSE'}; +{ + $agent->select("clauses", ["0"]); + $agent->click("Up"); + ok $agent->form_name('BuildQuery'), "found the form again"; + $agent->content_like(qr/error: can\S+t move up/, "i shouldn't have been able to hit up"); + is_deeply selectedClauses, ["0"], 'the one we tried to move is selected'; +} + +diag "Can not move left the left most clause" if $ENV{'TEST_VERBOSE'}; +{ + $agent->click("Left"); + ok($agent->form_name('BuildQuery'), "found the form again"); + $agent->content_like(qr/error: can\S+t move left/, "i shouldn't have been able to hit left"); + is_deeply selectedClauses, ["0"], 'the one we tried to move is selected'; +} + +diag "Add a condition into a nested block" if $ENV{'TEST_VERBOSE'}; +{ + $agent->select("clauses", ["1"]); + $agent->select("ValueOfStatus" => "stalled"); + $agent->submit; + ok $agent->form_name('BuildQuery'), "found the form again"; + is_deeply selectedClauses, ["2"], 'the one we added is only selected'; + is getQueryFromForm, + "( id > 1234 AND Status = 'stalled' ) OR Queue != 'Regression'", + "added new one"; +} + +diag "click advanced, enter 'C1 OR ( C2 AND C3 )', apply, aggregators should stay the same." + if $ENV{'TEST_VERBOSE'}; +{ + my $response = $agent->get($url."Search/Edit.html"); + ok( $response->is_success, "Fetched /Search/Edit.html" ); + ok($agent->form_number(3), "found the form"); + $agent->field("Query", "Status = 'new' OR ( Status = 'open' AND Subject LIKE 'office' )"); + $agent->submit; + is( getQueryFromForm, + "Status = 'new' OR ( Status = 'open' AND Subject LIKE 'office' )", + "no aggregators change" + ); +} + +# - new items go one level down +# - add items at currently selected level +# - if nothing is selected, add at end, one level down +# +# move left +# - error if nothing selected +# - same item should be selected after move +# - can't move left if you're at the top level +# +# move right +# - error if nothing selected +# - same item should be selected after move +# - can always move right (no max depth...should there be?) +# +# move up +# - error if nothing selected +# - same item should be selected after move +# - can't move up if you're first in the list +# +# move down +# - error if nothing selected +# - same item should be selected after move +# - can't move down if you're last in the list +# +# toggle +# - error if nothing selected +# - change all aggregators in the grouping +# - don't change any others +# +# delete +# - error if nothing selected +# - delete currently selected item +# - delete all children of a grouping +# - if delete leaves a node with no children, delete that, too +# - what should be selected? +# +# Clear +# - clears entire query +# - clears it from the session, too + +# }}} + +# create a custom field with nonascii name and try to add a condition +{ + my $cf = RT::CustomField->new( $RT::SystemUser ); + $cf->LoadByName( Name => "\x{442}", Queue => 0 ); + if ( $cf->id ) { + is($cf->Type, 'Freeform', 'loaded and type is correct'); + } else { + my ($return, $msg) = $cf->Create( + Name => "\x{442}", + Queue => 0, + Type => 'Freeform', + ); + ok($return, 'created CF') or diag "error: $msg"; + } + + my $response = $agent->get($url."Search/Build.html?NewQuery=1"); + ok( $response->is_success, "Fetched " . $url."Search/Build.html" ); + + ok($agent->form_name('BuildQuery'), "found the form once"); + $agent->field("ValueOf'CF.{\x{442}}'", "\x{441}"); + $agent->submit(); + is( getQueryFromForm, + "'CF.{\x{442}}' LIKE '\x{441}'", + "no changes, no duplicate condition with badly encoded text" + ); + +} + +diag "input a condition, select (several conditions), click delete" + if $ENV{'TEST_VERBOSE'}; +{ + my $response = $agent->get( $url."Search/Edit.html" ); + ok $response->is_success, "Fetched /Search/Edit.html"; + ok $agent->form_number(3), "found the form"; + $agent->field("Query", "( Status = 'new' OR Status = 'open' )"); + $agent->submit; + is( getQueryFromForm, + "( Status = 'new' OR Status = 'open' )", + "query is the same" + ); + $agent->select("clauses", [qw(0 1 2)]); + $agent->field( ValueOfid => 10 ); + $agent->click("DeleteClause"); + + is( getQueryFromForm, + "id < 10", + "replaced query successfuly" + ); +} + +1; diff --git a/rt/t/web/quicksearch.t b/rt/t/web/quicksearch.t new file mode 100644 index 000000000..cd9a8e76c --- /dev/null +++ b/rt/t/web/quicksearch.t @@ -0,0 +1,51 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use RT::Test tests => 7; +my ($baseurl, $m) = RT::Test->started_ok; +my $url = $m->rt_base_url; + +# merged tickets still show up in search +my $t1 = RT::Ticket->new($RT::SystemUser); +$t1->Create( + Subject => 'base ticket'.$$, + Queue => 'general', + Owner => 'root', + Requestor => 'customsearch@localhost', + MIMEObj => MIME::Entity->build( + From => 'customsearch@localhost', + To => 'rt@localhost', + Subject => 'base ticket'.$$, + Data => "DON'T SEARCH FOR ME", + ), +); +ok(my $id1 = $t1->id, 'created ticket for custom search'); + +my $t2 = RT::Ticket->new($RT::SystemUser); +$t2->Create( + Subject => 'merged away'.$$, + Queue => 'general', + Owner => 'root', + Requestor => 'customsearch@localhost', + MIMEObj => MIME::Entity->build( + From => 'customsearch@localhost', + To => 'rt@localhost', + Subject => 'merged away'.$$, + Data => "MERGEDAWAY", + ), +); +ok(my $id2 = $t2->id, 'created ticket for custom search'); + +my ($ok, $msg) = $t2->MergeInto($id1); +ok($ok, "merge: $msg"); + +ok($m->login, 'logged in'); + +$m->form_with_fields('q'); +$m->field(q => 'fulltext:MERGEDAWAY'); +TODO: { + local $TODO = "We don't yet handle merged ticket content searches right"; +$m->content_contains('Found 1 ticket'); +} +$m->content_contains('base ticket', "base ticket is found, not the merged-away ticket"); diff --git a/rt/t/web/rest-non-ascii-subject.t b/rt/t/web/rest-non-ascii-subject.t new file mode 100644 index 000000000..70c910afe --- /dev/null +++ b/rt/t/web/rest-non-ascii-subject.t @@ -0,0 +1,55 @@ +#!/usr/bin/env perl +# Test ticket creation with REST using non ascii subject +use strict; +use warnings; +use RT::Test tests => 7; + +local $RT::Test::SKIP_REQUEST_WORK_AROUND = 1; + +use Encode; +# \x{XX} where XX is less than 255 is not treated as unicode code point +my $subject = Encode::decode('latin1', "Sujet accentu\x{e9}"); +my $text = Encode::decode('latin1', "Contenu accentu\x{e9}"); + +my ($baseurl, $m) = RT::Test->started_ok; + +my $queue = RT::Test->load_or_create_queue(Name => 'General'); +ok($queue->Id, "loaded the General queue"); + +my $content = "id: ticket/new +Queue: General +Requestor: root +Subject: $subject +Cc: +AdminCc: +Owner: +Status: new +Priority: +InitialPriority: +FinalPriority: +TimeEstimated: +Starts: 2009-03-10 16:14:55 +Due: 2009-03-10 16:14:55 +Text: $text"; + +$m->post("$baseurl/REST/1.0/ticket/new", [ + user => 'root', + pass => 'password', +# error message from HTTP::Message: content must be bytes + content => Encode::encode_utf8($content), +], 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, $subject, "ticket subject successfully set"); + +my $attach = $ticket->Transactions->First->Attachments->First; +is($attach->Subject, $subject, "attachement subject successfully set"); +TODO: { + local $TODO = "Not fixed yet, but not a regression"; + is($attach->GetHeader('Subject'), $subject, "attachement header subject successfully set"); +} diff --git a/rt/t/web/rest.t b/rt/t/web/rest.t new file mode 100644 index 000000000..b3a7c558b --- /dev/null +++ b/rt/t/web/rest.t @@ -0,0 +1,71 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use RT::Test tests => 16; + +my ($baseurl, $m) = RT::Test->started_ok; + +for my $name ("severity", "fu()n:k/") { + my $cf = RT::Test->load_or_create_custom_field( + Name => $name, + Type => 'Freeform', + Queue => 'General', + ); + ok($cf->Id, "created a CustomField"); + is($cf->Name, $name, "correct CF name"); +} + +my $queue = RT::Test->load_or_create_queue(Name => 'General'); +ok($queue->Id, "loaded the General queue"); + +$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-fu()n:k/: maximum"; # old style +push @lines, "CF.{severity}: explosive"; # new style + +$text = join "\n", @lines; + +ok($text =~ s/Subject:\s*$/Subject: REST interface/m, "successfully replaced subject"); + +$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, "REST interface", "subject successfully set"); +is($ticket->FirstCustomFieldValue("fu()n:k/"), "maximum", "CF successfully set"); + +$m->post("$baseurl/REST/1.0/search/ticket", [ + user => 'root', + pass => 'password', + query => "id=$id", + fields => "Subject,CF-fu()n:k/,CF.{severity},Status", +]); + +# the fields are interpreted server-side a hash (why?), so we can't depend +# on order +for ("id: ticket/1", + "Subject: REST interface", + "CF.{fu()n:k/}: maximum", + "CF.{severity}: explosive", + "Status: new") { + $m->content_contains($_); +} + diff --git a/rt/t/web/rights.t b/rt/t/web/rights.t new file mode 100644 index 000000000..b47ba99af --- /dev/null +++ b/rt/t/web/rights.t @@ -0,0 +1,85 @@ +#!/usr/bin/perl -w +use strict; +use warnings; + +use RT::Test tests => 14; + +my ($baseurl, $m) = RT::Test->started_ok; +ok $m->login, "logged in"; + +$m->follow_link_ok({ text => 'Configuration' }); +$m->follow_link_ok({ text => 'Global' }); +$m->follow_link_ok({ text => 'Group Rights' }); + + +sub get_rights { + my $agent = shift; + my $principal_id = shift; + my $object = shift; + $agent->form_number(3); + my @inputs = $agent->current_form->find_input("RevokeRight-$principal_id-$object"); + my @rights = sort grep $_, map $_->possible_values, grep $_, @inputs; + return @rights; +}; + +diag "load Everyone group" if $ENV{'TEST_VERBOSE'}; +my ($everyone, $everyone_gid); +{ + $everyone = RT::Group->new( $RT::SystemUser ); + $everyone->LoadSystemInternalGroup('Everyone'); + ok($everyone_gid = $everyone->id, "loaded 'everyone' group"); +} + +diag "revoke all global rights from Everyone group" if $ENV{'TEST_VERBOSE'}; +my @has = get_rights( $m, $everyone_gid, 'RT::System-1' ); +if ( @has ) { + $m->form_number(3); + $m->tick("RevokeRight-$everyone_gid-RT::System-1", $_) foreach @has; + $m->submit; + + is_deeply([get_rights( $m, $everyone_gid, 'RT::System-1' )], [], 'deleted all rights' ); +} else { + ok(1, 'the group has no global rights'); +} + +diag "grant SuperUser right to everyone" if $ENV{'TEST_VERBOSE'}; +{ + $m->form_number(3); + $m->select("GrantRight-$everyone_gid-RT::System-1", ['SuperUser']); + $m->submit; + + $m->content_contains('Right Granted', 'got message'); + RT::Principal::InvalidateACLCache(); + ok($everyone->PrincipalObj->HasRight( Right => 'SuperUser', Object => $RT::System ), 'group has right'); + is_deeply( [get_rights( $m, $everyone_gid, 'RT::System-1' )], ['SuperUser'], 'granted SuperUser right' ); +} + +diag "revoke the right" if $ENV{'TEST_VERBOSE'}; +{ + $m->form_number(3); + $m->tick("RevokeRight-$everyone_gid-RT::System-1", 'SuperUser'); + $m->submit; + + $m->content_contains('Right revoked', 'got message'); + RT::Principal::InvalidateACLCache(); + ok(!$everyone->PrincipalObj->HasRight( Right => 'SuperUser', Object => $RT::System ), 'group has no right'); + is_deeply( [get_rights( $m, $everyone_gid, 'RT::System-1' )], [], 'revoked SuperUser right' ); +} + + +diag "return rights the group had in the beginning" if $ENV{'TEST_VERBOSE'}; +if ( @has ) { + $m->form_number(3); + $m->select("GrantRight-$everyone_gid-RT::System-1", \@has); + $m->submit; + + $m->content_contains('Right Granted', 'got message'); + is_deeply( + [ get_rights( $m, $everyone_gid, 'RT::System-1' ) ], + [ @has ], + 'returned back all rights' + ); +} else { + ok(1, 'the group had no global rights, so nothing to return'); +} + diff --git a/rt/t/web/rights1.t b/rt/t/web/rights1.t new file mode 100644 index 000000000..6da204cc9 --- /dev/null +++ b/rt/t/web/rights1.t @@ -0,0 +1,134 @@ +#!/usr/bin/perl -w +use strict; +use HTTP::Cookies; + +use RT::Test tests => 35; +my ($baseurl, $agent) = RT::Test->started_ok; + +# Create a user with basically no rights, to start. +my $user_obj = RT::User->new($RT::SystemUser); +my ($ret, $msg) = $user_obj->LoadOrCreateByEmail('customer-'.$$.'@example.com'); +ok($ret, 'ACL test user creation'); +$user_obj->SetName('customer-'.$$); +$user_obj->SetPrivileged(1); +($ret, $msg) = $user_obj->SetPassword('customer'); +ok($ret, "ACL test password set. $msg"); + +# Now test the web interface, making sure objects come and go as +# required. + + +my $cookie_jar = HTTP::Cookies->new; + +# give the agent a place to stash the cookies + +$agent->cookie_jar($cookie_jar); + +no warnings 'once'; +# get the top page +login($agent, $user_obj); + +# Test for absence of Configure and Preferences tabs. +ok(!$agent->find_link( url => "$RT::WebPath/Admin/", + text => 'Configuration'), "No config tab" ); +ok(!$agent->find_link( url => "$RT::WebPath/User/Prefs.html", + text => 'Preferences'), "No prefs pane" ); + +# Now test for their presence, one at a time. Sleep for a bit after +# ACL changes, thanks to the 10s ACL cache. +my ($grantid,$grantmsg) =$user_obj->PrincipalObj->GrantRight(Right => 'ShowConfigTab', Object => $RT::System); + +ok($grantid,$grantmsg); + +$agent->reload; + +like($agent->{'content'} , qr/Logout/i, "Reloaded page successfully"); +ok($agent->find_link( url => "$RT::WebPath/Admin/", + text => 'Configuration'), "Found config tab" ); +my ($revokeid,$revokemsg) =$user_obj->PrincipalObj->RevokeRight(Right => 'ShowConfigTab'); +ok ($revokeid,$revokemsg); +($grantid,$grantmsg) =$user_obj->PrincipalObj->GrantRight(Right => 'ModifySelf'); +ok ($grantid,$grantmsg); +$agent->reload(); +like($agent->{'content'} , qr/Logout/i, "Reloaded page successfully"); +ok($agent->find_link( + text => 'Preferences'), "Found prefs pane" ); +($revokeid,$revokemsg) = $user_obj->PrincipalObj->RevokeRight(Right => 'ModifySelf'); +ok ($revokeid,$revokemsg); +# Good. Now load the search page and test Load/Save Search. +$agent->follow_link( url => "$RT::WebPath/Search/Build.html", + text => 'Tickets'); +is($agent->{'status'}, 200, "Fetched search builder page"); +ok($agent->{'content'} !~ /Load saved search/i, "No search loading box"); +ok($agent->{'content'} !~ /Saved searches/i, "No saved searches box"); + +($grantid,$grantmsg) = $user_obj->PrincipalObj->GrantRight(Right => 'LoadSavedSearch'); +ok($grantid,$grantmsg); +$agent->reload(); +like($agent->{'content'} , qr/Load saved search/i, "Search loading box exists"); +ok($agent->{'content'} !~ /input\s+type=['"]submit['"][^>]+name=['"]SavedSearchSave['"]/i, + "Still no saved searches box"); + +($grantid,$grantmsg) =$user_obj->PrincipalObj->GrantRight(Right => 'CreateSavedSearch'); +ok ($grantid,$grantmsg); +$agent->reload(); +like($agent->{'content'} , qr/Load saved search/i, + "Search loading box still exists"); +like($agent->{'content'} , qr/input\s+type=['"]submit['"][^>]+name=['"]SavedSearchSave['"]/i, + "Saved searches box exists"); + +# Create a group, and a queue, so we can test limited user visibility +# via SelectOwner. + +my $queue_obj = RT::Queue->new($RT::SystemUser); +($ret, $msg) = $queue_obj->Create(Name => 'CustomerQueue-'.$$, + Description => 'queue for SelectOwner testing'); +ok($ret, "SelectOwner test queue creation. $msg"); +my $group_obj = RT::Group->new($RT::SystemUser); +($ret, $msg) = $group_obj->CreateUserDefinedGroup(Name => 'CustomerGroup-'.$$, + Description => 'group for SelectOwner testing'); +ok($ret, "SelectOwner test group creation. $msg"); + +# Add our customer to the customer group, and give it queue rights. +($ret, $msg) = $group_obj->AddMember($user_obj->PrincipalObj->Id()); +ok($ret, "Added customer to its group. $msg"); +($grantid,$grantmsg) =$group_obj->PrincipalObj->GrantRight(Right => 'OwnTicket', + Object => $queue_obj); + +ok($grantid,$grantmsg); +($grantid,$grantmsg) =$group_obj->PrincipalObj->GrantRight(Right => 'SeeQueue', + Object => $queue_obj); +ok ($grantid,$grantmsg); +# Now. When we look at the search page we should be able to see +# ourself in the list of possible owners. + +$agent->reload(); +ok($agent->form_name('BuildQuery'), "Yep, form is still there"); +my $input = $agent->current_form->find_input('ValueOfActor'); +ok(grep(/customer-$$/, $input->value_names()), "Found self in the actor listing"); + +sub login { + my $agent = shift; + + my $url = "http://localhost:" . RT->Config->Get('WebPort') . RT->Config->Get('WebPath') . "/"; + $agent->get($url); + is( $agent->{'status'}, 200, + "Loaded a page - http://localhost" . RT->Config->Get('WebPath') ); + + # {{{ test a login + + # follow the link marked "Login" + + ok( $agent->{form}->find_input('user') ); + + ok( $agent->{form}->find_input('pass') ); + like( $agent->{'content'} , qr/username:/i ); + $agent->field( 'user' => $user_obj->Name ); + $agent->field( 'pass' => 'customer' ); + + # the field isn't named, so we have to click link 0 + $agent->click(0); + is( $agent->{'status'}, 200, "Fetched the page ok" ); + like( $agent->{'content'} , qr/Logout/i, "Found a logout link" ); +} +1; diff --git a/rt/t/web/saved_search_chart.t b/rt/t/web/saved_search_chart.t new file mode 100644 index 000000000..105166233 --- /dev/null +++ b/rt/t/web/saved_search_chart.t @@ -0,0 +1,86 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use RT::Test tests => 19; +my ( $url, $m ) = RT::Test->started_ok; +use RT::Attribute; +my $search = RT::Attribute->new($RT::SystemUser); +my $ticket = RT::Ticket->new($RT::SystemUser); +my ( $ret, $msg ) = $ticket->Create( + Subject => 'base ticket' . $$, + Queue => 'general', + Owner => 'root', + Requestor => 'root@localhost', + MIMEObj => MIME::Entity->build( + From => 'root@localhost', + To => 'rt@localhost', + Subject => 'base ticket' . $$, + Data => "", + ), +); +ok( $ret, "ticket created: $msg" ); + +ok( $m->login, 'logged in' ); + +$m->get_ok( $url . "/Search/Chart.html?Query=" . 'id=1' ); +my ($owner) = $m->content =~ /value="(RT::User-\d+)"/; + +$m->submit_form( + form_name => 'SaveSearch', + fields => { + SavedSearchDescription => 'first chart', + SavedSearchOwner => $owner, + }, + button => 'SavedSearchSave', +); + +$m->content_like( qr/Chart first chart saved/, 'saved first chart' ); + +my ( $search_uri, $id ) = $m->content =~ /value="(RT::User-\d+-SavedSearch-(\d+))"/; +$m->submit_form( + form_name => 'SaveSearch', + fields => { SavedSearchLoad => $search_uri }, +); + +$m->content_like( qr/name="SavedSearchDelete"\s+value="Delete"/, + 'found Delete button' ); +$m->content_like( + qr/name="SavedSearchDescription"\s+value="first chart"/, + 'found Description input with the value filled' +); +$m->content_like( qr/name="SavedSearchSave"\s+value="Update"/, + 'found Update button' ); +$m->content_unlike( qr/name="SavedSearchSave"\s+value="Save"/, + 'no Save button' ); + +$m->submit_form( + form_name => 'SaveSearch', + fields => { + Query => 'id=2', + PrimaryGroupBy => 'Status', + ChartStyle => 'pie', + }, + button => 'SavedSearchSave', +); + +$m->content_like( qr/Chart first chart updated/, 'found updated message' ); +$m->content_like( qr/id=2/, 'Query is updated' ); +$m->content_like( qr/value="Status"\s+selected="selected"/, + 'PrimaryGroupBy is updated' ); +$m->content_like( qr/value="pie"\s+selected="selected"/, + 'ChartType is updated' ); +ok( $search->Load($id) ); +is( $search->SubValue('Query'), 'id=2', 'Query is indeed updated' ); +is( $search->SubValue('PrimaryGroupBy'), + 'Status', 'PrimaryGroupBy is indeed updated' ); +is( $search->SubValue('ChartStyle'), 'pie', 'ChartStyle is indeed updated' ); + +# finally, let's test delete +$m->submit_form( + form_name => 'SaveSearch', + button => 'SavedSearchDelete', +); +$m->content_like( qr/Chart first chart deleted/, 'found deleted message' ); +$m->content_unlike( qr/value="RT::User-\d+-SavedSearch-\d+"/, + 'no saved search' ); diff --git a/rt/t/web/saved_search_permissions.t b/rt/t/web/saved_search_permissions.t new file mode 100644 index 000000000..f91ca13c6 --- /dev/null +++ b/rt/t/web/saved_search_permissions.t @@ -0,0 +1,34 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use RT::Test tests => 10; +my $user = RT::User->new($RT::SystemUser); +ok( + $user->Create( + Name => 'foo', + Privileged => 1, + Password => 'foobar' + ) +); + +my ( $url, $m ) = RT::Test->started_ok; +ok( $m->login, 'root logged in' ); +$m->get_ok( $url . '/Search/Build.html?Query=id<100' ); +$m->submit_form( + form_name => 'BuildQuery', + fields => { SavedSearchDescription => 'test' }, + button => 'SavedSearchSave', +); +$m->content_contains( q{name="SavedSearchDescription" value="test"}, + 'saved test search' ); +my ($id) = $m->content =~ /value="(RT::User-\d+-SavedSearch-\d+)"/; +ok( $m->login( 'foo', 'foobar' ), 'logged in' ); +$m->get_ok( $url . "/Search/Build.html?SavedSearchLoad=$id" ); + +my $message = qq{Can not load saved search "$id"}; +RT::Interface::Web::EscapeUTF8( \$message ); +$m->content_contains( $message, 'user foo can not load saved search of root' ); + +$m->warning_like( qr/User #\d+ tried to load container user #\d+/, + 'get warning' ); diff --git a/rt/t/web/search_bulk_update_links.t b/rt/t/web/search_bulk_update_links.t new file mode 100644 index 000000000..d6bfdfd3c --- /dev/null +++ b/rt/t/web/search_bulk_update_links.t @@ -0,0 +1,147 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use RT::Test tests => 28; +my ( $url, $m ) = RT::Test->started_ok; +ok( $m->login, 'logged in' ); + +my $rtname = RT->Config->Get('rtname'); + +# create tickets +use RT::Ticket; + +my ( @link_tickets, @search_tickets ); +for ( 1 .. 3 ) { + my $link_ticket = RT::Ticket->new($RT::SystemUser); + my ( $ret, $msg ) = $link_ticket->Create( + Subject => "link ticket $_", + Queue => 'general', + Owner => 'root', + Requestor => 'root@localhost', + ); + ok( $ret, "link ticket created: $msg" ); + push @link_tickets, $ret; +} + +for ( 1 .. 3 ) { + my $ticket = RT::Ticket->new($RT::SystemUser); + my ( $ret, $msg ) = $ticket->Create( + Subject => "search ticket $_", + Queue => 'general', + Owner => 'root', + Requestor => 'root@localhost', + ); + ok( $ret, "search ticket created: $msg" ); + push @search_tickets, $ret; +} + +# let's add link to 1 search ticket first +$m->get_ok( $url . "/Search/Bulk.html?Query=id=$search_tickets[0]&Rows=10" ); +$m->content_contains( 'Current Links', 'has current links part' ); +$m->content_lacks( 'DeleteLink--', 'no delete link stuff' ); +$m->submit_form( + form_number => 3, + fields => { + 'Ticket-DependsOn' => $link_tickets[0], + 'Ticket-MemberOf' => $link_tickets[1], + 'Ticket-RefersTo' => $link_tickets[2], + }, +); +$m->content_contains( + "Ticket $search_tickets[0] depends on Ticket $link_tickets[0]", + 'depends on msg', +); +$m->content_contains( + "Ticket $search_tickets[0] member of Ticket $link_tickets[1]", + 'member of msg', +); +$m->content_contains( + "Ticket $search_tickets[0] refers to Ticket $link_tickets[2]", + 'refers to msg', +); + +$m->content_contains( + "DeleteLink--DependsOn-fsck.com-rt://$rtname/ticket/$link_tickets[0]", + 'found depends on link' ); +$m->content_contains( + "DeleteLink--MemberOf-fsck.com-rt://$rtname/ticket/$link_tickets[1]", + 'found member of link' ); +$m->content_contains( + "DeleteLink--RefersTo-fsck.com-rt://$rtname/ticket/$link_tickets[2]", + 'found refers to link' ); + +# here we check the *real* bulk update +my $query = join ' OR ', map { "id=$_" } @search_tickets; +$m->get_ok( $url . "/Search/Bulk.html?Query=$query&Rows=10" ); +$m->content_contains( 'Current Links', 'has current links part' ); +$m->content_lacks( 'DeleteLink--', 'no delete link stuff' ); + +# test DependsOn, MemberOf and RefersTo +$m->submit_form( + form_number => 3, + fields => { + 'Ticket-DependsOn' => $link_tickets[0], + 'Ticket-MemberOf' => $link_tickets[1], + 'Ticket-RefersTo' => $link_tickets[2], + }, +); + +$m->content_contains( + "DeleteLink--DependsOn-fsck.com-rt://$rtname/ticket/$link_tickets[0]", + 'found depends on link' ); +$m->content_contains( + "DeleteLink--MemberOf-fsck.com-rt://$rtname/ticket/$link_tickets[1]", + 'found member of link' ); +$m->content_contains( + "DeleteLink--RefersTo-fsck.com-rt://$rtname/ticket/$link_tickets[2]", + 'found refers to link' ); + +$m->submit_form( + form_number => 3, + fields => { + "DeleteLink--DependsOn-fsck.com-rt://$rtname/ticket/$link_tickets[0]" => + 1, + "DeleteLink--MemberOf-fsck.com-rt://$rtname/ticket/$link_tickets[1]" => + 1, + "DeleteLink--RefersTo-fsck.com-rt://$rtname/ticket/$link_tickets[2]" => + 1, + }, +); + +$m->content_lacks( 'DeleteLink--', 'links are all deleted' ); + +# test DependedOnBy, Members and ReferredToBy + +$m->submit_form( + form_number => 3, + fields => { + 'DependsOn-Ticket' => $link_tickets[0], + 'MemberOf-Ticket' => $link_tickets[1], + 'RefersTo-Ticket' => $link_tickets[2], + }, +); + +$m->content_contains( + "DeleteLink-fsck.com-rt://$rtname/ticket/$link_tickets[0]-DependsOn-", + 'found depended on link' ); +$m->content_contains( + "DeleteLink-fsck.com-rt://$rtname/ticket/$link_tickets[1]-MemberOf-", + 'found members link' ); +$m->content_contains( + "DeleteLink-fsck.com-rt://$rtname/ticket/$link_tickets[2]-RefersTo-", + 'found referrd to link' ); + +$m->submit_form( + form_number => 3, + fields => { + "DeleteLink-fsck.com-rt://$rtname/ticket/$link_tickets[0]-DependsOn-" => + 1, + "DeleteLink-fsck.com-rt://$rtname/ticket/$link_tickets[1]-MemberOf-" => + 1, + "DeleteLink-fsck.com-rt://$rtname/ticket/$link_tickets[2]-RefersTo-" => + 1, + }, +); +$m->content_lacks( 'DeleteLink--', 'links are all deleted' ); + diff --git a/rt/t/web/ticket-create-utf8.t b/rt/t/web/ticket-create-utf8.t new file mode 100644 index 000000000..a4d7ae98d --- /dev/null +++ b/rt/t/web/ticket-create-utf8.t @@ -0,0 +1,83 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use RT::Test tests => 14; + +$RT::Test::SKIP_REQUEST_WORK_AROUND = 1; + +use Encode; + +my $ru_test = "\x{442}\x{435}\x{441}\x{442}"; +my $ru_autoreply = "\x{410}\x{432}\x{442}\x{43e}\x{43e}\x{442}\x{432}\x{435}\x{442}"; +my $ru_support = "\x{43f}\x{43e}\x{434}\x{434}\x{435}\x{440}\x{436}\x{43a}\x{430}"; + +my $q = RT::Test->load_or_create_queue( Name => 'Regression' ); +ok $q && $q->id, 'loaded or created queue'; + +RT::Test->set_rights( + Principal => 'Everyone', + Right => ['CreateTicket', 'ShowTicket', 'SeeQueue', 'ReplyToTicket', 'ModifyTicket'], +); + +my ($baseurl, $m) = RT::Test->started_ok; +ok $m->login, 'logged in'; + +# create a ticket with a subject only +{ + ok $m->goto_create_ticket( $q ), "go to create ticket"; + $m->form_number(3); + $m->field( Subject => $ru_test ); + $m->submit; + + $m->content_like( + qr{<td\s+class="message-header-value"[^>]*>\s*\Q$ru_test\E\s*</td>}i, + 'header on the page' + ); + + my $ticket = RT::Test->last_ticket; + is $ticket->Subject, $ru_test, "correct subject"; +} + +# create a ticket with a subject and content +{ + ok $m->goto_create_ticket( $q ), "go to create ticket"; + $m->form_number(3); + $m->field( Subject => $ru_test ); + $m->field( Content => $ru_support ); + $m->submit; + + $m->content_like( + qr{<td\s+class="message-header-value"[^>]*>\s*\Q$ru_test\E\s*</td>}i, + 'header on the page' + ); + $m->content_like( + qr{\Q$ru_support\E}i, + 'content on the page' + ); + + my $ticket = RT::Test->last_ticket; + is $ticket->Subject, $ru_test, "correct subject"; +} + +# create a ticket with a subject and content +{ + ok $m->goto_create_ticket( $q ), "go to create ticket"; + $m->form_number(3); + $m->field( Subject => $ru_test ); + $m->field( Content => $ru_support ); + $m->submit; + + $m->content_like( + qr{<td\s+class="message-header-value"[^>]*>\s*\Q$ru_test\E\s*</td>}i, + 'header on the page' + ); + $m->content_like( + qr{\Q$ru_support\E}i, + 'content on the page' + ); + + my $ticket = RT::Test->last_ticket; + is $ticket->Subject, $ru_test, "correct subject"; +} diff --git a/rt/t/web/ticket_owner.t b/rt/t/web/ticket_owner.t new file mode 100644 index 000000000..0bacaf1bc --- /dev/null +++ b/rt/t/web/ticket_owner.t @@ -0,0 +1,356 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use RT::Test tests => 91; + +my $queue = RT::Test->load_or_create_queue( Name => 'Regression' ); +ok $queue && $queue->id, 'loaded or created queue'; + +my $user_a = RT::Test->load_or_create_user( + Name => 'user_a', Password => 'password', +); +ok $user_a && $user_a->id, 'loaded or created user'; + +my $user_b = RT::Test->load_or_create_user( + Name => 'user_b', Password => 'password', +); +ok $user_b && $user_b->id, 'loaded or created user'; + +RT::Test->started_ok; + +ok( RT::Test->set_rights( + { Principal => $user_a, Right => [qw(SeeQueue ShowTicket CreateTicket ReplyToTicket)] }, + { Principal => $user_b, Right => [qw(SeeQueue ShowTicket OwnTicket)] }, +), 'set rights'); + +my $agent_a = RT::Test::Web->new; +ok $agent_a->login('user_a', 'password'), 'logged in as user A'; + +diag "current user has no right to own, nobody selected as owner on create" if $ENV{TEST_VERBOSE}; +{ + $agent_a->get_ok('/', 'open home page'); + $agent_a->form_name('CreateTicketInQueue'); + $agent_a->select( 'Queue', $queue->id ); + $agent_a->submit; + + $agent_a->content_like(qr/Create a new ticket/i, 'opened create ticket page'); + my $form = $agent_a->form_name('TicketCreate'); + is $form->value('Owner'), $RT::Nobody->id, 'correct owner selected'; + ok !grep($_ == $user_a->id, $form->find_input('Owner')->possible_values), + 'user A can not own tickets'; + $agent_a->submit; + + $agent_a->content_like(qr/Ticket \d+ created in queue/i, 'created ticket'); + my ($id) = ($agent_a->content =~ /Ticket (\d+) created in queue/); + ok $id, 'found id of the ticket'; + + my $ticket = RT::Ticket->new( $RT::SystemUser ); + $ticket->Load( $id ); + ok $ticket->id, 'loaded the ticket'; + is $ticket->Owner, $RT::Nobody->id, 'correct owner'; +} + +diag "user can chose owner of a new ticket" if $ENV{TEST_VERBOSE}; +{ + $agent_a->get_ok('/', 'open home page'); + $agent_a->form_name('CreateTicketInQueue'); + $agent_a->select( 'Queue', $queue->id ); + $agent_a->submit; + + $agent_a->content_like(qr/Create a new ticket/i, 'opened create ticket page'); + my $form = $agent_a->form_name('TicketCreate'); + is $form->value('Owner'), $RT::Nobody->id, 'correct owner selected'; + + ok grep($_ == $user_b->id, $form->find_input('Owner')->possible_values), + 'user B is listed as potential owner'; + $agent_a->select('Owner', $user_b->id); + $agent_a->submit; + + $agent_a->content_like(qr/Ticket \d+ created in queue/i, 'created ticket'); + my ($id) = ($agent_a->content =~ /Ticket (\d+) created in queue/); + ok $id, 'found id of the ticket'; + + my $ticket = RT::Ticket->new( $RT::SystemUser ); + $ticket->Load( $id ); + ok $ticket->id, 'loaded the ticket'; + is $ticket->Owner, $user_b->id, 'correct owner'; +} + +my $agent_b = RT::Test::Web->new; +ok $agent_b->login('user_b', 'password'), 'logged in as user B'; + +diag "user A can not change owner after create" if $ENV{TEST_VERBOSE}; +{ + my $ticket = RT::Ticket->new( $user_a ); + my ($id, $txn, $msg) = $ticket->Create( + Queue => $queue->id, + Owner => $user_b->id, + Subject => 'test', + ); + ok $id, 'created a ticket #'. $id or diag "error: $msg"; + is $ticket->Owner, $user_b->id, 'correct owner'; + + # try the following group of tests twice with different agents(logins) + my $test_cb = sub { + my $agent = shift; + $agent->goto_ticket( $id ); + $agent->follow_link_ok({text => 'Basics'}, 'Ticket -> Basics'); + my $form = $agent->form_number(3); + is $form->value('Owner'), $user_b->id, 'correct owner selected'; + $agent->select('Owner', $RT::Nobody->id); + $agent->submit; + + $agent->content_like( + qr/Permission denied/i, + 'no way to change owner after create if you have no rights' + ); + + my $ticket = RT::Ticket->new( $RT::SystemUser ); + $ticket->Load( $id ); + ok $ticket->id, 'loaded the ticket'; + is $ticket->Owner, $user_b->id, 'correct owner'; + }; + + $test_cb->($agent_a); + diag "even owner(user B) can not change owner" if $ENV{TEST_VERBOSE}; + $test_cb->($agent_b); +} + +diag "on reply correct owner is selected" if $ENV{TEST_VERBOSE}; +{ + my $ticket = RT::Ticket->new( $user_a ); + my ($id, $txn, $msg) = $ticket->Create( + Queue => $queue->id, + Owner => $user_b->id, + Subject => 'test', + ); + ok $id, 'created a ticket #'. $id or diag "error: $msg"; + is $ticket->Owner, $user_b->id, 'correct owner'; + + $agent_a->goto_ticket( $id ); + $agent_a->follow_link_ok({text => 'Reply'}, 'Ticket -> Basics'); + + my $form = $agent_a->form_number(3); + is $form->value('Owner'), '', 'empty value selected'; + $agent_a->submit; + + $ticket = RT::Ticket->new( $RT::SystemUser ); + $ticket->Load( $id ); + ok $ticket->id, 'loaded the ticket'; + is $ticket->Owner, $user_b->id, 'correct owner'; +} + +ok( RT::Test->set_rights( + { Principal => $user_a, Right => [qw(SeeQueue ShowTicket CreateTicket OwnTicket)] }, + { Principal => $user_b, Right => [qw(SeeQueue ShowTicket OwnTicket)] }, +), 'set rights'); + +diag "Couldn't take without coresponding right" if $ENV{TEST_VERBOSE}; +{ + my $ticket = RT::Ticket->new( $user_a ); + my ($id, $txn, $msg) = $ticket->Create( + Queue => $queue->id, + Subject => 'test', + ); + ok $id, 'created a ticket #'. $id or diag "error: $msg"; + is $ticket->Owner, $RT::Nobody->id, 'correct owner'; + + $agent_a->goto_ticket( $id ); + ok !($agent_a->find_all_links( text => 'Take' ))[0], + 'no Take link'; + ok !($agent_a->find_all_links( text => 'Steal' ))[0], + 'no Steal link as well'; +} + +diag "Couldn't steal without coresponding right" if $ENV{TEST_VERBOSE}; +{ + my $ticket = RT::Ticket->new( $user_a ); + my ($id, $txn, $msg) = $ticket->Create( + Queue => $queue->id, + Owner => $user_b->id, + Subject => 'test', + ); + ok $id, 'created a ticket #'. $id or diag "error: $msg"; + is $ticket->Owner, $user_b->id, 'correct owner'; + + $agent_a->goto_ticket( $id ); + ok !($agent_a->find_all_links( text => 'Steal' ))[0], + 'no Steal link'; + ok !($agent_a->find_all_links( text => 'Take' ))[0], + 'no Take link as well'; +} + +ok( RT::Test->set_rights( + { Principal => $user_a, Right => [qw(SeeQueue ShowTicket CreateTicket TakeTicket)] }, +), 'set rights'); + +diag "TakeTicket require OwnTicket to work" if $ENV{TEST_VERBOSE}; +{ + my $ticket = RT::Ticket->new( $user_a ); + my ($id, $txn, $msg) = $ticket->Create( + Queue => $queue->id, + Subject => 'test', + ); + ok $id, 'created a ticket #'. $id or diag "error: $msg"; + is $ticket->Owner, $RT::Nobody->id, 'correct owner'; + + $agent_a->goto_ticket( $id ); + ok !($agent_a->find_all_links( text => 'Take' ))[0], + 'no Take link'; + ok !($agent_a->find_all_links( text => 'Steal' ))[0], + 'no Steal link as well'; +} + +ok( RT::Test->set_rights( + { Principal => $user_a, Right => [qw(SeeQueue ShowTicket CreateTicket OwnTicket TakeTicket)] }, + { Principal => $user_b, Right => [qw(SeeQueue ShowTicket OwnTicket)] }, +), 'set rights'); + +diag "TakeTicket+OwnTicket work" if $ENV{TEST_VERBOSE}; +{ + my $ticket = RT::Ticket->new( $user_a ); + my ($id, $txn, $msg) = $ticket->Create( + Queue => $queue->id, + Subject => 'test', + ); + ok $id, 'created a ticket #'. $id or diag "error: $msg"; + is $ticket->Owner, $RT::Nobody->id, 'correct owner'; + + $agent_a->goto_ticket( $id ); + ok !($agent_a->find_all_links( text => 'Steal' ))[0], + 'no Steal link'; + $agent_a->follow_link_ok({text => 'Take'}, 'Ticket -> Take'); + + $ticket = RT::Ticket->new( $RT::SystemUser ); + $ticket->Load( $id ); + ok $ticket->id, 'loaded the ticket'; + is $ticket->Owner, $user_a->id, 'correct owner'; +} + +diag "TakeTicket+OwnTicket don't work when owner is not nobody" if $ENV{TEST_VERBOSE}; +{ + my $ticket = RT::Ticket->new( $user_a ); + my ($id, $txn, $msg) = $ticket->Create( + Queue => $queue->id, + Owner => $user_b->id, + Subject => 'test', + ); + ok $id, 'created a ticket #'. $id or diag "error: $msg"; + is $ticket->Owner, $user_b->id, 'correct owner'; + + $agent_a->goto_ticket( $id ); + ok !($agent_a->find_all_links( text => 'Take' ))[0], + 'no Take link'; + ok !($agent_a->find_all_links( text => 'Steal' ))[0], + 'no Steal link too'; +} + +ok( RT::Test->set_rights( + { Principal => $user_a, Right => [qw(SeeQueue ShowTicket CreateTicket StealTicket)] }, + { Principal => $user_b, Right => [qw(SeeQueue ShowTicket OwnTicket)] }, +), 'set rights'); + +diag "StealTicket require OwnTicket to work" if $ENV{TEST_VERBOSE}; +{ + my $ticket = RT::Ticket->new( $user_a ); + my ($id, $txn, $msg) = $ticket->Create( + Queue => $queue->id, + Owner => $user_b->id, + Subject => 'test', + ); + ok $id, 'created a ticket #'. $id or diag "error: $msg"; + is $ticket->Owner, $user_b->id, 'correct owner'; + + $agent_a->goto_ticket( $id ); + ok !($agent_a->find_all_links( text => 'Steal' ))[0], + 'no Steal link'; + ok !($agent_a->find_all_links( text => 'Take' ))[0], + 'no Take link too'; +} + +ok( RT::Test->set_rights( + { Principal => $user_a, Right => [qw(SeeQueue ShowTicket CreateTicket OwnTicket StealTicket)] }, + { Principal => $user_b, Right => [qw(SeeQueue ShowTicket OwnTicket)] }, +), 'set rights'); + +diag "StealTicket+OwnTicket work" if $ENV{TEST_VERBOSE}; +{ + my $ticket = RT::Ticket->new( $user_a ); + my ($id, $txn, $msg) = $ticket->Create( + Queue => $queue->id, + Owner => $user_b->id, + Subject => 'test', + ); + ok $id, 'created a ticket #'. $id or diag "error: $msg"; + is $ticket->Owner, $user_b->id, 'correct owner'; + + $agent_a->goto_ticket( $id ); + ok !($agent_a->find_all_links( text => 'Take' ))[0], + 'but no Take link'; + $agent_a->follow_link_ok({text => 'Steal'}, 'Ticket -> Steal'); + + $ticket = RT::Ticket->new( $RT::SystemUser ); + $ticket->Load( $id ); + ok $ticket->id, 'loaded the ticket'; + is $ticket->Owner, $user_a->id, 'correct owner'; +} + +diag "StealTicket+OwnTicket don't work when owner is nobody" if $ENV{TEST_VERBOSE}; +{ + my $ticket = RT::Ticket->new( $user_a ); + my ($id, $txn, $msg) = $ticket->Create( + Queue => $queue->id, + Subject => 'test', + ); + ok $id, 'created a ticket #'. $id or diag "error: $msg"; + is $ticket->Owner, $RT::Nobody->id, 'correct owner'; + + $agent_a->goto_ticket( $id ); + ok !($agent_a->find_all_links( text => 'Steal' ))[0], + 'no Steal link'; + ok !($agent_a->find_all_links( text => 'Take' ))[0], + 'no Take link as well (no right)'; +} + +ok( RT::Test->set_rights( + { Principal => $user_a, Right => [qw(SeeQueue ShowTicket CreateTicket OwnTicket TakeTicket StealTicket)] }, + { Principal => $user_b, Right => [qw(SeeQueue ShowTicket OwnTicket)] }, +), 'set rights'); + +diag "no Steal link when owner nobody" if $ENV{TEST_VERBOSE}; +{ + my $ticket = RT::Ticket->new( $user_a ); + my ($id, $txn, $msg) = $ticket->Create( + Queue => $queue->id, + Subject => 'test', + ); + ok $id, 'created a ticket #'. $id or diag "error: $msg"; + is $ticket->Owner, $RT::Nobody->id, 'correct owner'; + + $agent_a->goto_ticket( $id ); + ok !($agent_a->find_all_links( text => 'Steal' ))[0], + 'no Steal link'; + ok( ($agent_a->find_all_links( text => 'Take' ))[0], + 'but have Take link'); +} + +diag "no Take link when owner is not nobody" if $ENV{TEST_VERBOSE}; +{ + my $ticket = RT::Ticket->new( $user_a ); + my ($id, $txn, $msg) = $ticket->Create( + Queue => $queue->id, + Owner => $user_b->id, + Subject => 'test', + ); + ok $id, 'created a ticket #'. $id or diag "error: $msg"; + is $ticket->Owner, $user_b->id, 'correct owner'; + + $agent_a->goto_ticket( $id ); + ok !($agent_a->find_all_links( text => 'Take' ))[0], + 'no Take link'; + ok( ($agent_a->find_all_links( text => 'Steal' ))[0], + 'but have Steal link'); +} + diff --git a/rt/t/web/ticket_seen.t b/rt/t/web/ticket_seen.t new file mode 100644 index 000000000..00b2632d8 --- /dev/null +++ b/rt/t/web/ticket_seen.t @@ -0,0 +1,80 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use RT::Test tests => 16; + +my $queue = RT::Test->load_or_create_queue( Name => 'Regression' ); +ok $queue && $queue->id, 'loaded or created queue'; + +my $user_a = RT::Test->load_or_create_user( + Name => 'user_a', Password => 'password', +); +ok $user_a && $user_a->id, 'loaded or created user'; + +my $user_b = RT::Test->load_or_create_user( + Name => 'user_b', Password => 'password', +); +ok $user_b && $user_b->id, 'loaded or created user'; + +ok( RT::Test->set_rights( + { Principal => $user_a, Right => [qw(SeeQueue ShowTicket CreateTicket OwnTicket ModifyTicket)] }, + { Principal => $user_b, Right => [qw(SeeQueue ShowTicket ReplyToTicket)] }, +), 'set rights'); +RT::Test->started_ok; + +my $agent_a = RT::Test::Web->new; +ok $agent_a->login('user_a', 'password'), 'logged in as user A'; + +my $agent_b = RT::Test::Web->new; +ok $agent_b->login('user_b', 'password'), 'logged in as user B'; + +diag "create a ticket for testing" if $ENV{TEST_VERBOSE}; +my $tid; +{ + my $ticket = RT::Ticket->new( $user_a ); + my ($txn, $msg); + ($tid, $txn, $msg) = $ticket->Create( + Queue => $queue->id, + Owner => $user_a->id, + Subject => 'test', + ); + ok $tid, 'created a ticket #'. $tid or diag "error: $msg"; + is $ticket->Owner, $user_a->id, 'correct owner'; +} + +diag "user B adds a message, we check that user A see notification and can clear it" if $ENV{TEST_VERBOSE}; +{ + my $ticket = RT::Ticket->new( $user_b ); + $ticket->Load( $tid ); + ok $ticket->id, 'loaded the ticket'; + + my ($status, $msg) = $ticket->Correspond( Content => 'bla-bla' ); + ok $status, 'added reply' or diag "error: $msg"; + + $agent_a->goto_ticket($tid); + $agent_a->content_like(qr/bla-bla/ims, 'the message on the page'); + + $agent_a->content_like( + qr/unread message/ims, + 'we have not seen something' + ); + + $agent_a->follow_link_ok({text => 'jump to the first unread message and mark all messages as seen'}, 'try to mark all as seen'); + $agent_a->content_like( + qr/Marked all messages as seen/ims, + 'see success message' + ); + + $agent_a->goto_ticket($tid); + $agent_a->content_unlike( + qr/unread message/ims, + 'we have seen everything, so no messages' + ); +} + + + + + diff --git a/rt/t/web/ticket_update_without_content.t b/rt/t/web/ticket_update_without_content.t new file mode 100644 index 000000000..595cb74e9 --- /dev/null +++ b/rt/t/web/ticket_update_without_content.t @@ -0,0 +1,52 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use RT::Test tests => 10; +my ( $url, $m ) = RT::Test->started_ok; + +# merged tickets still show up in search +my $ticket = RT::Ticket->new($RT::SystemUser); +my ( $ret, $msg ) = $ticket->Create( + Subject => 'base ticket' . $$, + Queue => 'general', + Owner => 'root', + Requestor => 'root@localhost', + MIMEObj => MIME::Entity->build( + From => 'root@localhost', + To => 'rt@localhost', + Subject => 'base ticket' . $$, + Data => "", + ), +); +ok( $ret, "ticket created: $msg" ); + +ok( $m->login, 'logged in' ); + +$m->get_ok( $url . "/Ticket/ModifyAll.html?id=" . $ticket->id ); + +$m->submit_form( + form_number => 3, + fields => { Priority => '1', } +); + +$m->content_like(qr/priority changed/i); +$m->content_unlike(qr/message recorded/i); + +my $root = RT::User->new( $RT::SystemUser ); +$root->Load('root'); +( $ret, $msg ) = $root->SetSignature(<<EOF); +best wishes +foo +EOF + +ok( $ret, $msg ); + +$m->get_ok( $url . "/Ticket/ModifyAll.html?id=" . $ticket->id ); + +$m->submit_form( + form_number => 3, + fields => { Priority => '2', } +); +$m->content_like(qr/priority changed/i); +$m->content_unlike(qr/message recorded/i); diff --git a/rt/t/web/unlimited_search.t b/rt/t/web/unlimited_search.t new file mode 100644 index 000000000..d98baaac0 --- /dev/null +++ b/rt/t/web/unlimited_search.t @@ -0,0 +1,41 @@ +#!/usr/bin/perl + +use strict; + +use RT::Test tests => 8; +RT::Test->started_ok; + +my $ticket = RT::Ticket->new($RT::SystemUser); +for ( 1 .. 75 ) { + $ticket->Create( + Subject => 'Ticket ' . $_, + Queue => 'General', + Owner => 'root', + Requestor => 'unlimitedsearch@localhost', + ); +} + +my $agent = RT::Test::Web->new; +ok $agent->login('root', 'password'), 'logged in as root'; + +$agent->get_ok('/Search/Build.html'); +$agent->form_name('BuildQuery'); +$agent->field('idOp', '>'); +$agent->field('ValueOfid', '0'); +$agent->submit('AddClause'); +$agent->form_name('BuildQuery'); +$agent->field('RowsPerPage', '0'); +$agent->submit('DoSearch'); +$agent->follow_link_ok({text=>'Show Results'}); +$agent->content_like(qr/Ticket 75/); + +$agent->follow_link_ok({text=>'New Search'}); +$agent->form_name('BuildQuery'); +$agent->field('idOp', '>'); +$agent->field('ValueOfid', '0'); +$agent->submit('AddClause'); +$agent->form_name('BuildQuery'); +$agent->field('RowsPerPage', '50'); +$agent->submit('DoSearch'); +$agent->follow_link_ok({text=>'Bulk Update'}); +$agent->content_unlike(qr/Ticket 51/); |