summaryrefslogtreecommitdiff
path: root/rt/t/web
diff options
context:
space:
mode:
authorIvan Kohler <ivan@freeside.biz>2015-07-09 22:18:55 -0700
committerIvan Kohler <ivan@freeside.biz>2015-07-09 22:18:55 -0700
commit1c538bfabc2cd31f27067505f0c3d1a46cba6ef0 (patch)
tree96922ad4459eda1e649327fd391d60c58d454c53 /rt/t/web
parent4f5619288413a185e9933088d9dd8c5afbc55dfa (diff)
RT 4.2.11, ticket#13852
Diffstat (limited to 'rt/t/web')
-rw-r--r--rt/t/web/admin_queue_lifecycle.t2
-rw-r--r--rt/t/web/admin_user.t6
-rw-r--r--rt/t/web/articles-links.t2
-rw-r--r--rt/t/web/attachment_dropping.t52
-rw-r--r--rt/t/web/attachment_encoding.t2
-rw-r--r--rt/t/web/attachment_truncation.t53
-rw-r--r--rt/t/web/attachments.t586
-rw-r--r--rt/t/web/basic.t12
-rw-r--r--rt/t/web/basic_auth.t34
-rw-r--r--rt/t/web/case-sensitivity.t4
-rw-r--r--rt/t/web/cf_access.t10
-rw-r--r--rt/t/web/cf_date.t8
-rw-r--r--rt/t/web/cf_datetime.t6
-rw-r--r--rt/t/web/cf_groupings.t277
-rw-r--r--rt/t/web/cf_groupings_user.t110
-rw-r--r--rt/t/web/cf_image.t61
-rw-r--r--rt/t/web/cf_onqueue.t2
-rw-r--r--rt/t/web/cf_pattern.t80
-rw-r--r--rt/t/web/cf_render_type.t2
-rw-r--r--rt/t/web/cf_select_one.t37
-rw-r--r--rt/t/web/cf_textarea.t75
-rw-r--r--rt/t/web/cf_values_class.t2
-rw-r--r--rt/t/web/charting.t51
-rw-r--r--rt/t/web/class_create.t2
-rw-r--r--rt/t/web/command_line.t121
-rw-r--r--rt/t/web/compilation_errors.t10
-rw-r--r--rt/t/web/config_tab_right.t6
-rw-r--r--rt/t/web/crypt-gnupg.t70
-rw-r--r--rt/t/web/csrf.t6
-rw-r--r--rt/t/web/custom_search.t2
-rw-r--r--rt/t/web/dashboards-basics.t30
-rw-r--r--rt/t/web/dashboards-groups.t10
-rw-r--r--rt/t/web/dashboards-in-menu.t85
-rw-r--r--rt/t/web/dashboards-search-cache.t46
-rw-r--r--rt/t/web/gnupg-select-keys-on-create.t16
-rw-r--r--rt/t/web/gnupg-select-keys-on-update.t19
-rw-r--r--rt/t/web/group_create.t2
-rw-r--r--rt/t/web/helpers-http-cache-headers.t8
-rw-r--r--rt/t/web/html/Callbacks/logout.t/NoAuth/Logout.html/ModifyLoginRedirect (renamed from rt/t/web/html/Callbacks/logout.t/NoAuth/Logout.html/Default)0
-rw-r--r--rt/t/web/html_template.t4
-rw-r--r--rt/t/web/install.t173
-rw-r--r--rt/t/web/language_update.t22
-rw-r--r--rt/t/web/login.t5
-rw-r--r--rt/t/web/mobile.t210
-rw-r--r--rt/t/web/offline.t77
-rw-r--r--rt/t/web/offline_messages_utf8.t64
-rw-r--r--rt/t/web/offline_utf8.t53
-rw-r--r--rt/t/web/owner_disabled_group_19221.t4
-rw-r--r--rt/t/web/path-traversal.t23
-rw-r--r--rt/t/web/psgi-wrap.t15
-rw-r--r--rt/t/web/query_builder.t6
-rw-r--r--rt/t/web/query_builder_queue_limits.t30
-rw-r--r--rt/t/web/query_log.t3
-rw-r--r--rt/t/web/queue_create.t2
-rw-r--r--rt/t/web/redirect-after-login.t4
-rw-r--r--rt/t/web/reminder-permissions.t178
-rw-r--r--rt/t/web/reminders.t2
-rw-r--r--rt/t/web/remote_user.t207
-rw-r--r--rt/t/web/rest-search-group.t102
-rw-r--r--rt/t/web/rest-search-queue.t104
-rw-r--r--rt/t/web/rest-search-user.t115
-rw-r--r--rt/t/web/rest.t6
-rw-r--r--rt/t/web/rest_user_cf.t26
-rw-r--r--rt/t/web/richtext-autohandler.t14
-rw-r--r--rt/t/web/rights.t2
-rw-r--r--rt/t/web/rights1.t24
-rw-r--r--rt/t/web/saved_search_chart.t8
-rw-r--r--rt/t/web/saved_search_permissions.t2
-rw-r--r--rt/t/web/scrips.t219
-rw-r--r--rt/t/web/search_bulk_update_links.t4
-rw-r--r--rt/t/web/search_ical.t196
-rw-r--r--rt/t/web/search_rss.t13
-rw-r--r--rt/t/web/search_simple.t4
-rw-r--r--rt/t/web/self_service.t5
-rw-r--r--rt/t/web/simple_search.t (renamed from rt/t/web/googleish_search.t)29
-rw-r--r--rt/t/web/smime/outgoing.t384
-rw-r--r--rt/t/web/squish.t16
-rw-r--r--rt/t/web/static/js/not-by-default.js (renamed from rt/t/web/html/NoAuth/js/not-by-default.js)0
-rw-r--r--rt/t/web/template.t2
-rw-r--r--rt/t/web/ticket-create-utf8.t6
-rw-r--r--rt/t/web/ticket_forward.t72
-rw-r--r--rt/t/web/ticket_links.t6
-rw-r--r--rt/t/web/ticket_modify_all.t33
-rw-r--r--rt/t/web/ticket_modify_people.t14
-rw-r--r--rt/t/web/ticket_owner.t120
-rw-r--r--rt/t/web/ticket_preserve_basics.t110
-rw-r--r--rt/t/web/ticket_txn_content.t4
-rw-r--r--rt/t/web/user_update.t10
-rw-r--r--rt/t/web/walk.t2
89 files changed, 3965 insertions, 676 deletions
diff --git a/rt/t/web/admin_queue_lifecycle.t b/rt/t/web/admin_queue_lifecycle.t
index 295e9ea57..6b8401283 100644
--- a/rt/t/web/admin_queue_lifecycle.t
+++ b/rt/t/web/admin_queue_lifecycle.t
@@ -24,7 +24,7 @@ my $lifecycle_input = $form->find_input('Lifecycle');
is( $lifecycle_input->value, 'default', 'default lifecycle' );
my @lifecycles = sort $lifecycle_input->possible_values;
-is_deeply( \@lifecycles, [qw/approvals default foo/], 'found all lifecycles' );
+is_deeply( \@lifecycles, [qw/default foo/], 'found all lifecycles' );
$m->submit_form();
$m->content_lacks( 'Lifecycle changed from',
diff --git a/rt/t/web/admin_user.t b/rt/t/web/admin_user.t
index 36b9af1b4..dc984eb75 100644
--- a/rt/t/web/admin_user.t
+++ b/rt/t/web/admin_user.t
@@ -27,9 +27,9 @@ diag "test the history page" if $ENV{TEST_VERBOSE};
$m->get_ok( $url . '/Admin/Users/History.html?id=' . $root->id );
$m->content_contains('User created', 'has User created entry');
-diag "test gnupg page" if $ENV{TEST_VERBOSE};
-$m->follow_link_ok( { text => 'GnuPG' } );
-$m->content_contains('GnuPG public key');
+diag "test keys page" if $ENV{TEST_VERBOSE};
+$m->follow_link_ok( { text => 'Private keys' } );
+$m->content_contains('Public key&#40;s&#41; for rt-test@example.com');
$m->content_contains('The key is ultimately trusted');
$m->content_contains('F0CB3B482CFA485680A4A0BDD328035D84881F1B');
$m->content_contains('Tue Aug 07 2007');
diff --git a/rt/t/web/articles-links.t b/rt/t/web/articles-links.t
index eb6de51b3..4aa8f9133 100644
--- a/rt/t/web/articles-links.t
+++ b/rt/t/web/articles-links.t
@@ -44,7 +44,7 @@ $m->click('SubmitTicket');
$m->follow_link_ok({text => 'Links'});
-$m->text_contains('Article ' . $article->id . ': instance of ticket #17421', 'Article appears with its name in the links table');
+$m->text_contains('Article #' . $article->id . ': instance of ticket #17421', 'Article appears with its name in the links table');
my $refers_to = $ticket->RefersTo;
is($refers_to->Count, 1, 'the ticket has a refers-to link');
diff --git a/rt/t/web/attachment_dropping.t b/rt/t/web/attachment_dropping.t
new file mode 100644
index 000000000..466f7a0f0
--- /dev/null
+++ b/rt/t/web/attachment_dropping.t
@@ -0,0 +1,52 @@
+use warnings;
+use strict;
+
+use RT::Test tests => undef;
+use File::Temp 'tempfile';
+
+my $content = 'a' x 1000 . 'b' x 10;
+my ( $fh, $path ) = tempfile( UNLINK => 1, SUFFIX => '.txt' );
+print $fh $content;
+close $fh;
+
+my $name = ( File::Spec->splitpath($path) )[2];
+
+RT->Config->Set( 'WebSessionClass', "Apache::Session::File");
+RT->Config->Set( 'MaxAttachmentSize', 1000 );
+RT->Config->Set( 'TruncateLongAttachments', '0' );
+RT->Config->Set( 'DropLongAttachments', '1' );
+
+my $cf = RT::CustomField->new( RT->SystemUser );
+ok(
+ $cf->Create(
+ Name => 'test truncation',
+ Queue => '0',
+ Type => 'FreeformSingle',
+ ),
+);
+my $cfid = $cf->id;
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in';
+
+my $queue = RT::Test->load_or_create_queue( Name => 'General' );
+ok( $queue->id, "Loaded General queue" );
+$m->get_ok( $baseurl . '/Ticket/Create.html?Queue=' . $queue->id );
+$m->content_contains( "Create a new ticket", 'ticket create page' );
+
+$m->form_name('TicketCreate');
+$m->field( 'Subject', 'Attachments dropping test' );
+$m->field( 'Attach', $path );
+$m->field( 'Content', 'Some content' );
+my $cf_content = 'cf' . 'a' x 998 . 'cfb';
+$m->field( "Object-RT::Ticket--CustomField-$cfid-Value", $cf_content );
+$m->submit;
+is( $m->status, 200, "request successful" );
+
+$m->content_contains( "File '$name' dropped because its size (1010 bytes) exceeded configured maximum size setting (1000 bytes).", 'dropped message' );
+$m->content_lacks( 'cfaaaa', 'cf value was dropped' );
+$m->follow_link_ok( { text => "Download $name" } );
+is( $m->content, 'Large attachment dropped', 'dropped $name' );
+
+undef $m;
+done_testing;
diff --git a/rt/t/web/attachment_encoding.t b/rt/t/web/attachment_encoding.t
index f49720e0f..3f7d6d1cf 100644
--- a/rt/t/web/attachment_encoding.t
+++ b/rt/t/web/attachment_encoding.t
@@ -86,7 +86,7 @@ diag 'test with attachemnts' if $ENV{TEST_VERBOSE};
'-> /Ticket/Attachment/...' );
$m->content_contains( $filename, "has file content $filename" );
- ( $id ) = $m->uri =~ /(\d+)\D+$/;
+ ( $id ) = $m->uri =~ m{/(\d+)/[^/]+$};
ok( $id, 'found attachment id' );
$attachment = RT::Attachment->new( $RT::SystemUser );
ok($attachment->Load($id), "load att $id");
diff --git a/rt/t/web/attachment_truncation.t b/rt/t/web/attachment_truncation.t
new file mode 100644
index 000000000..b60f29e90
--- /dev/null
+++ b/rt/t/web/attachment_truncation.t
@@ -0,0 +1,53 @@
+use warnings;
+use strict;
+
+use RT::Test tests => undef;
+use File::Temp 'tempfile';
+
+my $content = 'a' x 1000 . 'b' x 10;
+my ( $fh, $path ) = tempfile( UNLINK => 1, SUFFIX => '.txt' );
+print $fh $content;
+close $fh;
+my $name = ( File::Spec->splitpath($path) )[2];
+
+RT->Config->Set( 'WebSessionClass', "Apache::Session::File");
+RT->Config->Set( 'MaxAttachmentSize', 1000 );
+RT->Config->Set( 'TruncateLongAttachments', '1' );
+
+my $queue = RT::Test->load_or_create_queue( Name => 'General' );
+ok( $queue->id, "Loaded General queue" );
+
+my $cf = RT::CustomField->new( RT->SystemUser );
+ok(
+ $cf->Create(
+ Name => 'test truncation',
+ Queue => '0',
+ Type => 'FreeformSingle',
+ ),
+);
+my $cfid = $cf->id;
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in';
+
+$m->get_ok( $baseurl . '/Ticket/Create.html?Queue=' . $queue->id );
+$m->content_contains( "Create a new ticket", 'ticket create page' );
+
+$m->form_name('TicketCreate');
+$m->field( 'Subject', 'Attachments test' );
+$m->field( 'Attach', $path );
+$m->field( 'Content', 'Some content' );
+my $cf_content = 'cf' . 'a' x 998 . 'cfb';
+$m->field( "Object-RT::Ticket--CustomField-$cfid-Value", $cf_content );
+$m->submit;
+is( $m->status, 200, "request successful" );
+
+$m->content_contains( "File '$name' truncated because its size (1010 bytes) exceeded configured maximum size setting (1000 bytes).", 'truncated message' );
+$m->content_contains( 'cf' . 'a' x 998, 'has the first 1000 cf chars' );
+$m->content_lacks( 'aaacfb', 'lacks cf chars after that' );
+$m->follow_link_ok( { text => "Download $name" } );
+$m->content_contains( 'a' x 1000, 'has the first 1000 chars' );
+$m->content_lacks( 'b', 'lacks chars after that' );
+
+undef $m;
+done_testing;
diff --git a/rt/t/web/attachments.t b/rt/t/web/attachments.t
index b518ec176..0ae407d7f 100644
--- a/rt/t/web/attachments.t
+++ b/rt/t/web/attachments.t
@@ -1,94 +1,506 @@
use strict;
use warnings;
-use RT::Test tests => 33;
+use RT::Test tests => 159;
-use constant LogoFile => $RT::MasonComponentRoot .'/NoAuth/images/bpslogo.png';
-use constant FaviconFile => $RT::MasonComponentRoot .'/NoAuth/images/favicon.png';
-use constant TextFile => $RT::MasonComponentRoot .'/NoAuth/css/print.css';
+use constant LogoFile => $RT::StaticPath .'/images/bpslogo.png';
+use constant FaviconFile => $RT::StaticPath .'/images/favicon.png';
+use constant TextFile => $RT::StaticPath .'/css/mobile.css';
-my ($baseurl, $m) = RT::Test->started_ok;
+my ($url, $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_contains("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_contains('Attachments test', 'we have subject on the page');
-$m->content_contains('Some content', 'and content');
-$m->content_contains('Download bpslogo.png', 'page has file name');
-
-open LOGO, "<", LogoFile or die "Can't open logo file: $!";
-binmode LOGO;
-my $logo_contents = do {local $/; <LOGO>};
-close LOGO;
-$m->follow_link_ok({text => "Download bpslogo.png"});
-is($m->content_type, "image/png");
-is($m->content, $logo_contents, "Binary content matches");
-
-$m->back;
-$m->follow_link_ok({text => 'Reply'}, "reply to the ticket");
-$m->form_name('TicketUpdate');
-$m->field('Attach', TextFile);
-$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_contains('Download bpslogo.png', 'page has file name');
-$m->content_contains('Download favicon.png', 'page has file name');
-$m->content_contains('Download print.css', 'page has file name');
-
-$m->follow_link_ok( { text => 'Download bpslogo.png' } );
-is( $m->response->header('Content-Type'), 'image/png', 'Content-Type of png lacks charset' );
-
-$m->back;
-
-$m->follow_link_ok( { text => 'Download print.css' } );
-is( $m->response->header('Content-Type'),
- 'text/css;charset=UTF-8', 'Content-Type of text has charset' );
-
-diag "test mobile ui";
-$m->get_ok( $baseurl . '/m/ticket/create?Queue=' . $qid );
-
-$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_contains('Attachments test', 'we have subject on the page');
-$m->content_contains('bpslogo.png', '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_contains('bpslogo.png', 'page has file name');
-$m->content_contains('favicon.png', 'page has file name');
+my $queue = RT::Test->load_or_create_queue( Name => 'General' );
+ok( $queue && $queue->id, "Loaded General queue" );
+
+diag "create a ticket in full interface";
+diag "w/o attachments";
+{
+ $m->goto_create_ticket( $queue );
+ is($m->status, 200, "request successful");
+
+ $m->form_name('TicketCreate');
+ $m->content_contains("Create a new ticket", 'ticket create page');
+ $m->submit;
+ is($m->status, 200, "request successful");
+}
+
+diag "with one attachment";
+{
+ $m->goto_create_ticket( $queue );
+
+ $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_contains('Attachments test', 'we have subject on the page');
+ $m->content_contains('Some content', 'and content');
+ $m->content_contains('Download bpslogo.png', 'page has file name');
+}
+
+diag "with two attachments";
+{
+ $m->goto_create_ticket( $queue );
+
+ $m->form_name('TicketCreate');
+ $m->field('Attach', LogoFile);
+ $m->click('AddMoreAttach');
+ is($m->status, 200, "request successful");
+
+ $m->form_name('TicketCreate');
+ $m->field('Attach', FaviconFile);
+ $m->field('Subject', 'Attachments test');
+ $m->field('Content', 'Some content');
+
+ $m->submit;
+ is($m->status, 200, "request successful");
+
+ $m->content_contains('Attachments test', 'we have subject on the page');
+ $m->content_contains('Some content', 'and content');
+ $m->content_contains('Download bpslogo.png', 'page has file name');
+ $m->content_contains('Download favicon.png', 'page has file name');
+}
+
+diag "with one attachment, but delete one along the way";
+{
+ $m->goto_create_ticket( $queue );
+
+ $m->form_name('TicketCreate');
+ $m->field('Attach', LogoFile);
+ $m->click('AddMoreAttach');
+ is($m->status, 200, "request successful");
+
+ $m->form_name('TicketCreate');
+ $m->field('Attach', FaviconFile);
+ $m->tick( 'DeleteAttach', LogoFile );
+ $m->field('Subject', 'Attachments test');
+ $m->field('Content', 'Some content');
+
+ $m->submit;
+ is($m->status, 200, "request successful");
+
+ $m->content_contains('Attachments test', 'we have subject on the page');
+ $m->content_contains('Some content', 'and content');
+ $m->content_lacks('Download bpslogo.png', 'page has file name');
+ $m->content_contains('Download favicon.png', 'page has file name');
+}
+
+diag "with one attachment, but delete one along the way";
+{
+ $m->goto_create_ticket( $queue );
+
+ $m->form_name('TicketCreate');
+ $m->field('Attach', LogoFile);
+ $m->click('AddMoreAttach');
+ is($m->status, 200, "request successful");
+
+ $m->form_name('TicketCreate');
+ $m->tick( 'DeleteAttach', LogoFile );
+ $m->click('AddMoreAttach');
+ is($m->status, 200, "request successful");
+
+ $m->form_name('TicketCreate');
+ $m->field('Attach', FaviconFile);
+ $m->click('AddMoreAttach');
+ is($m->status, 200, "request successful");
+
+ $m->form_name('TicketCreate');
+ $m->field('Subject', 'Attachments test');
+ $m->field('Content', 'Some content');
+
+ $m->submit;
+ is($m->status, 200, "request successful");
+
+ $m->content_contains('Attachments test', 'we have subject on the page');
+ $m->content_contains('Some content', 'and content');
+ $m->content_lacks('Download bpslogo.png', 'page has file name');
+ $m->content_contains('Download favicon.png', 'page has file name');
+}
+
+diag "reply to a ticket in full interface";
+diag "with one attachment";
+{
+ my $ticket = RT::Test->create_ticket(
+ Queue => $queue,
+ Subject => 'Attachments test',
+ Content => 'Some content',
+ );
+
+ $m->goto_ticket( $ticket->id );
+ $m->follow_link_ok({text => 'Reply'}, "reply to the ticket");
+ $m->form_name('TicketUpdate');
+ $m->field('Attach', LogoFile);
+ $m->field('UpdateContent', 'Message');
+ $m->click('SubmitTicket');
+ is($m->status, 200, "request successful");
+
+ $m->content_contains('Download bpslogo.png', 'page has file name');
+}
+
+diag "with two attachments";
+{
+ my $ticket = RT::Test->create_ticket(
+ Queue => $queue,
+ Subject => 'Attachments test',
+ Content => 'Some content',
+ );
+
+ $m->goto_ticket( $ticket->id );
+ $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_contains('Download bpslogo.png', 'page has file name');
+ $m->content_contains('Download favicon.png', 'page has file name');
+}
+
+diag "with one attachment, delete one along the way";
+{
+ my $ticket = RT::Test->create_ticket(
+ Queue => $queue,
+ Subject => 'Attachments test',
+ Content => 'Some content',
+ );
+
+ $m->goto_ticket( $ticket->id );
+ $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->tick('DeleteAttach', LogoFile);
+ $m->field('Attach', FaviconFile);
+ $m->field('UpdateContent', 'Message');
+ $m->click('SubmitTicket');
+ is($m->status, 200, "request successful");
+
+ $m->content_lacks('Download bpslogo.png', 'page has file name');
+ $m->content_contains('Download favicon.png', 'page has file name');
+}
+
+diag "jumbo interface";
+diag "with one attachment";
+{
+ my $ticket = RT::Test->create_ticket(
+ Queue => $queue,
+ Subject => 'Attachments test',
+ Content => 'Some content',
+ );
+
+ $m->goto_ticket( $ticket->id );
+ $m->follow_link_ok({text => 'Jumbo'}, "jumbo the ticket");
+ $m->form_name('TicketModifyAll');
+ $m->field('Attach', LogoFile);
+ $m->field('UpdateContent', 'Message');
+ $m->click('SubmitTicket');
+ is($m->status, 200, "request successful");
+
+ $m->goto_ticket( $ticket->id );
+ $m->content_contains('Download bpslogo.png', 'page has file name');
+}
+
+diag "with two attachments";
+{
+ my $ticket = RT::Test->create_ticket(
+ Queue => $queue,
+ Subject => 'Attachments test',
+ Content => 'Some content',
+ );
+
+ $m->goto_ticket( $ticket->id );
+ $m->follow_link_ok({text => 'Jumbo'}, "jumbo the ticket");
+ $m->form_name('TicketModifyAll');
+ $m->field('Attach', LogoFile);
+ $m->click('AddMoreAttach');
+ is($m->status, 200, "request successful");
+
+ $m->form_name('TicketModifyAll');
+ $m->field('Attach', FaviconFile);
+ $m->field('UpdateContent', 'Message');
+ $m->click('SubmitTicket');
+ is($m->status, 200, "request successful");
+
+ $m->goto_ticket( $ticket->id );
+ $m->content_contains('Download bpslogo.png', 'page has file name');
+ $m->content_contains('Download favicon.png', 'page has file name');
+}
+
+diag "with one attachment, delete one along the way";
+{
+ my $ticket = RT::Test->create_ticket(
+ Queue => $queue,
+ Subject => 'Attachments test',
+ Content => 'Some content',
+ );
+
+ $m->goto_ticket( $ticket->id );
+ $m->follow_link_ok({text => 'Jumbo'}, "jumbo the ticket");
+ $m->form_name('TicketModifyAll');
+ $m->field('Attach', LogoFile);
+ $m->click('AddMoreAttach');
+ is($m->status, 200, "request successful");
+
+ $m->form_name('TicketModifyAll');
+ $m->tick('DeleteAttach', LogoFile);
+ $m->field('Attach', FaviconFile);
+ $m->field('UpdateContent', 'Message');
+ $m->click('SubmitTicket');
+ is($m->status, 200, "request successful");
+
+ $m->goto_ticket( $ticket->id );
+ $m->content_lacks('Download bpslogo.png', 'page has file name');
+ $m->content_contains('Download favicon.png', 'page has file name');
+}
+
+diag "bulk update";
+diag "one attachment";
+{
+ my @tickets = RT::Test->create_tickets(
+ {
+ Queue => $queue,
+ Subject => 'Attachments test',
+ Content => 'Some content',
+ },
+ {},
+ {},
+ );
+ my $query = join ' OR ', map "id=$_", map $_->id, @tickets;
+ $query =~ s/ /%20/g;
+ $m->get_ok( $url . "/Search/Bulk.html?Query=$query&Rows=10" );
+
+ $m->form_name('BulkUpdate');
+ $m->field('Attach', FaviconFile);
+ $m->field('UpdateContent', 'Message');
+ $m->submit;
+ is($m->status, 200, "request successful");
+
+ foreach my $ticket ( @tickets ) {
+ $m->goto_ticket( $ticket->id );
+ $m->content_lacks('Download bpslogo.png', 'page has file name');
+ $m->content_contains('Download favicon.png', 'page has file name');
+ }
+}
+
+diag "two attachments";
+{
+ my @tickets = RT::Test->create_tickets(
+ {
+ Queue => $queue,
+ Subject => 'Attachments test',
+ Content => 'Some content',
+ },
+ {},
+ {},
+ );
+ my $query = join ' OR ', map "id=$_", map $_->id, @tickets;
+ $query =~ s/ /%20/g;
+ $m->get_ok( $url . "/Search/Bulk.html?Query=$query&Rows=10" );
+
+ $m->form_name('BulkUpdate');
+ $m->field('Attach', LogoFile);
+ $m->click('AddMoreAttach');
+ is($m->status, 200, "request successful");
+
+ $m->form_name('BulkUpdate');
+ $m->field('Attach', FaviconFile);
+ $m->field('UpdateContent', 'Message');
+ $m->submit;
+ is($m->status, 200, "request successful");
+
+ foreach my $ticket ( @tickets ) {
+ $m->goto_ticket( $ticket->id );
+ $m->content_contains('Download bpslogo.png', 'page has file name');
+ $m->content_contains('Download favicon.png', 'page has file name');
+ }
+}
+
+diag "one attachment, delete one along the way";
+{
+ my @tickets = RT::Test->create_tickets(
+ {
+ Queue => $queue,
+ Subject => 'Attachments test',
+ Content => 'Some content',
+ },
+ {},
+ {},
+ );
+ my $query = join ' OR ', map "id=$_", map $_->id, @tickets;
+ $query =~ s/ /%20/g;
+ $m->get_ok( $url . "/Search/Bulk.html?Query=$query&Rows=10" );
+
+ $m->form_name('BulkUpdate');
+ $m->field('Attach', LogoFile);
+ $m->click('AddMoreAttach');
+ is($m->status, 200, "request successful");
+
+ $m->form_name('BulkUpdate');
+ $m->tick('DeleteAttach', LogoFile);
+ $m->field('Attach', FaviconFile);
+ $m->field('UpdateContent', 'Message');
+ $m->submit;
+ is($m->status, 200, "request successful");
+
+ foreach my $ticket ( @tickets ) {
+ $m->goto_ticket( $ticket->id );
+ $m->content_lacks('Download bpslogo.png', 'page has file name');
+ $m->content_contains('Download favicon.png', 'page has file name');
+ }
+}
+
+diag "self service";
+diag "create with attachment";
+{
+ $m->get_ok( $url . "/SelfService/Create.html?Queue=". $queue->id );
+
+ $m->form_name('TicketCreate');
+ $m->field('Attach', FaviconFile);
+ $m->field('Subject', 'Subject');
+ $m->field('Content', 'Message');
+ ok($m->current_form->find_input('AddMoreAttach'), "more than one attachment");
+ $m->submit;
+ is($m->status, 200, "request successful");
+
+ $m->content_contains('Download favicon.png', 'page has file name');
+}
+
+diag "update with attachment";
+{
+ my $ticket = RT::Test->create_ticket(
+ Queue => $queue,
+ Subject => 'Attachments test',
+ Content => 'Some content',
+ );
+
+ $m->get_ok( $url . "/SelfService/Update.html?id=". $ticket->id );
+ $m->form_name('TicketUpdate');
+ $m->field('Attach', FaviconFile);
+ $m->field('UpdateContent', 'Message');
+ ok($m->current_form->find_input('AddMoreAttach'), "more than one attachment");
+ $m->click('SubmitTicket');
+ is($m->status, 200, "request successful");
+
+ $m->content_contains('Download favicon.png', 'page has file name');
+}
+
+diag "mobile ui";
+
+diag "simple create + reply";
+{
+ $m->get_ok( $url . '/m/ticket/create?Queue=' . $queue->id );
+
+ $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_contains('Attachments test', 'we have subject on the page');
+ $m->content_contains('bpslogo.png', '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_contains('bpslogo.png', 'page has file name');
+ $m->content_contains('favicon.png', 'page has file name');
+}
+
+
+diag "check content type and content";
+{
+ $m->goto_create_ticket( $queue );
+
+ $m->form_name('TicketCreate');
+ $m->field('Attach', LogoFile);
+ $m->click('AddMoreAttach');
+ is($m->status, 200, "request successful");
+
+ $m->form_name('TicketCreate');
+ $m->field('Attach', TextFile);
+ $m->field('Subject', 'Attachments test');
+ $m->field('Content', 'Some content');
+
+ $m->submit;
+ is($m->status, 200, "request successful");
+
+ $m->content_contains('Attachments test', 'we have subject on the page');
+ $m->content_contains('Some content', 'and content');
+ $m->content_contains('Download bpslogo.png', 'page has file name');
+ $m->content_contains('Download mobile.css', 'page has file name');
+
+ $m->follow_link_ok({text => "Download bpslogo.png"});
+ is($m->response->header('Content-Type'), 'image/png', 'Content-Type of png lacks charset' );
+ is($m->content_type, "image/png");
+ is($m->content, RT::Test->file_content(LogoFile), "Binary content matches");
+ $m->back;
+
+ $m->follow_link_ok( { text => 'Download mobile.css' } );
+ is( $m->response->header('Content-Type'),
+ 'text/css;charset=UTF-8',
+ 'Content-Type of text has charset',
+ );
+ is($m->content_type, "text/css");
+ is($m->content, RT::Test->file_content(TextFile), "Text content matches");
+}
+
+diag "concurent actions";
+my $m2 = RT::Test::Web->new;
+ok $m2->login, 'second login';
+
+diag "update and create";
+{
+ my $ticket = RT::Test->create_ticket(
+ Queue => $queue,
+ Subject => 'Attachments test',
+ Content => 'Some content',
+ );
+
+ $m2->goto_ticket( $ticket->id );
+ $m2->follow_link_ok({text => 'Reply'}, "reply to the ticket");
+ $m2->form_name('TicketUpdate');
+ $m2->field('Attach', LogoFile);
+ $m2->click('AddMoreAttach');
+ is($m2->status, 200, "request successful");
+
+ $m->goto_create_ticket( $queue );
+
+ $m->form_name('TicketCreate');
+ $m->field('Attach', FaviconFile);
+ $m->field('Subject', 'Attachments test');
+ $m->field('Content', 'Some content');
+ $m->submit;
+ is($m->status, 200, "request successful");
+
+ $m->content_lacks('Download bpslogo.png', 'page has file name');
+ $m->content_contains('Download favicon.png', 'page has file name');
+
+ $m2->form_name('TicketUpdate');
+ $m2->click('SubmitTicket');
+ $m2->content_contains('Download bpslogo.png', 'page has file name');
+ $m2->content_lacks('Download favicon.png', 'page has no file name');
+}
+
diff --git a/rt/t/web/basic.t b/rt/t/web/basic.t
index 02483b208..79c247d24 100644
--- a/rt/t/web/basic.t
+++ b/rt/t/web/basic.t
@@ -2,7 +2,7 @@
use strict;
use warnings;
-use RT::Test tests => 23;
+use RT::Test tests => 24;
my ($baseurl, $agent) = RT::Test->started_ok;
@@ -71,16 +71,15 @@ my $url = $agent->rt_base_url;
fields => { TimeWorked => 5, 'TimeWorked-TimeUnits' => "hours" }
);
- $agent->content_contains("to &#39;300&#39;", "5 hours is 300 minutes");
+ $agent->content_contains("5 hours", "5 hours is displayed");
+ $agent->content_contains("300 min", "but minutes is also");
}
-TODO: {
- todo_skip("Need to handle mason trying to compile images",1);
-$agent->get( $url."NoAuth/images/test.png" );
+$agent->get( $url."static/images/test.png" );
my $file = RT::Test::get_relocatable_file(
File::Spec->catfile(
- qw(.. .. share html NoAuth images test.png)
+ qw(.. .. share static images test.png)
)
);
is(
@@ -88,7 +87,6 @@ is(
-s $file,
"got a file of the correct size ($file)",
);
-}
#
# XXX: hey-ho, we have these tests in t/web/query-builder
diff --git a/rt/t/web/basic_auth.t b/rt/t/web/basic_auth.t
new file mode 100644
index 000000000..ff77f29f2
--- /dev/null
+++ b/rt/t/web/basic_auth.t
@@ -0,0 +1,34 @@
+use strict;
+use warnings;
+use RT;
+use RT::Test tests => 9;
+
+RT->Config->Set( DevelMode => 0 );
+RT->Config->Set( WebRemoteUserAuth => 1 );
+
+my ( $url, $m ) = RT::Test->started_ok( basic_auth => 1 );
+
+# This tests the plack middleware, not RT
+$m->get($url);
+is($m->status, 401, "Initial request with no creds gets 401");
+
+# This tests the plack middleware, not RT
+$m->get($url, $m->auth_header( root => "wrong" ));
+is($m->status, 401, "Request with wrong creds gets 401");
+
+$m->get($url, $m->auth_header( root => "password" ));
+is($m->status, 200, "Request with right creds gets 200");
+
+$m->content_like(
+ qr{<span class="current-user">\Qroot\E</span>}i,
+ "Has user on the page"
+);
+$m->content_unlike(qr/Logout/i, "Has no logout button, no WebFallbackToRTLogin");
+
+# Again, testing the plack middleware
+$m->get($url);
+is($m->status, 401, "Subsequent requests without credentials aren't still logged in");
+
+
+# Put the credentials back for the warnings check at the end
+$m->auth( root => "password" );
diff --git a/rt/t/web/case-sensitivity.t b/rt/t/web/case-sensitivity.t
index 5f40ef690..759937192 100644
--- a/rt/t/web/case-sensitivity.t
+++ b/rt/t/web/case-sensitivity.t
@@ -22,7 +22,7 @@ $m->login;
require JSON;
is_deeply(
JSON::from_json( $m->content ),
- [{"value" => "root\@localhost","label" => "Enoch Root", id=>$root_id}]
+ [{id => 12, "value" => "root\@localhost","label" => "root (Enoch Root)"}]
);
}
@@ -73,7 +73,7 @@ my $cf;
# test custom field values auto completer
{
- $m->get_ok('/Helpers/Autocomplete/CustomFieldValues?term=eNo&Object---CustomField-'. $cf->id .'-Value&ContextId=1&ContextType=RT::Queue');
+ $m->get_ok('/Helpers/Autocomplete/CustomFieldValues?term=eNo&Object-RT::Ticket--CustomField-'. $cf->id .'-Value&ContextId=1&ContextType=RT::Queue');
require JSON;
is_deeply(
JSON::from_json( $m->content ),
diff --git a/rt/t/web/cf_access.t b/rt/t/web/cf_access.t
index 675fa2177..48ab5a21b 100644
--- a/rt/t/web/cf_access.t
+++ b/rt/t/web/cf_access.t
@@ -5,14 +5,14 @@ use RT::Test tests => 32;
my ($baseurl, $m) = RT::Test->started_ok;
-use constant ImageFile => $RT::MasonComponentRoot .'/NoAuth/images/bpslogo.png';
+use constant ImageFile => $RT::StaticPath .'/images/bpslogo.png';
use constant ImageFileContent => RT::Test->file_content(ImageFile);
ok $m->login, 'logged in';
diag "Create a CF";
{
- $m->follow_link( id => 'tools-config-custom-fields-create');
+ $m->follow_link( id => 'admin-custom-fields-create');
# Test form validation
$m->submit_form(
@@ -94,10 +94,10 @@ diag "apply the CF to General queue";
my ( $cf, $cfid, $tid );
{
$m->title_is(q/Editing CustomField img/, 'admin-cf created');
- $m->follow_link( id => 'tools-config-queues');
+ $m->follow_link( id => 'admin-queues');
$m->follow_link( text => 'General' );
$m->title_is(q/Configuration for queue General/, 'admin-queue: general');
- $m->follow_link( id => 'page-ticket-custom-fields');
+ $m->follow_link( id => 'page-custom-fields-tickets');
$m->title_is(q/Custom Fields for queue General/, 'admin-queue: general cfid');
$m->form_name('EditCustomFields');
@@ -215,7 +215,7 @@ diag "create a ticket with an image";
}
$m->get( $m->rt_base_url );
-$m->follow_link( id => 'search-new');
+$m->follow_link( id => 'search-tickets-new');
$m->title_is(q/Query Builder/, 'Query building');
$m->submit_form(
form_name => "BuildQuery",
diff --git a/rt/t/web/cf_date.t b/rt/t/web/cf_date.t
index 2180e140f..a38388972 100644
--- a/rt/t/web/cf_date.t
+++ b/rt/t/web/cf_date.t
@@ -14,7 +14,7 @@ my $cf_name = 'test cf date';
my $cfid;
diag "Create a CF";
{
- $m->follow_link( id => 'tools-config-custom-fields-create');
+ $m->follow_link( id => 'admin-custom-fields-create');
$m->submit_form(
form_name => "ModifyCustomField",
fields => {
@@ -33,12 +33,12 @@ my $queue = RT::Test->load_or_create_queue( Name => 'General' );
ok $queue && $queue->id, 'loaded or created queue';
{
- $m->follow_link( id => 'tools-config-queues-select');
+ $m->follow_link( id => 'admin-queues-select');
$m->title_is( q/Admin queues/, 'admin-queues screen' );
$m->follow_link( text => 'General' );
$m->title_is( q/Configuration for queue General/,
'admin-queue: general' );
- $m->follow_link( text => 'Ticket Custom Fields' );
+ $m->follow_link( id => 'page-custom-fields-tickets' );
$m->title_is( q/Custom Fields for queue General/,
'admin-queue: general cfid' );
@@ -186,7 +186,7 @@ diag 'check invalid inputs';
my @warnings = $m->get_warnings;
chomp @warnings;
- is_deeply( @warnings, q{Couldn't parse date 'foodate' by Time::ParseDate} );
+ is_deeply( [@warnings], [(q{Couldn't parse date 'foodate' by Time::ParseDate})x2] );
}
diag 'retain values when adding attachments';
diff --git a/rt/t/web/cf_datetime.t b/rt/t/web/cf_datetime.t
index 72a8b3f7e..da938ab85 100644
--- a/rt/t/web/cf_datetime.t
+++ b/rt/t/web/cf_datetime.t
@@ -24,7 +24,7 @@ if ( ( $ENV{RT_TEST_WEB_HANDLER} || '' ) =~ /^apache(\+mod_perl)?$/
my $cfid;
diag "Create a CF";
{
- $m->follow_link( id => 'tools-config-custom-fields-create');
+ $m->follow_link( id => 'admin-custom-fields-create');
$m->submit_form(
form_name => "ModifyCustomField",
fields => {
@@ -47,7 +47,7 @@ ok $queue && $queue->id, 'loaded or created queue';
$m->title_is(q/Admin queues/, 'admin-queues screen');
$m->follow_link( text => 'General' );
$m->title_is(q/Configuration for queue General/, 'admin-queue: general');
- $m->follow_link( text => 'Ticket Custom Fields' );
+ $m->follow_link( id => 'page-custom-fields-tickets' );
$m->title_is(q/Custom Fields for queue General/, 'admin-queue: general cfid');
$m->form_name('EditCustomFields');
@@ -212,7 +212,7 @@ diag 'check invalid inputs';
my @warnings = $m->get_warnings;
chomp @warnings;
- is_deeply( @warnings, q{Couldn't parse date 'foodate' by Time::ParseDate} );
+ is_deeply( [@warnings], [(q{Couldn't parse date 'foodate' by Time::ParseDate})x2] );
}
diag 'retain values when adding attachments';
diff --git a/rt/t/web/cf_groupings.t b/rt/t/web/cf_groupings.t
new file mode 100644
index 000000000..0a40f71af
--- /dev/null
+++ b/rt/t/web/cf_groupings.t
@@ -0,0 +1,277 @@
+use strict;
+use warnings;
+
+use RT::Test tests => undef;
+
+my @groupings = qw/Basics Dates People Links More/;
+RT->Config->Set( 'CustomFieldGroupings',
+ 'RT::Ticket' => {
+ map { +($_ => ["Test$_"]) } @groupings,
+ },
+);
+
+my %CF;
+for my $grouping (@groupings) {
+ my $name = "Test$grouping";
+ my $cf = RT::CustomField->new( RT->SystemUser );
+ my ($id, $msg) = $cf->Create(
+ Name => $name,
+ Queue => '0',
+ Description => 'A Testing custom field',
+ Type => 'FreeformSingle',
+ Pattern => '^(?!bad value).*$',
+ );
+ ok $id, "custom field '$name' correctly created";
+ $CF{$grouping} = $id;
+}
+
+my $queue = RT::Test->load_or_create_queue( Name => 'General' );
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in as root';
+
+my %location = (
+ Basics => ".ticket-info-basics",
+ Dates => ".ticket-info-dates",
+ People => "#ticket-create-message",
+ Links => ".ticket-info-links",
+ More => ".ticket-info-cfs",
+);
+{
+ note "testing Create";
+ $m->goto_create_ticket($queue);
+
+ my $prefix = 'Object-RT::Ticket--CustomField:';
+ my $dom = $m->dom;
+ $m->form_name('TicketCreate');
+ $m->field("Subject", "CF grouping test");
+
+ for my $grouping (@groupings) {
+ my $input_name = $prefix . "$grouping-$CF{$grouping}-Value";
+ is $dom->find(qq{input[name="$input_name"]})->size, 1, "only one CF input on the page";
+ ok $dom->at(qq{$location{$grouping} input[name="$input_name"]}), "CF is in the right place";
+ $m->field( $input_name, "Test" . $grouping . "Value" );
+ }
+ $m->submit;
+}
+
+my $id = $m->get_ticket_id;
+{
+ note "testing Display";
+ ok $id, "created a ticket";
+ my $dom = $m->dom;
+
+ $location{People} = ".ticket-info-people";
+ foreach my $grouping (@groupings) {
+ my $row_id = "CF-$CF{$grouping}-ShowRow";
+ is $dom->find(qq{#$row_id})->size, 1, "CF on the page";
+ is $dom->at(qq{#$row_id})->all_text, "Test$grouping: Test${grouping}Value", "value is set";
+ ok $dom->at(qq{$location{$grouping} #$row_id}), "CF is in the right place";
+ }
+}
+
+{
+ note "testing Basics/People/Dates/Links pages";
+ my $prefix = 'Object-RT::Ticket-'. $id .'-CustomField:';
+ { # Basics and More both show up on "Basics"
+ for my $name (qw/Basics More/) {
+ $m->follow_link_ok({id => 'page-basics'}, 'Ticket -> Basics');
+ is $m->dom->find(qq{input[name^="$prefix"][name\$="-Value"]})->size, 2,
+ "two CF inputs on the page";
+
+ my $input_name = "$prefix$name-$CF{$name}-Value";
+ ok $m->dom->at(qq{$location{$name} input[name="$input_name"]}),
+ "CF is in the right place";
+ $m->submit_form_ok({
+ with_fields => { $input_name => "Test${name}Changed" },
+ button => 'SubmitTicket',
+ });
+ $m->content_like(qr{to Test${name}Changed});
+
+ $m->submit_form_ok({
+ with_fields => { $input_name => "bad value" },
+ button => 'SubmitTicket',
+ });
+ $m->content_like(qr{Test\Q$name\E: Input must match});
+ }
+ }
+
+ # Everything else gets its own page
+ foreach my $name ( qw(People Dates Links) ) {
+ $m->follow_link_ok({id => "page-\L$name"}, "Ticket's $name page");
+ is $m->dom->find(qq{input[name^="$prefix"][name\$="-Value"]})->size, 1,
+ "only one CF input on the page";
+ my $input_name = "$prefix$name-$CF{$name}-Value";
+ $m->submit_form_ok({
+ with_fields => { $input_name => "Test${name}Changed" },
+ button => 'SubmitTicket',
+ });
+ $m->content_like(qr{to Test${name}Changed});
+
+ $m->submit_form_ok({
+ with_fields => { $input_name => "bad value" },
+ button => 'SubmitTicket',
+ });
+ $m->content_like(qr{Could not add new custom field value: Input must match});
+ }
+}
+
+{
+ note "testing Jumbo";
+ my $prefix = 'Object-RT::Ticket-'. $id .'-CustomField:';
+ $m->follow_link_ok({id => "page-jumbo"}, "Ticket's Jumbo page");
+ my $dom = $m->dom;
+ $m->form_name("TicketModifyAll");
+
+ foreach my $name ( qw(Basics People Dates Links More) ) {
+ my $input_name = "$prefix$name-$CF{$name}-Value";
+ is $dom->find(qq{input[name="$input_name"]})->size, 1,
+ "only one CF input on the page";
+ $m->field( $input_name, "Test${name}Again" );
+ }
+ $m->click('SubmitTicket');
+ foreach my $name ( qw(Basics People Dates Links More) ) {
+ $m->content_like(qr{to Test${name}Again});
+ }
+}
+
+{
+ note "Reconfigure to place one CF in multiple boxes";
+ $m->no_warnings_ok;
+ RT::Test->stop_server;
+
+ RT->Config->Set( 'CustomFieldGroupings',
+ 'RT::Ticket' => {
+ Basics => [ 'TestMore' ],
+ More => [ 'TestMore' ],
+ },
+ );
+
+ ( $baseurl, $m ) = RT::Test->started_ok;
+ ok $m->login, 'logged in as root';
+}
+
+{
+ note "Testing one CF in multiple boxes";
+ $m->goto_create_ticket($queue);
+
+ my $prefix = 'Object-RT::Ticket--CustomField:';
+ my $dom = $m->dom;
+ $m->form_name('TicketCreate');
+
+ my $cf = $CF{More};
+ is $m->dom->find(qq{input[name^="$prefix"][name\$="-$cf-Value"]})->size, 2,
+ "Two 'More' CF inputs on the page";
+ for my $grouping (qw/Basics More/) {
+ my $input_name = $prefix . "$grouping-$cf-Value";
+ is $dom->find(qq{input[name="$input_name"]})->size, 1, "Found the $grouping grouping";
+ ok $dom->at(qq{$location{$grouping} input[name="$input_name"]}), "CF is in the right place";
+ $m->field( $input_name, "TestMoreValue" );
+ }
+ $m->submit;
+ $m->no_warnings_ok( "Submitting CF with two (identical) values had no warnings" );
+}
+
+$id = $m->get_ticket_id;
+my $ticket = RT::Ticket->new ( RT->SystemUser );
+$ticket->Load( $id );
+is $ticket->CustomFieldValuesAsString( "TestMore", Separator => "|" ), "TestMoreValue",
+ "Value submitted twice is set correctly (and only once)";
+
+my $cf = $CF{More};
+my $prefix = 'Object-RT::Ticket-'. $id .'-CustomField:';
+{
+ note "Updating with multiple appearances of a CF";
+ $m->follow_link_ok({id => 'page-basics'}, 'Ticket -> Basics');
+
+ is $m->dom->find(qq{input[name^="$prefix"][name\$="-$cf-Value"]})->size, 2,
+ "Two 'More' CF inputs on the page";
+ my @inputs;
+ for my $grouping (qw/Basics More/) {
+ my $input_name = "$prefix$grouping-$cf-Value";
+ push @inputs, $input_name;
+ ok $m->dom->at(qq{$location{$grouping} input[name="$input_name"]}),
+ "CF is in the right place";
+ }
+ $m->submit_form_ok({
+ with_fields => {
+ map {+($_ => "TestMoreChanged")} @inputs,
+ },
+ button => 'SubmitTicket',
+ });
+ $m->no_warnings_ok;
+ $m->content_like(qr{to TestMoreChanged});
+
+ $ticket->Load( $id );
+ is $ticket->CustomFieldValuesAsString( "TestMore", Separator => "|" ), "TestMoreChanged",
+ "Updated value submitted twice is set correctly (and only once)";
+}
+
+{
+ note "Updating with _differing_ values in multiple appearances of a CF";
+
+ my %inputs = map {+($_ => "$prefix$_-$cf-Value")} qw/Basics More/;
+ $m->submit_form_ok({
+ with_fields => {
+ $inputs{Basics} => "BasicsValue",
+ $inputs{More} => "MoreValue",
+ },
+ button => 'SubmitTicket',
+ });
+ $m->warning_like(qr{CF $cf submitted with multiple differing values});
+ $m->content_like(qr{to BasicsValue}, "Arbitrarily chose first value");
+
+ $ticket->Load( $id );
+ is $ticket->CustomFieldValuesAsString( "TestMore", Separator => "|" ), "BasicsValue",
+ "Conflicting value submitted twice is set correctly (and only once)";
+}
+
+{
+ note "Configuring CF to be a select-multiple";
+ my $custom_field = RT::CustomField->new( RT->SystemUser );
+ $custom_field->Load( $cf );
+ $custom_field->SetType( "Select" );
+ $custom_field->SetMaxValues( 0 );
+ $custom_field->AddValue( Name => $_ ) for 1..9;
+}
+
+{
+ note "Select multiples do not interfere with each other when appearing multiple times";
+ $m->follow_link_ok({id => 'page-basics'}, 'Ticket -> Basics');
+
+ $m->form_name('TicketModify');
+ my %inputs = map {+($_ => "$prefix$_-$cf-Values")} qw/Basics More/;
+ ok $m->dom->at(qq{select[name="$inputs{Basics}"]}), "Found 'More' CF in Basics box";
+ ok $m->dom->at(qq{select[name="$inputs{More}"]}), "Found 'More' CF in More box";
+
+ $m->select( $inputs{Basics} => [1, 3, 9] );
+ $m->select( $inputs{More} => [1, 3, 9] );
+ $m->click( 'SubmitTicket' );
+ $m->no_warnings_ok;
+ $m->content_like(qr{$_ added as a value for TestMore}) for 1, 3, 9;
+ $m->content_like(qr{BasicsValue is no longer a value for custom field TestMore});
+
+ $ticket->Load( $id );
+ is $ticket->CustomFieldValuesAsString( "TestMore", Separator => "|" ), "1|3|9",
+ "Multi-select values submitted correctly";
+}
+
+{
+ note "Submit multiples correctly choose one set of values when conflicting information is submitted";
+ $m->form_name('TicketModify');
+ my %inputs = map {+($_ => "$prefix$_-$cf-Values")} qw/Basics More/;
+ $m->select( $inputs{Basics} => [2, 3, 4] );
+ $m->select( $inputs{More} => [8, 9] );
+ $m->click( 'SubmitTicket' );
+ $m->warning_like(qr{CF $cf submitted with multiple differing values});
+ $m->content_like(qr{$_ added as a value for TestMore}) for 2, 4;
+ $m->content_unlike(qr{$_ added as a value for TestMore}) for 8;
+ $m->content_like(qr{$_ is no longer a value for custom field TestMore}) for 1, 9;
+
+ $ticket->Load( $id );
+ is $ticket->CustomFieldValuesAsString( "TestMore", Separator => "|" ), "3|2|4",
+ "Multi-select values submitted correctly";
+}
+
+undef $m;
+done_testing;
diff --git a/rt/t/web/cf_groupings_user.t b/rt/t/web/cf_groupings_user.t
new file mode 100644
index 000000000..fe79ae5ad
--- /dev/null
+++ b/rt/t/web/cf_groupings_user.t
@@ -0,0 +1,110 @@
+use strict;
+use warnings;
+
+use RT::Test tests => undef;
+
+RT->Config->Set( 'CustomFieldGroupings',
+ 'RT::User' => {
+ Identity => ['TestIdentity'],
+ 'Access control' => ['TestAccessControl'],
+ Location => ['TestLocation'],
+ Phones => ['TestPhones'],
+ More => ['TestMore'],
+ },
+);
+
+my %CF;
+
+while (my ($group,$cfs) = each %{ RT->Config->Get('CustomFieldGroupings')->{'RT::User'} } ) {
+ my $name = $cfs->[0];
+ my $cf = RT::CustomField->new( RT->SystemUser );
+ my ($id, $msg) = $cf->Create(
+ Name => $name,
+ Description => 'A custom field',
+ LookupType => RT::User->new( $RT::SystemUser )->CustomFieldLookupType,
+ Type => 'FreeformSingle',
+ Pattern => '^(?!bad value).*$',
+ );
+ ok $id, "custom field '$name' correctly created";
+
+ ($id, $msg) = $cf->AddToObject( RT::User->new( $cf->CurrentUser ) );
+ ok $id, "applied custom field" or diag "error: $msg";
+
+ $group =~ s/\W//g;
+ $CF{$name} = "$group-" . $cf->Id;
+}
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in as root';
+
+my %location = (
+ Identity => ".user-info-identity",
+ AccessControl => ".user-info-access-control",
+ Location => ".user-info-location",
+ Phones => ".user-info-phones",
+ More => ".user-info-cfs",
+);
+{
+ note "testing Create";
+ $m->follow_link_ok({id => 'admin-users-create'}, 'Create ');
+
+ my $dom = $m->dom;
+ $m->form_name('UserCreate');
+
+ $m->field( 'Name', 'user1' );
+
+ my $prefix = 'Object-RT::User--CustomField:';
+ for my $name (keys %location) {
+ my $input_name = $prefix . $CF{"Test$name"} .'-Value';
+ is $dom->find(qq{input[name="$input_name"]})->size, 1, "only one CF input on the page";
+ ok $dom->at(qq{$location{$name} input[name="$input_name"]}), "CF is in the right place";
+ $m->field( $input_name, "Test${name}Value" );
+ }
+
+ $m->submit;
+ $m->content_like(qr{User created});
+}
+
+my ($id) = ($m->uri =~ /id=(\d+)/);
+ok $id, "found user's id #$id";
+
+{
+ note "testing values on Modify page and on the object";
+ my $user = RT::User->new( RT->SystemUser );
+ $user->Load( $id );
+ ok $user->id, "loaded user";
+
+ my $dom = $m->dom;
+ $m->form_name('UserModify');
+ my $prefix = "Object-RT::User-$id-CustomField:";
+ foreach my $name ( keys %location ) {
+ is $user->FirstCustomFieldValue("Test$name"), "Test${name}Value",
+ "correct value of Test$name CF";
+ my $input_name = $prefix . $CF{"Test$name"} .'-Value';
+ is $m->value($input_name), "Test${name}Value",
+ "correct value in UI";
+ $m->field( $input_name, "Test${name}Changed" );
+ ok $dom->at(qq{$location{$name} input[name="$input_name"]}), "CF is in the right place";
+ }
+ $m->submit;
+}
+
+{
+ note "testing that update works";
+ my $user = RT::User->new( RT->SystemUser );
+ $user->Load( $id );
+ ok $user->id, "loaded user";
+
+ $m->form_name('UserModify');
+ my $prefix = "Object-RT::User-$id-CustomField:";
+ foreach my $name ( keys %location ) {
+ is $user->FirstCustomFieldValue("Test$name"), "Test${name}Changed",
+ "correct value of Test$name CF";
+ my $input = $prefix . $CF{"Test$name"} .'-Value';
+ is $m->value($input), "Test${name}Changed",
+ "correct value in UI";
+ }
+}
+
+undef $m;
+done_testing;
diff --git a/rt/t/web/cf_image.t b/rt/t/web/cf_image.t
new file mode 100644
index 000000000..355f25968
--- /dev/null
+++ b/rt/t/web/cf_image.t
@@ -0,0 +1,61 @@
+use strict;
+use warnings;
+
+use RT::Test tests => 'no_declare';
+
+my (undef, $m) = RT::Test->started_ok;
+$m->login;
+$m->follow_link( id => 'admin-custom-fields-create' );
+$m->submit_form_ok({
+ form_name => "ModifyCustomField",
+ fields => {
+ Name => 'Images',
+ TypeComposite => 'Image-1',
+ LookupType => 'RT::Queue-RT::Ticket',
+ },
+});
+$m->content_contains("Object created");
+my $cfid = $m->form_name('ModifyCustomField')->value('id');
+ok $cfid, "Created CF correctly";
+
+$m->follow_link_ok( {id => "page-applies-to"} );
+$m->form_with_fields( "AddCustomField-1" );
+$m->tick( "AddCustomField-1", 0 );
+$m->click_ok( "UpdateObjs" );
+$m->content_contains("Object created");
+
+
+$m->submit_form_ok({
+ form_name => "CreateTicketInQueue",
+ fields => { Queue => 'General' },
+});
+$m->content_contains("Upload one image");
+$m->submit_form_ok({
+ form_name => "TicketCreate",
+ fields => {
+ Subject => 'Test ticket',
+ Content => 'test',
+ },
+});
+$m->content_like( qr/Ticket \d+ created/,
+ "a ticket is created succesfully" );
+
+$m->follow_link_ok( {id => "page-basics"} );
+$m->content_contains("Upload one image");
+$m->submit_form_ok({
+ form_name => "TicketModify",
+ fields => {
+ "Object-RT::Ticket-1-CustomField-1-Upload" =>
+ RT::Test::get_relocatable_file('bpslogo.png', '..', 'data'),
+ },
+});
+$m->content_contains("bpslogo.png added");
+$m->content_contains("/Download/CustomFieldValue/1/bpslogo.png");
+
+$m->form_name("TicketModify");
+$m->tick("Object-RT::Ticket-1-CustomField-1-DeleteValueIds", 1);
+$m->click_ok("SubmitTicket");
+$m->content_lacks("/Download/CustomFieldValue/1/bpslogo.png");
+
+undef $m;
+done_testing;
diff --git a/rt/t/web/cf_onqueue.t b/rt/t/web/cf_onqueue.t
index bd6ae66aa..dd3320a25 100644
--- a/rt/t/web/cf_onqueue.t
+++ b/rt/t/web/cf_onqueue.t
@@ -8,7 +8,7 @@ ok $m->login, 'logged in';
diag "Create a queue CF";
{
- $m->follow_link( id => 'tools-config-custom-fields-create');
+ $m->follow_link( id => 'admin-custom-fields-create');
$m->submit_form(
form_name => "ModifyCustomField",
fields => {
diff --git a/rt/t/web/cf_pattern.t b/rt/t/web/cf_pattern.t
new file mode 100644
index 000000000..ff85ec6c7
--- /dev/null
+++ b/rt/t/web/cf_pattern.t
@@ -0,0 +1,80 @@
+use strict;
+use warnings;
+
+use RT::Test tests => 'no_declare';
+
+my ($base, $m) = RT::Test->started_ok;
+
+my $cf = RT::Test->load_or_create_custom_field(
+ Name => 'Yaks',
+ Type => 'FreeformSingle',
+ Pattern => '(?#Digits)^\d+$',
+ Queue => 0,
+ LookupType => 'RT::Queue-RT::Ticket',
+);
+ok $cf && $cf->id, "Created CF with Pattern";
+
+my $ticket = RT::Test->create_ticket(
+ Queue => 1,
+ Subject => 'a test ticket',
+);
+ok $ticket && $ticket->id, "Created ticket";
+
+$m->login;
+
+for my $page ("/Ticket/Create.html?Queue=1", "/Ticket/Modify.html?id=".$ticket->id) {
+ diag $page;
+ $m->get_ok($page, "Fetched $page");
+ $m->content_contains("Yaks");
+ $m->content_contains("Input must match [Digits]");
+ $m->content_lacks("cfinvalidfield");
+
+ my $cfinput = RT::Interface::Web::GetCustomFieldInputName(
+ Object => ( $page =~ /Create/ ? RT::Ticket->new( RT->SystemUser ) : $ticket ),
+ CustomField => $cf,
+ );
+ $m->submit_form_ok({
+ with_fields => {
+ $cfinput => "too many",
+ "${cfinput}-Magic" => "1",
+ },
+ });
+ $m->content_contains("Input must match [Digits]");
+ $m->content_contains("cfinvalidfield");
+
+ $m->submit_form_ok({
+ with_fields => {
+ $cfinput => "42",
+ "${cfinput}-Magic" => "1",
+ },
+ });
+
+ if ($page =~ /Create/) {
+ $m->content_like(qr/Ticket \d+ created/, "Created ticket");
+ } else {
+ $m->content_contains("Yaks 42 added", "Updated ticket");
+ $m->content_contains("Input must match [Digits]");
+ $m->content_lacks("cfinvalidfield");
+ }
+}
+
+diag "Quick ticket creation";
+{
+ $m->get_ok("/");
+ $m->submit_form_ok({
+ with_fields => {
+ Subject => "test quick create",
+ QuickCreate => 1,
+ },
+ });
+ my $tickets = RT::Tickets->new(RT->SystemUser);
+ $tickets->FromSQL("Subject = 'test quick create'");
+ is $tickets->Count, 0, "No ticket created";
+
+ like $m->uri, qr/Ticket\/Create\.html/, "Redirected to the ticket create page";
+ $m->content_contains("Yaks: Input must match", "Found CF validation error");
+ $m->content_contains("test quick create", "Found prefilled Subject");
+}
+
+undef $m;
+done_testing;
diff --git a/rt/t/web/cf_render_type.t b/rt/t/web/cf_render_type.t
index 8d8efa897..42efb32bc 100644
--- a/rt/t/web/cf_render_type.t
+++ b/rt/t/web/cf_render_type.t
@@ -11,7 +11,7 @@ my $cf_name = 'test render type';
my $cfid;
diag "Create a CF";
{
- $m->follow_link( id => 'tools-config-custom-fields-create');
+ $m->follow_link( id => 'admin-custom-fields-create');
$m->submit_form(
form_name => "ModifyCustomField",
fields => {
diff --git a/rt/t/web/cf_select_one.t b/rt/t/web/cf_select_one.t
index 92fcf53f3..4f81e2a1a 100644
--- a/rt/t/web/cf_select_one.t
+++ b/rt/t/web/cf_select_one.t
@@ -2,7 +2,7 @@
use strict;
use warnings;
-use RT::Test tests => 45;
+use RT::Test tests => undef;
my ($baseurl, $m) = RT::Test->started_ok;
ok $m->login, 'logged in as root';
@@ -12,7 +12,7 @@ my $cf_name = 'test select one value';
my $cfid;
diag "Create a CF";
{
- $m->follow_link( id => 'tools-config-custom-fields-create');
+ $m->follow_link( id => 'admin-custom-fields-create');
$m->submit_form(
form_name => "ModifyCustomField",
fields => {
@@ -49,10 +49,10 @@ ok $queue && $queue->id, 'loaded or created queue';
diag "apply the CF to General queue";
{
- $m->follow_link( id => 'tools-config-queues');
+ $m->follow_link( id => 'admin-queues');
$m->follow_link( text => 'General' );
$m->title_is(q/Configuration for queue General/, 'admin-queue: general');
- $m->follow_link( id => 'page-ticket-custom-fields');
+ $m->follow_link( id => 'page-custom-fields-tickets');
$m->title_is(q/Custom Fields for queue General/, 'admin-queue: general cfid');
$m->form_name('EditCustomFields');
@@ -151,3 +151,32 @@ diag "check that we can set empty value when the current is 0";
undef, 'API returns correct value';
}
+diag 'retain selected cf values when adding attachments';
+{
+ my ( $ticket, $id );
+ $m->submit_form(
+ form_name => "CreateTicketInQueue",
+ fields => { Queue => 'General' },
+ );
+ $m->content_contains($cf_name, 'Found cf field' );
+
+ $m->submit_form_ok(
+ { form_name => "TicketCreate",
+ fields => {
+ Subject => 'test defaults',
+ Content => 'test',
+ "Object-RT::Ticket--CustomField-$cfid-Values" => 'qwe',
+ },
+ button => 'AddMoreAttach',
+ },
+ 'Add an attachment on create'
+ );
+
+ $m->form_name("TicketCreate");
+ is($m->value("Object-RT::Ticket--CustomField-$cfid-Values"),
+ "qwe",
+ "Selected value still on form" );
+}
+
+undef $m;
+done_testing;
diff --git a/rt/t/web/cf_textarea.t b/rt/t/web/cf_textarea.t
new file mode 100644
index 000000000..d11bda4d5
--- /dev/null
+++ b/rt/t/web/cf_textarea.t
@@ -0,0 +1,75 @@
+use strict;
+use warnings;
+
+use RT::Test tests => 'no_declare';
+
+my $content = join ' ', ('The quick brown fox jumps over the lazy dog.') x 5;
+$content = join "\n\n", $content, $content, $content;
+
+my ($base, $m) = RT::Test->started_ok;
+
+$m->login;
+
+my $ticket = RT::Test->create_ticket(
+ Queue => 1,
+ Subject => 'a test ticket',
+);
+ok $ticket && $ticket->id, "Created ticket";
+
+my $EditUrl = "/Ticket/Modify.html?id=" . $ticket->id;
+
+my $cfs = {
+ area => {
+ type => 'Text',
+ name => 'TheTextarea',
+ },
+ text => {
+ type => 'FreeformSingle',
+ name => 'TheControlField',
+ },
+};
+
+while ( my( $label, $data ) = each %$cfs ) {
+ my $cf = $data->{obj} = RT::Test->load_or_create_custom_field(
+ Name => $data->{name},
+ Type => $data->{type},
+ Queue => 0,
+ LookupType => 'RT::Queue-RT::Ticket',
+ );
+ ok $cf && $cf->id, "Created $data->{type} CF";
+
+ # get cf input field name
+ $data->{input} = RT::Interface::Web::GetCustomFieldInputName(
+ Object => $ticket,
+ CustomField => $cf,
+ );
+}
+
+# open ticket "Basics" page
+$m->get_ok($EditUrl, "Fetched $EditUrl");
+$m->content_contains($_->{name} . ':') for ( values %$cfs );
+
+$m->submit_form_ok({
+ with_fields => {
+ $cfs->{area}{input} => $content,
+ $cfs->{area}{input} . '-Magic' => "1",
+ $cfs->{text}{input} => 'value a',
+ $cfs->{text}{input} . '-Magic' => "1",
+ },
+}, 'submitted form to initially set CFs');
+$m->content_contains('<li>TheControlField value a added</li>');
+$m->content_contains("<li>TheTextarea $content added</li>", 'content found');
+
+# http://issues.bestpractical.com/Ticket/Display.html?id=30378
+# #30378: RT 4.2.6 - Very long text fields get updated even when they haven't changed
+$m->submit_form_ok({
+ with_fields => {
+ $cfs->{text}{input} => 'value b',
+ $cfs->{text}{input} . '-Magic' => "1",
+ },
+}, 'submitted form to initially set CFs');
+$m->content_contains('<li>TheControlField value a changed to value b</li>');
+$m->content_lacks("<li>TheTextarea $content changed to $content</li>", 'textarea wasnt updated');
+
+undef $m;
+done_testing;
diff --git a/rt/t/web/cf_values_class.t b/rt/t/web/cf_values_class.t
index 646642781..6535c505b 100644
--- a/rt/t/web/cf_values_class.t
+++ b/rt/t/web/cf_values_class.t
@@ -14,7 +14,7 @@ my $cf_name = 'test values class';
my $cfid;
diag "Create a CF";
{
- $m->follow_link( id => 'tools-config-custom-fields-create');
+ $m->follow_link( id => 'admin-custom-fields-create');
$m->submit_form(
form_name => "ModifyCustomField",
fields => {
diff --git a/rt/t/web/charting.t b/rt/t/web/charting.t
index e19ec41ae..5131f9cef 100644
--- a/rt/t/web/charting.t
+++ b/rt/t/web/charting.t
@@ -1,16 +1,10 @@
use strict;
use warnings;
-BEGIN {
- require RT::Test;
-
- if (eval { require GD; 1 }) {
- RT::Test->import(plan => 'no_plan');
- }
- else {
- RT::Test->import(skip_all => 'GD required.');
- }
-}
+use RT::Test tests => undef;
+
+plan skip_all => 'GD required'
+ unless GD->require;
for my $n (1..7) {
my $ticket = RT::Ticket->new( RT->SystemUser );
@@ -35,8 +29,8 @@ ok( $m->login, "Logged in" );
# Test that defaults work
$m->get_ok( "/Search/Chart.html?Query=id>0" );
-$m->content_like(qr{<th[^>]*>Queue\s*</th>\s*<th[^>]*>Tickets\s*</th>}, "Grouped by queue");
-$m->content_like(qr{General</a>\s*</td>\s*<td[^>]*>\s*<a[^>]*>7</a>}, "Found results in table");
+$m->content_like(qr{<th[^>]*>Status\s*</th>\s*<th[^>]*>Ticket count\s*</th>}, "Grouped by status");
+$m->content_like(qr{new\s*</th>\s*<td[^>]*>\s*<a[^>]*>7</a>}, "Found results in table");
$m->content_like(qr{<img src="/Search/Chart\?}, "Found image");
$m->get_ok( "/Search/Chart?Query=id>0" );
@@ -45,35 +39,41 @@ ok( length($m->content), "Has content" );
# Group by Queue
-$m->get_ok( "/Search/Chart.html?Query=id>0&PrimaryGroupBy=Queue" );
-$m->content_like(qr{<th[^>]*>Queue\s*</th>\s*<th[^>]*>Tickets\s*</th>}, "Grouped by queue");
-$m->content_like(qr{General</a>\s*</td>\s*<td[^>]*>\s*<a[^>]*>7</a>}, "Found results in table");
+$m->get_ok( "/Search/Chart.html?Query=id>0&GroupBy=Queue" );
+$m->content_like(qr{<th[^>]*>Queue\s*</th>\s*<th[^>]*>Ticket count\s*</th>}, "Grouped by queue");
+$m->content_like(qr{General\s*</th>\s*<td[^>]*>\s*<a[^>]*>7</a>}, "Found results in table");
$m->content_like(qr{<img src="/Search/Chart\?}, "Found image");
-$m->get_ok( "/Search/Chart?Query=id>0&PrimaryGroupBy=Queue" );
+$m->get_ok( "/Search/Chart?Query=id>0&GroupBy=Queue" );
is( $m->content_type, "image/png" );
ok( length($m->content), "Has content" );
# Group by Requestor email
-$m->get_ok( "/Search/Chart.html?Query=id>0&PrimaryGroupBy=Requestor.EmailAddress" );
-$m->content_like(qr{<th[^>]*>Requestor\.EmailAddress\s*</th>\s*<th[^>]*>Tickets\s*</th>},
+$m->get_ok( "/Search/Chart.html?Query=id>0&GroupBy=Requestor.EmailAddress" );
+$m->content_like(qr{<th[^>]*>Requestor\s+EmailAddress</th>\s*<th[^>]*>Ticket count\s*</th>},
"Grouped by requestor");
-$m->content_like(qr{root0\@localhost</a>\s*</td>\s*<td[^>]*>\s*<a[^>]*>3</a>}, "Found results in table");
+$m->content_like(qr{root0\@localhost\s*</th>\s*<td[^>]*>\s*<a[^>]*>3</a>}, "Found results in table");
$m->content_like(qr{<img src="/Search/Chart\?}, "Found image");
-$m->get_ok( "/Search/Chart?Query=id>0&PrimaryGroupBy=Requestor.Email" );
+$m->get_ok( "/Search/Chart?Query=id>0&GroupBy=Requestor.EmailAddress" );
is( $m->content_type, "image/png" );
ok( length($m->content), "Has content" );
-
# Group by Requestor phone -- which is bogus, and falls back to queue
-$m->get_ok( "/Search/Chart.html?Query=id>0&PrimaryGroupBy=Requestor.Phone" );
-$m->content_like(qr{General</a>\s*</td>\s*<td[^>]*>\s*<a[^>]*>7</a>},
+
+$m->get_ok( "/Search/Chart.html?Query=id>0&GroupBy=Requestor.Phone" );
+$m->warning_like( qr{'Requestor\.Phone' is not a valid grouping for reports} );
+
+TODO: {
+ local $TODO = "UI should show that it's group by status";
+ $m->content_like(qr{new\s*</th>\s*<td[^>]*>\s*<a[^>]*>7</a>},
"Found queue results in table, as a default");
+}
$m->content_like(qr{<img src="/Search/Chart\?}, "Found image");
-$m->get_ok( "/Search/Chart?Query=id>0&PrimaryGroupBy=Requestor.Phone" );
+$m->get_ok( "/Search/Chart?Query=id>0&GroupBy=Requestor.Phone" );
+$m->warning_like( qr{'Requestor\.Phone' is not a valid grouping for reports} );
is( $m->content_type, "image/png" );
ok( length($m->content), "Has content" );
@@ -93,3 +93,6 @@ $advanced = $m->find_link( text => 'Advanced' )->URI->equery;
like( $advanced, qr{Query=id%3E0},
'Advanced link still has Query param with id search'
);
+
+undef $m;
+done_testing;
diff --git a/rt/t/web/class_create.t b/rt/t/web/class_create.t
index 2d9ad035d..7723d7aa9 100644
--- a/rt/t/web/class_create.t
+++ b/rt/t/web/class_create.t
@@ -13,7 +13,7 @@ my $class_name = 'test class';
my $class_id;
diag "Create a class";
{
- $m->follow_link( id => 'tools-config-articles-classes-create');
+ $m->follow_link( id => 'admin-articles-classes-create');
# Test class form validation
$m->submit_form(
diff --git a/rt/t/web/command_line.t b/rt/t/web/command_line.t
index a5c52d261..47f672856 100644
--- a/rt/t/web/command_line.t
+++ b/rt/t/web/command_line.t
@@ -111,11 +111,11 @@ 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");
+ expect_like(qr/Comments added/, "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");
+ expect_like(qr/Correspondence added/, "Added the correspondence");
### should test to make sure it actually got added
my $test_email = RT::Test::get_relocatable_file('lorem-ipsum',
@@ -124,7 +124,7 @@ ok($val,$msg);
# text attachment
check_attachment($test_email);
# binary attachment
- check_attachment($RT::MasonComponentRoot.'/NoAuth/images/bpslogo.png');
+ check_attachment($RT::StaticPath . '/images/bpslogo.png');
# change a ticket's Owner
expect_send("edit ticket/$ticket_id set owner=root", 'Changing owner...');
@@ -158,7 +158,7 @@ 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_like(qr/Queue nonexistent-$$ 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');
@@ -213,7 +213,7 @@ 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/\QCF.{myCF$$}\E: 1,2,3/i, 'Verified change');
-expect_send("edit ticket/$ticket_id set CF-myCF$$=\"1's,2,3\"", 'Changing CF...');
+expect_send(qq{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/\QCF.{myCF$$}\E: 1's,2,3/i, 'Verified change');
@@ -238,32 +238,85 @@ 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/\QCF.{MultipleCF$$}\E: 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/\QCF.{MultipleCF$$}\E: '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/\QCF.{MultipleCF$$}\E: 'a,b,c'/i, 'Verified change');
+sub multi_round_trip {
+ my ($op, $value, $regex) = @_;
+ $Test::Builder::Level++;
+ # The outer double quotes are for the argument parsing that the
+ # command-line does; the extra layer of escaping is to for them, as
+ # well. It is equivilent to the quoting that the shell would
+ # require.
+ my $quoted = $value;
+ $quoted =~ s/(["\\])/\\$1/g;
+ expect_send(qq{edit ticket/$ticket_id $op CF.{MultipleCF$$}="$quoted"}, qq{CF $op $value});
+ expect_like(qr/Ticket $ticket_id updated/, qq{Got expected "updated" answer});
+ expect_send(qq{show ticket/$ticket_id -f CF.{MultipleCF$$}}, qq{Sent "show"});
+ expect_like(qr/\QCF.{MultipleCF$$}\E: $regex$/i, qq{Answer matches $regex});
+}
-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/\QCF.{MultipleCF$$}\E: '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/\QCF.{MultipleCF$$}\E: 'a,b,c'/i, 'Verified change');
-expect_send("edit ticket/$ticket_id del CF.{MultipleCF$$}=\"'a,b,c'\"", 'Changing CF...');
+# Test simple quoting
+my $ticket = RT::Ticket->new($RT::SystemUser);
+$ticket->Load($ticket_id);
+multi_round_trip(set => q|'a,b,c'|, qr/'a,b,c'/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 1, "Has only one CF value");
+is($ticket->FirstCustomFieldValue("MultipleCF$$"), q{a,b,c}, "And that CF value is as expected");
+
+multi_round_trip(del => q|a|, qr/'a,b,c'/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 1, "Still has only one CF value");
+is($ticket->FirstCustomFieldValue("MultipleCF$$"), q{a,b,c}, "And that CF value is as expected");
+
+multi_round_trip(set => q|q{a,b,c}|, qr/'a,b,c'/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 1, "Still has only one CF value");
+is($ticket->FirstCustomFieldValue("MultipleCF$$"), q{a,b,c}, "And that CF value is as expected");
+
+multi_round_trip(del => q|a|, qr/'a,b,c'/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 1, "Still has only one CF value");
+is($ticket->FirstCustomFieldValue("MultipleCF$$"), q{a,b,c}, "And that CF value is as expected");
+
+multi_round_trip(del => q|'a,b,c'|, qr/\s*/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 0, "Now has no CF values");
+
+multi_round_trip(set => q|q{1,2's,3}|, qr/'1,2\\'s,3'/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 1, "Still has only one CF value");
+is($ticket->FirstCustomFieldValue("MultipleCF$$"), q{1,2's,3}, "And that CF value is as expected");
+
+multi_round_trip(del => q|q{1,2's,3}|, qr/\s*/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 0, "Now has no CF values");
+
+# Test escaping of quotes - generate (foo)(bar') with no escapes
+multi_round_trip(set => q|'foo',bar'|, qr/foo,bar'/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 2, "Has two values");
+is($ticket->CustomFieldValues("MultipleCF$$")->First->Content, q|foo|, "Direct value checks out");
+is($ticket->CustomFieldValues("MultipleCF$$")->Last->Content, q|bar'|, "Direct value checks out");
+multi_round_trip(del => q|bar'|, qr/foo/);
+
+# With one \, generate (foo',bar)
+
+# We obviously need two \s in the following q|| string in order to
+# generate a string with one actual \ in it; this causes the string to,
+# in general, have twice as many \s in it as we wish to test.
+multi_round_trip(set => q|'foo\\',bar'|, qr/'foo\\',bar'/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 1, "Has one value");
+is($ticket->CustomFieldValues("MultipleCF$$")->First->Content, q|foo',bar|, "Direct value checks out");
+
+# With two \, generate (foo\)(bar')
+multi_round_trip(set => q|'foo\\\\',bar'|, qr/foo\\,bar'/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 2, "Has two values");
+is($ticket->CustomFieldValues("MultipleCF$$")->First->Content, q|foo\\|, "Direct value checks out");
+is($ticket->CustomFieldValues("MultipleCF$$")->Last->Content, q|bar'|, "Direct value checks out");
+multi_round_trip(del => q|bar'|, qr/foo\\/);
+
+# With three \, generate (foo\',bar)
+multi_round_trip(set => q|'foo\\\\\\',bar'|, qr/'foo\\\\\\',bar'/);
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 1, "Has one value");
+is($ticket->CustomFieldValues("MultipleCF$$")->First->Content, q|foo\\',bar|, "Direct value checks out");
+
+# Check that we don't infinite-loop on 'foo'bar,baz; this should be ('foo'bar)(baz)
+expect_send("edit ticket/$ticket_id set CF.{MultipleCF$$}=\"'foo'bar,baz\"", 'Changing CF to have quotes not at commas');
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/\QCF.{MultipleCF$$}\E: \s*$/i, 'Verified change');
+is($ticket->CustomFieldValues("MultipleCF$$")->Count, 2, "Has two value");
+is($ticket->CustomFieldValues("MultipleCF$$")->First->Content, q|'foo'bar|, "Direct value checks out");
+is($ticket->CustomFieldValues("MultipleCF$$")->Last->Content, q|baz|, "Direct value checks out");
-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/\QCF.{MultipleCF$$}\E: '1,2\\'s,3'/i, 'Verified change');
# ...
# change a ticket's ...[other properties]...
@@ -401,9 +454,9 @@ expect_send("merge $merge_ticket_B $merge_ticket_A", 'Merging the tickets...');
expect_like(qr/Merge completed/, 'Merged the tickets');
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_like(qr/Merged into #$merge_ticket_A: CLIMergeTest1-$$ 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');
+expect_like(qr/Merged into #$merge_ticket_A: CLIMergeTest1-$$ by root/, 'Merge recorded in second ticket');
{
# create a user; give them privileges to take and steal
@@ -522,7 +575,7 @@ 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_like(qr/Comments added/, "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");
@@ -536,7 +589,11 @@ sub check_attachment {
TODO: {
local $TODO = "Binary PNG content is getting mangled somewhere along the way"
if $attachment_path =~ /\.png$/;
- expect_is($attachment_content,"Attachment contains original text");
+ is(
+ MIME::Base64::encode_base64(Test::Expect::before()),
+ MIME::Base64::encode_base64($attachment_content),
+ "Attachment contains original text"
+ );
}
}
diff --git a/rt/t/web/compilation_errors.t b/rt/t/web/compilation_errors.t
index 126d33691..e4845e0de 100644
--- a/rt/t/web/compilation_errors.t
+++ b/rt/t/web/compilation_errors.t
@@ -6,7 +6,7 @@ BEGIN {
sub wanted {
-f && /\.html$/ && $_ !~ /Logout.html$/ && $File::Find::dir !~ /RichText/;
}
- my $tests = 8;
+ my $tests = 7;
find( sub { wanted() and $tests += 4 }, 'share/html/' );
plan tests => $tests + 1; # plus one for warnings check
}
@@ -36,12 +36,10 @@ is($agent->status, 200, "Fetched the page ok");
$agent->content_contains('Logout', "Found a logout link");
-find ( sub { wanted() and test_get($agent, $File::Find::name) } , 'share/html/');
+find ( { wanted => sub { wanted() and test_get($agent, $File::Find::name) }, no_chdir => 1 } , 'share/html/');
-TODO: {
- local $TODO = "we spew *lots* of undef warnings";
- $agent->no_warnings_ok;
-};
+# We expect to spew a lot of warnings; toss them away
+$agent->get_warnings;
sub test_get {
my $agent = shift;
diff --git a/rt/t/web/config_tab_right.t b/rt/t/web/config_tab_right.t
index 69bf80c69..df146903a 100644
--- a/rt/t/web/config_tab_right.t
+++ b/rt/t/web/config_tab_right.t
@@ -19,7 +19,7 @@ my ($baseurl, $m) = RT::Test->started_ok;
ok $m->login($uname, $upass), "logged in";
{
- $m->content_lacks('Configuration', 'no configuration tab');
+ $m->content_lacks('li-admin', 'no Admin tab');
$m->get('/Admin/');
is $m->status, 403, 'no access to /Admin/';
}
@@ -32,9 +32,9 @@ RT::Test->set_rights(
{
$m->get('/');
- $m->content_contains('Configuration', 'configuration tab is there');
+ $m->content_contains('li-admin', 'admin tab is there');
- $m->follow_link_ok({text => 'Configuration'});
+ $m->follow_link_ok({text => 'Admin'});
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
index 85e090cbc..995b45d99 100644
--- a/rt/t/web/crypt-gnupg.t
+++ b/rt/t/web/crypt-gnupg.t
@@ -2,7 +2,7 @@ use strict;
use warnings;
use RT::Test::GnuPG
- tests => 104,
+ tests => undef,
gnupg_options => {
passphrase => 'recipient',
'trust-model' => 'always',
@@ -17,9 +17,9 @@ 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',
+ 'OO-__Owner__-O',
'OR-__Requestors__-O',
- 'KO-__KeyOwnerName__-K',
+ 'KO-__KeyOwner__-K',
'KR-__KeyRequestors__-K',
Status});
@@ -101,7 +101,7 @@ MAIL
my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef};
is( $msg->GetHeader('X-RT-Privacy'),
- 'PGP',
+ 'GnuPG',
"RT's outgoing mail has crypto"
);
is( $msg->GetHeader('X-RT-Incoming-Encryption'),
@@ -169,7 +169,7 @@ MAIL
my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef};
is( $msg->GetHeader('X-RT-Privacy'),
- 'PGP',
+ 'GnuPG',
"RT's outgoing mail has crypto"
);
is( $msg->GetHeader('X-RT-Incoming-Encryption'),
@@ -241,7 +241,7 @@ MAIL
my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef};
is( $msg->GetHeader('X-RT-Privacy'),
- 'PGP',
+ 'GnuPG',
"RT's outgoing mail has crypto"
);
is( $msg->GetHeader('X-RT-Incoming-Encryption'),
@@ -307,7 +307,7 @@ MAIL
my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef};
is( $msg->GetHeader('X-RT-Privacy'),
- 'PGP',
+ 'GnuPG',
"RT's outgoing mail has crypto"
);
is( $msg->GetHeader('X-RT-Incoming-Encryption'),
@@ -351,8 +351,13 @@ $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);
+warning_like {
+ $tick->Create(Subject => 'owner lacks pubkey', Queue => 'general',
+ Owner => $nokey);
+} [
+ qr/nokey\@example.com: skipped: public key not found/,
+ qr/Recipient 'nokey\@example.com' is unusable/,
+];
ok(my $id = $tick->id, 'created ticket for owner-without-pubkey');
$tick = RT::Ticket->new( RT->SystemUser );
@@ -426,25 +431,36 @@ $m->get("$baseurl/Search/Simple.html?q=General");
my $content = $m->content;
$content =~ s/&#40;/(/g;
$content =~ s/&#41;/)/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");
+$content =~ s/<(a|span)\b[^>]+>//g;
+$content =~ s/<\/(a|span)>//g;
+$content =~ s/&lt;/</g;
+$content =~ s/&gt;/>/g;
+
+like($content, qr/OO-Nobody in particular-O/,
+ "original Owner untouched");
+like($content, qr/OO-nokey-O/,
+ "original Owner untouched");
+like($content, qr/OO-root \(Enoch Root\)-O/,
+ "original Owner untouched");
+like($content, qr/OR-<recipient\@example\.com>-O/,
+ "original Requestors untouched");
+like($content, qr/OR-nokey-O/,
+ "original Requestors untouched");
+
+like($content, qr/KO-Nobody in particular \(no pubkey!\)-K/,
+ "KeyOwner issues no-pubkey warning for nobody");
+like($content, qr/KO-nokey \(no pubkey!\)-K/,
+ "KeyOwner issues no-pubkey warning for root");
+like($content, qr/KO-root \(Enoch Root\)-K/,
+ "KeyOwner does not issue no-pubkey warning for recipient");
+like($content, qr/KR-<recipient\@example\.com>-K/,
+ "KeyRequestors does not issue no-pubkey warning for recipient\@example.com");
+like($content, qr/KR-nokey \(no pubkey!\)-K/,
+ "KeyRequestors DOES issue no-pubkey warning for nokey\@example.com");
$m->next_warning_like(qr/public key not found/);
-$m->next_warning_like(qr/above error may result from an unconfigured RT\/GPG/);
$m->next_warning_like(qr/public key not found/);
-$m->next_warning_like(qr/above error may result from an unconfigured RT\/GPG/);
$m->no_leftover_warnings_ok;
+
+undef $m;
+done_testing;
diff --git a/rt/t/web/csrf.t b/rt/t/web/csrf.t
index 24aae40a1..9d95d0685 100644
--- a/rt/t/web/csrf.t
+++ b/rt/t/web/csrf.t
@@ -99,9 +99,9 @@ $m->title_is('Possible cross-site request forgery');
my $link = $m->find_link(text_regex => qr{resume your request});
(my $broken_url = $link->url) =~ s/(CSRF_Token)=\w+/$1=crud/;
$m->get_ok($broken_url);
-$m->content_contains("Queue could not be loaded");
+$m->content_like(qr/Queue\s+could not be loaded/);
$m->title_is('RT Error');
-$m->warning_like(qr/Queue could not be loaded/);
+$m->warning_like(qr/Queue\s+could not be loaded/);
# The token doesn't work for other pages, or other arguments to the same page.
$m->add_header(Referer => undef);
@@ -134,7 +134,7 @@ $m->content_contains("Create a new ticket", 'ticket create page');
$m->form_name('TicketCreate');
$m->field('Subject', 'Attachments test');
-my $logofile = "$RT::MasonComponentRoot/NoAuth/images/bpslogo.png";
+my $logofile = "$RT::StaticPath/images/bpslogo.png";
open LOGO, "<", $logofile or die "Can't open logo file: $!";
binmode LOGO;
my $logo_contents = do {local $/; <LOGO>};
diff --git a/rt/t/web/custom_search.t b/rt/t/web/custom_search.t
index bf7d659cd..75f832d30 100644
--- a/rt/t/web/custom_search.t
+++ b/rt/t/web/custom_search.t
@@ -11,7 +11,7 @@ my $url = $m->rt_base_url;
my $t = RT::Ticket->new(RT->SystemUser);
$t->Create(Subject => 'for custom search'.$$, Queue => 'general',
- Owner => 'root', Requestor => 'customsearch@localhost');
+ Owner => 'root', Requestor => 'customsearch@localhost');
ok(my $id = $t->id, 'created ticket for custom search');
ok $m->login, 'logged in';
diff --git a/rt/t/web/dashboards-basics.t b/rt/t/web/dashboards-basics.t
index edb706810..c3533a3f1 100644
--- a/rt/t/web/dashboards-basics.t
+++ b/rt/t/web/dashboards-basics.t
@@ -41,24 +41,24 @@ $m->content_lacks('<a href="/Dashboards/Modify.html?Create=1">New</a>',
$m->no_warnings_ok;
$m->get_ok($url."Dashboards/Modify.html?Create=1");
-$m->content_contains("Permission denied");
+$m->content_contains("Permission Denied");
$m->content_lacks("Save Changes");
-$m->warning_like(qr/Permission denied/, "got a permission denied warning");
+$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_contains("Permission Denied");
$m->content_lacks("Save Changes");
-$m->warning_like(qr/Permission denied/, "got a permission denied warning");
+$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_lacks("Permission Denied");
$m->content_contains("Create");
$m->get_ok($url."Dashboards/index.html");
@@ -72,12 +72,12 @@ $m->content_contains("Saved dashboard different dashboard");
$user_obj->PrincipalObj->GrantRight(Right => 'SeeOwnDashboard', Object => $RT::System);
$m->get($url."Dashboards/index.html");
$m->follow_link_ok({ text => 'different dashboard'});
-$m->content_lacks("Permission denied", "we now have SeeOwnDashboard");
+$m->content_lacks("Permission Denied", "we now have SeeOwnDashboard");
$m->content_lacks('Delete', "Delete button hidden because we lack DeleteOwnDashboard");
$m->get_ok($url."Dashboards/index.html");
$m->content_contains("different dashboard", "we now have SeeOwnDashboard");
-$m->content_lacks("Permission denied");
+$m->content_lacks("Permission Denied");
$m->follow_link_ok({text => "different dashboard"});
$m->content_contains("Basics");
@@ -132,9 +132,9 @@ like($searches[1]->Name, qr/highest priority tickets I own/, "correct new search
my $ticket = RT::Ticket->new(RT->SystemUser);
$ticket->Create(
Queue => $queue->Id,
- Requestor => [ $user_obj->Name ],
- Owner => $user_obj,
- Subject => 'dashboard test',
+ Requestor => [ $user_obj->Name ],
+ Owner => $user_obj,
+ Subject => 'dashboard test',
);
$m->follow_link_ok({id => 'page-show'});
@@ -154,8 +154,8 @@ $m->content_contains("dashboard test", "ticket subject");
$m->get_ok("/Dashboards/Subscription.html?id=$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");
+$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");
$user_obj->Attributes->RedoSearch;
is($user_obj->Attributes->Named('Subscription'), 0, "no subscriptions");
@@ -172,7 +172,7 @@ $m->content_unlike( qr/Bookmarked Tickets.*Bookmarked Tickets/s,
$m->form_name('SubscribeDashboard');
$m->click_button(name => 'Save');
-$m->content_lacks("Permission denied");
+$m->content_lacks("Permission Denied");
$m->content_contains("Subscribed to dashboard different dashboard");
$user_obj->Attributes->RedoSearch;
@@ -183,9 +183,9 @@ $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->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");
+$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);
diff --git a/rt/t/web/dashboards-groups.t b/rt/t/web/dashboards-groups.t
index db2fccf1c..9f1c37deb 100644
--- a/rt/t/web/dashboards-groups.t
+++ b/rt/t/web/dashboards-groups.t
@@ -79,7 +79,7 @@ $m->form_name('ModifyDashboard');
$m->field("Name" => 'inner dashboard');
$m->field("Privacy" => "RT::Group-" . $inner_group->Id);
$m->click_button(value => 'Create');
-$m->content_lacks("Permission denied", "we now have SeeGroupDashboard");
+$m->content_lacks("Permission Denied", "we now have SeeGroupDashboard");
$m->content_contains("Saved dashboard inner dashboard");
$m->content_lacks('Delete', "Delete button hidden because we lack DeleteDashboard");
@@ -95,15 +95,15 @@ is($dashboard->PossibleHiddenSearches, 0, "all searches are visible");
$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_lacks("Permission Denied");
$m->content_contains('Subscription', "Subscription link not hidden because we have SubscribeDashboard");
$m->get_ok("/Dashboards/index.html");
$m->content_contains("inner dashboard", "We can see the inner dashboard from the UI");
-$m->get_ok("/index.html");
-$m->content_contains("inner dashboard", "We can see the inner dashboard from the menu drop-down");
+$m->get_ok("/Prefs/DashboardsInMenu.html");
+$m->content_contains("inner dashboard", "Can also see it in the menu options");
my ($group) = grep {$_->isa("RT::Group") and $_->Id == $inner_group->Id}
RT::Dashboard->new($currentuser)->_PrivacyObjects;
@@ -191,5 +191,5 @@ is_deeply(
$m->get_ok("/Dashboards/index.html");
$m->content_contains("inner dashboard", "The dashboards list includes superuser rights");
-$m->get_ok("/index.html");
+$m->get_ok("/Prefs/DashboardsInMenu.html");
$m->content_lacks("inner dashboard", "But the menu skips them");
diff --git a/rt/t/web/dashboards-in-menu.t b/rt/t/web/dashboards-in-menu.t
new file mode 100644
index 000000000..3126d55c3
--- /dev/null
+++ b/rt/t/web/dashboards-in-menu.t
@@ -0,0 +1,85 @@
+use strict;
+use warnings;
+
+use RT::Test tests => 31;
+my ($baseurl, $m) = RT::Test->started_ok;
+
+my $system_foo = RT::Dashboard->new($RT::SystemUser);
+$system_foo->Save(
+ Name => 'system foo',
+ Privacy => 'RT::System-' . $RT::System->id,
+);
+
+my $system_bar = RT::Dashboard->new($RT::SystemUser);
+$system_bar->Save(
+ Name => 'system bar',
+ Privacy => 'RT::System-' . $RT::System->id,
+);
+
+ok( $m->login(), "logged in" );
+
+diag "global setting";
+# in case "RT at a glance" contains dashboards stuff.
+$m->get_ok( $baseurl . "/Search/Simple.html" );
+ok( !$m->find_link( text => 'system foo' ), 'no system foo link' );
+$m->get_ok( $baseurl."/Admin/Global/DashboardsInMenu.html");
+
+my $form_name = 'SelectionBox-dashboards_in_menu';
+$m->form_name($form_name);
+
+$m->field('dashboards_in_menu-Available' => [$system_foo->id],);
+$m->click_button(name => 'add');
+$m->content_contains('Global dashboards in menu saved.', 'saved');
+
+$m->logout;
+ok( $m->login(), "relogged in" );
+
+$m->get_ok( $baseurl . "/Search/Simple.html" );
+$m->follow_link_ok( { text => 'system foo' }, 'follow system foo link' );
+$m->title_is( 'system foo Dashboard', 'got system foo dashboard page' );
+
+diag "setting in admin users";
+my $root = RT::CurrentUser->new( $RT::SystemUser );
+ok( $root->Load('root') );
+my $self_foo = RT::Dashboard->new($root);
+$self_foo->Save( Name => 'self foo', Privacy => 'RT::User-' . $root->id );
+my $self_bar = RT::Dashboard->new($root);
+$self_bar->Save( Name => 'self bar', Privacy => 'RT::User-' . $root->id );
+
+ok( !$m->find_link( text => 'self foo' ), 'no self foo link' );
+$m->get_ok( $baseurl."/Admin/Users/DashboardsInMenu.html?id=" . $root->id);
+$m->form_name($form_name);
+$m->field('dashboards_in_menu-Available' => [$self_foo->id]);
+$m->click_button(name => 'add');
+$m->content_contains( 'Preferences saved for dashboards in menu.',
+ 'prefs saved' );
+$m->form_name($form_name);
+$m->field('dashboards_in_menu-Selected' => [$system_foo->id]);
+$m->content_contains( 'Preferences saved for dashboards in menu.',
+ 'prefs saved' );
+$m->click_button(name => 'remove');
+
+$m->logout;
+ok( $m->login(), "relogged in" );
+$m->get_ok( $baseurl . "/Search/Simple.html" );
+ok( !$m->find_link( text => 'system foo' ), 'no system foo link' );
+$m->follow_link_ok( { text => 'self foo' }, 'follow self foo link' );
+$m->title_is( 'self foo Dashboard', 'got self foo dashboard page' );
+
+diag "setting in prefs";
+$m->get_ok( $baseurl."/Prefs/DashboardsInMenu.html");
+$m->form_name($form_name);
+$m->field('dashboards_in_menu-Available' => [$self_bar->id]);
+$m->click_button(name => 'add');
+$m->content_contains( 'Preferences saved for dashboards in menu.',
+ 'prefs saved' );
+$m->follow_link_ok( { text => 'self bar' }, 'follow self bar link' );
+$m->title_is( 'self bar Dashboard', 'got self bar dashboard page' );
+$m->get_ok( $baseurl."/Prefs/DashboardsInMenu.html");
+$m->form_with_fields('Reset');
+$m->click;
+$m->content_contains( 'Preferences saved', 'prefs saved' );
+ok( $m->find_link( text => 'system foo' ), 'got system foo link' );
+ok( !$m->find_link( text => 'self foo' ), 'no self foo link' );
+ok( !$m->find_link( text => 'self bar' ), 'no self bar link' );
+
diff --git a/rt/t/web/dashboards-search-cache.t b/rt/t/web/dashboards-search-cache.t
index 517e26ee6..18989d54e 100644
--- a/rt/t/web/dashboards-search-cache.t
+++ b/rt/t/web/dashboards-search-cache.t
@@ -1,7 +1,7 @@
use strict;
use warnings;
-use RT::Test tests => 20;
+use RT::Test tests => 33;
my ($baseurl, $m) = RT::Test->started_ok;
my $url = $m->rt_base_url;
@@ -20,6 +20,16 @@ $m->form_name('BuildQuery');
$m->field(SavedSearchDescription => 'Original Name');
$m->click('SavedSearchSave');
+# create the inner dashboard
+$m->get_ok("$url/Dashboards/Modify.html?Create=1");
+$m->form_name('ModifyDashboard');
+$m->field('Name' => 'inner dashboard');
+$m->click_button(value => 'Create');
+$m->text_contains('Saved dashboard inner dashboard');
+
+my ($inner_id) = $m->content =~ /name="id" value="(\d+)"/;
+ok($inner_id, "got an ID, $inner_id");
+
# create a dashboard
$m->get_ok("$url/Dashboards/Modify.html?Create=1");
$m->form_name('ModifyDashboard');
@@ -34,16 +44,28 @@ ok($dashboard_id, "got an ID, $dashboard_id");
$m->follow_link_ok({text => 'Content'});
my $form = $m->form_name('Dashboard-Searches-body');
my @input = $form->find_input('Searches-body-Available');
-my ($search) =
+my ($search_value) =
map { ( $_->possible_values )[1] }
grep { ( $_->value_names )[1] =~ /Saved Search: Original Name/ } @input;
-$form->value('Searches-body-Available' => $search );
+$form->value('Searches-body-Available' => $search_value );
+$m->click_button(name => 'add');
+$m->text_contains('Dashboard updated');
+
+# add the dashboard to the dashboard
+$m->follow_link_ok({text => 'Content'});
+$form = $m->form_name('Dashboard-Searches-body');
+@input = $form->find_input('Searches-body-Available');
+my ($dashboard_value) =
+ map { ( $_->possible_values )[1] }
+ grep { ( $_->value_names )[1] =~ /Dashboard: inner dashboard/ } @input;
+$form->value('Searches-body-Available' => $dashboard_value );
$m->click_button(name => 'add');
$m->text_contains('Dashboard updated');
# subscribe to the dashboard
$m->follow_link_ok({text => 'Subscription'});
$m->text_contains('Saved Search: Original Name');
+$m->text_contains('Dashboard: inner dashboard');
$m->form_name('SubscribeDashboard');
$m->click_button(name => 'Save');
$m->text_contains('Subscribed to dashboard cachey dashboard');
@@ -52,10 +74,10 @@ $m->text_contains('Subscribed to dashboard cachey dashboard');
$m->follow_link_ok({text => 'Tickets'}, 'to query builder');
$form = $m->form_name('BuildQuery');
@input = $form->find_input('SavedSearchLoad');
-($search) =
+($search_value) =
map { ( $_->possible_values )[1] }
grep { ( $_->value_names )[1] =~ /Original Name/ } @input;
-$form->value('SavedSearchLoad' => $search );
+$form->value('SavedSearchLoad' => $search_value );
$m->click_button(value => 'Load');
$m->text_contains('Loaded saved search "Original Name"');
@@ -64,10 +86,24 @@ $m->field('SavedSearchDescription' => 'New Name');
$m->click_button(value => 'Update');
$m->text_contains('Updated saved search "New Name"');
+# rename the dashboard
+$m->get_ok("/Dashboards/Modify.html?id=$inner_id");
+$m->form_name('ModifyDashboard');
+$m->field('Name' => 'recursive dashboard');
+$m->click_button(value => 'Save Changes');
+$m->text_contains('Dashboard recursive dashboard updated');
+
# check subscription page again
$m->get_ok("/Dashboards/Subscription.html?id=$dashboard_id");
TODO: {
local $TODO = 'we cache search names too aggressively';
$m->text_contains('Saved Search: New Name');
$m->text_unlike(qr/Saved Search: Original Name/); # t-w-m lacks text_lacks
+
+ $m->text_contains('Dashboard: recursive dashboard');
+ $m->text_unlike(qr/Dashboard: inner dashboard/); # t-w-m lacks text_lacks
}
+
+$m->get_ok("/Dashboards/Render.html?id=$dashboard_id");
+$m->text_contains('New Name');
+$m->text_unlike(qr/Original Name/); # t-w-m lacks text_lacks
diff --git a/rt/t/web/gnupg-select-keys-on-create.t b/rt/t/web/gnupg-select-keys-on-create.t
index 8c1ae448c..e30b264d9 100644
--- a/rt/t/web/gnupg-select-keys-on-create.t
+++ b/rt/t/web/gnupg-select-keys-on-create.t
@@ -1,7 +1,7 @@
use strict;
use warnings;
-use RT::Test::GnuPG tests => 83, gnupg_options => { passphrase => 'rt-test' };
+use RT::Test::GnuPG tests => 79, gnupg_options => { passphrase => 'rt-test' };
use RT::Action::SendEmail;
my $queue = RT::Test->load_or_create_queue(
@@ -37,7 +37,7 @@ diag "check that signing doesn't work if there is no key";
{
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');
+ my %res = RT::Crypt->GetKeysInfo( Key => 'rt-recipient@example.com' );
is $res{'info'}[0]{'TrustTerse'}, 'ultimate', 'ultimately trusted key';
}
@@ -66,11 +66,7 @@ diag "check that things don't work if there is no key";
my @mail = RT::Test->fetch_caught_mails;
ok !@mail, 'there are no outgoing emails';
- for (1 .. 4) {
- $m->next_warning_like(qr/public key not found/) ;
- $m->next_warning_like(qr/above error may result from an unconfigured RT\/GPG/);
- }
-
+ $m->next_warning_like(qr/public key not found/) for 1 .. 4;
$m->no_leftover_warnings_ok;
}
@@ -78,7 +74,7 @@ diag "import first key of rt-test\@example.com";
my $fpr1 = '';
{
RT::Test->import_gnupg_key('rt-test@example.com', 'public');
- my %res = RT::Crypt::GnuPG::GetKeysInfo('rt-test@example.com');
+ my %res = RT::Crypt->GetKeysInfo( Key => 'rt-test@example.com' );
is $res{'info'}[0]{'TrustLevel'}, 0, 'is not trusted key';
$fpr1 = $res{'info'}[0]{'Fingerprint'};
}
@@ -127,7 +123,7 @@ diag "import a second key of rt-test\@example.com";
my $fpr2 = '';
{
RT::Test->import_gnupg_key('rt-test@example.com.2', 'public');
- my %res = RT::Crypt::GnuPG::GetKeysInfo('rt-test@example.com');
+ my %res = RT::Crypt->GetKeysInfo( Key => 'rt-test@example.com' );
is $res{'info'}[1]{'TrustLevel'}, 0, 'is not trusted key';
$fpr2 = $res{'info'}[2]{'Fingerprint'};
}
@@ -174,7 +170,7 @@ diag "check that things still doesn't work if two keys are not trusted";
{
RT::Test->lsign_gnupg_key( $fpr1 );
- my %res = RT::Crypt::GnuPG::GetKeysInfo('rt-test@example.com');
+ my %res = RT::Crypt->GetKeysInfo( Key => 'rt-test@example.com' );
ok $res{'info'}[0]{'TrustLevel'} > 0, 'trusted key';
is $res{'info'}[1]{'TrustLevel'}, 0, 'is not trusted key';
}
diff --git a/rt/t/web/gnupg-select-keys-on-update.t b/rt/t/web/gnupg-select-keys-on-update.t
index a5b01d3ae..a666851db 100644
--- a/rt/t/web/gnupg-select-keys-on-update.t
+++ b/rt/t/web/gnupg-select-keys-on-update.t
@@ -1,7 +1,7 @@
use strict;
use warnings;
-use RT::Test::GnuPG tests => 88, gnupg_options => { passphrase => 'rt-test' };
+use RT::Test::GnuPG tests => 86, gnupg_options => { passphrase => 'rt-test' };
use RT::Action::SendEmail;
@@ -52,7 +52,7 @@ diag "check that signing doesn't work if there is no key";
{
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');
+ my %res = RT::Crypt->GetKeysInfo( Key => 'rt-recipient@example.com' );
is $res{'info'}[0]{'TrustTerse'}, 'ultimate', 'ultimately trusted key';
}
@@ -82,10 +82,7 @@ diag "check that things don't work if there is no key";
my @mail = RT::Test->fetch_caught_mails;
ok !@mail, 'there are no outgoing emails';
- for (1 .. 2) {
- $m->next_warning_like(qr/public key not found/);
- $m->next_warning_like(qr/above error may result from an unconfigured RT\/GPG/);
- }
+ $m->next_warning_like(qr/public key not found/) for 1 .. 2;
$m->no_leftover_warnings_ok;
}
@@ -94,7 +91,7 @@ diag "import first key of rt-test\@example.com";
my $fpr1 = '';
{
RT::Test->import_gnupg_key('rt-test@example.com', 'public');
- my %res = RT::Crypt::GnuPG::GetKeysInfo('rt-test@example.com');
+ my %res = RT::Crypt->GetKeysInfo( Key => 'rt-test@example.com' );
is $res{'info'}[0]{'TrustLevel'}, 0, 'is not trusted key';
$fpr1 = $res{'info'}[0]{'Fingerprint'};
}
@@ -144,7 +141,7 @@ diag "import a second key of rt-test\@example.com";
my $fpr2 = '';
{
RT::Test->import_gnupg_key('rt-test@example.com.2', 'public');
- my %res = RT::Crypt::GnuPG::GetKeysInfo('rt-test@example.com');
+ my %res = RT::Crypt->GetKeysInfo( Key => 'rt-test@example.com' );
is $res{'info'}[1]{'TrustLevel'}, 0, 'is not trusted key';
$fpr2 = $res{'info'}[2]{'Fingerprint'};
}
@@ -192,7 +189,7 @@ diag "check that things still doesn't work if two keys are not trusted";
{
RT::Test->lsign_gnupg_key( $fpr1 );
- my %res = RT::Crypt::GnuPG::GetKeysInfo('rt-test@example.com');
+ my %res = RT::Crypt->GetKeysInfo( Key => 'rt-test@example.com' );
ok $res{'info'}[0]{'TrustLevel'} > 0, 'trusted key';
is $res{'info'}[1]{'TrustLevel'}, 0, 'is not trusted key';
}
@@ -253,7 +250,7 @@ diag "check that key selector works and we can select trusted key";
$m->select( 'UseKey-rt-test@example.com' => $fpr1 );
$m->click('SubmitTicket');
- $m->content_contains('Message recorded', 'Message recorded' );
+ $m->content_contains('Correspondence added', 'Correspondence added' );
my @mail = RT::Test->fetch_caught_mails;
ok @mail, 'there are some emails';
@@ -289,7 +286,7 @@ diag "check encrypting of attachments";
$m->select( 'UseKey-rt-test@example.com' => $fpr1 );
$m->click('SubmitTicket');
- $m->content_contains('Message recorded', 'Message recorded' );
+ $m->content_contains('Correspondence added', 'Correspondence added' );
my @mail = RT::Test->fetch_caught_mails;
ok @mail, 'there are some emails';
diff --git a/rt/t/web/group_create.t b/rt/t/web/group_create.t
index 548970d2d..f62e56595 100644
--- a/rt/t/web/group_create.t
+++ b/rt/t/web/group_create.t
@@ -13,7 +13,7 @@ my $group_name = 'test group';
my $group_id;
diag "Create a group";
{
- $m->follow_link( id => 'tools-config-groups-create');
+ $m->follow_link( id => 'admin-groups-create');
# Test group form validation
$m->submit_form(
diff --git a/rt/t/web/helpers-http-cache-headers.t b/rt/t/web/helpers-http-cache-headers.t
index 1731e9d17..1020832ca 100644
--- a/rt/t/web/helpers-http-cache-headers.t
+++ b/rt/t/web/helpers-http-cache-headers.t
@@ -23,10 +23,14 @@ ok $m->login, 'logged in';
my $docroot = join '/', qw(share html);
# find endpoints to loop over
-my @endpoints = ('/NoAuth/css/print.css');
+my @endpoints = (
+ "/NoAuth/css/aileron/squished-".("0"x32).".css",
+ '/static/images/bpslogo.png',
+);
find({
wanted => sub {
if ( -f $_ && $_ !~ m|autohandler$| ) {
+ return if m{/\.[^/]+\.sw[op]$}; # vim swap files
( my $endpoint = $_ ) =~ s|^$docroot||;
push @endpoints, $endpoint;
}
@@ -76,7 +80,7 @@ foreach my $endpoint ( @endpoints ) {
my $header_key = 'default';
if ( $endpoint =~ m|Autocomplete| ) {
$header_key = 'Autocomplete';
- } elsif ( $endpoint =~ m|NoAuth| ) {
+ } elsif ( $endpoint =~ m/NoAuth|static/ ) {
$header_key = 'NoAuth';
}
my $headers = $expected->{$header_key};
diff --git a/rt/t/web/html/Callbacks/logout.t/NoAuth/Logout.html/Default b/rt/t/web/html/Callbacks/logout.t/NoAuth/Logout.html/ModifyLoginRedirect
index 90278ae49..90278ae49 100644
--- a/rt/t/web/html/Callbacks/logout.t/NoAuth/Logout.html/Default
+++ b/rt/t/web/html/Callbacks/logout.t/NoAuth/Logout.html/ModifyLoginRedirect
diff --git a/rt/t/web/html_template.t b/rt/t/web/html_template.t
index a2764556f..108d83fa1 100644
--- a/rt/t/web/html_template.t
+++ b/rt/t/web/html_template.t
@@ -13,8 +13,8 @@ my $template = Encode::decode("UTF-8", "你好 éèà€");
my $subject = Encode::decode("UTF-8", "标题");
my $content = Encode::decode("UTF-8", "测试");
{
- $m->follow_link_ok( { id => 'tools-config-global-templates' }, '-> Templates' );
- $m->follow_link_ok( { text => 'Autoreply' }, '-> Autoreply' );
+ $m->follow_link_ok( { id => 'admin-global-templates' }, '-> Templates' );
+ $m->follow_link_ok( { text => 'Autoreply in HTML' }, '-> Autoreply in HTML' );
$m->submit_form(
form_name => 'ModifyTemplate',
diff --git a/rt/t/web/install.t b/rt/t/web/install.t
new file mode 100644
index 000000000..e33e58b16
--- /dev/null
+++ b/rt/t/web/install.t
@@ -0,0 +1,173 @@
+use strict;
+use warnings;
+use File::Spec;
+
+$ENV{RT_TEST_WEB_HANDLER} = 'plack+rt-server';
+use RT::Test
+ tests => undef,
+ nodb => 1,
+ server_ok => 1;
+
+my $dbname = 'rt4test_install_xxx';
+my $rtname = 'rttestname';
+my $domain = 'rttes.com';
+my $password = 'newpass';
+my $correspond = 'reply@example.com';
+my $comment = 'comment@example.com';
+
+# use bin/rt to fake sendmail to make sure the file exists
+my $sendmail = File::Spec->catfile( $RT::BinPath, 'rt' );
+my $owner = 'root@localhost';
+
+unlink File::Spec->catfile( $RT::VarPath, $dbname );
+
+my ( $url, $m ) = RT::Test->started_ok;
+$m->warning_like(qr/If this is a new installation of RT/,
+ "Got startup warning");
+
+my ($port) = $url =~ /:(\d+)/;
+$m->get_ok($url);
+
+is( $m->uri, $url . '/Install/index.html', 'install page' );
+$m->select( 'Lang', 'zh-cn' );
+$m->click('ChangeLang');
+$m->content_contains( Encode::decode("UTF-8",'语言'), 'select chinese' );
+
+$m->click('Run');
+$m->content_contains( Encode::decode("UTF-8",'数据库'), 'select db type in chinese' );
+
+$m->back;
+$m->select( 'Lang', 'en' );
+$m->click('ChangeLang');
+$m->content_contains( 'Select another language', 'back to english' );
+
+$m->click('Run');
+
+is( $m->uri, $url . '/Install/DatabaseType.html', 'db type page' );
+my $select_type = $m->current_form->find_input('DatabaseType');
+my @possible_types = $select_type->possible_values;
+ok( @possible_types, 'we have at least 1 db type' );
+
+SKIP: {
+ skip 'no mysql found', 7 unless grep { /mysql/ } @possible_types;
+ $m->select( 'DatabaseType', 'mysql' );
+ $m->click;
+ for my $field (qw/Name Host Port Admin AdminPassword User Password/) {
+ ok( $m->current_form->find_input("Database$field"),
+ "db mysql has field Database$field" );
+ }
+ $m->back;
+}
+
+SKIP: {
+ skip 'no pg found', 8 unless grep { /Pg/ } @possible_types;
+ $m->select( 'DatabaseType', 'Pg' );
+ $m->click;
+ for my $field (
+ qw/Name Host Port Admin AdminPassword User Password/)
+ {
+ ok( $m->current_form->find_input("Database$field"),
+ "db Pg has field Database$field" );
+ }
+ $m->back;
+}
+
+$m->select( 'DatabaseType', 'SQLite' );
+$m->click;
+
+is( $m->uri, $url . '/Install/DatabaseDetails.html', 'db details page' );
+$m->field( 'DatabaseName' => $dbname );
+$m->submit_form( fields => { DatabaseName => $dbname } );
+$m->content_contains( 'Connection succeeded', 'succeed msg' );
+$m->content_contains(
+qq{$dbname already exists, but does not contain RT&#39;s tables or metadata. The &#39;Initialize Database&#39; step later on can insert tables and metadata into this existing database. if this is acceptable, click &#39;Customize Basic&#39; below to continue customizing RT.},
+ 'more db state msg'
+);
+$m->click;
+
+is( $m->uri, $url . '/Install/Basics.html', 'basics page' );
+$m->click;
+$m->content_contains(
+ 'You must enter an Administrative password',
+ "got password can't be empty error"
+);
+
+for my $field (qw/rtname WebDomain WebPort Password/) {
+ ok( $m->current_form->find_input($field), "has field $field" );
+}
+is( $m->value('WebPort'), $port, 'default port' );
+$m->field( 'rtname' => $rtname );
+$m->field( 'WebDomain' => $domain );
+$m->field( 'Password' => $password );
+$m->click;
+
+is( $m->uri, $url . '/Install/Sendmail.html', 'mail page' );
+for my $field (qw/SendmailPath OwnerEmail/) {
+ ok( $m->current_form->find_input($field), "has field $field" );
+}
+
+$m->field( 'OwnerEmail' => '' );
+$m->click;
+$m->content_contains( "doesn&#39;t look like an email address",
+ 'got email error' );
+
+$m->field( 'SendmailPath' => '/fake/path/sendmail' );
+$m->click;
+$m->content_contains( "/fake/path/sendmail doesn&#39;t exist",
+ 'got sendmail error' );
+
+$m->field( 'SendmailPath' => $sendmail );
+$m->field( 'OwnerEmail' => $owner );
+$m->click;
+
+is( $m->uri, $url . '/Install/Global.html', 'global page' );
+for my $field (qw/CommentAddress CorrespondAddress/) {
+ ok( $m->current_form->find_input($field), "has field $field" );
+}
+
+$m->click;
+is( $m->uri, $url . '/Install/Initialize.html', 'init db page' );
+$m->back;
+
+is( $m->uri, $url . '/Install/Global.html', 'global page' );
+$m->field( 'CorrespondAddress' => 'reply' );
+$m->click;
+$m->content_contains( "doesn&#39;t look like an email address",
+ 'got email error' );
+$m->field( 'CommentAddress' => 'comment' );
+$m->click;
+$m->content_contains( "doesn&#39;t look like an email address",
+ 'got email error' );
+
+$m->field( 'CorrespondAddress' => 'reply@example.com' );
+$m->field( 'CommentAddress' => 'comment@example.com' );
+$m->click;
+
+is( $m->uri, $url . '/Install/Initialize.html', 'init db page' );
+$m->click;
+
+is( $m->uri, $url . '/Install/Finish.html', 'finish page' );
+$m->click;
+
+is( $m->uri, $url . '/', 'home page' );
+$m->login( 'root', $password );
+$m->content_contains( 'RT at a glance', 'logged in with newpass' );
+
+RT->LoadConfig;
+my $config = RT->Config;
+
+is( $config->Get('DatabaseType'), 'SQLite', 'DatabaseType in config' );
+is( $config->Get('DatabaseName'), $dbname, 'DatabaseName in config' );
+is( $config->Get('rtname'), $rtname, 'rtname in config' );
+is( $config->Get('WebDomain'), $domain, 'WebDomain email in config' );
+is( $config->Get('WebPort'), $port, 'WebPort email in config' );
+is( $config->Get('SendmailPath'), $sendmail, 'SendmailPath in config' );
+is( $config->Get('OwnerEmail'), $owner, 'OwnerEmail in config' );
+is( $config->Get('CorrespondAddress'),
+ $correspond, 'correspond address in config' );
+is( $config->Get('CommentAddress'), $comment, 'comment address in config' );
+
+unlink File::Spec->catfile( $RT::VarPath, $dbname );
+
+undef $m;
+done_testing;
diff --git a/rt/t/web/language_update.t b/rt/t/web/language_update.t
new file mode 100644
index 000000000..35082f886
--- /dev/null
+++ b/rt/t/web/language_update.t
@@ -0,0 +1,22 @@
+use strict;
+use warnings;
+use RT::Test tests => 9;
+
+my ( $url, $m ) = RT::Test->started_ok;
+ok( $m->login(), 'logged in' );
+
+$m->follow_link_ok({text => 'About me'});
+$m->form_with_fields('Lang');
+$m->field(Lang => 'zh_TW');
+$m->submit;
+
+$m->text_contains(Encode::decode("UTF-8","並讓現存的 iCal feeds不再能用"), "successfully updated to zh_TW");
+$m->text_contains(Encode::decode("UTF-8","使用語言 的值從 (無) 改為 'zh_TW'"), "when updating to language zh_TW, results are in zh_TW");
+
+$m->form_with_fields('Lang');
+$m->field(Lang => 'en_us');
+$m->submit;
+
+$m->text_contains("breaking all existing iCal feeds", "successfully updated to en_us");
+$m->text_contains("Lang changed from 'zh_TW' to 'en_us'", "when updating to language en_us, results are in en_us");
+
diff --git a/rt/t/web/login.t b/rt/t/web/login.t
index d0213c373..4b3620d41 100644
--- a/rt/t/web/login.t
+++ b/rt/t/web/login.t
@@ -1,7 +1,9 @@
use strict;
use warnings;
-use RT::Test tests => 34;
+use RT::Test;
+
+RT::Config->Set(AllowLoginPasswordAutoComplete => 1);
my ( $baseurl, $m ) = RT::Test->started_ok;
@@ -17,6 +19,7 @@ diag "normal login";
$m->get($baseurl);
$m->title_is('Login');
is( $m->uri, $baseurl, "right url" );
+ $m->content_lacks('autocomplete="off"');
$m->submit_form(
form_id => 'login',
diff --git a/rt/t/web/mobile.t b/rt/t/web/mobile.t
new file mode 100644
index 000000000..3f32e49e6
--- /dev/null
+++ b/rt/t/web/mobile.t
@@ -0,0 +1,210 @@
+use strict;
+use warnings;
+use RT::Test tests => 170;
+
+my ( $url, $m ) = RT::Test->started_ok;
+my $root = RT::Test->load_or_create_user( Name => 'root' );
+
+diag "create another queue";
+my $test_queue = RT::Queue->new( $RT::SystemUser );
+ok( $test_queue->Create( Name => 'foo' ) );
+
+diag "create cf cfbar";
+my $cfbar = RT::CustomField->new( $RT::SystemUser );
+ok(
+ $cfbar->Create(
+ Name => 'cfbar',
+ Type => 'Freeform',
+ LookupType => 'RT::Queue-RT::Ticket'
+ )
+);
+
+$cfbar->AddToObject( $test_queue );
+
+diag "create some tickets to link";
+# yep, create 3 tickets for DependsOn
+my @tickets = map { { Subject => "link of $_" } }
+ qw/DependsOn DependsOn DependsOn DependedOnBy HasMember HasMember
+ MemberOf RefersTo RefersTo ReferredToBy/;
+RT::Test->create_tickets( { Status => 'resolved' }, @tickets );
+
+diag "test different mobile agents";
+my @agents = (
+ 'hiptop', 'Blazer', 'Novarra', 'Vagabond',
+ 'SonyEricsson', 'Symbian', 'NetFront', 'UP.Browser',
+ 'UP.Link', 'Windows CE', 'MIDP', 'J2ME',
+ 'DoCoMo', 'J-PHONE', 'PalmOS', 'PalmSource',
+ 'iPhone', 'iPod', 'AvantGo', 'Nokia',
+ 'Android', 'WebOS', 'S60'
+);
+
+for my $agent (@agents) {
+ $m->agent($agent);
+ $m->get_ok($url);
+ $m->content_contains( 'Not using a mobile browser',
+ "mobile login page for agent $agent" );
+}
+
+$m->submit_form( fields => { user => 'root', pass => 'password' } );
+is( $m->uri, $url . '/m/', 'logged in via mobile ui' );
+ok( $m->find_link( text => 'Home' ), 'has homepage link, so really logged in' );
+
+diag "create some tickets";
+$m->follow_link_ok( { text => 'New ticket' } );
+like( $m->uri, qr'/m/ticket/select_create_queue', 'queue select page' );
+$m->follow_link_ok( { text => 'General' } );
+like( $m->uri, qr'/m/ticket/create', 'ticket create page' );
+$m->submit_form(
+ fields => {
+ Subject => 'ticket1',
+ Content => 'content 1',
+ Status => 'open',
+ Cc => 'cc@example.com',
+ AdminCc => 'admincc@example.com',
+ InitialPriority => 13,
+ FinalPriority => 93,
+ TimeEstimated => 2,
+ 'TimeEstimated-TimeUnits' => 'hours',
+ TimeWorked => 30,
+ TimeLeft => 60,
+ Starts => '2011-01-11 11:11:11',
+ Due => '2011-02-12 12:12:12',
+ 'new-DependsOn' => '1 2 3',
+ 'DependsOn-new' => '4',
+ 'new-MemberOf' => '5 6',
+ 'MemberOf-new' => '7',
+ 'new-RefersTo' => '8 9',
+ 'RefersTo-new' => '10',
+ }
+);
+like( $m->uri, qr'/m/ticket/show', 'ticket show page' );
+$m->content_contains( 'ticket1', 'subject' );
+$m->content_contains( 'open', 'status' );
+$m->content_contains( 'cc@example.com', 'cc' );
+$m->content_contains( 'admincc@example.com', 'admincc' );
+$m->content_contains( '13/93', 'priority' );
+$m->content_contains( '2 hour', 'time estimates' );
+$m->content_contains( '30 min', 'time worked' );
+$m->content_contains( '60 min', 'time left' );
+$m->content_contains( 'Tue Jan 11 11:11:11', 'starts' );
+$m->content_contains( 'Sat Feb 12 12:12:12', 'due' );
+$m->content_like( qr/(link of DependsOn).*\1.*\1/s, 'depends on' );
+$m->content_contains( 'link of DependedOnBy', 'depended on by' );
+$m->content_like( qr/(link of HasMember).*\1/s, 'has member' );
+$m->content_contains( 'link of MemberOf', 'member of' );
+$m->content_like( qr/(link of RefersTo).*\1/s, 'refers to' );
+$m->content_contains( 'link of ReferredToBy', 'referred to by' );
+
+diag "test ticket reply";
+$m->follow_link_ok( { text => 'Reply' } );
+like( $m->uri, qr'/m/ticket/reply', 'ticket reply page' );
+$m->submit_form(
+ fields => {
+ UpdateContent => 'reply 1',
+ UpdateTimeWorked => '30',
+ UpdateStatus => 'resolved',
+ UpdateType => 'response',
+ },
+ button => 'SubmitTicket',
+);
+like( $m->uri, qr'/m/ticket/show', 'back to ticket show page' );
+$m->content_contains( '1 hour', 'time worked' );
+$m->content_contains( 'resolved', 'status' );
+$m->follow_link_ok( { text => 'Reply' } );
+like( $m->uri, qr'/m/ticket/reply', 'ticket reply page' );
+$m->submit_form(
+ fields => {
+ UpdateContent => 'reply 2',
+ UpdateSubject => 'ticket1',
+ UpdateStatus => 'open',
+ UpdateType => 'private',
+ },
+ button => 'SubmitTicket',
+);
+$m->no_warnings_ok;
+$m->content_contains( 'ticket1', 'subject' );
+$m->content_contains( 'open', 'status' );
+
+like( $m->uri, qr'/m/ticket/show', 'back to ticket show page' );
+
+diag "test ticket history";
+$m->follow_link_ok( { text => 'History' } );
+like( $m->uri, qr'/m/ticket/history', 'ticket history page' );
+$m->content_contains( 'content 1', 'has main content' );
+$m->content_contains( 'reply 1', 'has replied content' );
+$m->content_contains( 'reply 2', 'has replied content' );
+
+diag "create another ticket in queue foo";
+$m->follow_link_ok( { text => 'Home' } );
+is( $m->uri, "$url/m/", 'main mobile page' );
+$m->follow_link_ok( { text => 'New ticket' } );
+like( $m->uri, qr'/m/ticket/select_create_queue', 'queue select page' );
+$m->follow_link_ok( { text => 'foo' } );
+like( $m->uri, qr'/m/ticket/create', 'ticket create page' );
+$m->content_contains( 'cfbar', 'has cf name' );
+$m->content_contains( 'Object-RT::Ticket--CustomField-' . $cfbar->id . '-Value', 'has cf input name' );
+$m->submit_form(
+ fields => {
+ Subject => 'ticket2',
+ Content => 'content 2',
+ Owner => $root->id,
+ 'Object-RT::Ticket--CustomField-' . $cfbar->id . '-Value' => 'cfvalue',
+ }
+);
+$m->no_warnings_ok;
+like( $m->uri, qr'/m/ticket/show', 'ticket show page' );
+$m->content_contains( 'cfbar', 'has cf name' );
+$m->content_contains( 'cfvalue', 'has cf value' );
+
+$m->follow_link_ok( { text => 'Home' } );
+is( $m->uri, "$url/m/", 'main mobile page' );
+
+diag "test unowned tickets link";
+$m->follow_link_ok( { text => 'Unowned tickets' } );
+$m->content_contains( 'Found 1 ticket', 'found 1 ticket' );
+$m->content_contains( 'ticket1', 'has ticket1' );
+$m->content_lacks( 'ticket2', 'no ticket2' );
+$m->back;
+
+diag "test tickets I own link";
+$m->follow_link_ok( { text => 'Tickets I own' } );
+$m->content_contains( 'Found 1 ticket', 'found 1 ticket' );
+$m->content_lacks( 'ticket1', 'no ticket1' );
+ok( $m->find_link( text_regex => qr/ticket2/ ), 'has ticket2 link' );
+$m->back;
+
+diag "test all tickets link";
+$m->follow_link_ok( { text => 'All tickets' } );
+$m->content_contains( 'Found 12 tickets', 'found 12 tickets' );
+ok( $m->find_link( text_regex => qr/ticket1/ ), 'has ticket1 link' );
+ok( $m->find_link( text_regex => qr/ticket2/ ), 'has ticket2 link' );
+$m->back;
+
+diag "test bookmarked tickets link";
+my $ticket = RT::Ticket->new(RT::CurrentUser->new('root'));
+$ticket->Load(11);
+$root->ToggleBookmark($ticket);
+
+$m->follow_link_ok( { text => 'Bookmarked tickets' } );
+$m->content_contains( 'Found 1 ticket', 'found 1 ticket' );
+ok( $m->find_link( text_regex => qr/ticket1/ ), 'has ticket1 link' );
+$m->content_lacks( 'ticket2', 'no ticket2' );
+$m->back;
+
+diag "test tickets search";
+$m->submit_form( fields => { q => 'ticket2' } );
+$m->content_contains( 'Found 1 ticket', 'found 1 ticket' );
+$m->content_lacks( 'ticket1', 'no ticket1' );
+ok( $m->find_link( text_regex => qr/ticket2/ ), 'has ticket2 link' );
+$m->back;
+
+diag "test logout link";
+$m->follow_link_ok( { text => 'Logout' } );
+is( $m->uri, "$url/m/", 'still in mobile' );
+$m->submit_form( fields => { user => 'root', pass => 'password' } );
+
+diag "test notmobile link";
+$m->follow_link_ok( { text => 'Home' } );
+$m->follow_link_ok( { text => 'Not using a mobile browser?' } );
+is( $m->uri, $url . '/', 'got full ui' );
+
diff --git a/rt/t/web/offline.t b/rt/t/web/offline.t
deleted file mode 100644
index 06d51913a..000000000
--- a/rt/t/web/offline.t
+++ /dev/null
@@ -1,77 +0,0 @@
-use strict;
-use warnings;
-
-use RT::Test tests => 20;
-
-my ( $url, $m ) = RT::Test->started_ok;
-ok( $m->login, 'logged in' );
-
-{
- my $template = <<EOF;
-===Create-Ticket: ticket1
-Queue: General
-Subject: test
-Status: new
-EOF
- my $ticket = create_ticket_offline( $m, $template );
- ok $ticket->id, 'created a ticket with offline tool';
- is $ticket->QueueObj->Name, 'General', 'correct value';
- is $ticket->Subject, 'test', 'correct value';
- is $ticket->Status, 'new', 'correct value';
-}
-
-{
- my $template = <<'EOF';
-===Create-Ticket: ticket1
-Queue: General
-Subject: test
-Status: new
-Requestor: test@example.com
-EOF
- my $ticket = create_ticket_offline( $m, $template );
- ok $ticket->id, 'created a ticket with offline tool';
- is $ticket->RequestorAddresses, 'test@example.com', 'correct value';
-}
-
-{
- my $group = RT::Group->new(RT->SystemUser);
- my ($id, $msg) = $group->CreateUserDefinedGroup( Name => 'test' );
- ok $id, "created a user defined group";
-
- my $template = <<'EOF';
-===Create-Ticket: ticket1
-Queue: General
-Subject: test
-Status: new
-Requestor: test@example.com
-RequestorGroup: test
-EOF
- my $ticket = create_ticket_offline( $m, $template );
- ok $ticket->id, 'created a ticket with offline tool';
- ok grep(
- { $_->MemberId eq $group->id }
- @{ $ticket->Requestors->MembersObj->ItemsArrayRef }
- ), 'correct value' ;
- is $ticket->RequestorAddresses, 'test@example.com', 'correct value';
-}
-
-sub create_ticket_offline {
- my ($m, $template) = @_;
-
- $m->get_ok( $url . '/Tools/Offline.html' );
-
- $m->submit_form(
- form_name => 'TicketUpdate',
- fields => { string => $template },
- button => 'UpdateTickets',
- );
-
- my $ticket = RT::Ticket->new( RT->SystemUser );
- $m->content_like( qr/Ticket \d+ created/, 'found ticket created message' )
- or return $ticket;
-
- $ticket->Load( $m->content =~ /Ticket (\d+) created/ );
- return $ticket;
-}
-
-
diff --git a/rt/t/web/offline_messages_utf8.t b/rt/t/web/offline_messages_utf8.t
deleted file mode 100644
index 4cf6954bd..000000000
--- a/rt/t/web/offline_messages_utf8.t
+++ /dev/null
@@ -1,64 +0,0 @@
-use strict;
-use warnings;
-
-use RT::Test tests => 8;
-use RT::Ticket;
-
-my ( $url, $m ) = RT::Test->started_ok;
-$m->default_header( 'Accept-Language' => "zh-tw" );
-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::encode("UTF-8", $m->content);
- ok( $content =~ m/申請單 #(\d+) 成功新增於 &#39;General&#39; 表單/, '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::encode("UTF-8", $m->content);
- ok(
- $content =~
-qr/主題\s*的值從\s*&#39;test message&#39;\s*改為\s*&#39;test message update&#39;/,
- 'subject is updated'
- );
-}
-
diff --git a/rt/t/web/offline_utf8.t b/rt/t/web/offline_utf8.t
deleted file mode 100644
index aab3049a3..000000000
--- a/rt/t/web/offline_utf8.t
+++ /dev/null
@@ -1,53 +0,0 @@
-use strict;
-use warnings;
-
-use RT::Test tests => 9;
-
-use RT::Ticket;
-my $file = File::Spec->catfile( RT::Test->temp_directory, 'template' );
-open my $fh, '>', $file or die $!;
-my $template = Encode::decode("UTF-8",<<EOF);
-===Create-Ticket: ticket1
-Queue: General
-Subject: 标题
-Status: new
-Content:
-这是正文
-ENDOFCONTENT
-EOF
-
-print $fh Encode::encode("UTF-8",$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( Encode::decode("UTF-8",'这是正文'), 'content is parsed right' );
-
-$m->submit_form(
- form_name => 'TicketUpdate',
- button => 'UpdateTickets',
-
- # mimic what browsers do: they seems decoded $template
- fields => { string => $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, Encode::decode("UTF-8",'标题'), 'subject in $ticket is right' );
-
-$m->goto_ticket($ticket_id);
-$m->content_contains( Encode::decode("UTF-8",'这是正文'),
- 'content is right in ticket display page' );
-
diff --git a/rt/t/web/owner_disabled_group_19221.t b/rt/t/web/owner_disabled_group_19221.t
index d41decfd2..b71fc5b3e 100644
--- a/rt/t/web/owner_disabled_group_19221.t
+++ b/rt/t/web/owner_disabled_group_19221.t
@@ -122,7 +122,7 @@ diag "Check WithMember and WithoutMember recursively";
{
my $with = RT::Groups->new( RT->SystemUser );
$with->WithMember( PrincipalId => $user->PrincipalObj->Id, Recursively => 1 );
- $with->Limit( FIELD => 'domain', OPERATOR => '=', VALUE => 'UserDefined' );
+ $with->LimitToUserDefinedGroups;
is_deeply(
[map {$_->Name} @{$with->ItemsArrayRef}],
['Disabled Group','Supergroup'],
@@ -131,7 +131,7 @@ diag "Check WithMember and WithoutMember recursively";
my $without = RT::Groups->new( RT->SystemUser );
$without->WithoutMember( PrincipalId => $user->PrincipalObj->Id, Recursively => 1 );
- $without->Limit( FIELD => 'domain', OPERATOR => '=', VALUE => 'UserDefined' );
+ $without->LimitToUserDefinedGroups;
is_deeply(
[map {$_->Name} @{$without->ItemsArrayRef}],
[],
diff --git a/rt/t/web/path-traversal.t b/rt/t/web/path-traversal.t
index 01302e672..8207265ef 100644
--- a/rt/t/web/path-traversal.t
+++ b/rt/t/web/path-traversal.t
@@ -8,35 +8,30 @@ ok($agent->login);
$agent->get("$baseurl/NoAuth/../Elements/HeaderJavascript");
is($agent->status, 400);
-$agent->warning_like(qr/Invalid request.*aborting/,);
+$agent->warning_like(qr/Invalid request.*aborting/);
$agent->get("$baseurl/NoAuth/../%45lements/HeaderJavascript");
is($agent->status, 400);
-$agent->warning_like(qr/Invalid request.*aborting/,);
+$agent->warning_like(qr/Invalid request.*aborting/);
$agent->get("$baseurl/NoAuth/%2E%2E/Elements/HeaderJavascript");
is($agent->status, 400);
-$agent->warning_like(qr/Invalid request.*aborting/,);
+$agent->warning_like(qr/Invalid request.*aborting/);
$agent->get("$baseurl/NoAuth/../../../etc/RT_Config.pm");
is($agent->status, 400);
-SKIP: {
- skip "Apache rejects busting up above / for us", 2 if $ENV{RT_TEST_WEB_HANDLER} =~ /^apache/;
- $agent->warning_like(qr/Invalid request.*aborting/,);
-};
+$agent->warning_like(qr/Invalid request.*aborting/) unless $ENV{RT_TEST_WEB_HANDLER} =~ /^apache/;
-$agent->get("$baseurl/NoAuth/css/web2/images/../../../../../../etc/RT_Config.pm");
-is($agent->status, 400);
-SKIP: {
- skip "Apache rejects busting up above / for us", 2 if $ENV{RT_TEST_WEB_HANDLER} =~ /^apache/;
- $agent->warning_like(qr/Invalid request.*aborting/,);
-};
+$agent->get("$baseurl/static/css/web2/images/../../../../../../etc/RT_Config.pm");
+# Apache hardcodes a 400m but the static handler returns a 403 for traversal too high
+is($agent->status, $ENV{RT_TEST_WEB_HANDLER} =~ /^apache/ ? 400 : 403);
# Do not reject a simple /. in the URL, for downloading uploaded
# dotfiles, for example.
$agent->get("$baseurl/Ticket/Attachment/28/9/.bashrc");
is($agent->status, 200); # Even for a file not found, we return 200
-$agent->content_contains("Bad attachment id");
+$agent->next_warning_like(qr/could not be loaded/, "couldn't loaded warning");
+$agent->content_like(qr/Attachment \S+ could not be loaded/);
# do not reject these URLs, even though they contain /. outside the path
$agent->get("$baseurl/index.html?ignored=%2F%2E");
diff --git a/rt/t/web/psgi-wrap.t b/rt/t/web/psgi-wrap.t
new file mode 100644
index 000000000..0e4b0532b
--- /dev/null
+++ b/rt/t/web/psgi-wrap.t
@@ -0,0 +1,15 @@
+use strict;
+use warnings;
+
+use RT::Test
+ tests => undef,
+ plugins => [qw(RT::Extension::PSGIWrap)];
+
+my ($base, $m) = RT::Test->started_ok;
+$m->login;
+ok(my $res = $m->get("/"));
+is($res->code, 200, 'Successful request to /');
+ok($res->header('X-RT-PSGIWrap'), 'X-RT-PSGIWrap header set from the plugin');
+
+undef $m;
+done_testing();
diff --git a/rt/t/web/query_builder.t b/rt/t/web/query_builder.t
index 3589c381a..dbe909939 100644
--- a/rt/t/web/query_builder.t
+++ b/rt/t/web/query_builder.t
@@ -196,7 +196,7 @@ diag "click advanced, enter 'C1 OR ( C2 AND C3 )', apply, aggregators should sta
# 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 );
+ $cf->LoadByName( Name => "\x{442}", LookupType => RT::Ticket->CustomFieldLookupType, ObjectId => 0 );
if ( $cf->id ) {
is($cf->Type, 'Freeform', 'loaded and type is correct');
} else {
@@ -212,10 +212,10 @@ diag "click advanced, enter 'C1 OR ( C2 AND C3 )', apply, aggregators should sta
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->field("ValueOfCF.{\x{442}}", "\x{441}");
$agent->submit();
is( getQueryFromForm($agent),
- "'CF.{\x{442}}' LIKE '\x{441}'",
+ "CF.{\x{442}} LIKE '\x{441}'",
"no changes, no duplicate condition with badly encoded text"
);
diff --git a/rt/t/web/query_builder_queue_limits.t b/rt/t/web/query_builder_queue_limits.t
index 332cc939c..6bbf33386 100644
--- a/rt/t/web/query_builder_queue_limits.t
+++ b/rt/t/web/query_builder_queue_limits.t
@@ -71,9 +71,9 @@ $m->get_ok( $url . '/Search/Build.html' );
diag "check default statuses, cf and owners";
my $form = $m->form_name('BuildQuery');
ok( $form, 'found BuildQuery form' );
-ok( $form->find_input("ValueOf'CF.{global_cf}'"), 'found global_cf by default' );
-ok( !$form->find_input("ValueOf'CF.{general_cf}'"), 'no general_cf by default' );
-ok( !$form->find_input("ValueOf'CF.{foo_cf}'"), 'no foo_cf by default' );
+ok( $form->find_input("ValueOfCF.{global_cf}"), 'found global_cf by default' );
+ok( !$form->find_input("ValueOfCF.{general_cf}"), 'no general_cf by default' );
+ok( !$form->find_input("ValueOfCF.{foo_cf}"), 'no foo_cf by default' );
my $status_input = $form->find_input('ValueOfStatus');
my @statuses = sort $status_input->possible_values;
@@ -94,9 +94,9 @@ $m->submit_form(
);
$form = $m->form_name('BuildQuery');
-ok( $form->find_input("ValueOf'CF.{foo_cf}'"), 'found foo_cf' );
-ok( $form->find_input("ValueOf'CF.{global_cf}'"), 'found global_cf' );
-ok( !$form->find_input("ValueOf'CF.{general_cf}'"), 'still no general_cf' );
+ok( $form->find_input("ValueOfCF.{foo_cf}"), 'found foo_cf' );
+ok( $form->find_input("ValueOfCF.{global_cf}"), 'found global_cf' );
+ok( !$form->find_input("ValueOfCF.{general_cf}"), 'still no general_cf' );
$status_input = $form->find_input('ValueOfStatus');
@statuses = sort $status_input->possible_values;
is_deeply(
@@ -119,9 +119,9 @@ $m->submit_form(
);
$form = $m->form_name('BuildQuery');
-ok( $form->find_input("ValueOf'CF.{general_cf}'"), 'found general_cf' );
-ok( $form->find_input("ValueOf'CF.{foo_cf}'"), 'found foo_cf' );
-ok( $form->find_input("ValueOf'CF.{global_cf}'"), 'found global_cf' );
+ok( $form->find_input("ValueOfCF.{general_cf}"), 'found general_cf' );
+ok( $form->find_input("ValueOfCF.{foo_cf}"), 'found foo_cf' );
+ok( $form->find_input("ValueOfCF.{global_cf}"), 'found global_cf' );
$status_input = $form->find_input('ValueOfStatus');
@statuses = sort $status_input->possible_values;
is_deeply(
@@ -144,9 +144,9 @@ $m->submit_form(
);
$form = $m->form_name('BuildQuery');
-ok( $form->find_input("ValueOf'CF.{global_cf}'"), 'found global_cf' );
-ok( !$form->find_input("ValueOf'CF.{foo_cf}'"), 'no foo_cf' );
-ok( !$form->find_input("ValueOf'CF.{general_cf}'"), 'no general_cf' );
+ok( $form->find_input("ValueOfCF.{global_cf}"), 'found global_cf' );
+ok( !$form->find_input("ValueOfCF.{foo_cf}"), 'no foo_cf' );
+ok( !$form->find_input("ValueOfCF.{general_cf}"), 'no general_cf' );
$status_input = $form->find_input('ValueOfStatus');
@statuses = sort $status_input->possible_values;
is_deeply(
@@ -166,9 +166,9 @@ $m->submit_form(
fields => { Query => q{Queue = 'General' OR Queue = 'foo'} },
);
$form = $m->form_name('BuildQuery');
-ok( $form->find_input("ValueOf'CF.{general_cf}'"), 'found general_cf' );
-ok( $form->find_input("ValueOf'CF.{foo_cf}'"), 'found foo_cf' );
-ok( $form->find_input("ValueOf'CF.{global_cf}'"), 'found global_cf' );
+ok( $form->find_input("ValueOfCF.{general_cf}"), 'found general_cf' );
+ok( $form->find_input("ValueOfCF.{foo_cf}"), 'found foo_cf' );
+ok( $form->find_input("ValueOfCF.{global_cf}"), 'found global_cf' );
$status_input = $form->find_input('ValueOfStatus');
@statuses = sort $status_input->possible_values;
is_deeply(
diff --git a/rt/t/web/query_log.t b/rt/t/web/query_log.t
index 89cca2d7b..cfb4d81d7 100644
--- a/rt/t/web/query_log.t
+++ b/rt/t/web/query_log.t
@@ -14,6 +14,5 @@ $root->LoadByEmail('root@localhost');
$m->get_ok("/Admin/Tools/Queries.html");
$m->text_contains("/index.html", "we include info about a page we hit while logging in");
$m->text_contains("Stack:", "stack traces");
-$m->text_like(qr{share/html/autohandler:\d+}, "stack trace includes mason components");
+$m->text_like(qr{/autohandler:\d+}, "stack trace includes mason components");
$m->text_contains("SELECT * FROM Principals WHERE id = '".$root->id."'", "we interpolate bind params");
-
diff --git a/rt/t/web/queue_create.t b/rt/t/web/queue_create.t
index 566876231..40f7b3b8b 100644
--- a/rt/t/web/queue_create.t
+++ b/rt/t/web/queue_create.t
@@ -13,7 +13,7 @@ my $queue_name = 'test queue';
my $queue_id;
diag "Create a queue";
{
- $m->follow_link( id => 'tools-config-queues-create');
+ $m->follow_link( id => 'admin-queues-create');
# Test queue form validation
$m->submit_form(
diff --git a/rt/t/web/redirect-after-login.t b/rt/t/web/redirect-after-login.t
index 35025a1e1..eb2718cf3 100644
--- a/rt/t/web/redirect-after-login.t
+++ b/rt/t/web/redirect-after-login.t
@@ -4,8 +4,6 @@ use warnings;
use RT::Test tests => 122;
-RT->Config->Set( GnuPG => Enable => 0 );
-
my ($baseurl, $agent) = RT::Test->started_ok;
my $url = $agent->rt_base_url;
@@ -226,7 +224,7 @@ for my $path (qw(Prefs/Other.html /Prefs/Other.html)) {
unlike($agent->content, qr/Your username or password is incorrect/, "didn't get any error message");
}
-# XXX TODO: we should also be testing WebExternalAuth here, but we don't have
+# XXX TODO: we should also be testing WebRemoteUserAuth here, but we don't have
# the framework for dealing with that
1;
diff --git a/rt/t/web/reminder-permissions.t b/rt/t/web/reminder-permissions.t
new file mode 100644
index 000000000..dd859cd33
--- /dev/null
+++ b/rt/t/web/reminder-permissions.t
@@ -0,0 +1,178 @@
+use strict;
+use warnings;
+use RT::Test tests => 40;
+
+my $user_a = RT::Test->load_or_create_user(
+ Name => 'user_a',
+ Password => 'password',
+);
+
+ok( $user_a && $user_a->id, 'created user_a' );
+ok(
+ RT::Test->add_rights(
+ {
+ Principal => $user_a,
+ Right => [qw/SeeQueue CreateTicket ShowTicket OwnTicket/]
+ },
+ ),
+ 'add basic rights for user_a'
+);
+
+ok(
+ RT::Test->add_rights(
+ {
+ Principal => 'Owner',
+ Right => [qw/ModifyTicket/],
+ },
+ ),
+ 'add basic rights for owner'
+);
+
+my $ticket = RT::Test->create_ticket(
+ Subject => 'test reminder permission',
+ Queue => 'General',
+);
+
+ok( $ticket->id, 'created a ticket' );
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+$m->login;
+
+my ( $root_reminder_id, $user_a_reminder_id );
+diag "create two reminders, with owner root and user_a, respectively";
+{
+ $m->goto_ticket( $ticket->id );
+ $m->text_contains( 'New reminder:', 'can create a new reminder' );
+ $m->form_name('UpdateReminders');
+ $m->field( 'NewReminder-Subject' => "root reminder" );
+ $m->submit;
+ $m->text_contains( "Reminder 'root reminder': Created",
+ 'created root reminder' );
+
+ $m->form_name('UpdateReminders');
+ $m->field( 'NewReminder-Subject' => "user_a reminder", );
+ $m->field( 'NewReminder-Owner' => $user_a->id, );
+ $m->submit;
+ $m->text_contains( "Reminder 'user_a reminder': Created",
+ 'created user_a reminder' );
+
+ my $reminders = RT::Reminders->new($user_a);
+ $reminders->Ticket( $ticket->id );
+ my $col = $reminders->Collection;
+ while ( my $c = $col->Next ) {
+ if ( $c->Subject eq 'root reminder' ) {
+ $root_reminder_id = $c->id;
+ }
+ elsif ( $c->Subject eq 'user_a reminder' ) {
+ $user_a_reminder_id = $c->id;
+ }
+ }
+}
+
+diag "check root_a can update user_a reminder but not root reminder";
+my $m_a = RT::Test::Web->new;
+{
+ ok( $m_a->login( user_a => 'password' ), 'logged in as user_a' );
+ $m_a->goto_ticket( $ticket->id );
+ $m_a->content_lacks( 'New reminder:', 'can not create a new reminder' );
+ $m_a->content_contains( 'root reminder', 'can see root reminder' );
+ $m_a->content_contains( 'user_a reminder', 'can see user_a reminder' );
+ $m_a->content_like(
+qr!<input[^/]+name="Complete-Reminder-$root_reminder_id"[^/]+disabled="disabled"!,
+ "root reminder checkbox is disabled"
+ );
+
+ $m_a->form_name('UpdateReminders');
+ $m_a->tick( "Complete-Reminder-$user_a_reminder_id" => 1 );
+ $m_a->submit;
+ $m_a->text_contains(
+ "Reminder 'user_a reminder': Status changed from 'open' to 'resolved'",
+ 'complete user_a reminder' );
+
+ $m_a->follow_link_ok( { id => 'page-reminders' } );
+ $m_a->title_is( "Reminders for ticket #" . $ticket->id );
+ $m_a->content_contains( 'root reminder', 'can see root reminder' );
+ $m_a->content_contains( 'user_a reminder', 'can see user_a reminder' );
+ $m_a->content_lacks( 'New reminder:', 'can not create a new reminder' );
+ $m_a->content_like(
+qr!<input[^/]+name="Complete-Reminder-$root_reminder_id"[^/]+disabled="disabled"!,
+ "root reminder checkbox is disabled"
+ );
+
+ $m_a->form_name('UpdateReminders');
+ $m_a->untick( "Complete-Reminder-$user_a_reminder_id", 1 );
+ $m_a->submit;
+ $m_a->text_contains(
+ "Reminder 'user_a reminder': Status changed from 'resolved' to 'open'",
+ 'reopen user_a reminder'
+ );
+
+}
+
+diag "set ticket owner to user_a to let user_a grant modify ticket right";
+{
+ $ticket->SetOwner( $user_a->id );
+
+ $m_a->goto_ticket( $ticket->id );
+ $m_a->content_contains( 'New reminder:', 'can create a new reminder' );
+ $m_a->content_like(
+qr!<input[^/]+name="Complete-Reminder-$root_reminder_id"[^/]+disabled="disabled"!,
+ "root reminder checkbox is still disabled"
+ );
+ $m_a->form_name('UpdateReminders');
+ $m_a->field( 'NewReminder-Subject' => "user_a from display reminder" );
+ $m_a->submit;
+ $m_a->text_contains( "Reminder 'user_a from display reminder': Created",
+ 'created user_a from display reminder' );
+
+ $m_a->follow_link_ok( { id => 'page-reminders' } );
+ $m_a->title_is( "Reminders for ticket #" . $ticket->id );
+ $m_a->content_contains( 'New reminder:', 'can create a new reminder' );
+ $m_a->content_like(
+qr!<input[^/]+name="Complete-Reminder-$root_reminder_id"[^/]+disabled="disabled"!,
+ "root reminder checkbox is still disabled"
+ );
+ $m_a->form_name('UpdateReminders');
+ $m_a->field( 'NewReminder-Subject' => "user_a from reminders reminder" );
+ $m_a->submit;
+ $m_a->text_contains( "Reminder 'user_a from reminders reminder': Created",
+ 'created user_a from reminders reminder' );
+}
+
+diag "grant user_a with ModifyTicket globally";
+{
+ ok(
+ RT::Test->add_rights(
+ {
+ Principal => $user_a,
+ Right => [qw/ModifyTicket/],
+ },
+ ),
+ 'add ModifyTicket rights to user_a'
+ );
+
+ $m_a->goto_ticket( $ticket->id );
+ $m_a->content_unlike(
+qr!<input[^/]+name="Complete-Reminder-$root_reminder_id"[^/]+disabled="disabled"!,
+ "root reminder checkbox is enabled"
+ );
+ $m_a->form_name('UpdateReminders');
+ $m_a->tick( "Complete-Reminder-$root_reminder_id" => 1 );
+ $m_a->submit;
+ $m_a->text_contains(
+ "Reminder 'root reminder': Status changed from 'open' to 'resolved'",
+ 'complete root reminder' );
+
+ $m_a->follow_link_ok( { id => 'page-reminders' } );
+ $m_a->content_unlike(
+qr!<input[^/]+name="Complete-Reminder-$root_reminder_id"[^/]+disabled="disabled"!,
+ "root reminder checkbox is enabled"
+ );
+ $m_a->form_name('UpdateReminders');
+ $m_a->untick( "Complete-Reminder-$root_reminder_id" => 1 );
+ $m_a->submit;
+ $m_a->text_contains(
+ "Reminder 'root reminder': Status changed from 'resolved' to 'open'",
+ 'reopen root reminder' );
+}
+
diff --git a/rt/t/web/reminders.t b/rt/t/web/reminders.t
index 510235156..98a8d6954 100644
--- a/rt/t/web/reminders.t
+++ b/rt/t/web/reminders.t
@@ -26,7 +26,7 @@ $m->goto_ticket($ticket->id);
$m->form_name('UpdateReminders');
$m->field( 'NewReminder-Subject' => "baby's first reminder" );
$m->submit;
-$m->content_contains("Reminder &#39;baby&#39;s first reminder&#39; added");
+$m->content_contains("Reminder &#39;baby&#39;s first reminder&#39;: Created");
$ticket->SetStatus('deleted');
is( $ticket->Status, 'deleted', 'deleted ticket' );
diff --git a/rt/t/web/remote_user.t b/rt/t/web/remote_user.t
index edad6ef95..c17a93379 100644
--- a/rt/t/web/remote_user.t
+++ b/rt/t/web/remote_user.t
@@ -1,36 +1,197 @@
use strict;
use warnings;
use RT;
-use RT::Test tests => 9;
-use MIME::Base64 qw//;
+use RT::Test plan => 'no_plan';
-RT->Config->Set( DevelMode => 0 );
-RT->Config->Set( WebExternalAuth => 1 );
+sub stop_server {
+ my $mech = shift;
-sub auth {
- return Authorization => "Basic " .
- MIME::Base64::encode( join(":", @_) );
+ # Ensure we're logged in for the final warnings check
+ $$mech->auth("root");
+
+ # Force the warnings check before we stop the server
+ undef $$mech;
+
+ RT::Test->stop_server;
+}
+
+diag "Continuous + Fallback";
+{
+ RT->Config->Set( DevelMode => 0 );
+ RT->Config->Set( WebRemoteUserAuth => 1 );
+ RT->Config->Set( WebRemoteUserAuthContinuous => 1 );
+ RT->Config->Set( WebFallbackToRTLogin => 1 );
+ RT->Config->Set( WebRemoteUserAutocreate => 0 );
+
+ my ( $url, $m ) = RT::Test->started_ok( basic_auth => 'anon' );
+
+ diag "Internal auth";
+ {
+ # Empty REMOTE_USER
+ $m->auth("");
+
+ # First request gets the login form
+ $m->get_ok($url, "No basic auth is OK");
+ $m->content_like(qr/Login/, "Login form");
+
+ # Log in using RT's form
+ $m->submit_form_ok({
+ with_fields => {
+ user => 'root',
+ pass => 'password',
+ },
+ }, "Submitted login form");
+ ok $m->logged_in_as("root"), "Logged in as root";
+
+ # Still logged in on another request without REMOTE_USER
+ $m->follow_link_ok({ text => 'My Tickets' });
+ ok $m->logged_in_as("root"), "Logged in as root";
+
+ ok $m->logout, "Logged out";
+
+ # We're definitely logged out?
+ $m->get_ok($url);
+ $m->content_like(qr/Login/, "Login form");
+ }
+
+ diag "External auth";
+ {
+ # REMOTE_USER of root
+ $m->auth("root");
+
+ # Automatically logged in as root without Login page
+ $m->get_ok($url);
+ ok $m->logged_in_as("root"), "Logged in as root";
+
+ # Still logged in on another request
+ $m->follow_link_ok({ text => 'My Tickets' });
+ ok $m->logged_in_as("root"), "Still logged in as root";
+
+ # Drop credentials and...
+ $m->auth("");
+
+ # ...see if RT notices
+ $m->get($url);
+ is $m->status, 403, "403 Forbidden from RT";
+
+ # Next request gets us the login form
+ $m->get_ok($url);
+ $m->content_like(qr/Login/, "Login form");
+ }
+
+ diag "External auth with invalid user, login internally";
+ {
+ # REMOTE_USER of invalid
+ $m->auth("invalid");
+
+ # Login internally via the login link
+ $m->get("$url/Search/Build.html");
+ is $m->status, 403, "403 Forbidden";
+ $m->follow_link_ok({ url_regex => qr'NoAuth/Login\.html' }, "follow logout link");
+ $m->content_like(qr/Login/, "Login form");
+
+ # Log in using RT's form
+ $m->submit_form_ok({
+ with_fields => {
+ user => 'root',
+ pass => 'password',
+ },
+ }, "Submitted login form");
+ ok $m->logged_in_as("root"), "Logged in as root";
+ like $m->uri, qr'Search/Build\.html', "at our originally requested page";
+
+ # Still logged in on another request
+ $m->follow_link_ok({ text => 'Tools' });
+ ok $m->logged_in_as("root"), "Logged in as root";
+
+ ok $m->logout, "Logged out";
+
+ $m->next_warning_like(qr/Couldn't find internal user for 'invalid'/, "found warning for first request");
+ $m->next_warning_like(qr/Couldn't find internal user for 'invalid'/, "found warning for second request");
+ }
+
+ stop_server(\$m);
}
-my ( $url, $m ) = RT::Test->started_ok( basic_auth => 1 );
-$m->get($url);
-is($m->status, 401, "Initial request with no creds gets 401");
+diag "Fallback OFF";
+{
+ RT->Config->Set( DevelMode => 0 );
+ RT->Config->Set( WebRemoteUserAuth => 1 );
+ RT->Config->Set( WebRemoteUserContinuous => 0 );
+ RT->Config->Set( WebFallbackToRTLogin => 0 );
+ RT->Config->Set( WebRemoteUserAutocreate => 0 );
-$m->get($url, auth( root => "wrong" ));
-is($m->status, 401, "Request with wrong creds gets 401");
+ my ( $url, $m ) = RT::Test->started_ok( basic_auth => 'anon' );
-$m->get($url, auth( root => "password" ));
-is($m->status, 200, "Request with right creds gets 200");
+ diag "No remote user";
+ {
+ $m->auth("");
+ $m->get($url);
+ is $m->status, 403, "Forbidden";
+ }
+
+ stop_server(\$m);
+}
-$m->content_like(
- qr{<span class="current-user">\Qroot\E</span>}i,
- "Has user on the page"
-);
-$m->content_unlike(qr/Logout/i, "Has no logout button, no WebFallbackToInternalAuth");
+diag "WebRemoteUserAutocreate";
+{
+ RT->Config->Set( DevelMode => 0 );
+ RT->Config->Set( WebRemoteUserAuth => 1 );
+ RT->Config->Set( WebRemoteUserContinuous => 1 );
+ RT->Config->Set( WebFallbackToRTLogin => 0 );
+ RT->Config->Set( WebRemoteUserAutocreate => 1 );
+ RT->Config->Set( UserAutocreateDefaultsOnLogin => { Organization => "BPS" } );
-$m->get($url);
-is($m->status, 401, "Subsequent requests without credentials aren't still logged in");
+ my ( $url, $m ) = RT::Test->started_ok( basic_auth => 'anon' );
+ diag "New user";
+ {
+ $m->auth("anewuser");
+ $m->get_ok($url);
+ ok $m->logged_in_as("anewuser"), "Logged in as anewuser";
+
+ my $user = RT::User->new( RT->SystemUser );
+ $user->Load("anewuser");
+ ok $user->id, "Found newly created user";
+ is $user->Organization, "BPS", "Found Organization from UserAutocreateDefaultsOnLogin hash";
+ ok $user->Privileged, "Privileged by default";
+ }
+
+ stop_server(\$m);
+ RT->Config->Set(
+ UserAutocreateDefaultsOnLogin => {
+ Privileged => 0,
+ EmailAddress => 'foo@example.com',
+ },
+ );
+ ( $url, $m ) = RT::Test->started_ok( basic_auth => 'anon' );
+
+ diag "Create unprivileged users";
+ {
+ $m->auth("unpriv");
+ $m->get_ok($url);
+ ok $m->logged_in_as("unpriv"), "Logged in as an unpriv user";
+ like $m->uri->path, RT->Config->Get('SelfServiceRegex'), "SelfService URL";
+
+ my $user = RT::User->new( RT->SystemUser );
+ $user->Load("unpriv");
+ ok $user->id, "Found newly created user";
+ ok !$user->Privileged, "Unprivileged per config";
+ is $user->EmailAddress, 'foo@example.com', "Email address per config";
+ }
+
+ diag "User creation failure";
+ {
+ $m->auth("conflicting");
+ $m->get($url);
+ is $m->status, 403, "Forbidden";
+ $m->next_warning_like(qr/Couldn't auto-create user 'conflicting' when attempting WebRemoteUser: Email address in use/, 'found failed auth warning');
+
+ my $user = RT::User->new( RT->SystemUser );
+ $user->Load("conflicting");
+ ok !$user->id, "Couldn't find conflicting user";
+ }
+
+ stop_server(\$m);
+}
-# Put the credentials back for the warnings check at the end
-$m->default_header( auth( root => "password" ));
diff --git a/rt/t/web/rest-search-group.t b/rt/t/web/rest-search-group.t
new file mode 100644
index 000000000..b62aa09e4
--- /dev/null
+++ b/rt/t/web/rest-search-group.t
@@ -0,0 +1,102 @@
+use strict;
+use warnings;
+use RT::Test tests => undef;
+
+my $group_foo = RT::Group->new($RT::SystemUser);
+$group_foo->CreateUserDefinedGroup( Name => 'foo' );
+
+my $group_bar = RT::Group->new($RT::SystemUser);
+$group_bar->CreateUserDefinedGroup( Name => 'bar' );
+
+my $group_baz = RT::Group->new($RT::SystemUser);
+$group_baz->CreateUserDefinedGroup( Name => 'baz' );
+$group_baz->SetDisabled(1);
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+
+ok( $m->login, 'logged in' );
+
+search_groups_ok(
+ { query => 'id = ' . $group_foo->id },
+ [ $group_foo->id . ': foo' ],
+ 'search by id'
+);
+
+search_groups_ok(
+ {
+ query => 'Name = ' . $group_foo->Name,
+ format => 's',
+ fields => 'id,name',
+ },
+ [ "id\tName", $group_foo->id . "\tfoo" ],
+ 'search by name with customized fields'
+);
+
+search_groups_ok(
+ { query => 'foo = 3' },
+ ['Invalid field specification: foo'],
+ 'invalid field'
+);
+
+search_groups_ok(
+ { query => 'id foo 3' },
+ ['Invalid operator specification: foo'],
+ 'invalid op'
+);
+
+search_groups_ok(
+ { query => '', orderby => 'id' },
+ [ $group_foo->id . ': foo', $group_bar->id . ': bar', ],
+ 'order by id'
+);
+
+search_groups_ok(
+ { query => '', orderby => 'name' },
+ [ $group_bar->id . ': bar', $group_foo->id . ': foo' ],
+ 'order by name'
+);
+
+search_groups_ok(
+ { query => '', orderby => '+name' },
+ [ $group_bar->id . ': bar', $group_foo->id . ': foo' ],
+ 'order by +name'
+);
+
+search_groups_ok(
+ { query => '', orderby => '-name' },
+ [ $group_foo->id . ': foo', $group_bar->id . ': bar' ],
+ 'order by -name'
+);
+
+search_groups_ok(
+ { query => 'Disabled = 0', orderby => 'id' },
+ [ $group_foo->id . ': foo', $group_bar->id . ': bar' ],
+ 'enabled groups'
+);
+
+search_groups_ok(
+ { query => 'Disabled = 1', orderby => 'id' },
+ [ $group_baz->id . ': baz' ],
+ 'disabled groups'
+);
+
+sub search_groups_ok {
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+ my $query = shift;
+ my $expected = shift;
+ my $name = shift || 'search groups';
+
+ my $uri = URI->new("$baseurl/REST/1.0/search/group");
+ $uri->query_form(%$query);
+ $m->get_ok($uri);
+
+ my @lines = split /\n/, $m->content;
+ shift @lines; # header
+ shift @lines; # empty line
+
+ is_deeply( \@lines, $expected, $name );
+
+}
+
+undef $m;
+done_testing();
diff --git a/rt/t/web/rest-search-queue.t b/rt/t/web/rest-search-queue.t
new file mode 100644
index 000000000..a827d8643
--- /dev/null
+++ b/rt/t/web/rest-search-queue.t
@@ -0,0 +1,104 @@
+use strict;
+use warnings;
+use RT::Test tests => undef;
+
+my $queue_foo = RT::Test->load_or_create_queue( Name => 'Foo' );
+my $queue_bar = RT::Test->load_or_create_queue( Name => 'Bar' );
+my $queue_baz = RT::Test->load_or_create_queue( Name => 'Baz' );
+$queue_baz->SetDisabled(1);
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+
+ok( $m->login, 'logged in' );
+
+search_queues_ok( { query => 'id = 1' }, ['1: General'], 'search id = 1' );
+search_queues_ok(
+ {
+ query => 'Name = General',
+ format => 's',
+ fields => 'id,name,description'
+ },
+ [ "id\tName\tDescription", "1\tGeneral\tThe default queue" ],
+ 'search by name with customized fields'
+);
+
+search_queues_ok(
+ { query => 'id > 10' },
+ ['No matching results.'],
+ 'no matching results'
+);
+
+search_queues_ok(
+ { query => 'foo = 3' },
+ ['Invalid field specification: foo'],
+ 'invalid field'
+);
+
+search_queues_ok(
+ { query => 'id foo 3' },
+ ['Invalid operator specification: foo'],
+ 'invalid op'
+);
+
+search_queues_ok(
+ { query => '', orderby => 'id' },
+ [ '1: General', $queue_foo->id . ': Foo', $queue_bar->id . ': Bar', ],
+ 'order by id'
+);
+
+search_queues_ok(
+ { query => '', orderby => 'name' },
+ [ $queue_bar->id . ': Bar', $queue_foo->id . ': Foo', '1: General', ],
+ 'order by name'
+);
+
+search_queues_ok(
+ { query => '', orderby => '+name' },
+ [ $queue_bar->id . ': Bar', $queue_foo->id . ': Foo', '1: General', ],
+ 'order by +name'
+);
+
+search_queues_ok(
+ { query => '', orderby => '-name' },
+ [ '1: General', $queue_foo->id . ': Foo', $queue_bar->id . ': Bar', ],
+ 'order by -name'
+);
+
+search_queues_ok(
+ { query => 'Disabled = 0', orderby => 'id' },
+ [ '1: General', $queue_foo->id . ': Foo', $queue_bar->id . ': Bar', ],
+ 'enabled queues'
+);
+
+search_queues_ok(
+ { query => 'Disabled = 1', orderby => 'id' },
+ [ $queue_baz->id . ': Baz', ],
+ 'disabled queues'
+);
+
+search_queues_ok(
+ { query => 'Disabled = 2', orderby => 'id' },
+ [ '2: ___Approvals', ],
+ 'special Approvals queue'
+);
+
+sub search_queues_ok {
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+ my $query = shift;
+ my $expected = shift;
+ my $name = shift || 'search queues';
+
+ my $uri = URI->new("$baseurl/REST/1.0/search/queue");
+ $uri->query_form(%$query);
+ $m->get_ok($uri);
+
+ my @lines = split /\n/, $m->content;
+ shift @lines; # header
+ shift @lines; # empty line
+
+ is_deeply( \@lines, $expected, $name );
+
+}
+
+undef $m;
+done_testing();
diff --git a/rt/t/web/rest-search-user.t b/rt/t/web/rest-search-user.t
new file mode 100644
index 000000000..84a967377
--- /dev/null
+++ b/rt/t/web/rest-search-user.t
@@ -0,0 +1,115 @@
+use strict;
+use warnings;
+use RT::Test tests => undef;
+
+my $root = RT::Test->load_or_create_user( Name => 'root', );
+my $user_foo = RT::Test->load_or_create_user(
+ Name => 'foo',
+ Password => 'password',
+);
+my $user_bar = RT::Test->load_or_create_user( Name => 'bar' );
+my $user_baz = RT::Test->load_or_create_user( Name => 'baz' );
+$user_baz->SetDisabled(1);
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+
+ok( $m->login, 'logged in' );
+
+search_users_ok(
+ { query => 'id = ' . $user_foo->id },
+ [ $user_foo->id . ': foo' ],
+ 'search by id'
+);
+
+search_users_ok(
+ {
+ query => 'Name = ' . $user_foo->Name,
+ format => 's',
+ fields => 'id,name'
+ },
+ [ "id\tName", $user_foo->id . "\tfoo" ],
+ 'search by name with customized fields'
+);
+
+
+search_users_ok(
+ { query => 'foo = 3' },
+ ['Invalid field specification: foo'],
+ 'invalid field'
+);
+
+search_users_ok(
+ { query => 'id foo 3' },
+ ['Invalid operator specification: foo'],
+ 'invalid op'
+);
+
+search_users_ok(
+ { query => 'password = foo' },
+ ['Invalid field specification: password'],
+ "can't search password"
+);
+
+search_users_ok(
+ { query => '', orderby => 'id' },
+ [ $root->id . ': root', $user_foo->id . ': foo', $user_bar->id . ': bar', ],
+ 'order by id'
+);
+
+search_users_ok(
+ { query => '', orderby => 'name' },
+ [ $user_bar->id . ': bar', $user_foo->id . ': foo', $root->id . ': root' ],
+ 'order by name'
+);
+
+search_users_ok(
+ { query => '', orderby => '+name' },
+ [ $user_bar->id . ': bar', $user_foo->id . ': foo', $root->id . ': root' ],
+ 'order by +name'
+);
+
+search_users_ok(
+ { query => '', orderby => '-name' },
+ [ $root->id . ': root', $user_foo->id . ': foo', $user_bar->id . ': bar' ],
+ 'order by -name'
+);
+
+search_users_ok(
+ { query => 'Disabled = 0', orderby => 'id' },
+ [ $root->id . ': root', $user_foo->id . ': foo', $user_bar->id . ': bar', ],
+ 'enabled users'
+);
+
+search_users_ok(
+ { query => 'Disabled = 1', orderby => 'id' },
+ [ $user_baz->id . ': baz', ],
+ 'disabled users'
+);
+
+ok( $m->login( 'foo', 'password', logout => 1 ), 'logged in as foo' );
+search_users_ok(
+ { query => 'id = ' . $user_foo->id },
+ [ 'Permission denied' ],
+ "can't search without permission"
+);
+
+sub search_users_ok {
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+ my $query = shift;
+ my $expected = shift;
+ my $name = shift || 'search users';
+
+ my $uri = URI->new("$baseurl/REST/1.0/search/user");
+ $uri->query_form(%$query);
+ $m->get_ok($uri);
+
+ my @lines = split /\n/, $m->content;
+ shift @lines; # header
+ shift @lines; # empty line
+
+ is_deeply( \@lines, $expected, $name );
+
+}
+
+undef $m;
+done_testing();
diff --git a/rt/t/web/rest.t b/rt/t/web/rest.t
index 3a84b2a01..8b8cbcb86 100644
--- a/rt/t/web/rest.t
+++ b/rt/t/web/rest.t
@@ -204,7 +204,7 @@ is($link, 1, "Check ticket link.") or diag("'content' obtained:\n", $m->content)
$text = $m->content;
$text =~ s/.*?\n\n//;
$text =~ s/\n\n/\n/;
- $text =~ s{CF\.{severity}:.*\n}{}img;
+ $text =~ s{CF\.\{severity\}:.*\n}{}img;
$text .= "CF.{severity}: explosive, a bit\n";
$m->post(
"$baseurl/REST/1.0/ticket/edit",
@@ -234,7 +234,7 @@ is($link, 1, "Check ticket link.") or diag("'content' obtained:\n", $m->content)
]
);
$text = $m->content;
- $text =~ s{CF\.{severity}:.*\n}{}img;
+ $text =~ s{CF\.\{severity\}:.*\n}{}img;
$text .= "CF.{severity}:\n";
$m->post(
"$baseurl/REST/1.0/ticket/edit",
@@ -301,7 +301,7 @@ is($link, 1, "Check ticket link.") or diag("'content' obtained:\n", $m->content)
]
);
$text = $m->content;
- $text =~ s{CF\.{single}:.*\n}{}img;
+ $text =~ s{CF\.\{single\}:.*\n}{}img;
$text .= "CF.{single}: that\n";
$m->post(
"$baseurl/REST/1.0/ticket/edit",
diff --git a/rt/t/web/rest_user_cf.t b/rt/t/web/rest_user_cf.t
new file mode 100644
index 000000000..d9f4ea3ba
--- /dev/null
+++ b/rt/t/web/rest_user_cf.t
@@ -0,0 +1,26 @@
+use strict;
+use warnings;
+use RT::Interface::REST;
+
+use RT::Test tests => undef;
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+
+my $cf = RT::Test->load_or_create_custom_field(
+ Name => 'foo',
+ Type => 'Freeform',
+ LookupType => 'RT::User',
+);
+$cf->AddToObject(RT::User->new(RT->SystemUser));
+
+my $root = RT::User->new( RT->SystemUser );
+$root->Load('root');
+$root->AddCustomFieldValue( Field => 'foo', Value => 'blabla' );
+is( $root->FirstCustomFieldValue('foo'), 'blabla', 'cf is set' );
+
+ok( $m->login, 'logged in' );
+$m->post( "$baseurl/REST/1.0/show", [ id => 'user/12', ] );
+like( $m->content, qr/CF-foo: blabla/, 'found the cf' );
+
+undef $m;
+done_testing;
diff --git a/rt/t/web/richtext-autohandler.t b/rt/t/web/richtext-autohandler.t
deleted file mode 100644
index 724a7b34c..000000000
--- a/rt/t/web/richtext-autohandler.t
+++ /dev/null
@@ -1,14 +0,0 @@
-use strict;
-use warnings;
-
-use RT::Test tests => 9;
-my ($baseurl, $agent) = RT::Test->started_ok;
-
-$agent->get("$baseurl/NoAuth/RichText/ckeditor/config.js");
-is($agent->status, 403);
-$agent->content_lacks("config.disableNativeSpellChecker");
-
-$agent->get_ok("/NoAuth/RichText/config.js");
-$agent->content_contains("config.disableNativeSpellChecker");
-
-$agent->warning_like(qr/Invalid request directly to the rich text editor/,);
diff --git a/rt/t/web/rights.t b/rt/t/web/rights.t
index 23b357f79..c7e8aac00 100644
--- a/rt/t/web/rights.t
+++ b/rt/t/web/rights.t
@@ -6,7 +6,7 @@ use RT::Test tests => 14;
my ($baseurl, $m) = RT::Test->started_ok;
ok $m->login, "logged in";
-$m->follow_link_ok({ id => 'tools-config-global-group-rights'});
+$m->follow_link_ok({ id => 'admin-global-group-rights'});
sub get_rights {
diff --git a/rt/t/web/rights1.t b/rt/t/web/rights1.t
index 63ddb38c4..2cc7689c6 100644
--- a/rt/t/web/rights1.t
+++ b/rt/t/web/rights1.t
@@ -29,9 +29,9 @@ $agent->login( $user_obj->Name, 'customer');
# Test for absence of Configure and Preferences tabs.
ok(!$agent->find_link( url => "$RT::WebPath/Admin/",
- text => 'Configuration'), "No config tab" );
+ text => 'Admin'), "No admin tab" );
ok(!$agent->find_link( url => "$RT::WebPath/User/Prefs.html",
- text => 'Preferences'), "No prefs pane" );
+ 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.
@@ -43,20 +43,20 @@ $agent->reload;
$agent->content_contains('Logout', "Reloaded page successfully");
ok($agent->find_link( url => "$RT::WebPath/Admin/",
- text => 'Configuration'), "Found config tab" );
+ text => 'Admin'), "Found admin 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();
$agent->content_contains('Logout', "Reloaded page successfully");
-ok($agent->find_link(
- id => 'preferences-settings' ), "Found prefs pane" );
+ok($agent->find_link(
+ id => 'preferences-settings' ), "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');
+ text => 'Tickets');
is($agent->status, 200, "Fetched search builder page");
$agent->content_lacks("Load saved search", "No search loading box");
$agent->content_lacks("Saved searches", "No saved searches box");
@@ -79,23 +79,23 @@ $agent->content_like(qr/input\s+type=['"]submit['"][^>]+name=['"]SavedSearchSave
# via SelectOwner.
my $queue_obj = RT::Queue->new(RT->SystemUser);
-($ret, $msg) = $queue_obj->Create(Name => 'CustomerQueue-'.$$,
- Description => 'queue for SelectOwner testing');
+($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');
+ 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);
-
+ Object => $queue_obj);
+
ok($grantid,$grantmsg);
($grantid,$grantmsg) =$group_obj->PrincipalObj->GrantRight(Right => 'SeeQueue',
- Object => $queue_obj);
+ 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.
diff --git a/rt/t/web/saved_search_chart.t b/rt/t/web/saved_search_chart.t
index 70111b97c..3737b512e 100644
--- a/rt/t/web/saved_search_chart.t
+++ b/rt/t/web/saved_search_chart.t
@@ -58,7 +58,7 @@ $m->submit_form(
form_name => 'SaveSearch',
fields => {
Query => 'id=2',
- PrimaryGroupBy => 'Status',
+ GroupBy => 'Status',
ChartStyle => 'pie',
},
button => 'SavedSearchSave',
@@ -67,13 +67,13 @@ $m->submit_form(
$m->content_contains("Chart first chart updated", 'found updated message' );
$m->content_contains("id=2", 'Query is updated' );
$m->content_like( qr/value="Status"\s+selected="selected"/,
- 'PrimaryGroupBy is updated' );
+ 'GroupBy 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('GroupBy'),
+ 'Status', 'GroupBy is indeed updated' );
is( $search->SubValue('ChartStyle'), 'pie', 'ChartStyle is indeed updated' );
# finally, let's test delete
diff --git a/rt/t/web/saved_search_permissions.t b/rt/t/web/saved_search_permissions.t
index f61c931a0..e24ae6146 100644
--- a/rt/t/web/saved_search_permissions.t
+++ b/rt/t/web/saved_search_permissions.t
@@ -26,7 +26,7 @@ ok( $m->login( 'foo', 'foobar', logout => 1 ), '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 );
+RT::Interface::Web::EscapeHTML( \$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+/,
diff --git a/rt/t/web/scrips.t b/rt/t/web/scrips.t
index 0ff46bf26..d669f4c4e 100644
--- a/rt/t/web/scrips.t
+++ b/rt/t/web/scrips.t
@@ -1,7 +1,9 @@
use strict;
use warnings;
-use RT::Test tests => 14;
+use RT::Test tests => undef;
+
+RT->Config->Set( UseTransactionBatch => 1 );
# TODO:
# Test the rest of the conditions.
@@ -9,10 +11,16 @@ use RT::Test tests => 14;
# Test templates?
# Test cleanup scripts.
+my $queue_g = RT::Test->load_or_create_queue( Name => 'General' );
+ok $queue_g && $queue_g->id, 'loaded or created queue';
+
+my $queue_r = RT::Test->load_or_create_queue( Name => 'Regression' );
+ok $queue_r && $queue_r->id, 'loaded or created queue';
+
my ($baseurl, $m) = RT::Test->started_ok;
ok $m->login, "logged in";
-$m->follow_link_ok({id => 'tools-config-global-scrips-create'});
+$m->follow_link_ok({id => 'admin-global-scrips-create'});
sub prepare_code_with_value {
my $value = shift;
@@ -47,16 +55,17 @@ sub prepare_code_with_value {
foreach my $data (@values_for_actions) {
my ($condition, $prepare_code_value) = @$data;
diag "Create Scrip (Cond #$condition)" if $ENV{TEST_VERBOSE};
- $m->follow_link_ok({id => 'tools-config-global-scrips-create'});
+ $m->follow_link_ok({id => 'admin-global-scrips-create'});
my $prepare_code = prepare_code_with_value($prepare_code_value);
- $m->form_name('ModifyScrip');
+ $m->form_name('CreateScrip');
$m->set_fields(
- 'Scrip-new-ScripCondition' => $condition,
- 'Scrip-new-ScripAction' => 15, # User Defined
- 'Scrip-new-Template' => 1, # Blank
- 'Scrip-new-CustomPrepareCode' => $prepare_code,
+ 'ScripCondition' => $condition,
+ 'ScripAction' => 'User Defined',
+ 'Template' => 'Blank',
+ 'CustomPrepareCode' => $prepare_code,
);
- $m->submit;
+ $m->click('Create');
+ $m->content_like(qr{Scrip Created});
}
my $ticket_obj = RT::Test->create_ticket(
@@ -76,7 +85,7 @@ sub prepare_code_with_value {
$m->submit_form(
form_name => 'ForwardMessage',
fields => {
- To => 'rt-test, rt-to@example.com',
+ To => 'rt-test@example.com, rt-to@example.com',
},
button => 'ForwardAndReturn'
);
@@ -92,7 +101,7 @@ sub prepare_code_with_value {
$m->submit_form(
form_name => 'ForwardMessage',
fields => {
- To => 'rt-test, rt-to@example.com',
+ To => 'rt-test@example.com, rt-to@example.com',
},
button => 'ForwardAndReturn'
);
@@ -101,3 +110,191 @@ sub prepare_code_with_value {
RT::Test->clean_caught_mails;
}
+
+note "check basics in scrip's admin interface";
+{
+ $m->follow_link_ok( { id => 'admin-global-scrips-create' } );
+ ok $m->form_name('CreateScrip');
+ is $m->value_name('Description'), '', 'empty value';
+ is $m->value_name('ScripAction'), '-', 'empty value';
+ is $m->value_name('ScripCondition'), '-', 'empty value';
+ is $m->value_name('Template'), '-', 'empty value';
+ $m->field('Description' => 'test');
+ $m->click('Create');
+ $m->content_contains("Action is mandatory argument");
+
+ ok $m->form_name('CreateScrip');
+ is $m->value_name('Description'), 'test', 'value stays on the page';
+ $m->select('ScripAction' => 'Notify Ccs');
+ $m->click('Create');
+ $m->content_contains("Template is mandatory argument");
+
+ ok $m->form_name('CreateScrip');
+ is $m->value_name('Description'), 'test', 'value stays on the page';
+ is $m->value_name('ScripAction'), 'Notify Ccs', 'value stays on the page';
+ $m->select('Template' => 'Blank');
+ $m->click('Create');
+ $m->content_contains("Condition is mandatory argument");
+
+ ok $m->form_name('CreateScrip');
+ is $m->value_name('Description'), 'test', 'value stays on the page';
+ is $m->value_name('ScripAction'), 'Notify Ccs', 'value stays on the page';
+ $m->select('ScripCondition' => 'On Close');
+ $m->click('Create');
+ $m->content_contains("Scrip Created");
+
+ ok $m->form_name('ModifyScrip');
+ is $m->value_name('Description'), 'test', 'correct value';
+ is $m->value_name('ScripCondition'), 'On Close', 'correct value';
+ is $m->value_name('ScripAction'), 'Notify Ccs', 'correct value';
+ is $m->value_name('Template'), 'Blank', 'correct value';
+ $m->field('Description' => 'test test');
+ $m->click('Update');
+ # regression
+ $m->content_lacks("Template is mandatory argument");
+
+ ok $m->form_name('ModifyScrip');
+ is $m->value_name('Description'), 'test test', 'correct value';
+ $m->content_contains("Description changed from", "found action result message");
+}
+
+note "check application in admin interface";
+{
+ $m->follow_link_ok({ id => 'admin-global-scrips-create' });
+ $m->submit_form_ok({
+ with_fields => {
+ Description => "testing application",
+ ScripCondition => "On Create",
+ ScripAction => "Open Tickets",
+ Template => "Blank",
+ },
+ button => 'Create',
+ }, "created scrip");
+ $m->content_contains("Scrip Created", "found result message");
+
+ my ($sid) = ($m->content =~ /Modify scrip #(\d+)/);
+ ok $sid, "found scrip id on the page";
+ RT::Test->object_scrips_are($sid, [0]);
+
+ $m->follow_link_ok({ id => 'page-applies-to' });
+ ok $m->form_name("AddRemoveScrip"), "found form";
+ $m->tick("RemoveScrip-$sid", 0);
+ $m->click_ok("Update", "update scrip application");
+ RT::Test->object_scrips_are($sid, []);
+
+ ok $m->form_name("AddRemoveScrip"), "found form";
+ $m->tick("AddScrip-$sid", 0);
+ $m->tick("AddScrip-$sid", $queue_g->id);
+ $m->click_ok("Update", "update scrip application");
+ RT::Test->object_scrips_are($sid, [0], [$queue_g->id, $queue_r->id]);
+}
+
+note "check templates in scrip's admin interface";
+{
+ my $template = RT::Template->new( RT->SystemUser );
+ my ($status, $msg) = $template->Create( Queue => $queue_g->id, Name => 'foo' );
+ ok $status, 'created a template';
+
+ my $templates = RT::Templates->new( RT->SystemUser );
+ $templates->LimitToGlobal;
+
+ my @default = (
+ '',
+ map $_->Name, @{$templates->ItemsArrayRef}
+ );
+
+ $m->follow_link_ok( { id => 'admin-global-scrips-create' } );
+ ok $m->form_name('CreateScrip');
+ my @templates = ($m->find_all_inputs( type => 'option', name => 'Template' ))[0]
+ ->possible_values;
+ is_deeply([sort @templates], [sort @default]);
+
+ $m->follow_link_ok( { id => 'admin-queues' } );
+ $m->follow_link_ok( { text => 'General' } );
+ $m->follow_link_ok( { id => 'page-scrips-create' } );
+
+ ok $m->form_name('CreateScrip');
+ @templates = ($m->find_all_inputs( type => 'option', name => 'Template' ))[0]
+ ->possible_values;
+ is_deeply([sort @templates], [sort @default, 'foo']);
+
+note "make sure we can not apply scrip to queue without required template";
+ $m->field('Description' => 'test template');
+ $m->select('ScripCondition' => 'On Close');
+ $m->select('ScripAction' => 'Notify Ccs');
+ $m->select('Template' => 'foo');
+ $m->click('Create');
+ $m->content_contains("Scrip Created");
+
+ $m->follow_link_ok( { id => 'page-applies-to' } );
+ my ($id) = ($m->content =~ /Modify associated objects for scrip #(\d+)/);
+ $m->form_name('AddRemoveScrip');
+ $m->tick('AddScrip-'.$id, $queue_r->id);
+ $m->click('Update');
+ $m->content_like(qr{No template foo in queue Regression or global});
+
+note "unapply the scrip from any queue";
+ $m->form_name('AddRemoveScrip');
+ $m->tick('RemoveScrip-'.$id, $queue_g->id);
+ $m->click('Update');
+ $m->content_like(qr{Object deleted});
+
+note "you can pick any template";
+ $m->follow_link_ok( { id => 'page-basics' } );
+ ok $m->form_name('ModifyScrip');
+ @templates = ($m->find_all_inputs( type => 'option', name => 'Template' ))[0]
+ ->possible_values;
+ is_deeply(
+ [sort @templates],
+ [sort do {
+ my $t = RT::Templates->new( RT->SystemUser );
+ $t->UnLimit;
+ ('', $t->DistinctFieldValues('Name'))
+ }],
+ );
+
+note "go to apply page and apply with template change";
+ $m->follow_link_ok( { id => 'page-applies-to' } );
+ $m->form_name('AddRemoveScrip');
+ $m->field('Template' => 'blank');
+ $m->tick('AddScrip-'.$id, $queue_g->id);
+ $m->tick('AddScrip-'.$id, $queue_r->id);
+ $m->click('Update');
+ $m->content_contains("Template: Template changed from ");
+ $m->content_contains("Object created");
+}
+
+note "apply scrip in different stage to different queues";
+{
+ $m->follow_link_ok( { id => 'admin-queues' } );
+ $m->follow_link_ok( { text => 'General' } );
+ $m->follow_link_ok( { id => 'page-scrips-create'});
+
+ ok $m->form_name('CreateScrip');
+ $m->field('Description' => 'test stage');
+ $m->select('ScripCondition' => 'On Close');
+ $m->select('ScripAction' => 'Notify Ccs');
+ $m->select('Template' => 'Blank');
+ $m->click('Create');
+ $m->content_contains("Scrip Created");
+
+ my ($sid) = ($m->content =~ /Modify scrip #(\d+)/);
+ ok $sid, "found scrip id on the page";
+
+ $m->follow_link_ok({ text => 'Applies to' });
+ ok $m->form_name('AddRemoveScrip');
+ $m->select('Stage' => 'Batch');
+ $m->tick( "AddScrip-$sid" => $queue_r->id );
+ $m->click('Update');
+ $m->content_contains("Object created");
+
+ $m->follow_link_ok({ text => 'General' });
+ $m->follow_link_ok({ id => 'page-scrips' });
+
+ my (@matches) = $m->content =~ /test stage/g;
+ # regression
+ is scalar @matches, 1, 'scrip mentioned only once';
+}
+
+undef $m;
+done_testing;
diff --git a/rt/t/web/search_bulk_update_links.t b/rt/t/web/search_bulk_update_links.t
index ffe2efe81..d9b477e03 100644
--- a/rt/t/web/search_bulk_update_links.t
+++ b/rt/t/web/search_bulk_update_links.t
@@ -1,7 +1,7 @@
use strict;
use warnings;
-use RT::Test tests => 47;
+use RT::Test tests => 46;
my ( $url, $m ) = RT::Test->started_ok;
ok( $m->login, 'logged in' );
@@ -79,7 +79,7 @@ $m->content_lacks( 'DeleteLink--', 'no delete link stuff' );
$m->form_name('BulkUpdate');
my @fields = qw/Owner AddRequestor DeleteRequestor AddCc DeleteCc AddAdminCc
DeleteAdminCc Subject Priority Queue Status Starts_Date Told_Date Due_Date
-Resolved_Date UpdateSubject UpdateContent/;
+UpdateSubject UpdateContent/;
for my $field ( @fields ) {
is( $m->value($field), '', "default $field is empty" );
}
diff --git a/rt/t/web/search_ical.t b/rt/t/web/search_ical.t
new file mode 100644
index 000000000..094d8a2de
--- /dev/null
+++ b/rt/t/web/search_ical.t
@@ -0,0 +1,196 @@
+use strict;
+use warnings;
+
+use Data::ICal;
+use RT::Test tests => 77;
+
+my $start_obj = RT::Date->new( RT->SystemUser );
+$start_obj->SetToNow;
+my $start = $start_obj->iCal( Time => 1);
+
+my $due_obj = RT::Date->new( RT->SystemUser );
+$due_obj->SetToNow;
+$due_obj->AddDays(2);
+my $due = $due_obj->iCal( Time => 1);
+
+diag 'Test iCal with date only';
+{
+ my ($baseurl, $agent) = RT::Test->started_ok;
+
+ my $ticket = RT::Ticket->new(RT->SystemUser);
+
+ for ( 1 .. 5 ) {
+ $ticket->Create(
+ Subject => 'Ticket ' . $_,
+ Queue => 'General',
+ Owner => 'root',
+ Requestor => 'ical@localhost',
+ Starts => $start_obj->ISO,
+ Due => $due_obj->ISO,
+ );
+ }
+
+ 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('DoSearch');
+ $agent->follow_link_ok({id => 'page-results'});
+
+ for ( 1 .. 5 ) {
+ $agent->content_contains('Ticket ' . $_);
+ }
+
+ $agent->follow_link_ok( { text => 'iCal' } );
+
+ is( $agent->content_type, 'text/calendar', 'content type is text/calendar' );
+
+ for ( 1 .. 5 ) {
+ $agent->content_like(qr/URL\:$baseurl\/Ticket\/Display\.html\?id=$_/);
+ }
+
+ my $ical = Data::ICal->new(data => $agent->content);
+
+ my @entries = $ical->entries;
+ my $ical_count = @{$entries[0]};
+ is( $ical_count, 10, "Got $ical_count ical entries");
+
+ my $prop_ref = $entries[0]->[0]->properties;
+ my $start_as_root = RT::Date->new( RT::CurrentUser->new( 'root' ) );
+ $start_as_root->Unix( $start_obj->Unix );
+ my $start = $start_as_root->ISO( Time => 0, Timezone => 'user' );
+ $start =~ s/-//g;
+ is($prop_ref->{'dtstart'}->[0]->value, $start, "Got start date: $start");
+ like( $prop_ref->{'dtstart'}->[0]->as_string, qr/VALUE=DATE\:/, 'Got DATE value');
+
+ $prop_ref = $entries[0]->[1]->properties;
+ my $due_as_root = RT::Date->new( RT::CurrentUser->new( 'root' ) );
+ $due_as_root->Unix( $due_obj->Unix );
+ my $due = $due_as_root->ISO( Time => 0, Timezone => 'user' );
+ $due =~ s/-//g;
+ is($prop_ref->{'dtend'}->[0]->value, $due, "Got due date: $due");
+ like( $prop_ref->{'dtend'}->[0]->as_string, qr/VALUE=DATE\:/, 'Got DATE value');
+}
+
+RT::Test->stop_server;
+
+diag 'Test iCal with date and time with config option';
+{
+ RT->Config->Set(TimeInICal =>1);
+ my ($baseurl, $agent) = RT::Test->started_ok;
+
+ 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('DoSearch');
+ $agent->follow_link_ok({id => 'page-results'});
+
+ for ( 1 .. 5 ) {
+ $agent->content_contains('Ticket ' . $_);
+ }
+
+ my $link = $agent->find_link( text => 'iCal' ); # use $link later
+ $agent->get_ok($link->url);
+
+ is( $agent->content_type, 'text/calendar', 'content type is text/calendar' );
+
+ for ( 1 .. 5 ) {
+ $agent->content_like(qr/URL\:$baseurl\/Ticket\/Display\.html\?id=$_/);
+ }
+
+ my $ical = Data::ICal->new(data => $agent->content);
+
+ my @entries = $ical->entries;
+ my $ical_count = @{$entries[0]};
+ is( $ical_count, 10, "Got $ical_count ical entries");
+
+ my $prop_ref = $entries[0]->[0]->properties;
+ $start =~ s/-//g;
+ is($prop_ref->{'dtstart'}->[0]->value, $start, "Got start date with time: $start");
+ like( $prop_ref->{'dtstart'}->[0]->as_string, qr/VALUE=DATE-TIME\:/, 'Got DATE-TIME value');
+
+ $prop_ref = $entries[0]->[1]->properties;
+ $due =~ s/-//g;
+ is($prop_ref->{'dtend'}->[0]->value, $due, "Got due date with time: $due");
+ like( $prop_ref->{'dtend'}->[0]->as_string, qr/VALUE=DATE-TIME\:/, 'Got DATE-TIME value');
+}
+
+RT::Test->stop_server;
+
+diag 'Test iCal with date and time using query param';
+{
+ RT->Config->Set(TimeInICal =>0);
+ my ($baseurl, $agent) = RT::Test->started_ok;
+
+ 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('DoSearch');
+ $agent->follow_link_ok({id => 'page-results'});
+
+ for ( 1 .. 5 ) {
+ $agent->content_contains('Ticket ' . $_);
+ }
+
+ my $link = $agent->find_link( text => 'iCal' );
+ $agent->get_ok($link->url . '?Time=1');
+
+ is( $agent->content_type, 'text/calendar', 'content type is text/calendar' );
+
+ for ( 1 .. 5 ) {
+ $agent->content_like(qr/URL\:$baseurl\/Ticket\/Display\.html\?id=$_/);
+ }
+
+ my $ical = Data::ICal->new(data => $agent->content);
+
+ my @entries = $ical->entries;
+ my $ical_count = @{$entries[0]};
+ is( $ical_count, 10, "Got $ical_count ical entries");
+
+ my $prop_ref = $entries[0]->[0]->properties;
+ $start =~ s/-//g;
+ is($prop_ref->{'dtstart'}->[0]->value, $start, "Got start date with time: $start");
+ like( $prop_ref->{'dtstart'}->[0]->as_string, qr/VALUE=DATE-TIME\:/, 'Got DATE-TIME value');
+
+ $prop_ref = $entries[0]->[1]->properties;
+ $due =~ s/-//g;
+ is($prop_ref->{'dtend'}->[0]->value, $due, "Got due date with time: $due");
+ like( $prop_ref->{'dtend'}->[0]->as_string, qr/VALUE=DATE-TIME\:/, 'Got DATE-TIME value');
+
+ diag 'Test iCal with date and time in single events';
+
+ my $url = $link->url . '?SingleEvent=1&Time=1';
+ $agent->get_ok($url);
+
+ is( $agent->content_type, 'text/calendar', 'content type is text/calendar' );
+
+ for ( 1 .. 5 ) {
+ $agent->content_like(qr/URL\:$baseurl\/Ticket\/Display\.html\?id=$_/);
+ }
+
+ $ical = Data::ICal->new(data => $agent->content);
+
+ @entries = $ical->entries;
+ $ical_count = @{$entries[0]};
+
+ # Only 5 entries in single event mode
+ is( $ical_count, 5, "Got $ical_count ical entries");
+
+ $prop_ref = $entries[0]->[0]->properties;
+ $start =~ s/-//g;
+ is($prop_ref->{'dtstart'}->[0]->value, $start, "Got start date with time: $start");
+ like( $prop_ref->{'dtstart'}->[0]->as_string, qr/VALUE=DATE-TIME\:/, 'Got DATE-TIME value');
+
+ $prop_ref = $entries[0]->[1]->properties;
+ $due =~ s/-//g;
+ is($prop_ref->{'dtend'}->[0]->value, $due, "Got due date with time: $due");
+ like( $prop_ref->{'dtend'}->[0]->as_string, qr/VALUE=DATE-TIME\:/, 'Got DATE-TIME value');
+}
diff --git a/rt/t/web/search_rss.t b/rt/t/web/search_rss.t
index 9a53a8d94..7f1fdc1c3 100644
--- a/rt/t/web/search_rss.t
+++ b/rt/t/web/search_rss.t
@@ -39,14 +39,11 @@ my $rss_content = $agent->content;
$agent->get_ok($rdf_path);
is($agent->content, $rss_content, 'old Results.rdf still works');
-SKIP: {
- eval { require XML::Simple; };
- skip 'no XML::Simple found', 6 if $@;
- my $rss = XML::Simple::XMLin( $rss_content );
- is( scalar @{ $rss->{item} }, 5, 'item number' );
- for ( 1 .. 5 ) {
- is( $rss->{item}[$_-1]{title}, 'Ticket ' . $_, 'title' . $_ );
- }
+use XML::Simple;
+my $rss = XML::Simple::XMLin( $rss_content );
+is( scalar @{ $rss->{item} }, 5, 'item number' );
+for ( 1 .. 5 ) {
+ is( $rss->{item}[$_-1]{title}, 'Ticket ' . $_, 'title' . $_ );
}
# not login at all
diff --git a/rt/t/web/search_simple.t b/rt/t/web/search_simple.t
index a1a3ce806..d7c47279f 100644
--- a/rt/t/web/search_simple.t
+++ b/rt/t/web/search_simple.t
@@ -44,14 +44,14 @@ my $t = RT::Ticket->new(RT->SystemUser);
{
my ($status, $msg) = $t->AddCustomFieldValue(
Field => $cf1->id,
- Value => 'Downtown');
+ Value => 'Downtown');
ok( $status, "Added CF value - $msg" );
}
{
my ($status, $msg) = $t->AddCustomFieldValue(
Field => $cf2->id,
- Value => 'Proxy');
+ Value => 'Proxy');
ok( $status, "Added CF value - $msg" );
}
diff --git a/rt/t/web/self_service.t b/rt/t/web/self_service.t
index adc90d776..7afc008c6 100644
--- a/rt/t/web/self_service.t
+++ b/rt/t/web/self_service.t
@@ -18,9 +18,8 @@ ok( $user_a && $user_a->id, 'loaded or created user' );
ok( ! $user_a->Privileged, 'user is not privileged' );
# Load Cc group
-my $Cc = RT::Group->new( RT->SystemUser );
-my($ok, $msg) = $Cc->LoadSystemRoleGroup( 'Cc' );
-ok($ok, $msg);
+my $Cc = RT::System->RoleGroup( 'Cc' );
+ok($Cc->id);
RT::Test->add_rights( { Principal => $Cc, Right => ['ShowTicket'] } );
my ($ticket) = RT::Test->create_ticket(
diff --git a/rt/t/web/googleish_search.t b/rt/t/web/simple_search.t
index a5f834eee..710efb1d1 100644
--- a/rt/t/web/googleish_search.t
+++ b/rt/t/web/simple_search.t
@@ -21,40 +21,41 @@ ok $two_words_queue && $two_words_queue->id, 'loaded or created a queue';
my $active = "( ".join( " OR ", map "Status = '$_'", RT::Queue->ActiveStatusArray())." )";
my $inactive = "( ".join( " OR ", map "Status = '$_'", RT::Queue->InactiveStatusArray())." )";
- require RT::Search::Googleish;
- my $parser = RT::Search::Googleish->new(
+ require RT::Search::Simple;
+ my $parser = RT::Search::Simple->new(
TicketsObj => $tickets,
Argument => '',
);
- is $parser->QueryToSQL("foo"), "$active AND ( Subject LIKE 'foo' )", "correct parsing";
+ is $parser->QueryToSQL("foo"), "( Subject LIKE 'foo' ) AND $active", "correct parsing";
+ is $parser->QueryToSQL("1 foo"), "( Subject LIKE 'foo' AND Subject LIKE '1' ) AND $active", "correct parsing";
is $parser->QueryToSQL("1"), "( Id = 1 )", "correct parsing";
is $parser->QueryToSQL("#1"), "( Id = 1 )", "correct parsing";
- is $parser->QueryToSQL("'1'"), "$active AND ( Subject LIKE '1' )", "correct parsing";
+ is $parser->QueryToSQL("'1'"), "( Subject LIKE '1' ) AND $active", "correct parsing";
is $parser->QueryToSQL("foo bar"),
- "$active AND ( Subject LIKE 'foo' AND Subject LIKE 'bar' )",
+ "( Subject LIKE 'foo' AND Subject LIKE 'bar' ) AND $active",
"correct parsing";
is $parser->QueryToSQL("'foo bar'"),
- "$active AND ( Subject LIKE 'foo bar' )",
+ "( Subject LIKE 'foo bar' ) AND $active",
"correct parsing";
is $parser->QueryToSQL("'foo \\' bar'"),
- "$active AND ( Subject LIKE 'foo \\' bar' )",
+ "( Subject LIKE 'foo \\' bar' ) AND $active",
"correct parsing";
is $parser->QueryToSQL('"foo \' bar"'),
- "$active AND ( Subject LIKE 'foo \\' bar' )",
+ "( Subject LIKE 'foo \\' bar' ) AND $active",
"correct parsing";
is $parser->QueryToSQL('"\f\o\o"'),
- "$active AND ( Subject LIKE '\\\\f\\\\o\\\\o' )",
+ "( Subject LIKE '\\\\f\\\\o\\\\o' ) AND $active",
"correct parsing";
is $parser->QueryToSQL("General"), "( Queue = 'General' ) AND $active", "correct parsing";
- is $parser->QueryToSQL("'Two Words'"), "$active AND ( Subject LIKE 'Two Words' )", "correct parsing";
+ is $parser->QueryToSQL("'Two Words'"), "( Subject LIKE 'Two Words' ) AND $active", "correct parsing";
is $parser->QueryToSQL("queue:'Two Words'"), "( Queue = 'Two Words' ) AND $active", "correct parsing";
is $parser->QueryToSQL("subject:'Two Words'"), "$active AND ( Subject LIKE 'Two Words' )", "correct parsing";
is $parser->QueryToSQL("me"), "( Owner.id = '__CurrentUser__' ) AND $active", "correct parsing";
- is $parser->QueryToSQL("'me'"), "$active AND ( Subject LIKE 'me' )", "correct parsing";
+ is $parser->QueryToSQL("'me'"), "( Subject LIKE 'me' ) AND $active", "correct parsing";
is $parser->QueryToSQL("owner:me"), "( Owner.id = '__CurrentUser__' ) AND $active", "correct parsing";
is $parser->QueryToSQL("owner:'me'"), "( Owner = 'me' ) AND $active", "correct parsing";
is $parser->QueryToSQL('owner:root@localhost'), "( Owner.EmailAddress = 'root\@localhost' ) AND $active", "Email address as owner";
@@ -164,7 +165,9 @@ for my $quote ( q{'}, q{"} ) {
Subject => qq!base${quote}ticket $$!,
Queue => 'general',
Owner => $user->Name,
- Requestor => qq!custom${quote}search\@localhost!,
+ ( $quote eq q{'}
+ ? (Requestor => qq!custom${quote}search\@localhost!)
+ : () ),
Content => qq!this is base${quote}ticket with quote inside!,
);
ok( $ticket_quote->id, 'created ticket with quote for custom search' );
@@ -188,7 +191,7 @@ for my $quote ( q{'}, q{"} ) {
$m->field( q => $q );
$m->submit;
my $escape_quote = $quote;
- RT::Interface::Web::EscapeUTF8(\$escape_quote);
+ RT::Interface::Web::EscapeHTML(\$escape_quote);
$m->content_contains( "base${escape_quote}ticket",
"base${quote}ticket is found" );
}
diff --git a/rt/t/web/smime/outgoing.t b/rt/t/web/smime/outgoing.t
new file mode 100644
index 000000000..21d2328f2
--- /dev/null
+++ b/rt/t/web/smime/outgoing.t
@@ -0,0 +1,384 @@
+use strict;
+use warnings;
+
+use RT::Test::SMIME tests => undef;
+my $test = 'RT::Test::SMIME';
+
+use RT::Action::SendEmail;
+use File::Temp qw(tempdir);
+
+use_ok('RT::Crypt::SMIME');
+
+RT::Test::SMIME->import_key('sender@example.com');
+
+my $user_email = 'root@example.com';
+{
+ my $user = RT::Test->load_or_create_user(
+ Name => $user_email, EmailAddress => $user_email
+ );
+ ok $user && $user->id, 'loaded or created user';
+ RT::Test::SMIME->import_key($user_email, $user);
+}
+
+my $queue = RT::Test->load_or_create_queue(
+ Name => 'Regression',
+ CorrespondAddress => 'sender@example.com',
+ CommentAddress => 'sender@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 => $user_email,
+ );
+ 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 => $user_email,
+ );
+ 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 sender@ so we can verify signatures and decrypt
+# like we are on another side recieving emails
+# ------------------------------------------------------------------------------
+
+my $keyring = $test->keyring_path;
+unlink $_ foreach glob( $keyring ."/*" );
+RT::Test::SMIME->import_key('sender@example.com.crt');
+RT::Test::SMIME->import_key($user_email);
+
+$queue = RT::Test->load_or_create_queue(
+ Name => 'Regression',
+ CorrespondAddress => $user_email,
+ CommentAddress => $user_email,
+);
+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 $txn->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'), 'SMIME',
+ "RT's outgoing mail has crypto" or exit 0;
+ is $msg->GetHeader('X-RT-Incoming-Encryption'), 'Not encrypted',
+ "RT's outgoing mail looks not encrypted";
+ like $msg->GetHeader('X-RT-Incoming-Signature'),
+ qr/<sender\@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'), 'SMIME',
+ "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'), 'SMIME',
+ "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/<sender\@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;
+
+ describe_options('creating a ticket: ', %args);
+
+ $m->goto_create_ticket( $queue );
+ $m->form_name('TicketCreate');
+ $m->field( Subject => 'test' );
+ $m->field( Requestors => $user_email );
+ $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;
+
+ describe_options('updating ticket #'. $tid .': ', %args);
+
+ 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/Correspondence added/, 'Correspondence added');# 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 );
+}
+
+undef $m;
+done_testing;
+
+sub check_text_emails {
+ my %args = %{ shift @_ };
+ my @mail = @_;
+
+ describe_options('testing that we got at least one mail: ', %args);
+
+ 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{'Encrypt'} ) {
+ like $mail, qr/application\/(?:x-)?pkcs7-mime/, 'outgoing email was processed';
+ } elsif ( $args{'Sign'} ) {
+ like $mail, qr/(?:x-)?pkcs7-signature/, 'outgoing email was processed';
+ } else {
+ unlike $mail, qr/smime/, 'outgoing email was not processed';
+ }
+ }
+ 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 RT-Originator RT-Ticket X-RT-Loop-Prevention) ) {
+ $mail =~ s/^$field:.*?\n(?! |\t)//gmsi;
+ }
+ return $mail;
+}
+
+sub set_queue_crypt_options {
+ my %args = @_;
+
+ describe_options('setting queue options: ', %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;
+}
+
+sub describe_options {
+ return unless $ENV{'TEST_VERBOSE'};
+
+ my $msg = shift;
+ my %args = @_;
+ if ( $args{'Encrypt'} && $args{'Sign'} ) {
+ $msg .= 'encrypt and sign';
+ }
+ elsif ( $args{'Sign'} ) {
+ $msg .= 'sign';
+ }
+ elsif ( $args{'Encrypt'} ) {
+ $msg .= 'encrypt';
+ }
+ else {
+ $msg .= 'no encrypt and no sign';
+ }
+ diag $msg;
+}
+
diff --git a/rt/t/web/squish.t b/rt/t/web/squish.t
index ff43e74fb..9d1c01b1f 100644
--- a/rt/t/web/squish.t
+++ b/rt/t/web/squish.t
@@ -5,18 +5,18 @@ use RT::Test tests => 26;
RT->Config->Set( DevelMode => 0 );
RT->Config->Set( WebDefaultStylesheet => 'aileron' );
-RT->Config->Set( MasonLocalComponentRoot => RT::Test::get_abs_relocatable_dir('html') );
+RT->Config->Set( LocalStaticPath => RT::Test::get_abs_relocatable_dir('static') );
my ( $url, $m ) = RT::Test->started_ok;
$m->login;
diag "test squished files with devel mode disabled";
-$m->follow_link_ok( { url_regex => qr!aileron-squished-([a-f0-9]{32})\.css! },
+$m->follow_link_ok( { url_regex => qr!aileron/squished-([a-f0-9]{32})\.css! },
'follow squished css' );
$m->content_like( qr!/\*\* End of .*?.css \*/!, 'squished css' );
-$m->content_lacks( 'text-decoration: underline !important;',
- 'no print.css by default' );
+$m->content_lacks( 'counteract the titlebox',
+ 'no mobile.css by default' );
$m->back;
my ($js_link) =
@@ -29,16 +29,16 @@ RT::Test->stop_server;
diag "test squished files with customized files and devel mode disabled";
RT->AddJavaScript( 'not-by-default.js' );
-RT->AddStyleSheets( 'print.css' );
+RT->AddStyleSheets( 'mobile.css' );
( $url, $m ) = RT::Test->started_ok;
$m->login;
-$m->follow_link_ok( { url_regex => qr!aileron-squished-([a-f0-9]{32})\.css! },
+$m->follow_link_ok( { url_regex => qr!aileron/squished-([a-f0-9]{32})\.css! },
'follow squished css' );
$m->content_like( qr!/\*\* End of .*?.css \*/!, 'squished css' );
-$m->content_contains( 'text-decoration: underline !important;',
- 'has print.css' );
+$m->content_contains( 'counteract the titlebox',
+ 'has mobile.css' );
$m->back;
($js_link) =
diff --git a/rt/t/web/html/NoAuth/js/not-by-default.js b/rt/t/web/static/js/not-by-default.js
index 568f670ee..568f670ee 100644
--- a/rt/t/web/html/NoAuth/js/not-by-default.js
+++ b/rt/t/web/static/js/not-by-default.js
diff --git a/rt/t/web/template.t b/rt/t/web/template.t
index 4a2e6c13a..1a02dc98d 100644
--- a/rt/t/web/template.t
+++ b/rt/t/web/template.t
@@ -17,7 +17,7 @@ ok( RT::Test->set_rights(
ok $m->login('user_a', 'password'), 'logged in as user A';
# get to the templates screen
-$m->follow_link( text => 'Configuration' );
+$m->follow_link( text => 'Admin' );
$m->title_is(q{RT Administration}, 'admin screen');
$m->follow_link( text => 'Global' );
diff --git a/rt/t/web/ticket-create-utf8.t b/rt/t/web/ticket-create-utf8.t
index 107e41d71..ebb2d5eab 100644
--- a/rt/t/web/ticket-create-utf8.t
+++ b/rt/t/web/ticket-create-utf8.t
@@ -32,7 +32,7 @@ foreach my $test_str ( $ru_test, $l1_test ) {
$m->submit;
$m->content_like(
- qr{<td\s+class="message-header-value"[^>]*>\s*\Q$test_str\E\s*</td>}i,
+ qr{<td\s+class="message-header-value\s*"[^>]*>\s*\Q$test_str\E\s*</td>}i,
'header on the page'
);
@@ -50,7 +50,7 @@ foreach my $test_str ( $ru_test, $l1_test ) {
$m->submit;
$m->content_like(
- qr{<td\s+class="message-header-value"[^>]*>\s*\Q$test_str\E\s*</td>}i,
+ qr{<td\s+class="message-header-value\s*"[^>]*>\s*\Q$test_str\E\s*</td>}i,
'header on the page'
);
$m->content_contains(
@@ -73,7 +73,7 @@ foreach my $test_str ( $ru_test, $l1_test ) {
$m->submit;
$m->content_like(
- qr{<td\s+class="message-header-value"[^>]*>\s*\Q$test_str\E\s*</td>}i,
+ qr{<td\s+class="message-header-value\s*"[^>]*>\s*\Q$test_str\E\s*</td>}i,
'header on the page'
);
$m->content_contains(
diff --git a/rt/t/web/ticket_forward.t b/rt/t/web/ticket_forward.t
index adf4d6f69..439242d48 100644
--- a/rt/t/web/ticket_forward.t
+++ b/rt/t/web/ticket_forward.t
@@ -36,19 +36,21 @@ diag "Forward Ticket" if $ENV{TEST_VERBOSE};
$m->submit_form(
form_name => 'ForwardMessage',
fields => {
- To => 'rt-test, rt-to@example.com',
- Cc => 'rt-cc@example.com',
+ To => '"Foo" <rt-foo@example.com>, rt-too@example.com',
+ Cc => 'rt-cc@example.com',
+ Bcc => 'root',
},
button => 'ForwardAndReturn'
);
- $m->content_contains( 'Sent email successfully', 'sent mail msg' );
$m->content_contains(
- 'Forwarded Ticket to rt-test, rt-to@example.com, rt-cc@example.com',
+ 'Forwarded Ticket to Foo &lt;rt-foo@example.com&gt;, &lt;rt-too@example.com&gt;, &lt;rt-cc@example.com&gt;, root &#40;Enoch Root&#41;',
'txn msg' );
my ($mail) = RT::Test->fetch_caught_mails;
like( $mail, qr!Subject: test forward!, 'Subject field' );
- like( $mail, qr!To: rt-test, rt-to\@example.com!, 'To field' );
+ like( $mail, qr!To: .*?rt-foo\@example.com!i, 'To field' );
+ like( $mail, qr!To: .*?rt-too\@example.com!i, 'To field' );
like( $mail, qr!Cc: rt-cc\@example.com!i, 'Cc field' );
+ like( $mail, qr!Bcc: root\@localhost!i, 'Bcc field' );
like( $mail, qr!This is a forward of ticket!, 'content' );
like( $mail, qr!this is an attachment!, 'att content' );
like( $mail, qr!$att_name!, 'att file name' );
@@ -60,22 +62,22 @@ diag "Forward Transaction" if $ENV{TEST_VERBOSE};
$m->submit_form(
form_name => 'ForwardMessage',
fields => {
- To => 'rt-test, rt-to@example.com',
+ To => 'rt-to@example.com, rt-too@example.com',
Cc => 'rt-cc@example.com',
- Bcc => 'rt-bcc@example.com'
+ Bcc => 'root'
},
button => 'ForwardAndReturn'
);
- $m->content_contains( 'Sent email successfully', 'sent mail msg' );
$m->content_like(
-qr/Forwarded Transaction #\d+ to rt-test, rt-to\@example.com, rt-cc\@example.com, rt-bcc\@example.com/,
+qr/Forwarded .*?Transaction #\d+.*? to &lt;rt-to\@example\.com&gt;, &lt;rt-too\@example\.com&gt;, &lt;rt-cc\@example\.com&gt;, root &#40;Enoch Root&#41;/,
'txn msg'
);
my ($mail) = RT::Test->fetch_caught_mails;
like( $mail, qr!Subject: test forward!, 'Subject field' );
- like( $mail, qr!To: rt-test, rt-to\@example.com!, 'To field' );
+ like( $mail, qr!To: .*rt-to\@example.com!i, 'To field' );
+ like( $mail, qr!To: .*rt-too\@example.com!i, 'To field' );
like( $mail, qr!Cc: rt-cc\@example.com!i, 'Cc field' );
- like( $mail, qr!Bcc: rt-bcc\@example.com!i, 'Bcc field' );
+ like( $mail, qr!Bcc: root\@localhost!i, 'Bcc field' );
like( $mail, qr!This is a forward of transaction!, 'content' );
like( $mail, qr!$att_name!, 'att file name' );
like( $mail, qr!this is an attachment!, 'att content' );
@@ -93,9 +95,8 @@ diag "Forward Ticket without content" if $ENV{TEST_VERBOSE};
fields => { To => 'rt-test@example.com', },
button => 'ForwardAndReturn'
);
- $m->content_contains( 'Sent email successfully', 'sent mail msg' );
my ($mail) = RT::Test->fetch_caught_mails;
- like( $mail, qr/Subject: Fwd: \[example\.com #\d\] test forward without content/, 'Subject field' );
+ like( $mail, qr/Subject: \[example\.com #\d\] Fwd: test forward without content/, 'Subject field' );
like( $mail, qr/To: rt-test\@example\.com/, 'To field' );
like( $mail, qr/This is a forward of ticket #\d/, 'content' );
}
@@ -107,7 +108,7 @@ diag "Forward Transaction with attachments but empty content" if $ENV{TEST_VERBO
$m->form_name('TicketCreate');
my $attach = $m->current_form->find_input('Attach');
- $attach->filename("awesome.patch");
+ $attach->filename('awesome.pátch');
$attach->headers('Content-Type' => 'text/x-diff');
$m->set_fields(
Subject => 'test forward, empty content but attachments',
@@ -122,8 +123,8 @@ diag "Forward Transaction with attachments but empty content" if $ENV{TEST_VERBO
Attach => RT::Test::get_relocatable_file('bpslogo.png', '..', 'data'), # an image!
);
$m->submit;
- $m->content_like( qr/Ticket \d+ created/i, 'created the ticket' );
- $m->content_like( qr/awesome\.patch/, 'uploaded patch file' );
+ $m->content_like( qr/Ticket \d+ created/i, 'created the ticket' );
+ $m->content_like( qr/awesome.p\%C3\%A1tch/, 'uploaded patch file' );
$m->content_like( qr/text\/x-diff/, 'uploaded patch file content type' );
$m->content_like( qr/bpslogo\.png/, 'uploaded image file' );
$m->content_like( qr/image\/png/, 'uploaded image file content type' );
@@ -137,13 +138,12 @@ diag "Forward Transaction with attachments but empty content" if $ENV{TEST_VERBO
},
button => 'ForwardAndReturn'
);
- $m->content_contains( 'Sent email successfully', 'sent mail msg' );
- $m->content_like( qr/Forwarded Transaction #\d+ to rt-test\@example\.com/, 'txn msg' );
+ $m->content_like( qr/Forwarded .*?Transaction #\d+.*? to &lt;rt-test\@example\.com&gt;/, 'txn msg' );
my ($mail) = RT::Test->fetch_caught_mails;
like( $mail, qr/Subject: test forward, empty content but attachments/, 'Subject field' );
like( $mail, qr/To: rt-test\@example.com/, 'To field' );
like( $mail, qr/This is a forward of transaction/, 'content' );
- like( $mail, qr/awesome\.patch/, 'att file name' );
+ like( $mail, qr/filename\*\=\"UTF\-8\'\'awesome.p\%C3\%A1tch\"/, 'att file name' );
like( $mail, qr/this is an attachment/, 'att content' );
like( $mail, qr/text\/x-diff/, 'att content type' );
like( $mail, qr/bpslogo\.png/, 'att image file name' );
@@ -153,7 +153,7 @@ diag "Forward Transaction with attachments but empty content" if $ENV{TEST_VERBO
diag "Forward Transaction with attachments but no 'content' part" if $ENV{TEST_VERBOSE};
{
my $mime = MIME::Entity->build(
- From => 'test@example.com',
+ From => '"Tést" <test@example.com>',
Subject => 'attachments for everyone',
Type => 'multipart/mixed',
);
@@ -195,9 +195,8 @@ diag "Forward Transaction with attachments but no 'content' part" if $ENV{TEST_V
},
button => 'ForwardAndReturn'
);
- $m->content_contains( 'Sent email successfully', 'sent mail msg' );
- $m->content_like( qr/Forwarded Transaction #\d+ to rt-test\@example\.com/, 'txn msg' );
-
+ $m->content_like( qr/Forwarded .*?Transaction #\d+.*? to &lt;rt-test\@example\.com&gt;/, 'txn msg' );
+
# Forward ticket
$m->follow_link_ok( { text => 'Forward', n => 1 }, 'follow 1st Forward' );
$m->submit_form(
@@ -207,15 +206,15 @@ diag "Forward Transaction with attachments but no 'content' part" if $ENV{TEST_V
},
button => 'ForwardAndReturn'
);
- $m->content_contains( 'Sent email successfully', 'sent mail msg' );
- $m->content_like( qr/Forwarded Ticket to rt-test\@example\.com/, 'txn msg' );
+ $m->content_like( qr/Forwarded Ticket to &lt;rt-test\@example\.com&gt;/, 'txn msg' );
my ($forward_txn, $forward_ticket) = RT::Test->fetch_caught_mails;
- my $tag = qr/Fwd: \[example\.com #\d+\]/;
+ my $tag = qr/\[example\.com #\d+\] Fwd:/;
like( $forward_txn, qr/Subject: $tag attachments for everyone/, 'Subject field is from txn' );
like( $forward_txn, qr/This is a forward of transaction/, 'forward description' );
like( $forward_ticket, qr/Subject: $tag test forward, attachments but no "content"/, 'Subject field is from ticket' );
like( $forward_ticket, qr/This is a forward of ticket/, 'forward description' );
+ like( $forward_ticket, qr/From: \=\?UTF-8\?.* \<test\@example\.com\>/i );
for my $mail ($forward_txn, $forward_ticket) {
like( $mail, qr/To: rt-test\@example.com/, 'To field' );
@@ -259,7 +258,26 @@ diag "Forward Ticket Template with a Subject: line" if $ENV{TEST_VERBOSE};
);
my ($mail) = RT::Test->fetch_caught_mails;
- like($mail, qr/Subject: OVERRIDING SUBJECT/);
+ like($mail, qr/Subject: \[example.com #\d+\] OVERRIDING SUBJECT/);
+}
+
+diag "Forward Transaction with non-ascii subject" if $ENV{TEST_VERBOSE};
+{
+ $m->follow_link_ok( { text => 'Forward', n => 2 }, 'follow 2nd Forward' );
+ my $subject = Encode::decode("UTF-8", 'test non-ascii äöü');
+ $m->submit_form(
+ form_name => 'ForwardMessage',
+ fields => {
+ Subject => $subject,
+ To => 'rt-to@example.com',
+ },
+ button => 'ForwardAndReturn'
+ );
+ my ($mail) = RT::Test->fetch_caught_mails;
+ if ( $mail =~ /Subject: (.+)/ ) {
+ like( Encode::decode("UTF-8", RT::I18N::DecodeMIMEWordsToUTF8( $1, 'Subject' )), qr/$subject/, 'non-ascii subject' );
+ }
+ $m->content_contains( $subject, 'non-ascii subject got displayed correctly' );
}
undef $m;
diff --git a/rt/t/web/ticket_links.t b/rt/t/web/ticket_links.t
index efb615107..994630efd 100644
--- a/rt/t/web/ticket_links.t
+++ b/rt/t/web/ticket_links.t
@@ -52,7 +52,7 @@ for my $type ( "DependsOn", "MemberOf", "RefersTo" ) {
$m->submit;
$m->content_like(qr/Ticket \d+ created/, 'created ticket');
- $m->content_contains("Can&#39;t link to a deleted ticket");
+ $m->content_contains("Linking to a deleted ticket is not allowed");
$id = RT::Test->last_ticket->id;
}
@@ -75,7 +75,7 @@ for my $type ( "DependsOn", "MemberOf", "RefersTo" ) {
$m->field( "$type-$id", "$deleted_id $active_id $inactive_id" );
}
$m->submit;
- $m->content_contains("Can&#39;t link to a deleted ticket");
+ $m->content_contains("Linking to a deleted ticket is not allowed");
if ( $c eq 'base' ) {
$m->content_like(
@@ -165,7 +165,7 @@ for my $type ( "DependsOn", "MemberOf", "RefersTo" ) {
$m->content_lacks('hello test reminder subject');
if ($type eq 'RefersTo') {
$m->text_contains("$baseurl/test_ticket_reference");
- $m->text_contains("Article " . $article->Id . ': test article');
+ $m->text_contains("Article #" . $article->Id . ': test article');
}
}
}
diff --git a/rt/t/web/ticket_modify_all.t b/rt/t/web/ticket_modify_all.t
index 6d19b28e4..6b85d98cf 100644
--- a/rt/t/web/ticket_modify_all.t
+++ b/rt/t/web/ticket_modify_all.t
@@ -1,13 +1,15 @@
use strict;
use warnings;
-use RT::Test tests => 22;
+use RT::Test tests => undef;
my $ticket = RT::Test->create_ticket(
Subject => 'test bulk update',
Queue => 1,
);
+RT->Config->Set(AutocompleteOwners => 1);
+
my ( $url, $m ) = RT::Test->started_ok;
ok( $m->login, 'logged in' );
@@ -19,18 +21,12 @@ $m->submit_form(
button => 'SubmitTicket',
);
-$m->content_contains("Message recorded", 'updated ticket');
+$m->content_contains("Comments added", 'updated ticket');
$m->content_lacks("this is update content", 'textarea is clear');
$m->get_ok($url . '/Ticket/Display.html?id=' . $ticket->id );
$m->content_contains("this is update content", 'updated content in display page');
-# NOTE http://issues.bestpractical.com/Ticket/Display.html?id=18284
-RT::Test->stop_server;
-RT->Config->Set(AutocompleteOwners => 1);
-($url, $m) = RT::Test->started_ok;
-$m->login;
-
$m->get_ok($url . '/Ticket/ModifyAll.html?id=' . $ticket->id);
$m->form_name('TicketModifyAll');
@@ -57,10 +53,18 @@ $m->field('Told_Date' => "2015-01-01 00:00:00");
$m->click('SubmitTicket');
$m->text_contains("Last Contact: (Thu Jan 01 00:00:00 2015)", 'told date successfully updated');
-$m->form_name('TicketModifyAll');
-$m->field('Due_Date' => "2016-01-01 00:00:00");
-$m->click('SubmitTicket');
-$m->text_contains("Due: (Fri Jan 01 00:00:00 2016)", 'due date successfully updated');
+for my $unset ("0", "-", " ") {
+ $m->form_name('TicketModifyAll');
+ $m->field('Due_Date' => "2016-01-01 00:00:00");
+ $m->click('SubmitTicket');
+ $m->text_contains("Due: (Fri Jan 01 00:00:00 2016)", 'due date successfully updated');
+
+ $m->form_name('TicketModifyAll');
+ $m->field('Due_Date' => $unset);
+ $m->click('SubmitTicket');
+ $m->text_contains("Due: (Not set)", "due date successfully cleared with '$unset'");
+ $m->warning_like(qr/Couldn't parse date '-'/) if $unset eq "-";
+}
$m->get( $url . '/Ticket/ModifyAll.html?id=' . $ticket->id );
$m->form_name('TicketModifyAll');
@@ -76,8 +80,9 @@ $m->field(WatcherTypeEmail => 'Requestor');
$m->field(WatcherAddressEmail => 'root@localhost');
$m->click('SubmitTicket');
$m->text_contains(
- "root is already a Requestor for this ticket",
+ "root is already a Requestor",
'no duplicate watchers',
);
-# XXX TODO test other parts, i.e. links
+undef $m;
+done_testing;
diff --git a/rt/t/web/ticket_modify_people.t b/rt/t/web/ticket_modify_people.t
index 750be3f2c..cefbf915b 100644
--- a/rt/t/web/ticket_modify_people.t
+++ b/rt/t/web/ticket_modify_people.t
@@ -1,7 +1,7 @@
use strict;
use warnings;
-use RT::Test tests => 23;
+use RT::Test tests => 25;
my $root = RT::Test->load_or_create_user( Name => 'root' );
my $group_foo = RT::Group->new($RT::SystemUser);
@@ -80,7 +80,7 @@ ok(
$m->reload;
ok(
$m->find_link(
- text => 'Enoch Root',
+ text => 'root (Enoch Root)',
url_regex => qr!/Admin/Users/Modify\.html!,
),
'got link to modify user'
@@ -108,6 +108,16 @@ ok(
'got link to modify group'
);
+$m->submit_form_ok({
+ with_fields => {
+ WatcherTypeEmail1 => 'Cc',
+ WatcherAddressEmail1 => '"Foo Bar" <foo@example.com>',
+ },
+ button => 'SubmitTicket',
+}, "Added email with phrase as watcher");
+
+my $foo = RT::Test->load_or_create_user( EmailAddress => 'foo@example.com' );
+is $foo->RealName, "Foo Bar", "RealName matches";
# TODO test Add|Delete people
diff --git a/rt/t/web/ticket_owner.t b/rt/t/web/ticket_owner.t
index 81508534a..782e68f8d 100644
--- a/rt/t/web/ticket_owner.t
+++ b/rt/t/web/ticket_owner.t
@@ -2,7 +2,7 @@
use strict;
use warnings;
-use RT::Test nodata => 1, tests => 105;
+use RT::Test nodata => 1, tests => undef;
my $queue = RT::Test->load_or_create_queue( Name => 'Regression' );
ok $queue && $queue->id, 'loaded or created queue';
@@ -10,12 +10,18 @@ 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';
+ok $user_a && $user_a->id, 'loaded or created user: ' . $user_a->Name;
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 $user_b && $user_b->id, 'loaded or created user: ' . $user_b->Name;
+
+# To give ReassignTicket
+my $user_c = RT::Test->load_or_create_user(
+ Name => 'user_c', Password => 'password',
+);
+ok $user_c && $user_c->id, 'loaded or created user: ' . $user_c->Name;
my ($baseurl, $agent_a) = RT::Test->started_ok;
@@ -360,6 +366,7 @@ ok(
]
},
{ Principal => $user_b, Right => [qw(SeeQueue ShowTicket OwnTicket)] },
+ { Principal => $user_c, Right => [qw(SeeQueue ShowTicket ReassignTicket)] },
),
'set rights'
);
@@ -383,10 +390,12 @@ diag
fields => { Owner => $user_a->id },
button => 'SubmitTicket',
);
- $agent_a->content_like( qr/user_a\s+-\s+Taken/, 'got user_a Taken message' );
+ like($agent_a->dom->at('.transaction.people .description')->all_text,
+ qr/user_a\s*-\s*Taken/, 'got user_a Taken message' );
$agent_b->goto_ticket($id);
- $agent_b->content_like( qr/user_a\s+-\s+Taken/, 'got user_a Taken message for user b ' );
+ like($agent_b->dom->at('.transaction.people .description')->all_text,
+ qr/user_a\s*-\s*Taken/, 'got user_a Taken message for user b' );
}
diag
@@ -410,9 +419,106 @@ diag
$agent_a->content_contains( 'Owner changed from Nobody to user_a',
'got set message in Basics' );
$agent_a->goto_ticket($id);
- $agent_a->content_like( qr/user_a\s+-\s+Taken/, 'got user_a Taken message' );
+ like($agent_a->dom->at('.transaction.people .description')->all_text,
+ qr/user_a\s*-\s*Taken/, 'got user_a Taken message' );
$agent_b->goto_ticket($id);
- $agent_b->content_like( qr/user_a\s+-\s+Taken/, 'got user_a Taken message for user b ' );
+ like($agent_b->dom->at('.transaction.people .description')->all_text,
+ qr/user_a\s*-\s*Taken/, 'got user_a Taken message for user b' );
+}
+
+my $agent_c = RT::Test::Web->new;
+ok $agent_c->login('user_c', 'password'), 'logged in as user C';
+
+diag "user can assign ticket to new owner with ReassignTicket right";
+{
+ 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_c->goto_ticket($id);
+ ok !($agent_c->find_all_links( text => 'Take' ))[0], 'no Take link';
+ ok !($agent_c->find_all_links( text => 'Steal' ))[0], 'no Steal link';
+
+ $agent_a->goto_ticket($id);
+ $agent_a->content_lacks('Taken', 'no Taken');
+ $agent_a->follow_link_ok( { text => 'Basics' }, 'Ticket -> Basics' );
+ $agent_a->submit_form(
+ form_name => 'TicketModify',
+ fields => { Owner => $user_a->id },
+ );
+ $agent_a->content_contains( 'Owner changed from Nobody to user_a',
+ 'got set message in Basics' );
+ $agent_a->goto_ticket($id);
+ like($agent_a->dom->at('.transaction.people .description')->all_text,
+ qr{user_a\s*-\s*Taken}, 'got user_a Taken message' );
+
+ $agent_c->goto_ticket($id);
+ ok !($agent_c->find_all_links( text => 'Take' ))[0], 'no Take link';
+ ok !($agent_c->find_all_links( text => 'Steal' ))[0], 'no Steal link';
+ $agent_c->follow_link_ok( { text => 'Basics' }, 'Ticket -> Basics' );
+ my $form = $agent_c->form_name('TicketModify');
+ is $form->value('Owner'), $user_a->id, 'correct owner selected';
+
+ ok grep($_ == $user_b->id, $form->find_input('Owner')->possible_values),
+ 'user B is listed as potential owner';
+ $agent_c->select('Owner', $user_b->id);
+ $agent_c->submit;
+ $agent_c->content_contains( 'Owner changed from user_a to user_b',
+ 'got set message in Basics' );
+ $agent_c->goto_ticket($id);
+ $agent_c->content_like( qr{Owner forcibly changed}, 'got owner forcibly changed message' );
+ ok !($agent_c->find_all_links( text => 'Take' ))[0], 'no Take link';
+}
+
+ok(
+ RT::Test->add_rights(
+ { Principal => $user_c, Right => [qw(OwnTicket)] },
+ ),
+ 'add rights'
+);
+diag "user can take/steal ticket with ReassignTicket+OwnTicket right";
+{
+ 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_c->goto_ticket($id);
+ ok( ($agent_c->find_all_links( text => 'Take' ))[0], 'has Take link' );
+ ok !($agent_c->find_all_links( text => 'Steal' ))[0], 'no Steal link';
+
+ $agent_a->goto_ticket($id);
+ $agent_a->content_lacks('Taken', 'no Taken');
+ $agent_a->follow_link_ok( { text => 'Basics' }, 'Ticket -> Basics' );
+ $agent_a->submit_form(
+ form_name => 'TicketModify',
+ fields => { Owner => $user_a->id },
+ );
+ $agent_a->content_contains( 'Owner changed from Nobody to user_a',
+ 'got set message in Basics' );
+ $agent_a->goto_ticket($id);
+ like($agent_a->dom->at('.transaction.people .description')->all_text,
+ qr{user_a\s*-\s*Taken}, 'got user_a Taken message' );
+
+ $agent_c->goto_ticket($id);
+ ok !($agent_c->find_all_links( text => 'Take' ))[0], 'no Take link';
+ ok( ($agent_c->find_all_links( text => 'Steal' ))[0], 'has Steal link' );
+ $agent_c->follow_link_ok( { text => 'Steal' }, 'Ticket -> Steal' );
+ $agent_c->content_contains( 'Owner changed from user_a to user_c', 'steal message' );
+ ok !($agent_c->find_all_links( text => 'Take' ))[0], 'no Take link';
+ ok !($agent_c->find_all_links( text => 'Steal' ))[0], 'no Steal link';
}
+
+undef $agent_a;
+undef $agent_b;
+undef $agent_c;
+done_testing;
diff --git a/rt/t/web/ticket_preserve_basics.t b/rt/t/web/ticket_preserve_basics.t
new file mode 100644
index 000000000..145941407
--- /dev/null
+++ b/rt/t/web/ticket_preserve_basics.t
@@ -0,0 +1,110 @@
+use strict;
+use warnings;
+
+use RT::Test tests => undef;
+
+my $ticket = RT::Test->create_ticket(
+ Subject => 'test ticket basics',
+ Queue => 1,
+);
+
+my ( $url, $m ) = RT::Test->started_ok;
+ok( $m->login, 'logged in' );
+
+my $root = RT::Test->load_or_create_user( Name => 'root' );
+
+# Failing test where the time units are not preserved when you
+# click 'Add more files' on Display
+my @form_tries = (
+ {Subject => "hello rt"},
+ {Status => "open"},
+ {Owner => $root->id},
+
+ (
+ map +{
+ "Time$_" => undef,
+ "Time$_-TimeUnits" => 'hours',
+ }, qw/Estimated Worked Left/
+ ),
+ (
+ map +{
+ "Time$_" => '1',
+ "Time$_-TimeUnits" => 'hours',
+ }, qw/Estimated Worked Left/
+ ),
+
+ {InitialPriority => "10"},
+ {FinalPriority => "10"},
+);
+
+for my $try (@form_tries) {
+ $m->goto_create_ticket(1);
+ $m->form_name('TicketCreate');
+ $m->set_fields(%$try);
+ $m->click('AddMoreAttach');
+ $m->form_name('TicketCreate');
+ for my $field (keys %$try) {
+ is(
+ $m->value($field),
+ defined($try->{$field}) ? $try->{$field} : '',
+ "field $field is the same after the form was submitted"
+ );
+ }
+}
+
+# Test for time unit preservation in Jumbo
+for my $try (@form_tries) {
+ my $jumbo_ticket = RT::Test->create_ticket(
+ Subject => 'test jumbo ticket basics',
+ Queue => 1,
+ );
+
+ local($try->{Priority}) = delete local($try->{InitialPriority})
+ if exists $try->{InitialPriority};
+
+ $m->get( $url . "/Ticket/ModifyAll.html?id=" . $jumbo_ticket->id );
+ $m->form_name('TicketModifyAll');
+ $m->set_fields(%$try);
+ $m->click('AddMoreAttach');
+ $m->form_name('TicketModifyAll');
+ for my $field (keys %$try) {
+ is(
+ $m->value($field),
+ defined($try->{$field}) ? $try->{$field} : '',
+ "field $field is the same after the Jumbo form was submitted"
+ );
+ }
+}
+
+my $cf = RT::Test->load_or_create_custom_field(
+ Name => 'CF1',
+ Type => 'Freeform',
+ Pattern => '.', # mandatory
+ Queue => 'General',
+);
+
+# More time unit testing by a failing CF validation
+$m->get_ok($url.'/Admin/CustomFields/Objects.html?id='.$cf->id);
+$m->form_with_fields('UpdateObjs');
+$m->tick('AddCustomField-'.$cf->id => '0'); # Make CF global
+$m->click('UpdateObjs');
+$m->text_contains('Object created', 'CF applied globally');
+
+# Test for preservation when a ticket is submitted and CF validation fails
+for my $try (@form_tries) {
+ $m->goto_create_ticket(1);
+ $m->form_name('TicketCreate');
+ $m->set_fields(%$try);
+ $m->submit();
+ $m->form_name('TicketCreate');
+ for my $field (keys %$try) {
+ is(
+ $m->value($field),
+ defined($try->{$field}) ? $try->{$field} : '',
+ "field $field is the same after the form was submitted"
+ );
+ }
+}
+
+undef $m;
+done_testing();
diff --git a/rt/t/web/ticket_txn_content.t b/rt/t/web/ticket_txn_content.t
index c0cae976c..096d78e31 100644
--- a/rt/t/web/ticket_txn_content.t
+++ b/rt/t/web/ticket_txn_content.t
@@ -27,14 +27,14 @@ sub follow_parent_with_headers_link {
my $m = shift;
my $link = $m->find_link(@_)->url;
$link =~ s{/(\d+)$}{"/" . ($1-1)}e; # get the parent attach
- $m->get_ok($baseurl . $link);
+ $m->get_ok($link);
}
sub follow_with_headers_link {
my $m = shift;
my $link = $m->find_link(@_)->url;
$link =~ s{/\d+/(\d+)/.+$}{/WithHeaders/$1}; # frob into a with headers url
- $m->get_ok($baseurl . $link);
+ $m->get_ok($link);
}
for my $type ( 'text/plain', 'text/html' ) {
diff --git a/rt/t/web/user_update.t b/rt/t/web/user_update.t
index 54139d797..7be088b0a 100644
--- a/rt/t/web/user_update.t
+++ b/rt/t/web/user_update.t
@@ -8,7 +8,7 @@ ok( $m->login(), 'logged in' );
$m->follow_link_ok({text => 'About me'});
$m->submit_form_ok({ with_fields => { Lang => 'ja'} },
"Change to Japanese");
-$m->text_contains("Lang changed from (no value) to 'ja'");
+$m->text_contains(Encode::decode("UTF-8","Langは「(値なし)」から「'ja'」に変更されました"));
$m->text_contains(Encode::decode("UTF-8","実名"), "Page content is japanese");
# we only changed one field, and it wasn't the default, so this feedback is
@@ -19,9 +19,7 @@ $m->content_lacks("That is already the current value");
$m->submit_form_ok({ with_fields => { Lang => 'en_us'} },
"Change back to english");
-# This message shows up in Japanese
-# $m->text_contains("Lang changed from 'ja' to 'en_us'");
-$m->text_contains(Encode::decode("UTF-8","Langは「'ja'」から「'en_us'」に変更されました"));
+$m->text_contains("Lang changed from 'ja' to 'en_us'");
$m->text_contains("Real Name", "Page content is english");
# Check for a lack of spurious updates
@@ -30,11 +28,11 @@ $m->content_lacks("That is already the current value");
# Ensure that we can change the language back to the default.
$m->submit_form_ok({ with_fields => { Lang => 'ja'} },
"Back briefly to Japanese");
-$m->text_contains("Lang changed from 'en_us' to 'ja'");
+$m->text_contains(Encode::decode("UTF-8","Langは「'en_us'」から「'ja'」に変更されました"));
$m->text_contains(Encode::decode("UTF-8","実名"), "Page content is japanese");
$m->submit_form_ok({ with_fields => { Lang => ''} },
"And set to the default");
-$m->text_contains(Encode::decode("UTF-8","Langは「'ja'」から「(値なし)」に変更されました"));
+$m->text_contains("Lang changed from 'ja' to (no value)");
$m->text_contains("Real Name", "Page content is english");
undef $m;
diff --git a/rt/t/web/walk.t b/rt/t/web/walk.t
index 97aa36e12..2f7272739 100644
--- a/rt/t/web/walk.t
+++ b/rt/t/web/walk.t
@@ -53,7 +53,7 @@ my @links = (
'/Admin/Groups/Modify.html?id=' . $group->id,
'/Admin/Queues/Modify.html?id=' . $queue->id,
'/Admin/CustomFields/Modify.html?id=' . $cf->id,
- '/Admin/Global/Scrip.html?id=1',
+ '/Admin/Scrips/Modify.html?id=1',
'/Admin/Global/Template.html?Template=1',
'/Admin/Articles/Classes/Modify.html?id=' . $class->id,
'/Search/Build.html?Query=id<10',