summaryrefslogtreecommitdiff
path: root/rt/t
diff options
context:
space:
mode:
authorIvan Kohler <ivan@freeside.biz>2012-04-24 11:35:56 -0700
committerIvan Kohler <ivan@freeside.biz>2012-04-24 11:35:56 -0700
commit6587f6ba7d047ddc1686c080090afe7d53365bd4 (patch)
treeec77342668e8865aca669c9b4736e84e3077b523 /rt/t
parent47153aae5c2fc00316654e7277fccd45f72ff611 (diff)
first pass RT4 merge, RT#13852
Diffstat (limited to 'rt/t')
-rw-r--r--rt/t/api/action-createtickets.t44
-rw-r--r--rt/t/api/attachment.t2
-rw-r--r--rt/t/api/attachment_filename.t26
-rw-r--r--rt/t/api/attribute-tests.t7
-rw-r--r--rt/t/api/attribute.t11
-rw-r--r--rt/t/api/bookmarks.t24
-rw-r--r--rt/t/api/canonical_charset.t30
-rw-r--r--rt/t/api/cf_render_type.t49
-rw-r--r--rt/t/api/condition-ownerchange.t7
-rw-r--r--rt/t/api/condition-reject.t7
-rw-r--r--rt/t/api/config.t33
-rw-r--r--rt/t/api/cron.t89
-rw-r--r--rt/t/api/currentuser.t3
-rw-r--r--rt/t/api/customfield.t11
-rw-r--r--rt/t/api/date.t98
-rw-r--r--rt/t/api/emailparser.t23
-rw-r--r--rt/t/api/execute-code.t108
-rw-r--r--rt/t/api/group-rights.t137
-rw-r--r--rt/t/api/group.t19
-rw-r--r--rt/t/api/groups.t111
-rw-r--r--rt/t/api/has_rights.t43
-rw-r--r--rt/t/api/i18n.t3
-rw-r--r--rt/t/api/i18n_guess.t71
-rw-r--r--rt/t/api/link.t61
-rw-r--r--rt/t/api/password-types.t20
-rw-r--r--rt/t/api/queue.t21
-rw-r--r--rt/t/api/record.t23
-rw-r--r--rt/t/api/reminders.t10
-rw-r--r--rt/t/api/rights.t18
-rw-r--r--rt/t/api/rights_show_ticket.t28
-rw-r--r--rt/t/api/rt.t11
-rw-r--r--rt/t/api/rtname.t34
-rw-r--r--rt/t/api/safe-run-child-util.t201
-rw-r--r--rt/t/api/savedsearch.t181
-rw-r--r--rt/t/api/scrip.t10
-rw-r--r--rt/t/api/scrip_order.t11
-rw-r--r--rt/t/api/searchbuilder.t3
-rw-r--r--rt/t/api/squish.t16
-rw-r--r--rt/t/api/system.t5
-rw-r--r--rt/t/api/template-insert.t2
-rw-r--r--rt/t/api/template-simple.t275
-rw-r--r--rt/t/api/template.t5
-rw-r--r--rt/t/api/ticket.t53
-rw-r--r--rt/t/api/tickets.t29
-rw-r--r--rt/t/api/tickets_overlay_sql.t31
-rw-r--r--rt/t/api/txn_content.t2
-rw-r--r--rt/t/api/uri-fsck_com_rt.t7
-rw-r--r--rt/t/api/uri-t.t5
-rw-r--r--rt/t/api/user.t58
-rw-r--r--rt/t/api/users.t37
-rw-r--r--rt/t/api/versions_sorter.t22
-rw-r--r--rt/t/api/web-config.t163
-rw-r--r--rt/t/articles/article.t230
-rw-r--r--rt/t/articles/articles.t137
-rw-r--r--rt/t/articles/basic-api.t114
-rw-r--r--rt/t/articles/cfsearch.t94
-rw-r--r--rt/t/articles/class.t76
-rw-r--r--rt/t/articles/interface.t221
-rw-r--r--rt/t/articles/queue-specific-class.t218
-rw-r--r--rt/t/articles/search-interface.t113
-rw-r--r--rt/t/articles/upload-customfields.t90
-rw-r--r--rt/t/articles/uri-a.t28
-rw-r--r--rt/t/articles/uri-articles.t31
-rw-r--r--rt/t/customfields/access_via_queue.t30
-rw-r--r--rt/t/customfields/api.t221
-rw-r--r--rt/t/customfields/combo_cascade.t37
-rw-r--r--rt/t/customfields/date_search.t119
-rw-r--r--rt/t/customfields/datetime_search.t141
-rw-r--r--rt/t/customfields/external.t56
-rw-r--r--rt/t/customfields/ip.t285
-rw-r--r--rt/t/customfields/iprange.t469
-rw-r--r--rt/t/customfields/iprangev6.t474
-rw-r--r--rt/t/customfields/ipv6.t252
-rw-r--r--rt/t/customfields/pattern.t44
-rw-r--r--rt/t/customfields/single_values.t37
-rw-r--r--rt/t/customfields/sort_order.t20
-rw-r--r--rt/t/customfields/transaction.t60
-rw-r--r--rt/t/data/configs/passwords2
-rw-r--r--rt/t/fts/indexed_mysql.t134
-rw-r--r--rt/t/fts/indexed_oracle.t82
-rw-r--r--rt/t/fts/indexed_pg.t119
-rw-r--r--rt/t/fts/not_indexed.t61
-rw-r--r--rt/t/i18n/caching.t33
-rw-r--r--rt/t/i18n/footer.t29
-rw-r--r--rt/t/lifecycles/basics.t247
-rw-r--r--rt/t/lifecycles/dates.t317
-rw-r--r--rt/t/lifecycles/moving.t97
-rw-r--r--rt/t/lifecycles/unresolved-deps.t45
-rw-r--r--rt/t/lifecycles/utils.pl73
-rw-r--r--rt/t/mail/bounce.t42
-rw-r--r--rt/t/mail/charsets-outgoing.t67
-rw-r--r--rt/t/mail/crypt-gnupg.t114
-rw-r--r--rt/t/mail/dashboards.t397
-rw-r--r--rt/t/mail/digest-attributes.t168
-rw-r--r--rt/t/mail/disposition-outgoing.t69
-rw-r--r--rt/t/mail/extractsubjecttag.t22
-rw-r--r--rt/t/mail/fake-sendmail27
-rw-r--r--rt/t/mail/gateway.t201
-rw-r--r--rt/t/mail/gnupg-bad.t58
-rw-r--r--rt/t/mail/gnupg-incoming.t64
-rw-r--r--rt/t/mail/gnupg-outgoing-encrypted.t27
-rw-r--r--rt/t/mail/gnupg-outgoing-plain.t25
-rw-r--r--rt/t/mail/gnupg-outgoing-signed.t27
-rw-r--r--rt/t/mail/gnupg-outgoing-signed_encrypted.t28
-rw-r--r--rt/t/mail/gnupg-realmail.t36
-rw-r--r--rt/t/mail/gnupg-reverification.t77
-rw-r--r--rt/t/mail/gnupg-special.t33
-rw-r--r--rt/t/mail/mime_decoding.t36
-rw-r--r--rt/t/mail/multipart.t10
-rw-r--r--rt/t/mail/one-time-recipients.t209
-rw-r--r--rt/t/mail/outlook.t15
-rw-r--r--rt/t/mail/rfc822-attachment.t137
-rw-r--r--rt/t/mail/sendmail.t179
-rw-r--r--rt/t/mail/threading.t90
-rw-r--r--rt/t/mail/verp.t2
-rw-r--r--rt/t/mail/wrong_mime_charset.t21
-rw-r--r--rt/t/ticket/clicky.t142
-rw-r--r--rt/t/ticket/googleish_search.t43
-rw-r--r--rt/t/web/admin_groups.t59
-rw-r--r--rt/t/web/admin_user.t21
-rw-r--r--rt/t/web/articles-links.t52
-rw-r--r--rt/t/web/attachment-with-name-0.t23
-rw-r--r--rt/t/web/attachment_encoding.t15
-rw-r--r--rt/t/web/attachments.t46
-rw-r--r--rt/t/web/basic.t35
-rw-r--r--rt/t/web/case-sensitivity.t85
-rw-r--r--rt/t/web/cf_access.t129
-rw-r--r--rt/t/web/cf_date.t187
-rw-r--r--rt/t/web/cf_datetime.t235
-rw-r--r--rt/t/web/cf_onqueue.t24
-rw-r--r--rt/t/web/cf_render_type.t50
-rw-r--r--rt/t/web/cf_select_one.t81
-rw-r--r--rt/t/web/charting.t25
-rw-r--r--rt/t/web/class_create.t75
-rw-r--r--rt/t/web/clickjacking-preventions.t30
-rw-r--r--rt/t/web/command_line.t65
-rw-r--r--rt/t/web/command_line_with_unknown_field.t11
-rw-r--r--rt/t/web/compilation_errors.t38
-rw-r--r--rt/t/web/config_tab_right.t8
-rw-r--r--rt/t/web/crypt-gnupg.t77
-rw-r--r--rt/t/web/custom_frontpage.t39
-rw-r--r--rt/t/web/custom_search.t6
-rw-r--r--rt/t/web/dashboards-basics.t268
-rw-r--r--rt/t/web/dashboards-deleted-saved-search.t89
-rw-r--r--rt/t/web/dashboards-groups.t139
-rw-r--r--rt/t/web/dashboards-permissions.t10
-rw-r--r--rt/t/web/dashboards-search-cache.t73
-rw-r--r--rt/t/web/gnupg-headers.t53
-rw-r--r--rt/t/web/gnupg-select-keys-on-create.t183
-rw-r--r--rt/t/web/gnupg-select-keys-on-update.t197
-rw-r--r--rt/t/web/gnupg-tickyboxes.t84
-rw-r--r--rt/t/web/googleish_search.t219
-rw-r--r--rt/t/web/group_create.t75
-rw-r--r--rt/t/web/html/Callbacks/logout.t/NoAuth/Logout.html/Default6
-rw-r--r--rt/t/web/html/NoAuth/js/not-by-default.js3
-rw-r--r--rt/t/web/html/delete-article-name-method.html15
-rw-r--r--rt/t/web/html_template.t12
-rw-r--r--rt/t/web/logout.t39
-rw-r--r--rt/t/web/offline.t78
-rw-r--r--rt/t/web/offline_messages_utf8.t3
-rw-r--r--rt/t/web/offline_utf8.t15
-rw-r--r--rt/t/web/passthrough-jsmin5
-rw-r--r--rt/t/web/path-traversal.t12
-rw-r--r--rt/t/web/private-components.t6
-rw-r--r--rt/t/web/query_builder.t100
-rw-r--r--rt/t/web/query_log.t20
-rw-r--r--rt/t/web/queue_caching.t90
-rw-r--r--rt/t/web/queue_create.t75
-rw-r--r--rt/t/web/quickcreate.t37
-rw-r--r--rt/t/web/quicksearch.t6
-rw-r--r--rt/t/web/redirect-after-login.t26
-rw-r--r--rt/t/web/redirect.t106
-rw-r--r--rt/t/web/reminders.t88
-rw-r--r--rt/t/web/remote_user.t36
-rw-r--r--rt/t/web/requestor_groups_edit_link.t56
-rw-r--r--rt/t/web/requestor_groups_limit.t36
-rw-r--r--rt/t/web/rest-non-ascii-subject.t6
-rw-r--r--rt/t/web/rest-sort.t46
-rw-r--r--rt/t/web/rest.t4
-rw-r--r--rt/t/web/richtext-autohandler.t10
-rw-r--r--rt/t/web/rights.t38
-rw-r--r--rt/t/web/rights1.t33
-rw-r--r--rt/t/web/saved_search_chart.t82
-rw-r--r--rt/t/web/saved_search_context.t69
-rw-r--r--rt/t/web/saved_search_permissions.t6
-rw-r--r--rt/t/web/saved_search_update.t2
-rw-r--r--rt/t/web/scrips.t105
-rw-r--r--rt/t/web/scrub.t46
-rw-r--r--rt/t/web/search_bulk_update_links.t24
-rw-r--r--rt/t/web/search_cf_quotes.t53
-rw-r--r--rt/t/web/search_rss.t11
-rw-r--r--rt/t/web/search_simple.t22
-rw-r--r--rt/t/web/search_tabs.t86
-rw-r--r--rt/t/web/self_service.t19
-rw-r--r--rt/t/web/squish.t78
-rw-r--r--rt/t/web/template.t62
-rw-r--r--rt/t/web/ticket-create-utf8.t18
-rw-r--r--rt/t/web/ticket_display.t63
-rw-r--r--rt/t/web/ticket_forward.t232
-rw-r--r--rt/t/web/ticket_links.t110
-rw-r--r--rt/t/web/ticket_modify_all.t44
-rw-r--r--rt/t/web/ticket_modify_people.t113
-rw-r--r--rt/t/web/ticket_owner.t147
-rw-r--r--rt/t/web/ticket_owner_autocomplete.t185
-rw-r--r--rt/t/web/ticket_owner_issues_16656.t63
-rw-r--r--rt/t/web/ticket_seen.t24
-rw-r--r--rt/t/web/ticket_txn_content.t71
-rw-r--r--rt/t/web/ticket_update_without_content.t14
-rw-r--r--rt/t/web/transaction_batch.t55
-rw-r--r--rt/t/web/unlimited_search.t13
-rw-r--r--rt/t/web/user_update.t32
-rw-r--r--rt/t/web/walk.t92
212 files changed, 13590 insertions, 1664 deletions
diff --git a/rt/t/api/action-createtickets.t b/rt/t/api/action-createtickets.t
index 69ceb8d4d..c37e2ed12 100644
--- a/rt/t/api/action-createtickets.t
+++ b/rt/t/api/action-createtickets.t
@@ -2,7 +2,7 @@
use strict;
use warnings;
use RT;
-use RT::Test tests => 49;
+use RT::Test tests => 54;
{
@@ -14,10 +14,33 @@ use_ok('RT::ScripAction');
use_ok('RT::ScripCondition');
use_ok('RT::Ticket');
-my $approvalsq = RT::Queue->new($RT::SystemUser);
+
+use_ok('RT::CustomField');
+
+my $global_cf = RT::CustomField->new($RT::SystemUser);
+my ($id, $msg)= $global_cf->Create( Name => 'GlobalCF',
+ Queue => '0',
+ SortOrder => '1',
+ Description => 'A Testing custom field',
+ Type=> 'SelectSingle');
+ok($id, 'Global custom field correctly created');
+
+
+my $approvalsq = RT::Queue->new(RT->SystemUser);
$approvalsq->Create(Name => 'Approvals');
ok ($approvalsq->Id, "Created Approvals test queue");
+my $queue_cf = RT::CustomField->new($RT::SystemUser);
+($id) = $queue_cf->Create(
+ Name => 'QueueCF',
+ Queue => $approvalsq->Id,
+ SortOrder => 2,
+ Description => 'A testing queue-specific custom field',
+ Type => 'SelectSingle',
+);
+ok($id, 'Queue-specific custom field correctly created');
+
+
my $approvals =
'===Create-Ticket: approval
@@ -26,6 +49,8 @@ Type: approval
AdminCc: {join ("\nAdminCc: ",@admins) }
Depended-On-By: {$Tickets{"TOP"}->Id}
Refers-To: TOP
+CustomField-GlobalCF: A Value
+CustomField-QueueCF: Another Value
Subject: Approval for ticket: {$Tickets{"TOP"}->Id} - {$Tickets{"TOP"}->Subject}
Due: {time + 86400}
Content-Type: text/plain
@@ -45,16 +70,16 @@ ENDOFCONTENT
like ($approvals , qr/Content/, "Read in the approvals template");
-my $apptemp = RT::Template->new($RT::SystemUser);
+my $apptemp = RT::Template->new(RT->SystemUser);
$apptemp->Create( Content => $approvals, Name => "Approvals", Queue => "0");
ok ($apptemp->Id);
-my $q = RT::Queue->new($RT::SystemUser);
+my $q = RT::Queue->new(RT->SystemUser);
$q->Create(Name => 'WorkflowTest');
ok ($q->Id, "Created workflow test queue");
-my $scrip = RT::Scrip->new($RT::SystemUser);
+my $scrip = RT::Scrip->new(RT->SystemUser);
my ($sval, $smsg) =$scrip->Create( ScripCondition => 'On Transaction',
ScripAction => 'Create Tickets',
Template => 'Approvals',
@@ -65,7 +90,7 @@ ok ($scrip->TemplateObj->Id, "Created the scrip template");
ok ($scrip->ConditionObj->Id, "Created the scrip condition");
ok ($scrip->ActionObj->Id, "Created the scrip action");
-my $t = RT::Ticket->new($RT::SystemUser);
+my $t = RT::Ticket->new(RT->SystemUser);
my($tid, $ttrans, $tmsg) = $t->Create(Subject => "Sample workflow test",
Owner => "root",
Queue => $q->Id);
@@ -76,11 +101,15 @@ my $deps = $t->DependsOn;
is ($deps->Count, 1, "The ticket we created depends on one other ticket");
my $dependson= $deps->First->TargetObj;
ok ($dependson->Id, "It depends on a real ticket");
+is ($dependson->FirstCustomFieldValue('GlobalCF'), 'A Value',
+ 'global custom field was set');
+is ($dependson->FirstCustomFieldValue('QueueCF'), 'Another Value',
+ 'queue custom field was set');
unlike ($dependson->Subject, qr/{/, "The subject doesn't have braces in it. that means we're interpreting expressions");
is ($t->ReferredToBy->Count,1, "It's only referred to by one other ticket");
is ($t->ReferredToBy->First->BaseObj->Id,$t->DependsOn->First->TargetObj->Id, "The same ticket that depends on it refers to it.");
use RT::Action::CreateTickets;
-my $action = RT::Action::CreateTickets->new( CurrentUser => $RT::SystemUser);
+my $action = RT::Action::CreateTickets->new( CurrentUser => RT->SystemUser);
# comma-delimited templates
my $commas = <<"EOF";
@@ -237,4 +266,3 @@ foreach my $id ( sort keys %expected ) {
}
-1;
diff --git a/rt/t/api/attachment.t b/rt/t/api/attachment.t
index 282d2a3de..8b7cb608b 100644
--- a/rt/t/api/attachment.t
+++ b/rt/t/api/attachment.t
@@ -65,5 +65,3 @@ is ($#headers, 2, "testing a bunch of singline multiple headers" );
'body of ContentAsMIME is original'
);
}
-
-1;
diff --git a/rt/t/api/attachment_filename.t b/rt/t/api/attachment_filename.t
index 2eced0127..bcbfe0057 100644
--- a/rt/t/api/attachment_filename.t
+++ b/rt/t/api/attachment_filename.t
@@ -1,6 +1,6 @@
use RT::Test tests => 5;
use MIME::Entity;
-my $ticket = RT::Ticket->new($RT::SystemUser);
+my $ticket = RT::Ticket->new(RT->SystemUser);
my $mime = MIME::Entity->build(
From => 'test@example.com',
Type => 'text/html',
@@ -8,32 +8,32 @@ my $mime = MIME::Entity->build(
);
$mime->attach(
- Path => 'share/html/NoAuth/images/bplogo.gif',
- Type => 'image/gif',
+ Path => 'share/html/NoAuth/images/bpslogo.png',
+ Type => 'image/png',
);
$mime->attach(
- Path => 'share/html/NoAuth/images/bplogo.gif',
- Type => 'image/gif',
- Filename => 'bplogo.gif',
+ Path => 'share/html/NoAuth/images/bpslogo.png',
+ Type => 'image/png',
+ Filename => 'bpslogo.png',
);
$mime->attach(
- Path => 'share/html/NoAuth/images/bplogo.gif',
- Filename => 'images/bplogo.gif',
- Type => 'image/gif',
+ Path => 'share/html/NoAuth/images/bpslogo.png',
+ Filename => 'images/bpslogo.png',
+ Type => 'image/png',
);
my $id = $ticket->Create( MIMEObj => $mime, Queue => 'General' );
ok( $id, "created ticket $id" );
-my $atts = RT::Attachments->new( $RT::SystemUser );
-$atts->Limit( FIELD => 'ContentType', VALUE => 'image/gif' );
-is( $atts->Count, 3, 'got 3 gif files' );
+my $atts = RT::Attachments->new( RT->SystemUser );
+$atts->Limit( FIELD => 'ContentType', VALUE => 'image/png' );
+is( $atts->Count, 3, 'got 3 png files' );
# no matter if mime's filename include path or not,
# we should throw away the path all the time.
while ( my $att = $atts->Next ) {
- is( $att->Filename, 'bplogo.gif', "attachment's filename" );
+ is( $att->Filename, 'bpslogo.png', "attachment's filename" );
}
diff --git a/rt/t/api/attribute-tests.t b/rt/t/api/attribute-tests.t
index 90c3ddb7e..8489f1a56 100644
--- a/rt/t/api/attribute-tests.t
+++ b/rt/t/api/attribute-tests.t
@@ -1,7 +1,7 @@
use strict;
use warnings;
use RT;
-use RT::Test tests => 34;
+use RT::Test nodata => 1, tests => 34;
@@ -11,7 +11,7 @@ my $attribute = "squelch-$runid";
ok(require RT::Attributes);
-my $user = RT::User->new($RT::SystemUser);
+my $user = RT::User->new(RT->SystemUser);
ok (UNIVERSAL::isa($user, 'RT::User'));
my ($id,$msg) = $user->Create(Name => 'attrtest-'.$runid);
ok ($id, $msg);
@@ -81,6 +81,3 @@ ok(1, $attr->BuildSelectQuery);
@names = $attr->Names;
is("@names", "TestAttr");
-
-
-1;
diff --git a/rt/t/api/attribute.t b/rt/t/api/attribute.t
index cb2626ad8..417f01528 100644
--- a/rt/t/api/attribute.t
+++ b/rt/t/api/attribute.t
@@ -2,15 +2,15 @@
use strict;
use warnings;
use RT;
-use RT::Test tests => 7;
+use RT::Test nodata => 1, tests => 7;
{
-my $user = $RT::SystemUser;
+my $user = RT->SystemUser;
my ($id, $msg) = $user->AddAttribute(Name => 'SavedSearch', Content => { Query => 'Foo'} );
ok ($id, $msg);
-my $attr = RT::Attribute->new($RT::SystemUser);
+my $attr = RT::Attribute->new(RT->SystemUser);
$attr->Load($id);
is($attr->Name , 'SavedSearch');
$attr->SetSubValues( Format => 'baz');
@@ -28,15 +28,14 @@ is ($format, undef);
$attr->SetSubValues(Format => 'This is a format');
-my $attr2 = RT::Attribute->new($RT::SystemUser);
+my $attr2 = RT::Attribute->new(RT->SystemUser);
$attr2->Load($id);
is ($attr2->SubValue('Format'), 'This is a format');
$attr2->Delete;
-my $attr3 = RT::Attribute->new($RT::SystemUser);
+my $attr3 = RT::Attribute->new(RT->SystemUser);
($id) = $attr3->Load($id);
is ($id, 0);
}
-1;
diff --git a/rt/t/api/bookmarks.t b/rt/t/api/bookmarks.t
new file mode 100644
index 000000000..65b194526
--- /dev/null
+++ b/rt/t/api/bookmarks.t
@@ -0,0 +1,24 @@
+use strict;
+use warnings;
+use RT::Test tests => 36;
+
+my ( $url, $m ) = RT::Test->started_ok;
+my $root = RT::Test->load_or_create_user( Name => 'root' );
+
+my @tickets = RT::Test->create_tickets( { }, map { { Subject => "Test $_" } } ( 1 .. 9 ) );
+
+# 4.2 gives us $user->ToggleBookmark which is nicer
+$root->SetAttribute( Name => 'Bookmarks', Content => { map { $_ => 1 } (3,6,9) } );
+
+my $cu = RT::CurrentUser->new($root);
+my $bookmarks = RT::Tickets->new($cu);
+for my $search ( "Queue = 'General' AND id = '__Bookmarked__'",
+ "id = '__Bookmarked__' AND Queue = 'General'",
+ "id > 0 AND id = '__Bookmarked__'",
+ "id = '__Bookmarked__' AND id > 0",
+ "id = 3 OR id = '__Bookmarked__'",
+ "id = '__Bookmarked__' OR id = 3",
+ ) {
+ $bookmarks->FromSQL($search);
+ is($bookmarks->Count,3,"Found my 3 bookmarks for [$search]");
+}
diff --git a/rt/t/api/canonical_charset.t b/rt/t/api/canonical_charset.t
new file mode 100644
index 000000000..a426d89b6
--- /dev/null
+++ b/rt/t/api/canonical_charset.t
@@ -0,0 +1,30 @@
+use warnings;
+use strict;
+
+use RT::Test nodata => 1, tests => 11;
+use RT::I18N;
+use Encode;
+
+my %map = (
+ 'euc-cn' => 'gbk',
+ 'gb-2312' => 'gbk',
+ gb2312 => 'gbk',
+ utf8 => 'utf-8',
+ 'utf-8' => 'utf-8',
+);
+
+for my $charset ( keys %map ) {
+ is( RT::I18N::_CanonicalizeCharset($charset),
+ $map{$charset}, "$charset => $map{$charset}" );
+ is( RT::I18N::_CanonicalizeCharset( uc $charset ),
+ $map{$charset}, uc( $charset ) . " => $map{$charset}" );
+}
+
+my $mime = MIME::Entity->build(
+ Type => 'text/plain; charset=gb2312',
+ Data => [encode('gbk', decode_utf8("法新社倫敦11日電"))],
+);
+
+RT::I18N::SetMIMEEntityToUTF8($mime);
+is( $mime->stringify_body, '法新社倫敦11日電', 'gb2312 => gbk in mail' );
+
diff --git a/rt/t/api/cf_render_type.t b/rt/t/api/cf_render_type.t
new file mode 100644
index 000000000..ac090495e
--- /dev/null
+++ b/rt/t/api/cf_render_type.t
@@ -0,0 +1,49 @@
+use strict;
+use warnings;
+
+use RT::Test tests => 13;
+
+my $cf = RT::CustomField->new($RT::SystemUser);
+my ( $id, $ret, $msg );
+
+diag "single select";
+( $id, $msg ) = $cf->Create(
+ Name => 'single_select',
+ Type => 'Select',
+ MaxValues => '1',
+ Queue => 0,
+);
+ok( $id, $msg );
+
+is( $cf->RenderType, 'Select box', 'default render type is Select box' );
+( $ret, $msg ) = $cf->SetRenderType('Dropdown');
+ok( $ret, 'changed to Dropdown' );
+is( $cf->RenderType, 'Dropdown', 'render type is indeed updated' );
+
+( $ret, $msg ) = $cf->SetRenderType('List');
+ok( $ret, 'changed to List' );
+is( $cf->RenderType, 'List', 'render type is indeed updated' );
+
+( $ret, $msg ) = $cf->SetRenderType('fakeone');
+ok( !$ret, 'failed to set an invalid render type' );
+is( $cf->RenderType, 'List', 'render type is still List' );
+
+diag "multiple select";
+( $id, $msg ) = $cf->Create(
+ Name => 'multiple_select',
+ Type => 'Select',
+ MaxValues => '0',
+ Queue => 0,
+ RenderType => 'List',
+);
+
+is( $cf->RenderType, 'List', 'set render type to List' );
+( $ret, $msg ) = $cf->SetRenderType('Dropdown');
+ok( !$ret, 'Dropdown is invalid for multiple select' );
+
+is( $cf->RenderType, 'List', 'render type is still List' );
+
+( $ret, $msg ) = $cf->SetRenderType('Select box');
+ok( $ret, 'changed to Select box' );
+is( $cf->RenderType, 'Select box', 'render type is indeed updated' );
+
diff --git a/rt/t/api/condition-ownerchange.t b/rt/t/api/condition-ownerchange.t
index 4c4c49b29..2cfef7422 100644
--- a/rt/t/api/condition-ownerchange.t
+++ b/rt/t/api/condition-ownerchange.t
@@ -7,12 +7,12 @@ use RT::Test tests => 11;
{
-my $q = RT::Queue->new($RT::SystemUser);
+my $q = RT::Queue->new(RT->SystemUser);
$q->Create(Name =>'ownerChangeTest');
ok($q->Id, "Created a scriptest queue");
-my $s1 = RT::Scrip->new($RT::SystemUser);
+my $s1 = RT::Scrip->new(RT->SystemUser);
my ($val, $msg) =$s1->Create( Queue => $q->Id,
ScripAction => 'User Defined',
ScripCondition => 'On Owner Change',
@@ -26,7 +26,7 @@ my ($val, $msg) =$s1->Create( Queue => $q->Id,
);
ok($val,$msg);
-my $ticket = RT::Ticket->new($RT::SystemUser);
+my $ticket = RT::Ticket->new(RT->SystemUser);
my ($tv,$ttv,$tm) = $ticket->Create(Queue => $q->Id,
Subject => "hair on fire",
InitialPriority => '20'
@@ -48,4 +48,3 @@ is ($ticket->Priority , '24', "Ticket priority is set right");
}
-1;
diff --git a/rt/t/api/condition-reject.t b/rt/t/api/condition-reject.t
index 96789509d..c2ec8cdda 100644
--- a/rt/t/api/condition-reject.t
+++ b/rt/t/api/condition-reject.t
@@ -10,12 +10,12 @@ use RT::Test tests => 7;
{
-my $q = RT::Queue->new($RT::SystemUser);
+my $q = RT::Queue->new(RT->SystemUser);
$q->Create(Name =>'rejectTest');
ok($q->Id, "Created a scriptest queue");
-my $s1 = RT::Scrip->new($RT::SystemUser);
+my $s1 = RT::Scrip->new(RT->SystemUser);
my ($val, $msg) =$s1->Create( Queue => $q->Id,
ScripAction => 'User Defined',
ScripCondition => 'On reject',
@@ -29,7 +29,7 @@ my ($val, $msg) =$s1->Create( Queue => $q->Id,
);
ok($val,$msg);
-my $ticket = RT::Ticket->new($RT::SystemUser);
+my $ticket = RT::Ticket->new(RT->SystemUser);
my ($tv,$ttv,$tm) = $ticket->Create(Queue => $q->Id,
Subject => "hair on fire",
InitialPriority => '20'
@@ -42,4 +42,3 @@ is ($ticket->Priority , '21', "Condition is false, scrip skipped");
}
-1;
diff --git a/rt/t/api/config.t b/rt/t/api/config.t
new file mode 100644
index 000000000..a986c3c4f
--- /dev/null
+++ b/rt/t/api/config.t
@@ -0,0 +1,33 @@
+use strict;
+use warnings;
+use RT;
+use RT::Test nodb => 1, tests => 9;
+
+ok(
+ RT::Config->AddOption(
+ Name => 'foo',
+ Section => 'bar',
+ ),
+ 'added option foo'
+);
+
+my $meta = RT::Config->Meta('foo');
+is( $meta->{Section}, 'bar', 'Section is bar' );
+is( $meta->{Widget}, '/Widgets/Form/String', 'default Widget is string' );
+is_deeply( $meta->{WidgetArguments},
+ {},, 'default WidgetArguments is empty hashref' );
+
+ok(
+ RT::Config->UpdateOption(
+ Name => 'foo',
+ Section => 'baz',
+ Widget => '/Widgets/Form/Boolean',
+ ),
+ 'updated option foo to section baz'
+);
+is( $meta->{Section}, 'baz', 'section is updated to baz' );
+is( $meta->{Widget}, '/Widgets/Form/Boolean', 'widget is updated to boolean' );
+
+ok( RT::Config->DeleteOption( Name => 'foo' ), 'removed option foo' );
+is( RT::Config->Meta('foo'), undef, 'foo is indeed deleted' );
+
diff --git a/rt/t/api/cron.t b/rt/t/api/cron.t
new file mode 100644
index 000000000..6f9d7f644
--- /dev/null
+++ b/rt/t/api/cron.t
@@ -0,0 +1,89 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+use RT;
+use RT::Test nodata => 1, tests => 18;
+
+
+### Set up some testing data. Test the testing data because why not?
+
+# Create a user with rights, a queue, and some tickets.
+my $user_obj = RT::User->new(RT->SystemUser);
+my ($ret, $msg) = $user_obj->LoadOrCreateByEmail('tara@example.com');
+ok($ret, 'record test user creation');
+$user_obj->SetName('tara');
+$user_obj->PrincipalObj->GrantRight(Right => 'SuperUser');
+my $CurrentUser = RT::CurrentUser->new('tara');
+
+# Create our template, which will be used for tests of RT::Action::Record*.
+
+my $template_content = 'RT-Send-Cc: tla@example.com
+RT-Send-Bcc: jesse@example.com
+
+This is a content string with no content.';
+
+my $template_obj = RT::Template->new($CurrentUser);
+$template_obj->Create(Queue => '0',
+ Name => 'recordtest',
+ Description => 'testing Record actions',
+ Content => $template_content,
+ );
+
+# Create a queue and some tickets.
+
+my $queue_obj = RT::Queue->new($CurrentUser);
+($ret, $msg) = $queue_obj->Create(Name => 'recordtest', Description => 'queue for Action::Record testing');
+ok($ret, 'record test queue creation');
+
+my $ticket1 = RT::Ticket->new($CurrentUser);
+my ($id, $tobj, $msg2) = $ticket1->Create(Queue => $queue_obj,
+ Requestor => ['tara@example.com'],
+ Subject => 'bork bork bork',
+ Priority => 22,
+ );
+ok($id, 'record test ticket creation 1');
+my $ticket2 = RT::Ticket->new($CurrentUser);
+($id, $tobj, $msg2) = $ticket2->Create(Queue => $queue_obj,
+ Requestor => ['root@localhost'],
+ Subject => 'hurdy gurdy'
+ );
+ok($id, 'record test ticket creation 2');
+
+
+### OK. Have data, will travel.
+
+# First test the search.
+
+ok(require RT::Search::FromSQL, "Search::FromSQL loaded");
+my $ticketsqlstr = "Requestor.EmailAddress = '" . $CurrentUser->EmailAddress .
+ "' AND Priority > '20'";
+my $search = RT::Search::FromSQL->new(Argument => $ticketsqlstr, TicketsObj => RT::Tickets->new($CurrentUser),
+ );
+is(ref($search), 'RT::Search::FromSQL', "search created");
+ok($search->Prepare(), "fromsql search run");
+my $counter = 0;
+while(my $t = $search->TicketsObj->Next() ) {
+ is($t->Id(), $ticket1->Id(), "fromsql search results 1");
+ $counter++;
+}
+is ($counter, 1, "fromsql search results 2");
+
+# Right. Now test the actions.
+
+ok(require RT::Action::RecordComment);
+ok(require RT::Action::RecordCorrespondence);
+
+my ($comment_act, $correspond_act);
+ok($comment_act = RT::Action::RecordComment->new(TicketObj => $ticket1, TemplateObj => $template_obj, CurrentUser => $CurrentUser), "RecordComment created");
+ok($correspond_act = RT::Action::RecordCorrespondence->new(TicketObj => $ticket2, TemplateObj => $template_obj, CurrentUser => $CurrentUser), "RecordCorrespondence created");
+ok($comment_act->Prepare(), "Comment prepared");
+ok($correspond_act->Prepare(), "Correspond prepared");
+ok($comment_act->Commit(), "Comment committed");
+ok($correspond_act->Commit(), "Correspondence committed");
+
+# Now test for loop suppression.
+my ($trans, $desc, $transaction) = $ticket2->Comment(MIMEObj => $template_obj->MIMEObj);
+my $bogus_action = RT::Action::RecordComment->new(TicketObj => $ticket1, TemplateObj => $template_obj, TransactionObj => $transaction, CurrentUser => $CurrentUser);
+ok(!$bogus_action->Prepare(), "Comment aborted to prevent loop");
+
diff --git a/rt/t/api/currentuser.t b/rt/t/api/currentuser.t
index c15804824..f54074af9 100644
--- a/rt/t/api/currentuser.t
+++ b/rt/t/api/currentuser.t
@@ -2,7 +2,7 @@
use strict;
use warnings;
use RT;
-use RT::Test tests => 8;
+use RT::Test noinitialdata => 1, tests => 8;
{
@@ -29,4 +29,3 @@ SKIP: {
}
-1;
diff --git a/rt/t/api/customfield.t b/rt/t/api/customfield.t
index 44319c47f..6be50bb3a 100644
--- a/rt/t/api/customfield.t
+++ b/rt/t/api/customfield.t
@@ -2,14 +2,14 @@
use strict;
use warnings;
use RT;
-use RT::Test tests => 29;
+use RT::Test nodata => 1, tests => 29;
use Test::Warn;
{
use_ok('RT::CustomField');
-ok(my $cf = RT::CustomField->new($RT::SystemUser));
+ok(my $cf = RT::CustomField->new(RT->SystemUser));
ok(my ($id, $msg)= $cf->Create( Name => 'TestingCF',
Queue => '0',
SortOrder => '1',
@@ -28,7 +28,7 @@ ok(!$cf->SingleValue );
ok(my ($bogus_val, $bogus_msg) = $cf->SetType('BogusType') , "Trying to set a custom field's type to a bogus type");
is($bogus_val , 0, "Unable to set a custom field's type to a bogus type");
-ok(my $bad_cf = RT::CustomField->new($RT::SystemUser));
+ok(my $bad_cf = RT::CustomField->new(RT->SystemUser));
ok(my ($bad_id, $bad_msg)= $cf->Create( Name => 'TestingCF-bad',
Queue => '0',
SortOrder => '1',
@@ -41,7 +41,7 @@ is($bad_id , 0, 'Global custom field correctly decided to not create a cf with a
{
-ok(my $cf = RT::CustomField->new($RT::SystemUser));
+ok(my $cf = RT::CustomField->new(RT->SystemUser));
$cf->Load(1);
is($cf->Id , 1);
ok(my ($val,$msg) = $cf->AddValue(Name => 'foo' , Description => 'TestCFValue', SortOrder => '6'));
@@ -54,7 +54,7 @@ ok ($delval,"Deleting a cf value: $delmsg");
{
-ok(my $cf = RT::CustomField->new($RT::SystemUser));
+ok(my $cf = RT::CustomField->new(RT->SystemUser));
warning_like {
ok($cf->ValidateType('SelectSingle'));
@@ -71,4 +71,3 @@ ok(!$cf->ValidateType('SelectFooMultiple'));
}
-1;
diff --git a/rt/t/api/date.t b/rt/t/api/date.t
index bc1446f50..9756e51c4 100644
--- a/rt/t/api/date.t
+++ b/rt/t/api/date.t
@@ -1,47 +1,31 @@
#!/usr/bin/perl
use Test::MockTime qw(set_fixed_time restore_time);
-
-use Test::More;
-my $tests;
-
-my $localized_datetime_tests;
-BEGIN {
- $tests = 167;
- $localized_datetime_tests =
- eval { require DateTime; 1; } && eval { require DateTime::Locale; 1; } &&
- DateTime->can('format_cldr') && DateTime::Locale::root->can('date_format_full');
-
- if ($localized_datetime_tests) {
-
- # Include RT::Date::LocalizedDateTime tests
- $tests += 7;
- }
-}
+use DateTime;
use warnings; use strict;
-use RT::Test tests => $tests;
+use RT::Test tests => 172;
use RT::User;
use Test::Warn;
use_ok('RT::Date');
{
- my $date = RT::Date->new($RT::SystemUser);
+ my $date = RT::Date->new(RT->SystemUser);
isa_ok($date, 'RT::Date', "constructor returned RT::Date oject");
- $date = $date->new($RT::SystemUser);
+ $date = $date->new(RT->SystemUser);
isa_ok($date, 'RT::Date', "constructor returned RT::Date oject");
}
{
# set timezone in all places to UTC
- $RT::SystemUser->UserObj->__Set(Field => 'Timezone', Value => 'UTC')
- if $RT::SystemUser->UserObj->Timezone;
+ RT->SystemUser->UserObj->__Set(Field => 'Timezone', Value => 'UTC')
+ if RT->SystemUser->UserObj->Timezone;
RT->Config->Set( Timezone => 'UTC' );
}
my $current_user;
{
- my $user = RT::User->new($RT::SystemUser);
+ my $user = RT::User->new(RT->SystemUser);
my($uid, $msg) = $user->Create(
Name => "date_api". rand(200),
Lang => 'en',
@@ -53,7 +37,6 @@ my $current_user;
{
my $date = RT::Date->new( $current_user );
- is($date->Timezone, 'UTC', "dropped all timzones to UTC");
is($date->Timezone('user'), 'UTC', "dropped all timzones to UTC");
is($date->Timezone('server'), 'UTC', "dropped all timzones to UTC");
is($date->Timezone('unknown'), 'UTC', "with wrong context returns UTC");
@@ -65,7 +48,6 @@ my $current_user;
is($date->Timezone('user'),
'Europe/Moscow',
"in user context returns user's timezone");
- is($date->Timezone, 'UTC', "the deafult value is always UTC");
is($date->Timezone('server'), 'UTC', "wasn't changed");
RT->Config->Set( Timezone => 'Africa/Ouagadougou' );
@@ -75,7 +57,6 @@ my $current_user;
is($date->Timezone('user'),
'Europe/Moscow',
"in user context still returns user's timezone");
- is($date->Timezone, 'UTC', "the deafult value is always UTC");
$current_user->UserObj->__Set( Field => 'Timezone', Value => '');
is_empty($current_user->UserObj->Timezone,
@@ -83,7 +64,6 @@ my $current_user;
is($date->Timezone('user'),
'Africa/Ouagadougou',
"in user context returns timezone of the server if user's one is not defined");
- is($date->Timezone, 'UTC', "the deafult value is always UTC");
RT->Config->Set( Timezone => 'GMT' );
is($date->Timezone('server'),
@@ -91,7 +71,6 @@ my $current_user;
"timezone is GMT which one is alias for UTC");
RT->Config->Set( Timezone => '' );
- is($date->Timezone, 'UTC', "dropped all timzones to UTC");
is($date->Timezone('user'),
'UTC',
"user's and server's timzones are not defined, so UTC");
@@ -103,7 +82,7 @@ my $current_user;
}
{
- my $date = RT::Date->new($RT::SystemUser);
+ my $date = RT::Date->new(RT->SystemUser);
is($date->Unix, 0, "new date returns 0 in Unix format");
is($date->Get, '1970-01-01 00:00:00', "default is ISO format");
is($date->Get(Format =>'SomeBadFormat'),
@@ -117,7 +96,7 @@ my $current_user;
"RFC2822 format with defaults");
is($date->Get(Format =>'LocalizedDateTime'),
'Thu, Jan 1, 1970 12:00:00 AM',
- "LocalizedDateTime format with defaults") if ( $localized_datetime_tests );
+ "LocalizedDateTime format with defaults");
is($date->ISO(Time => 0),
'1970-01-01',
@@ -130,7 +109,7 @@ my $current_user;
"RFC2822 format without time part");
is($date->LocalizedDateTime(Time => 0),
'Thu, Jan 1, 1970',
- "LocalizedDateTime format without time part") if ( $localized_datetime_tests );
+ "LocalizedDateTime format without time part");
is($date->ISO(Date => 0),
'00:00:00',
@@ -143,7 +122,7 @@ my $current_user;
"RFC2822 format without date part");
is($date->LocalizedDateTime(Date => 0),
'12:00:00 AM',
- "LocalizedDateTime format without date part") if ( $localized_datetime_tests );
+ "LocalizedDateTime format without date part");
is($date->ISO(Date => 0, Seconds => 0),
'00:00',
@@ -164,16 +143,16 @@ my $current_user;
is($date->LocalizedDateTime(AbbrDay => 0),
'Thursday, Jan 1, 1970 12:00:00 AM',
- "LocalizedDateTime format without abbreviation of day") if ( $localized_datetime_tests );
+ "LocalizedDateTime format without abbreviation of day");
is($date->LocalizedDateTime(AbbrMonth => 0),
'Thu, January 1, 1970 12:00:00 AM',
- "LocalizedDateTime format without abbreviation of month") if ( $localized_datetime_tests );
+ "LocalizedDateTime format without abbreviation of month");
is($date->LocalizedDateTime(DateFormat => 'date_format_short'),
'1/1/70 12:00:00 AM',
- "LocalizedDateTime format with non default DateFormat") if ( $localized_datetime_tests );
+ "LocalizedDateTime format with non default DateFormat");
is($date->LocalizedDateTime(TimeFormat => 'time_format_short'),
'Thu, Jan 1, 1970 12:00 AM',
- "LocalizedDateTime format with non default TimeFormat") if ( $localized_datetime_tests );
+ "LocalizedDateTime format with non default TimeFormat");
is($date->Date,
'1970-01-01',
@@ -256,14 +235,14 @@ my $current_user;
warning_like
{ # bad format
- my $date = RT::Date->new($RT::SystemUser);
+ my $date = RT::Date->new(RT->SystemUser);
$date->Set( Format => 'bad' );
is($date->Unix, 0, "bad format");
-} qr'Unknown Date format: bad';
+} qr{Unknown Date format: bad};
{ # setting value via Unix method
- my $date = RT::Date->new($RT::SystemUser);
+ my $date = RT::Date->new(RT->SystemUser);
$date->Unix(1);
is($date->ISO, '1970-01-01 00:00:01', "correct value");
@@ -280,7 +259,7 @@ warning_like
my $year = (localtime(time))[5] + 1900;
{ # set+ISO format
- my $date = RT::Date->new($RT::SystemUser);
+ my $date = RT::Date->new(RT->SystemUser);
warning_like {
$date->Set(Format => 'ISO', Value => 'weird date');
} qr/Couldn't parse date 'weird date' as a ISO format/;
@@ -324,7 +303,7 @@ my $year = (localtime(time))[5] + 1900;
}
{ # set+datemanip format(Time::ParseDate)
- my $date = RT::Date->new($RT::SystemUser);
+ my $date = RT::Date->new(RT->SystemUser);
$date->Set(Format => 'unknown', Value => 'weird date');
is($date->Unix, 0, "date was wrong");
@@ -343,7 +322,7 @@ my $year = (localtime(time))[5] + 1900;
}
{ # set+unknown format(Time::ParseDate)
- my $date = RT::Date->new($RT::SystemUser);
+ my $date = RT::Date->new(RT->SystemUser);
$date->Set(Format => 'unknown', Value => 'weird date');
is($date->Unix, 0, "date was wrong");
@@ -380,7 +359,7 @@ my $year = (localtime(time))[5] + 1900;
}
{ # SetToMidnight
- my $date = RT::Date->new($RT::SystemUser);
+ my $date = RT::Date->new(RT->SystemUser);
RT->Config->Set( Timezone => 'Europe/Moscow' );
$date->Set(Format => 'ISO', Value => '2005-11-28 15:10:00');
@@ -414,7 +393,7 @@ my $year = (localtime(time))[5] + 1900;
}
{ # SetToNow
- my $date = RT::Date->new($RT::SystemUser);
+ my $date = RT::Date->new(RT->SystemUser);
my $time = time;
$date->SetToNow;
ok($date->Unix >= $time, 'close enough');
@@ -422,7 +401,7 @@ my $year = (localtime(time))[5] + 1900;
}
{
- my $date = RT::Date->new($RT::SystemUser);
+ my $date = RT::Date->new(RT->SystemUser);
$date->Unix(0);
$date->AddSeconds;
@@ -484,7 +463,7 @@ my $year = (localtime(time))[5] + 1900;
}
{ # DurationAsString
- my $date = RT::Date->new($RT::SystemUser);
+ my $date = RT::Date->new(RT->SystemUser);
is($date->DurationAsString(1), '1 sec', '1 sec');
is($date->DurationAsString(59), '59 sec', '59 sec');
@@ -505,7 +484,7 @@ my $year = (localtime(time))[5] + 1900;
}
{ # DiffAsString
- my $date = RT::Date->new($RT::SystemUser);
+ my $date = RT::Date->new(RT->SystemUser);
is($date->DiffAsString(1), '', 'no diff, wrong input');
is($date->DiffAsString(-1), '', 'no diff, wrong input');
is($date->DiffAsString('qwe'), '', 'no diff, wrong input');
@@ -516,14 +495,14 @@ my $year = (localtime(time))[5] + 1900;
is($date->DiffAsString(3), '1 sec ago', 'diff: 1 sec ago');
is($date->DiffAsString(1), '1 sec', 'diff: 1 sec');
- my $ndate = RT::Date->new($RT::SystemUser);
+ my $ndate = RT::Date->new(RT->SystemUser);
is($date->DiffAsString($ndate), '', 'no diff, wrong input');
$ndate->Unix(3);
is($date->DiffAsString($ndate), '1 sec ago', 'diff: 1 sec ago');
}
{ # Diff
- my $date = RT::Date->new($RT::SystemUser);
+ my $date = RT::Date->new(RT->SystemUser);
$date->SetToNow;
my $diff = $date->Diff;
ok($diff <= 0, 'close enought');
@@ -531,14 +510,14 @@ my $year = (localtime(time))[5] + 1900;
}
{ # AgeAsString
- my $date = RT::Date->new($RT::SystemUser);
+ my $date = RT::Date->new(RT->SystemUser);
$date->SetToNow;
my $diff = $date->AgeAsString;
like($diff, qr/^(0 sec|[1-5] sec ago)$/, 'close enought');
}
{ # GetWeekday
- my $date = RT::Date->new($RT::SystemUser);
+ my $date = RT::Date->new(RT->SystemUser);
is($date->GetWeekday(7), '', '7 and greater are invalid');
is($date->GetWeekday(6), 'Sat', '6 is Saturday');
is($date->GetWeekday(0), 'Sun', '0 is Sunday');
@@ -548,7 +527,7 @@ my $year = (localtime(time))[5] + 1900;
}
{ # GetMonth
- my $date = RT::Date->new($RT::SystemUser);
+ my $date = RT::Date->new(RT->SystemUser);
is($date->GetMonth(12), '', '12 and greater are invalid');
is($date->GetMonth(11), 'Dec', '11 is December');
is($date->GetMonth(0), 'Jan', '0 is January');
@@ -557,8 +536,19 @@ my $year = (localtime(time))[5] + 1900;
is($date->GetMonth(-13), '', '-13 and lesser are invalid');
}
+{
+ # set unknown format: edge cases
+ my $date = RT::Date->new(RT->SystemUser);
+ $date->Set( Value => 0, Format => 'unknown' );
+ is( $date->Unix(), 0, "unix is 0 with Value => 0, Format => 'unknown'" );
+
+ $date->Set( Value => '', Format => 'unknown' );
+ is( $date->Unix(), 0, "unix is 0 with Value => '', Format => 'unknown'" );
+
+ $date->Set( Value => ' ', Format => 'unknown' );
+ is( $date->Unix(), 0, "unix is 0 with Value => ' ', Format => 'unknown'" );
+}
+
#TODO: AsString
#TODO: RFC2822, W3CDTF with Timezones
-exit(0);
-
diff --git a/rt/t/api/emailparser.t b/rt/t/api/emailparser.t
index 940c26fde..790314603 100644
--- a/rt/t/api/emailparser.t
+++ b/rt/t/api/emailparser.t
@@ -2,7 +2,7 @@
use strict;
use warnings;
-use RT::Test tests => 4;
+use RT::Test nodb => 1, tests => 10;
RT->Config->Set( RTAddressRegexp => qr/^rt\@example.com$/i );
@@ -14,6 +14,23 @@ is(RT::EmailParser::IsRTAddress("","frt\@example.com"),undef, "Regexp didn't mat
my @before = ("rt\@example.com", "frt\@example.com");
my @after = ("frt\@example.com");
-ok(eq_array(RT::EmailParser::CullRTAddresses("",@before),@after), "CullRTAddresses only culls RT addresses");
+ok(eq_array(RT::EmailParser->CullRTAddresses(@before),@after), "CullRTAddresses only culls RT addresses");
+
+{
+ require RT::Interface::Email;
+ my ( $addr, $name ) =
+ RT::Interface::Email::ParseAddressFromHeader('foo@example.com');
+ is( $addr, 'foo@example.com', 'addr for foo@example.com' );
+ is( $name, undef, 'no name for foo@example.com' );
+
+ ( $addr, $name ) =
+ RT::Interface::Email::ParseAddressFromHeader('Foo <foo@example.com>');
+ is( $addr, 'foo@example.com', 'addr for Foo <foo@example.com>' );
+ is( $name, 'Foo', 'name for Foo <foo@example.com>' );
+
+ ( $addr, $name ) =
+ RT::Interface::Email::ParseAddressFromHeader('foo@example.com (Comment)');
+ is( $addr, 'foo@example.com', 'addr for foo@example.com (Comment)' );
+ is( $name, undef, 'no name for foo@example.com (Comment)' );
+}
-1;
diff --git a/rt/t/api/execute-code.t b/rt/t/api/execute-code.t
new file mode 100644
index 000000000..7f72be90a
--- /dev/null
+++ b/rt/t/api/execute-code.t
@@ -0,0 +1,108 @@
+use strict;
+use warnings;
+use RT::Test tests => 17;
+
+my $ticket = RT::Ticket->new(RT->SystemUser);
+ok(
+ $ticket->Create(
+ Subject => 'blue lines',
+ Queue => 'General',
+ )
+);
+
+my $attacker = RT::User->new(RT->SystemUser);
+ok(
+ $attacker->Create(
+ Name => 'attacker',
+ Password => 'foobar',
+ Privileged => 1,
+ )
+);
+
+my $template_as_attacker = RT::Template->new($attacker);
+
+# can't create templates without ModifyTemplate
+my ($ok, $msg) = $template_as_attacker->Create(
+ Name => 'Harmless, honest!',
+ Content => "\nhello ;)",
+ Type => 'Perl',
+);
+ok(!$ok, 'permission to create denied');
+
+
+# permit modifying templates but they must be simple
+$attacker->PrincipalObj->GrantRight(Right => 'ShowTemplate', Object => $RT::System);
+$attacker->PrincipalObj->GrantRight(Right => 'ModifyTemplate', Object => $RT::System);
+
+($ok, $msg) = $template_as_attacker->Create(
+ Name => 'Harmless, honest!',
+ Content => "\nhello ;)",
+ Type => 'Perl',
+);
+ok(!$ok, 'permission to create denied');
+
+
+($ok, $msg) = $template_as_attacker->Create(
+ Name => 'Harmless, honest!',
+ Content => "\nhello ;)",
+ Type => 'Simple',
+);
+ok($ok, 'created template now that we have ModifyTemplate');
+
+($ok, $msg) = $template_as_attacker->SetType('Perl');
+ok(!$ok, 'permission to update type to Perl denied');
+
+my $template_as_root = RT::Template->new(RT->SystemUser);
+$template_as_root->Load('Harmless, honest!');
+is($template_as_root->Content, "\nhello ;)");
+is($template_as_root->Type, 'Simple');
+
+$template_as_root->Parse(TicketObj => $ticket);
+is($template_as_root->MIMEObj->stringify_body, "hello ;)");
+
+
+# update the content to include code (even though Simple won't parse it)
+
+($ok, $msg) = $template_as_attacker->SetContent("\nYou are { (my \$message = 'bjarq') =~ tr/a-z/n-za-m/; \$message }!");
+ok($ok, 'updating Content permitted since the template is Simple');
+
+$template_as_root = RT::Template->new(RT->SystemUser);
+$template_as_root->Load('Harmless, honest!');
+
+is($template_as_root->Content, "\nYou are { (my \$message = 'bjarq') =~ tr/a-z/n-za-m/; \$message }!");
+is($template_as_root->Type, 'Simple');
+
+$template_as_root->Parse(TicketObj => $ticket);
+is($template_as_root->MIMEObj->stringify_body, "You are { (my \$message = 'bjarq') =~ tr/a-z/n-za-m/; \$message }!");
+
+
+# try again, why not
+($ok, $msg) = $template_as_attacker->SetType('Perl');
+ok(!$ok, 'permission to update type to Perl denied');
+
+
+# now root will change the template to genuine code
+$template_as_root = RT::Template->new(RT->SystemUser);
+$template_as_root->Load('Harmless, honest!');
+$template_as_root->SetType('Perl');
+$template_as_root->SetContent("\n{ scalar reverse \$Ticket->Subject }");
+
+$template_as_root->Parse(TicketObj => $ticket);
+is($template_as_root->MIMEObj->stringify_body, "senil eulb");
+
+
+# see if we can update anything
+$template_as_attacker = RT::Template->new($attacker);
+$template_as_attacker->Load('Harmless, honest!');
+
+($ok, $msg) = $template_as_attacker->SetContent("\nYou are { (my \$message = 'bjarq') =~ tr/a-z/n-za-m/; \$message }!");
+ok(!$ok, 'updating Content forbidden since the template is Perl');
+
+# try again just to be absolutely sure it doesn't work
+$template_as_root = RT::Template->new(RT->SystemUser);
+$template_as_root->Load('Harmless, honest!');
+$template_as_root->SetType('Perl');
+$template_as_root->SetContent("\n{ scalar reverse \$Ticket->Subject }");
+
+$template_as_root->Parse(TicketObj => $ticket);
+is($template_as_root->MIMEObj->stringify_body, "senil eulb");
diff --git a/rt/t/api/group-rights.t b/rt/t/api/group-rights.t
new file mode 100644
index 000000000..0494c286e
--- /dev/null
+++ b/rt/t/api/group-rights.t
@@ -0,0 +1,137 @@
+use strict;
+use warnings;
+use RT::Test nodata => 1, tests => 114;
+
+RT::Group->AddRights(
+ 'RTxGroupRight' => 'Just a right for testing rights',
+);
+
+# this company is split into two halves, the hackers and the non-hackers
+# herbert is a hacker but eric is not.
+my $herbert = RT::User->new(RT->SystemUser);
+my ($ok, $msg) = $herbert->Create(Name => 'herbert');
+ok($ok, $msg);
+
+my $eric = RT::User->new(RT->SystemUser);
+($ok, $msg) = $eric->Create(Name => 'eric');
+ok($ok, $msg);
+
+my $hackers = RT::Group->new(RT->SystemUser);
+($ok, $msg) = $hackers->CreateUserDefinedGroup(Name => 'Hackers');
+ok($ok, $msg);
+
+my $employees = RT::Group->new(RT->SystemUser);
+($ok, $msg) = $employees->CreateUserDefinedGroup(Name => 'Employees');
+ok($ok, $msg);
+
+($ok, $msg) = $employees->AddMember($hackers->PrincipalId);
+ok($ok, $msg);
+
+($ok, $msg) = $hackers->AddMember($herbert->PrincipalId);
+ok($ok, $msg);
+
+($ok, $msg) = $employees->AddMember($eric->PrincipalId);
+ok($ok, $msg);
+
+ok($employees->HasMemberRecursively($hackers->PrincipalId), 'employees has member hackers');
+ok($employees->HasMemberRecursively($herbert->PrincipalId), 'employees has member herbert');
+ok($employees->HasMemberRecursively($eric->PrincipalId), 'employees has member eric');
+
+ok($hackers->HasMemberRecursively($herbert->PrincipalId), 'hackers has member herbert');
+ok(!$hackers->HasMemberRecursively($eric->PrincipalId), 'hackers does not have member eric');
+
+# There's also a separate group, "Other", which both are a member of.
+my $other = RT::Group->new(RT->SystemUser);
+($ok, $msg) = $other->CreateUserDefinedGroup(Name => 'Other');
+ok($ok, $msg);
+($ok, $msg) = $other->AddMember($eric->PrincipalId);
+ok($ok, $msg);
+($ok, $msg) = $other->AddMember($herbert->PrincipalId);
+ok($ok, $msg);
+
+
+# Everyone can SeeGroup on all three groups
+my $everyone = RT::Group->new( RT->SystemUser );
+($ok, $msg) = $everyone->LoadSystemInternalGroup( 'Everyone' );
+ok($ok, $msg);
+$everyone->PrincipalObj->GrantRight(Right => 'SeeGroup', Object => $employees);
+$everyone->PrincipalObj->GrantRight(Right => 'SeeGroup', Object => $hackers);
+$everyone->PrincipalObj->GrantRight(Right => 'SeeGroup', Object => $other);
+
+sub CheckRights {
+ my $cu = shift;
+ my %groups = (Employees => 0, Hackers => 0, Other => 0, @_);
+ my $name = $cu->Name;
+
+ my $groups = RT::Groups->new(RT::CurrentUser->new($cu));
+ $groups->LimitToUserDefinedGroups;
+ $groups->ForWhichCurrentUserHasRight(Right => 'RTxGroupRight');
+ my %has_right = map { ($_->Name => 1) } @{ $groups->ItemsArrayRef };
+
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+ for my $groupname (sort keys %groups) {
+ my $g = RT::Group->new(RT::CurrentUser->new($cu));
+ $g->LoadUserDefinedGroup($groupname);
+ if ($groups{$groupname}) {
+ ok( $g->CurrentUserHasRight("RTxGroupRight"), "$name has right on $groupname (direct query)" );
+ ok( delete $has_right{$groupname}, "..and also in ForWhichCurrentUserHasRight");
+ } else {
+ ok( !$g->CurrentUserHasRight("RTxGroupRight"), "$name doesn't have right on $groupname (direct query)" );
+ ok( !delete $has_right{$groupname}, "..and also not in ForWhichCurrentUserHasRight");
+ }
+ }
+ ok(not(keys %has_right), "ForWhichCurrentUserHasRight has no extra groups");
+}
+
+# Neither should have it on any group yet
+CheckRights($eric);
+CheckRights($herbert);
+
+
+# Grant it to employees, on employees. Both Herbert and Eric will have
+# it on employees, though Herbert gets it by way of hackers. Neither
+# will have it on hackers, because the target does not recurse.
+$employees->PrincipalObj->GrantRight( Right => 'RTxGroupRight', Object => $employees);
+CheckRights($eric, Employees => 1);
+CheckRights($herbert, Employees => 1);
+
+
+# Grant it to employees, on hackers. This means both Eric and Herbert
+# will have the right on hackers, but not on employees.
+$employees->PrincipalObj->RevokeRight(Right => 'RTxGroupRight', Object => $employees);
+$employees->PrincipalObj->GrantRight( Right => 'RTxGroupRight', Object => $hackers);
+CheckRights($eric, Hackers => 1);
+CheckRights($herbert, Hackers => 1);
+
+
+# Grant it to hackers, on employees. Eric will have it nowhere, and
+# Herbert will have it on employees. Note that the target of the right
+# itself does _not_ recurse down, so Herbert will not have it on
+# hackers.
+$employees->PrincipalObj->RevokeRight(Right => 'RTxGroupRight', Object => $hackers);
+$hackers->PrincipalObj->GrantRight( Right => 'RTxGroupRight', Object => $employees);
+CheckRights($eric);
+CheckRights($herbert, Employees => 1);
+
+
+# Grant it globally to hackers; herbert will see the right on all
+# employees, hackers, and other.
+$hackers->PrincipalObj->RevokeRight( Right => 'RTxGroupRight', Object => $employees);
+$hackers->PrincipalObj->GrantRight( Right => 'RTxGroupRight', Object => RT->System);
+CheckRights($eric);
+CheckRights($herbert, Employees => 1, Hackers => 1, Other => 1 );
+
+
+# Grant it globally to employees; both eric and herbert will see the
+# right on all employees, hackers, and other.
+$hackers->PrincipalObj->RevokeRight( Right => 'RTxGroupRight', Object => RT->System);
+$employees->PrincipalObj->GrantRight( Right => 'RTxGroupRight', Object => RT->System);
+CheckRights($eric, Employees => 1, Hackers => 1, Other => 1 );
+CheckRights($herbert, Employees => 1, Hackers => 1, Other => 1 );
+
+
+# Disable the employees group. Neither eric nor herbert will see the
+# right anywhere.
+$employees->SetDisabled(1);
+CheckRights($eric);
+CheckRights($herbert);
diff --git a/rt/t/api/group.t b/rt/t/api/group.t
index 551d4f1a0..3ce3da999 100644
--- a/rt/t/api/group.t
+++ b/rt/t/api/group.t
@@ -2,20 +2,19 @@
use strict;
use warnings;
use RT;
-use RT::Test tests => 38;
+use RT::Test nodata => 1, tests => 38;
{
-# {{{ Tests
ok (require RT::Group);
-ok (my $group = RT::Group->new($RT::SystemUser), "instantiated a group object");
+ok (my $group = RT::Group->new(RT->SystemUser), "instantiated a group object");
ok (my ($id, $msg) = $group->CreateUserDefinedGroup( Name => 'TestGroup', Description => 'A test group',
), 'Created a new group');
isnt ($id , 0, "Group id is $id");
is ($group->Name , 'TestGroup', "The group's name is 'TestGroup'");
-my $ng = RT::Group->new($RT::SystemUser);
+my $ng = RT::Group->new(RT->SystemUser);
ok($ng->LoadUserDefinedGroup('TestGroup'), "Loaded testgroup");
is($ng->id , $group->id, "Loaded the right group");
@@ -30,7 +29,7 @@ ok($id, $msg);
# Group 1 now has members 1, 2 ,3
-my $group_2 = RT::Group->new($RT::SystemUser);
+my $group_2 = RT::Group->new(RT->SystemUser);
ok (my ($id_2, $msg_2) = $group_2->CreateUserDefinedGroup( Name => 'TestGroup2', Description => 'A second test group'), , 'Created a new group');
isnt ($id_2 , 0, "Created group 2 ok- $msg_2 ");
ok (($id,$msg) = $group_2->AddMember($ng->PrincipalId), "Made TestGroup a member of testgroup2");
@@ -40,7 +39,7 @@ ok($id, $msg);
# Group 2 how has 1, g1->{1, 2,3}
-my $group_3 = RT::Group->new($RT::SystemUser);
+my $group_3 = RT::Group->new(RT->SystemUser);
ok (my ($id_3, $msg_3) = $group_3->CreateUserDefinedGroup( Name => 'TestGroup3', Description => 'A second test group'), 'Created a new group');
isnt ($id_3 , 0, "Created group 3 ok - $msg_3");
ok (($id,$msg) =$group_3->AddMember($group_2->PrincipalId), "Made TestGroup a member of testgroup2");
@@ -48,10 +47,10 @@ ok($id, $msg);
# g3 now has g2->{1, g1->{1,2,3}}
-my $principal_1 = RT::Principal->new($RT::SystemUser);
+my $principal_1 = RT::Principal->new(RT->SystemUser);
$principal_1->Load('1');
-my $principal_2 = RT::Principal->new($RT::SystemUser);
+my $principal_2 = RT::Principal->new(RT->SystemUser);
$principal_2->Load('2');
ok (($id,$msg) = $group_3->AddMember('1' ), "Added member RT_System to the group TestGroup2");
@@ -81,14 +80,13 @@ is($group_2->HasMemberRecursively($principal_2), undef, "group 2 doesn't have me
is($ng->HasMember($principal_2), undef, "group 1 doesn't have member 2");
is($group_3->HasMemberRecursively($principal_2), undef, "group 3 has member 2 recursively");
-# }}}
}
{
-ok(my $u = RT::Group->new($RT::SystemUser));
+ok(my $u = RT::Group->new(RT->SystemUser));
ok($u->Load(4), "Loaded the first user");
is($u->PrincipalObj->ObjectId , 4, "user 4 is the fourth principal");
is($u->PrincipalObj->PrincipalType , 'Group' , "Principal 4 is a group");
@@ -96,4 +94,3 @@ is($u->PrincipalObj->PrincipalType , 'Group' , "Principal 4 is a group");
}
-1;
diff --git a/rt/t/api/groups.t b/rt/t/api/groups.t
index 995c844ba..d2dc126dc 100644
--- a/rt/t/api/groups.t
+++ b/rt/t/api/groups.t
@@ -1,87 +1,73 @@
-
use strict;
use warnings;
-use RT;
-use RT::Test tests => 28;
+use RT::Test nodata => 1, tests => 27;
+RT::Group->AddRights(
+ 'RTxGroupRight' => 'Just a right for testing rights',
+);
{
-
-ok (require RT::Groups);
-
-
+ my $g = RT::Group->new(RT->SystemUser);
+ my ($id, $msg) = $g->CreateUserDefinedGroup(Name => 'GroupsNotEqualTest');
+ ok ($id, "created group #". $g->id) or diag("error: $msg");
+
+ my $groups = RT::Groups->new(RT->SystemUser);
+ $groups->Limit( FIELD => 'id', OPERATOR => '!=', VALUE => $g->id );
+ $groups->LimitToUserDefinedGroups();
+ my $bug = grep $_->id == $g->id, @{$groups->ItemsArrayRef};
+ ok (!$bug, "didn't find group");
}
-{
-
-# next had bugs
-# Groups->Limit( FIELD => 'id', OPERATOR => '!=', VALUE => xx );
-my $g = RT::Group->new($RT::SystemUser);
-my ($id, $msg) = $g->CreateUserDefinedGroup(Name => 'GroupsNotEqualTest');
-ok ($id, "created group #". $g->id) or diag("error: $msg");
-
-my $groups = RT::Groups->new($RT::SystemUser);
-$groups->Limit( FIELD => 'id', OPERATOR => '!=', VALUE => $g->id );
-$groups->LimitToUserDefinedGroups();
-my $bug = grep $_->id == $g->id, @{$groups->ItemsArrayRef};
-ok (!$bug, "didn't find group");
-
-
-}
{
-
-my $u = RT::User->new($RT::SystemUser);
-my ($id, $msg) = $u->Create( Name => 'Membertests'. $$ );
-ok ($id, 'created user') or diag "error: $msg";
-
-my $g = RT::Group->new($RT::SystemUser);
-($id, $msg) = $g->CreateUserDefinedGroup(Name => 'Membertests');
-ok ($id, $msg);
-
-my ($aid, $amsg) =$g->AddMember($u->id);
-ok ($aid, $amsg);
-ok($g->HasMember($u->PrincipalObj),"G has member u");
-
-my $groups = RT::Groups->new($RT::SystemUser);
-$groups->LimitToUserDefinedGroups();
-$groups->WithMember(PrincipalId => $u->id);
-is ($groups->Count , 1,"found the 1 group - " . $groups->Count);
-is ($groups->First->Id , $g->Id, "it's the right one");
-
-
+ my $u = RT::User->new(RT->SystemUser);
+ my ($id, $msg) = $u->Create( Name => 'Membertests'. $$ );
+ ok ($id, 'created user') or diag "error: $msg";
+
+ my $g = RT::Group->new(RT->SystemUser);
+ ($id, $msg) = $g->CreateUserDefinedGroup(Name => 'Membertests');
+ ok ($id, $msg);
+
+ my ($aid, $amsg) =$g->AddMember($u->id);
+ ok ($aid, $amsg);
+ ok($g->HasMember($u->PrincipalObj),"G has member u");
+
+ my $groups = RT::Groups->new(RT->SystemUser);
+ $groups->LimitToUserDefinedGroups();
+ $groups->WithMember(PrincipalId => $u->id);
+ is ($groups->Count , 1,"found the 1 group - " . $groups->Count);
+ is ($groups->First->Id , $g->Id, "it's the right one");
}
-{
- no warnings qw/redefine once/;
+no warnings qw/redefine once/;
-my $q = RT::Queue->new($RT::SystemUser);
+my $q = RT::Queue->new(RT->SystemUser);
my ($id, $msg) =$q->Create( Name => 'GlobalACLTest');
ok ($id, $msg);
-my $testuser = RT::User->new($RT::SystemUser);
+my $testuser = RT::User->new(RT->SystemUser);
($id,$msg) = $testuser->Create(Name => 'JustAnAdminCc');
ok ($id,$msg);
-my $global_admin_cc = RT::Group->new($RT::SystemUser);
+my $global_admin_cc = RT::Group->new(RT->SystemUser);
$global_admin_cc->LoadSystemRoleGroup('AdminCc');
ok($global_admin_cc->id, "Found the global admincc group");
-my $groups = RT::Groups->new($RT::SystemUser);
+my $groups = RT::Groups->new(RT->SystemUser);
$groups->WithRight(Right => 'OwnTicket', Object => $q);
is($groups->Count, 1);
-($id, $msg) = $global_admin_cc->PrincipalObj->GrantRight(Right =>'OwnTicket', Object=> $RT::System);
+($id, $msg) = $global_admin_cc->PrincipalObj->GrantRight(Right =>'OwnTicket', Object=> RT->System);
ok ($id,$msg);
ok (!$testuser->HasRight(Object => $q, Right => 'OwnTicket') , "The test user does not have the right to own tickets in the test queue");
($id, $msg) = $q->AddWatcher(Type => 'AdminCc', PrincipalId => $testuser->id);
ok($id,$msg);
ok ($testuser->HasRight(Object => $q, Right => 'OwnTicket') , "The test user does have the right to own tickets now. thank god.");
-$groups = RT::Groups->new($RT::SystemUser);
+$groups = RT::Groups->new(RT->SystemUser);
$groups->WithRight(Right => 'OwnTicket', Object => $q);
ok ($id,$msg);
is($groups->Count, 3);
-my $RTxGroup = RT::Group->new($RT::SystemUser);
+my $RTxGroup = RT::Group->new(RT->SystemUser);
($id, $msg) = $RTxGroup->CreateUserDefinedGroup( Name => 'RTxGroup', Description => "RTx extension group");
ok ($id,$msg);
is ($RTxGroup->id, $id, "group loaded");
@@ -90,7 +76,7 @@ my $RTxSysObj = {};
bless $RTxSysObj, 'RTx::System';
*RTx::System::Id = sub { 1; };
*RTx::System::id = *RTx::System::Id;
-my $ace = RT::Record->new($RT::SystemUser);
+my $ace = RT::Record->new(RT->SystemUser);
$ace->Table('ACL');
$ace->_BuildTableAttributes unless ($RT::Record::_TABLE_ATTR->{ref($ace)});
($id, $msg) = $ace->Create( PrincipalId => $RTxGroup->id, PrincipalType => 'Group', RightName => 'RTxGroupRight', ObjectType => 'RTx::System', ObjectId => 1);
@@ -101,19 +87,19 @@ bless $RTxObj, 'RTx::System::Record';
*RTx::System::Record::Id = sub { 4; };
*RTx::System::Record::id = *RTx::System::Record::Id;
-$groups = RT::Groups->new($RT::SystemUser);
+$groups = RT::Groups->new(RT->SystemUser);
$groups->WithRight(Right => 'RTxGroupRight', Object => $RTxSysObj);
is($groups->Count, 1, "RTxGroupRight found for RTxSysObj");
-$groups = RT::Groups->new($RT::SystemUser);
+$groups = RT::Groups->new(RT->SystemUser);
$groups->WithRight(Right => 'RTxGroupRight', Object => $RTxObj);
is($groups->Count, 0, "RTxGroupRight not found for RTxObj");
-$groups = RT::Groups->new($RT::SystemUser);
+$groups = RT::Groups->new(RT->SystemUser);
$groups->WithRight(Right => 'RTxGroupRight', Object => $RTxObj, EquivObjects => [ $RTxSysObj ]);
is($groups->Count, 1, "RTxGroupRight found for RTxObj using EquivObjects");
-$ace = RT::Record->new($RT::SystemUser);
+$ace = RT::Record->new(RT->SystemUser);
$ace->Table('ACL');
$ace->_BuildTableAttributes unless ($RT::Record::_TABLE_ATTR->{ref($ace)});
($id, $msg) = $ace->Create( PrincipalId => $RTxGroup->id, PrincipalType => 'Group', RightName => 'RTxGroupRight', ObjectType => 'RTx::System::Record', ObjectId => 5 );
@@ -123,17 +109,10 @@ my $RTxObj2 = {};
bless $RTxObj2, 'RTx::System::Record';
*RTx::System::Record::Id = sub { 5; };
-$groups = RT::Groups->new($RT::SystemUser);
+$groups = RT::Groups->new(RT->SystemUser);
$groups->WithRight(Right => 'RTxGroupRight', Object => $RTxObj2);
is($groups->Count, 1, "RTxGroupRight found for RTxObj2");
-$groups = RT::Groups->new($RT::SystemUser);
+$groups = RT::Groups->new(RT->SystemUser);
$groups->WithRight(Right => 'RTxGroupRight', Object => $RTxObj2, EquivObjects => [ $RTxSysObj ]);
is($groups->Count, 1, "RTxGroupRight found for RTxObj2");
-
-
-
-
-}
-
-1;
diff --git a/rt/t/api/has_rights.t b/rt/t/api/has_rights.t
new file mode 100644
index 000000000..990fc0185
--- /dev/null
+++ b/rt/t/api/has_rights.t
@@ -0,0 +1,43 @@
+use RT::Test nodata => 1, tests => 9;
+
+use strict;
+use warnings;
+
+my $queue = RT::Test->load_or_create_queue( Name => 'A' );
+ok $queue && $queue->id, 'loaded or created queue_a';
+my $qid = $queue->id;
+
+my $user = RT::Test->load_or_create_user(
+ Name => 'user',
+ Password => 'password',
+ EmailAddress => 'test@example.com',
+);
+ok $user && $user->id, 'loaded or created user';
+
+{
+ cleanup();
+ RT::Test->set_rights(
+ { Principal => 'Everyone', Right => [qw(SeeQueue)] },
+ { Principal => 'Cc', Right => [qw(ShowTicket)] },
+ );
+ my ($t) = RT::Test->create_tickets(
+ { Queue => $queue->id },
+ { },
+ );
+ my $rights = $user->PrincipalObj->HasRights( Object => $t );
+ is_deeply( $rights, { SeeQueue => 1 }, 'got it' );
+
+ ($t) = RT::Test->create_tickets(
+ { Queue => $queue->id },
+ { Cc => $user->EmailAddress },
+ );
+ ok($t->Cc->HasMember( $user->id ), 'user is cc');
+ $rights = $user->PrincipalObj->HasRights( Object => $t );
+ is_deeply( $rights, { SeeQueue => 1, ShowTicket => 1 }, 'got it' )
+}
+
+sub cleanup {
+ RT::Test->delete_tickets( "Queue = $qid" );
+ RT::Test->delete_queue_watchers( $queue );
+};
+
diff --git a/rt/t/api/i18n.t b/rt/t/api/i18n.t
index 17d71b761..831532b90 100644
--- a/rt/t/api/i18n.t
+++ b/rt/t/api/i18n.t
@@ -2,7 +2,7 @@
use strict;
use warnings;
use RT;
-use RT::Test tests => 9;
+use RT::Test nodb => 1, tests => 9;
{
@@ -27,4 +27,3 @@ is($en->encoding , 'utf-8', "The encoding ".$en->encoding." is 'utf-8'");
}
-1;
diff --git a/rt/t/api/i18n_guess.t b/rt/t/api/i18n_guess.t
new file mode 100644
index 000000000..139ec1acd
--- /dev/null
+++ b/rt/t/api/i18n_guess.t
@@ -0,0 +1,71 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 16;
+
+use Encode qw(encode);
+
+use constant HAS_ENCODE_GUESS => do { local $@; eval { require Encode::Guess; 1 } };
+use constant HAS_ENCODE_DETECT => do { local $@; eval { require Encode::Detect::Detector; 1 } };
+
+my $string = "\x{442}\x{435}\x{441}\x{442} \x{43f}\x{43e}\x{434}\x{434}\x{435}\x{440}\x{436}\x{43a}\x{430}";
+
+sub guess {
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+ is( RT::I18N::_GuessCharset( Encode::encode($_[0], $_[1]) ), $_[2] || $_[0], "$_[0] guesses as @{[$_[2]||$_[0]]}" );
+}
+
+RT->Config->Set(EmailInputEncodings => qw(*));
+SKIP: {
+ skip "No Encode::Detect", 3 unless HAS_ENCODE_DETECT;
+ guess('utf-8', $string);
+ guess('cp1251', $string);
+ guess('koi8-r', $string);
+}
+
+RT->Config->Set(EmailInputEncodings => qw(UTF-8 cp1251 koi8-r));
+SKIP: {
+ skip "No Encode::Guess", 4 unless HAS_ENCODE_GUESS;
+ guess('utf-8', $string);
+ guess('cp1251', $string);
+ guess('windows-1251', $string, 'cp1251');
+ {
+ local $TODO = "Encode::Guess can't distinguish cp1251 from koi8-r";
+ guess('koi8-r', $string);
+ }
+}
+
+RT->Config->Set(EmailInputEncodings => qw(UTF-8 koi8-r cp1251));
+SKIP: {
+ skip "No Encode::Guess", 3 unless HAS_ENCODE_GUESS;
+ guess('utf-8', $string);
+ guess('koi8-r', $string);
+ {
+ local $TODO = "Encode::Guess can't distinguish cp1251 from koi8-r";
+ guess('cp1251', $string);
+ }
+}
+
+# windows-1251 is an alias for cp1251, post load check cleanups array for us
+RT->Config->Set(EmailInputEncodings => qw(UTF-8 windows-1251 koi8-r));
+RT->Config->PostLoadCheck;
+SKIP: {
+ skip "No Encode::Guess", 3 unless HAS_ENCODE_GUESS;
+ guess('utf-8', $string);
+ guess('cp1251', $string);
+ {
+ local $TODO = "Encode::Guess can't distinguish cp1251 from koi8-r";
+ guess('koi8-r', $string);
+ }
+}
+
+RT->Config->Set(EmailInputEncodings => qw(* UTF-8 cp1251 koi8-r));
+SKIP: {
+ skip "No Encode::Detect", 3 unless HAS_ENCODE_DETECT;
+ guess('utf-8', $string);
+ guess('cp1251', $string);
+ guess('koi8-r', $string);
+}
+
diff --git a/rt/t/api/link.t b/rt/t/api/link.t
index eac9ae29a..a9e54a716 100644
--- a/rt/t/api/link.t
+++ b/rt/t/api/link.t
@@ -1,13 +1,12 @@
-
use strict;
use warnings;
-use RT::Test tests => 77;
+use RT::Test nodata => 1, tests => 84;
use RT::Test::Web;
+use Test::Warn;
use RT::Link;
-my $link = RT::Link->new($RT::SystemUser);
-
+my $link = RT::Link->new(RT->SystemUser);
ok (ref $link);
isa_ok( $link, 'RT::Link');
@@ -18,29 +17,37 @@ isa_ok( $link, 'DBIx::SearchBuilder::Record');
my $queue = RT::Test->load_or_create_queue(Name => 'General');
ok($queue->Id, "loaded the General queue");
-my $parent = RT::Ticket->new($RT::SystemUser);
+my $parent = RT::Ticket->new(RT->SystemUser);
my ($pid, undef, $msg) = $parent->Create(
Queue => $queue->id,
Subject => 'parent',
);
ok $pid, 'created a ticket #'. $pid or diag "error: $msg";
-my $child = RT::Ticket->new($RT::SystemUser);
-my ($cid, undef, $msg) = $child->Create(
+my $child = RT::Ticket->new(RT->SystemUser);
+((my $cid), undef, $msg) = $child->Create(
Queue => $queue->id,
Subject => 'child',
);
ok $cid, 'created a ticket #'. $cid or diag "error: $msg";
{
+ my ($status, $msg);
clean_links();
- my ($status, $msg) = $parent->AddLink;
+
+ warning_like {
+ ($status, $msg) = $parent->AddLink;
+ } qr/Base or Target must be specified/, "warned about linking a ticket to itself";
ok(!$status, "didn't create a link: $msg");
- ($status, $msg) = $parent->AddLink( Base => $parent->id );
+ warning_like {
+ ($status, $msg) = $parent->AddLink( Base => $parent->id );
+ } qr/Can't link a ticket to itself/, "warned about linking a ticket to itself";
ok(!$status, "didn't create a link: $msg");
- ($status, $msg) = $parent->AddLink( Base => $parent->id, Type => 'HasMember' );
+ warning_like {
+ ($status, $msg) = $parent->AddLink( Base => $parent->id, Type => 'HasMember' );
+ } qr/Can't link a ticket to itself/, "warned about linking a ticket to itself";
ok(!$status, "didn't create a link: $msg");
}
@@ -197,8 +204,39 @@ ok $cid, 'created a ticket #'. $cid or diag "error: $msg";
;
}
+{
+ clean_links();
+ $child->SetStatus('deleted');
+
+ my ($status, $msg) = $parent->AddLink(
+ Type => 'MemberOf', Base => $child->id,
+ );
+ ok(!$status, "can't link to deleted ticket: $msg");
+
+ $child->SetStatus('new');
+ ($status, $msg) = $parent->AddLink(
+ Type => 'MemberOf', Base => $child->id,
+ );
+ ok($status, "created a link: $msg");
+
+ $child->SetStatus('deleted');
+ my $children = $parent->Members;
+ $children->RedoSearch;
+
+ my $total = 0;
+ $total++ while $children->Next;
+ is( $total, 0, 'Next skips deleted tickets' );
+
+ is( @{ $children->ItemsArrayRef },
+ 0, 'ItemsArrayRef skips deleted tickets' );
+
+ # back to active status
+ $child->SetStatus('new');
+}
+
sub clean_links {
- my $links = RT::Links->new( $RT::SystemUser );
+ my $links = RT::Links->new( RT->SystemUser );
+ $links->UnLimit;
while ( my $link = $links->Next ) {
my ($status, $msg) = $link->Delete;
$RT::Logger->error("Couldn't delete a link: $msg")
@@ -206,4 +244,3 @@ sub clean_links {
}
}
-1;
diff --git a/rt/t/api/password-types.t b/rt/t/api/password-types.t
index 267a6ede4..5f253d51e 100644
--- a/rt/t/api/password-types.t
+++ b/rt/t/api/password-types.t
@@ -5,27 +5,37 @@ use warnings;
use RT::Test;
use Digest::MD5;
+my $default = "sha512";
+
my $root = RT::User->new(RT->SystemUser);
$root->Load("root");
-# Salted truncated SHA-256
+# Salted SHA-512 (default)
my $old = $root->__Value("Password");
-is(length($old), 40, "Stored as truncated salted SHA-256");
+like($old, qr/^\!$default\!/, "Stored as salted $default");
ok($root->IsPassword("password"));
is($root->__Value("Password"), $old, "Unchanged after password check");
# Crypt
$root->_Set( Field => "Password", Value => crypt("something", "salt"));
ok($root->IsPassword("something"), "crypt()ed password works");
-is(length($root->__Value("Password")), 40, "And is now upgraded to truncated salted SHA-256");
+like($root->__Value("Password"), qr/^\!$default\!/, "And is now upgraded to salted $default");
# MD5, hex
$root->_Set( Field => "Password", Value => Digest::MD5::md5_hex("changed"));
ok($root->IsPassword("changed"), "Unsalted MD5 hex works");
-is(length($root->__Value("Password")), 40, "And is now upgraded to truncated salted SHA-256");
+like($root->__Value("Password"), qr/^\!$default\!/, "And is now upgraded to salted $default");
# MD5, base64
$root->_Set( Field => "Password", Value => Digest::MD5::md5_base64("new"));
ok($root->IsPassword("new"), "Unsalted MD5 base64 works");
-is(length($root->__Value("Password")), 40, "And is now upgraded to truncated salted SHA-256");
+like($root->__Value("Password"), qr/^\!$default\!/, "And is now upgraded to salted $default");
+# Salted truncated SHA-256
+my $trunc = MIME::Base64::encode_base64(
+ "salt" . substr(Digest::SHA::sha256("salt".Digest::MD5::md5("secret")),0,26),
+ ""
+);
+$root->_Set( Field => "Password", Value => $trunc);
+ok($root->IsPassword("secret"), "Unsalted MD5 base64 works");
+like($root->__Value("Password"), qr/^\!$default\!/, "And is now upgraded to salted $default");
diff --git a/rt/t/api/queue.t b/rt/t/api/queue.t
index 44d5cafce..07b8ed479 100644
--- a/rt/t/api/queue.t
+++ b/rt/t/api/queue.t
@@ -2,7 +2,7 @@
use strict;
use warnings;
use RT;
-use RT::Test tests => 24;
+use RT::Test nodata => 1, tests => 24;
{
@@ -14,7 +14,7 @@ use RT::Queue;
{
-my $q = RT::Queue->new($RT::SystemUser);
+my $q = RT::Queue->new(RT->SystemUser);
is($q->IsValidStatus('new'), 1, 'New is a valid status');
is($q->IsValidStatus('f00'), 0, 'f00 is not a valid status');
@@ -23,7 +23,7 @@ is($q->IsValidStatus('f00'), 0, 'f00 is not a valid status');
{
-my $q = RT::Queue->new($RT::SystemUser);
+my $q = RT::Queue->new(RT->SystemUser);
is($q->IsActiveStatus('new'), 1, 'New is a Active status');
is($q->IsActiveStatus('rejected'), 0, 'Rejected is an inactive status');
is($q->IsActiveStatus('f00'), 0, 'f00 is not a Active status');
@@ -33,7 +33,7 @@ is($q->IsActiveStatus('f00'), 0, 'f00 is not a Active status');
{
-my $q = RT::Queue->new($RT::SystemUser);
+my $q = RT::Queue->new(RT->SystemUser);
is($q->IsInactiveStatus('new'), 0, 'New is a Active status');
is($q->IsInactiveStatus('rejected'), 1, 'rejeected is an Inactive status');
is($q->IsInactiveStatus('f00'), 0, 'f00 is not a Active status');
@@ -43,7 +43,7 @@ is($q->IsInactiveStatus('f00'), 0, 'f00 is not a Active status');
{
-my $queue = RT::Queue->new($RT::SystemUser);
+my $queue = RT::Queue->new(RT->SystemUser);
my ($id, $val) = $queue->Create( Name => 'Test1');
ok($id, $val);
@@ -55,10 +55,10 @@ ok(!$id, $val);
{
-my $Queue = RT::Queue->new($RT::SystemUser);
+my $Queue = RT::Queue->new(RT->SystemUser);
my ($id, $msg) = $Queue->Create(Name => "Foo");
ok ($id, "Foo $id was created");
-ok(my $group = RT::Group->new($RT::SystemUser));
+ok(my $group = RT::Group->new(RT->SystemUser));
ok($group->LoadQueueRoleGroup(Queue => $id, Type=> 'Requestor'));
ok ($group->Id, "Found the requestors object for this Queue");
@@ -67,7 +67,7 @@ ok ($group->Id, "Found the requestors object for this Queue");
ok ($status, "Added bob at fsck.com as a requestor") or diag "error: $msg";
}
-ok(my $bob = RT::User->new($RT::SystemUser), "Creating a bob rt::user");
+ok(my $bob = RT::User->new(RT->SystemUser), "Creating a bob rt::user");
$bob->LoadByEmail('bob@fsck.com');
ok($bob->Id, "Found the bob rt user");
ok ($Queue->IsWatcher(Type => 'Cc', PrincipalId => $bob->PrincipalId), "The Queue actually has bob at fsck.com as a requestor");
@@ -79,14 +79,13 @@ ok ($Queue->IsWatcher(Type => 'Cc', PrincipalId => $bob->PrincipalId), "The Queu
"The Queue no longer has bob at fsck.com as a requestor");
}
-$group = RT::Group->new($RT::SystemUser);
+$group = RT::Group->new(RT->SystemUser);
ok($group->LoadQueueRoleGroup(Queue => $id, Type=> 'Cc'));
ok ($group->Id, "Found the cc object for this Queue");
-$group = RT::Group->new($RT::SystemUser);
+$group = RT::Group->new(RT->SystemUser);
ok($group->LoadQueueRoleGroup(Queue => $id, Type=> 'AdminCc'));
ok ($group->Id, "Found the AdminCc object for this Queue");
}
-1;
diff --git a/rt/t/api/record.t b/rt/t/api/record.t
index 6bf1af81e..4b6b0b89c 100644
--- a/rt/t/api/record.t
+++ b/rt/t/api/record.t
@@ -14,8 +14,8 @@ ok (require RT::Record);
{
-my $ticket = RT::Ticket->new($RT::SystemUser);
-my $group = RT::Group->new($RT::SystemUser);
+my $ticket = RT::Ticket->new(RT->SystemUser);
+my $group = RT::Group->new(RT->SystemUser);
is($ticket->ObjectTypeStr, 'Ticket', "Ticket returns correct typestring");
is($group->ObjectTypeStr, 'Group', "Group returns correct typestring");
@@ -24,14 +24,14 @@ is($group->ObjectTypeStr, 'Group', "Group returns correct typestring");
{
-my $t1 = RT::Ticket->new($RT::SystemUser);
+my $t1 = RT::Ticket->new(RT->SystemUser);
my ($id, $trans, $msg) = $t1->Create(Subject => 'DepTest1', Queue => 'general');
ok($id, "Created dep test 1 - $msg");
-my $t2 = RT::Ticket->new($RT::SystemUser);
+my $t2 = RT::Ticket->new(RT->SystemUser);
(my $id2, $trans, my $msg2) = $t2->Create(Subject => 'DepTest2', Queue => 'general');
ok($id2, "Created dep test 2 - $msg2");
-my $t3 = RT::Ticket->new($RT::SystemUser);
+my $t3 = RT::Ticket->new(RT->SystemUser);
(my $id3, $trans, my $msg3) = $t3->Create(Subject => 'DepTest3', Queue => 'general', Type => 'approval');
ok($id3, "Created dep test 3 - $msg3");
my ($addid, $addmsg);
@@ -40,7 +40,7 @@ ok ($addid, $addmsg);
ok (($addid, $addmsg) =$t1->AddLink( Type => 'DependsOn', Target => $t3->id));
ok ($addid, $addmsg);
-my $link = RT::Link->new($RT::SystemUser);
+my $link = RT::Link->new(RT->SystemUser);
(my $rv, $msg) = $link->Load($addid);
ok ($rv, $msg);
is ($link->LocalTarget , $t3->id, "Link LocalTarget is correct");
@@ -52,19 +52,18 @@ ok ($t1->HasUnresolvedDependencies( Type => 'approval' ), "Ticket ".$t1->Id." ha
ok (!$t2->HasUnresolvedDependencies, "Ticket ".$t2->Id." has no unresolved deps");
;
-my ($rid, $rmsg)= $t1->Resolve();
+my ($rid, $rmsg)= $t1->SetStatus('resolved');
ok(!$rid, $rmsg);
-my ($rid2, $rmsg2) = $t2->Resolve();
+my ($rid2, $rmsg2) = $t2->SetStatus('resolved');
ok ($rid2, $rmsg2);
-($rid, $rmsg)= $t1->Resolve();
+($rid, $rmsg)= $t1->SetStatus('resolved');
ok(!$rid, $rmsg);
-my ($rid3,$rmsg3) = $t3->Resolve;
+my ($rid3,$rmsg3) = $t3->SetStatus('resolved');
ok ($rid3,$rmsg3);
-($rid, $rmsg)= $t1->Resolve();
+($rid, $rmsg)= $t1->SetStatus('resolved');
ok($rid, $rmsg);
}
-1;
diff --git a/rt/t/api/reminders.t b/rt/t/api/reminders.t
index fd1c6a69f..b035fa8de 100644
--- a/rt/t/api/reminders.t
+++ b/rt/t/api/reminders.t
@@ -10,7 +10,7 @@ use RT::Test tests => 20;
# Create test queues
use_ok ('RT::Queue');
-ok(my $testqueue = RT::Queue->new($RT::SystemUser), 'Instantiate RT::Queue');
+ok(my $testqueue = RT::Queue->new(RT->SystemUser), 'Instantiate RT::Queue');
ok($testqueue->Create( Name => 'reminders tests'), 'Create new queue: reminders tests');
isnt($testqueue->Id , 0, 'Success creating queue');
@@ -20,10 +20,10 @@ isnt($testqueue->Id , 0, 'Success creating queue');
# Create test ticket
use_ok('RT::Ticket');
-my $u = RT::User->new($RT::SystemUser);
+my $u = RT::User->new(RT->SystemUser);
$u->Load("root");
ok ($u->Id, "Found the root user");
-ok(my $t = RT::Ticket->new($RT::SystemUser), 'Instantiate RT::Ticket');
+ok(my $t = RT::Ticket->new(RT->SystemUser), 'Instantiate RT::Ticket');
ok(my ($id, $msg) = $t->Create( Queue => $testqueue->Id,
Subject => 'Testing',
Owner => $u->Id
@@ -31,7 +31,7 @@ ok(my ($id, $msg) = $t->Create( Queue => $testqueue->Id,
isnt($id , 0, 'Success creating ticket');
# Add reminder
-my $due_obj = RT::Date->new( $RT::SystemUser );
+my $due_obj = RT::Date->new( RT->SystemUser );
$due_obj->SetToNow;
ok(my ( $add_id, $add_msg, $txnid ) = $t->Reminders->Add(
Subject => 'TestReminder',
@@ -85,4 +85,4 @@ while ( my $reminder = $reminders->Next ) {
is($r_resolved, 1, 'Reminder resolved');
}
-1;
+
diff --git a/rt/t/api/rights.t b/rt/t/api/rights.t
index a38bcea0c..a1795ca0a 100644
--- a/rt/t/api/rights.t
+++ b/rt/t/api/rights.t
@@ -47,14 +47,14 @@
#
# END BPS TAGGED BLOCK }}}
-use RT::Test tests => 30;
+use RT::Test nodata => 1, tests => 30;
use strict;
use warnings;
# clear all global right
{
- my $acl = RT::ACL->new($RT::SystemUser);
+ my $acl = RT::ACL->new(RT->SystemUser);
$acl->Limit( FIELD => 'RightName', OPERATOR => '!=', VALUE => 'SuperUser' );
$acl->LimitToObject( $RT::System );
while( my $ace = $acl->Next ) {
@@ -81,11 +81,11 @@ ok $user && $user->id, 'loaded or created user';
}
{
- my $group = RT::Group->new( $RT::SystemUser );
+ my $group = RT::Group->new( RT->SystemUser );
ok( $group->LoadQueueRoleGroup( Queue => $queue->id, Type=> 'Owner' ),
"load queue owners role group"
);
- my $ace = RT::ACE->new( $RT::SystemUser );
+ my $ace = RT::ACE->new( RT->SystemUser );
my ($ace_id, $msg) = $group->PrincipalObj->GrantRight(
Right => 'ReplyToTicket', Object => $queue
);
@@ -101,10 +101,10 @@ ok $user && $user->id, 'loaded or created user';
my $ticket;
{
# new ticket
- $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket = RT::Ticket->new(RT->SystemUser);
my ($ticket_id) = $ticket->Create( Queue => $queue->id, Subject => 'test');
ok( $ticket_id, 'new ticket created' );
- is( $ticket->Owner, $RT::Nobody->Id, 'owner of the new ticket is nobody' );
+ is( $ticket->Owner, RT->Nobody->Id, 'owner of the new ticket is nobody' );
ok( !$user->HasRight( Right => 'OwnTicket', Object => $ticket ),
"user can't reply to ticket"
@@ -136,11 +136,11 @@ my $ticket;
{
# Testing of EquivObjects
- my $group = RT::Group->new( $RT::SystemUser );
+ my $group = RT::Group->new( RT->SystemUser );
ok( $group->LoadQueueRoleGroup( Queue => $queue->id, Type=> 'AdminCc' ),
"load queue AdminCc role group"
);
- my $ace = RT::ACE->new( $RT::SystemUser );
+ my $ace = RT::ACE->new( RT->SystemUser );
my ($ace_id, $msg) = $group->PrincipalObj->GrantRight(
Right => 'ModifyTicket', Object => $queue
);
@@ -165,7 +165,7 @@ my $ticket;
my $ticket2;
{
- $ticket2 = RT::Ticket->new($RT::SystemUser);
+ $ticket2 = RT::Ticket->new(RT->SystemUser);
my ($id) = $ticket2->Create( Queue => $queue->id, Subject => 'test2');
ok( $id, 'new ticket created' );
ok( !$user->HasRight( Right => 'ModifyTicket', Object => $ticket2 ),
diff --git a/rt/t/api/rights_show_ticket.t b/rt/t/api/rights_show_ticket.t
index 3e1d0740f..62f62c422 100644
--- a/rt/t/api/rights_show_ticket.t
+++ b/rt/t/api/rights_show_ticket.t
@@ -1,6 +1,6 @@
#!/usr/bin/perl -w
-use RT::Test tests => 264;
+use RT::Test nodata => 1, tests => 264;
use strict;
use warnings;
@@ -228,7 +228,7 @@ sub create_tickets_set{
my @res;
foreach my $q ($queue_a, $queue_b) {
foreach my $n (1 .. 2) {
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ my $ticket = RT::Ticket->new( RT->SystemUser );
my ($tid) = $ticket->Create(
Queue => $q->id, Subject => $q->Name .' - '. $n
);
@@ -239,24 +239,8 @@ sub create_tickets_set{
return @res;
}
-sub cleanup { delete_tickets(); delete_watchers() };
-
-sub delete_tickets {
- my $tickets = RT::Tickets->new( $RT::SystemUser );
- $tickets->FromSQL( "Queue = $qa_id OR Queue = $qb_id" );
- while ( my $ticket = $tickets->Next ) {
- $ticket->Delete;
- }
-}
-
-sub delete_watchers {
- foreach my $q ($queue_a, $queue_b) {
- foreach my $u ($user_a, $user_b) {
- foreach my $t (qw(Cc AdminCc) ) {
- $q->DeleteWatcher( Type => $t, PrincipalId => $u->id )
- if $q->IsWatcher( Type => $t, PrincipalId => $u->id );
- }
- }
- }
-}
+sub cleanup {
+ RT::Test->delete_tickets( "Queue = $qa_id OR Queue = $qb_id" );
+ RT::Test->delete_queue_watchers( $queue_a, $queue_b );
+};
diff --git a/rt/t/api/rt.t b/rt/t/api/rt.t
index 3c06b5848..51c776250 100644
--- a/rt/t/api/rt.t
+++ b/rt/t/api/rt.t
@@ -2,17 +2,16 @@
use strict;
use warnings;
use RT;
-use RT::Test tests => 4;
+use RT::Test nodata => 1, tests => 4;
{
-is ($RT::Nobody->Name() , 'Nobody', "Nobody is nobody");
-isnt ($RT::Nobody->Name() , 'root', "Nobody isn't named root");
-is ($RT::SystemUser->Name() , 'RT_System', "The system user is RT_System");
-isnt ($RT::SystemUser->Name() , 'noname', "The system user isn't noname");
+is (RT->Nobody->Name() , 'Nobody', "Nobody is nobody");
+isnt (RT->Nobody->Name() , 'root', "Nobody isn't named root");
+is (RT->SystemUser->Name() , 'RT_System', "The system user is RT_System");
+isnt (RT->SystemUser->Name() , 'noname', "The system user isn't noname");
}
-1;
diff --git a/rt/t/api/rtname.t b/rt/t/api/rtname.t
new file mode 100644
index 000000000..ef6092bb2
--- /dev/null
+++ b/rt/t/api/rtname.t
@@ -0,0 +1,34 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use RT::Test nodata => 1, tests => 9;
+
+use RT::Interface::Email;
+
+# normal use case, regexp set to rtname
+RT->Config->Set( rtname => "site" );
+RT->Config->Set( EmailSubjectTagRegex => qr/site/ );
+RT->Config->Set( rtname => undef );
+is(RT::Interface::Email::ParseTicketId("[site #123] test"), 123);
+is(RT::Interface::Email::ParseTicketId("[othersite #123] test"), undef);
+
+# oops usecase, where the regexp is scragged
+RT->Config->Set( rtname => "site" );
+RT->Config->Set( EmailSubjectTagRegex => undef );
+is(RT::Interface::Email::ParseTicketId("[site #123] test"), 123);
+is(RT::Interface::Email::ParseTicketId("[othersite #123] test"), undef);
+
+# set to a simple regexp. NOTE: we no longer match "site"
+RT->Config->Set( rtname => "site");
+RT->Config->Set( EmailSubjectTagRegex => qr/newsite/);
+is(RT::Interface::Email::ParseTicketId("[site #123] test"), undef);
+is(RT::Interface::Email::ParseTicketId("[newsite #123] test"), 123);
+
+# set to a more complex regexp
+RT->Config->Set( rtname => "site" );
+RT->Config->Set( EmailSubjectTagRegex => qr/newsite|site/ );
+is(RT::Interface::Email::ParseTicketId("[site #123] test"), 123);
+is(RT::Interface::Email::ParseTicketId("[newsite #123] test"), 123);
+is(RT::Interface::Email::ParseTicketId("[othersite #123] test"), undef);
+
diff --git a/rt/t/api/safe-run-child-util.t b/rt/t/api/safe-run-child-util.t
new file mode 100644
index 000000000..b29e97177
--- /dev/null
+++ b/rt/t/api/safe-run-child-util.t
@@ -0,0 +1,201 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 35;
+use Test::Warn;
+
+use RT::Util qw(safe_run_child);
+use POSIX qw//;
+
+is_handle_ok();
+
+{
+ my $res = safe_run_child { return 1 };
+ is $res, 1, "correct return value";
+ is_handle_ok();
+}
+
+# test context
+{
+ my $context;
+ my $sub = sub {
+ if ( wantarray ) {
+ $context = 'array'; return 1, 2, 3;
+ } elsif ( defined wantarray ) {
+ $context = 'scalar'; return 'foo';
+ } elsif ( !wantarray ) {
+ $context = 'void'; return;
+ }
+ };
+ is_deeply [ safe_run_child { $sub->(@_) } ], [1, 2, 3];
+ is $context, 'array';
+ is_handle_ok();
+
+ is scalar safe_run_child {$sub->(@_)}, 'foo';
+ is $context, 'scalar';
+ is_handle_ok();
+
+ safe_run_child {$sub->(@_)};
+ is $context, 'void';
+ is_handle_ok();
+}
+
+# fork+child returns
+{
+ my $res = safe_run_child {
+ if (fork) { wait; return 'parent' }
+
+ open my $fh, '>', RT::Test->temp_directory .'/tttt';
+ print $fh "child";
+ close $fh;
+
+ return 'child';
+ };
+ is $res, 'parent', "correct return value";
+ is( RT::Test->file_content([RT::Test->temp_directory, 'tttt'], unlink => 1 ),
+ 'child',
+ 'correct file content',
+ );
+ is_handle_ok();
+}
+
+# fork+child dies
+{
+ warning_like {
+ my $res = safe_run_child {
+ if (fork) { wait; return 'parent' }
+
+ open my $fh, '>', RT::Test->temp_directory .'/tttt';
+ print $fh "child";
+ close $fh;
+
+ die 'child';
+ };
+ is $res, 'parent', "correct return value";
+ is( RT::Test->file_content([RT::Test->temp_directory, 'tttt'], unlink => 1 ),
+ 'child',
+ 'correct file content',
+ );
+ } qr/System Error: child/;
+ is_handle_ok();
+}
+
+# fork+child exits
+{
+ my $res = safe_run_child {
+ if (fork) { wait; return 'parent' }
+
+ open my $fh, '>', RT::Test->temp_directory .'/tttt';
+ print $fh "child";
+ close $fh;
+
+ exit 0;
+ };
+ is $res, 'parent', "correct return value";
+ is( RT::Test->file_content([RT::Test->temp_directory, 'tttt'], unlink => 1 ),
+ 'child',
+ 'correct file content',
+ );
+ is_handle_ok();
+}
+
+# parent dies
+{
+ my $res = eval { safe_run_child { die 'parent'; } };
+ is $res, undef, "correct return value";
+ like $@, qr'System Error: parent', "correct error message value";
+ is_handle_ok();
+}
+
+# fork+exec
+{
+ my $script = RT::Test->temp_directory .'/true.pl';
+ open my $fh, '>', $script;
+ print $fh <<END;
+#!$^X
+
+open my \$fh, '>', '$script.res';
+print \$fh "child";
+close \$fh;
+
+exit 0;
+END
+ close $fh;
+ chmod 0777, $script;
+
+ my $res = safe_run_child {
+ if (fork) { wait; return 'parent' }
+ exec $script;
+ };
+ is $res, 'parent', "correct return value";
+ is( RT::Test->file_content([$script .'.res'], unlink => 1 ),
+ 'child',
+ 'correct file content',
+ );
+ is_handle_ok();
+}
+
+# fork+parent that doesn't wait()
+{
+ require Time::HiRes;
+ my $start = Time::HiRes::time();
+ my $pid;
+
+ # Set up a poor man's semaphore
+ my $all_set = 0;
+ $SIG{USR1} = sub {$all_set++};
+
+ my $res = safe_run_child {
+ if ($pid = fork) { return 'parent' }
+
+ open my $fh, '>', RT::Test->temp_directory .'/first';
+ print $fh "child";
+ close $fh;
+ # Signal that the first file is now all set; we need to do this
+ # to avoid a race condition
+ kill POSIX::SIGUSR1(), getppid();
+
+ sleep 5;
+
+ open $fh, '>', RT::Test->temp_directory .'/second';
+ print $fh "child";
+ close $fh;
+
+ exit 0;
+ };
+ ok( Time::HiRes::time() - $start < 5, "Didn't wait until child finished" );
+
+ # Wait for up to 3 seconds to get signaled that the child has made
+ # the file (the USR1 will break out of the sleep()). This _should_
+ # be immediate, but there's a race between the parent and child
+ # here, since there's no wait()'ing. There's still a tiny race
+ # where the signal could come in betwene the $all_set check and the
+ # sleep, but that just means we sleep for 3 seconds uselessly.
+ sleep 3 unless $all_set;
+
+ is $res, 'parent', "correct return value";
+ is( RT::Test->file_content([RT::Test->temp_directory, 'first'], unlink => 1 ),
+ 'child',
+ 'correct file content',
+ );
+ ok( not(-f RT::Test->temp_directory.'/second'), "Second file does not exist yet");
+ is_handle_ok();
+
+ ok(waitpid($pid,0), "Waited until child finished to reap");
+ is( RT::Test->file_content([RT::Test->temp_directory, 'second'], unlink => 1 ),
+ 'child',
+ 'correct file content',
+ );
+ is_handle_ok();
+}
+
+sub is_handle_ok {
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+ my $test = $RT::Handle->dbh->selectall_arrayref(
+ "SELECT id FROM Users WHERE Name = 'Nobody'"
+ );
+ ok $test && $test->[0][0], "selected, DB is there";
+}
+
diff --git a/rt/t/api/savedsearch.t b/rt/t/api/savedsearch.t
new file mode 100644
index 000000000..0aa67eeda
--- /dev/null
+++ b/rt/t/api/savedsearch.t
@@ -0,0 +1,181 @@
+use strict;
+use warnings;
+BEGIN { $ENV{'LANG'} = 'C' }
+
+use RT::Test tests => 27;
+
+use_ok('RT::SavedSearch');
+use_ok('RT::SavedSearches');
+
+use Test::Warn;
+
+# Set up some infrastructure. These calls are tested elsewhere.
+
+my $searchuser = RT::User->new(RT->SystemUser);
+my ($ret, $msg) = $searchuser->Create(Name => 'searchuser'.$$,
+ Privileged => 1,
+ EmailAddress => "searchuser\@p$$.example.com",
+ RealName => 'Search user');
+ok($ret, "created searchuser: $msg");
+$searchuser->PrincipalObj->GrantRight(Right => 'LoadSavedSearch');
+$searchuser->PrincipalObj->GrantRight(Right => 'CreateSavedSearch');
+$searchuser->PrincipalObj->GrantRight(Right => 'ModifySelf');
+
+# This is the group whose searches searchuser should be able to see.
+my $ingroup = RT::Group->new(RT->SystemUser);
+$ingroup->CreateUserDefinedGroup(Name => 'searchgroup1'.$$);
+$ingroup->AddMember($searchuser->Id);
+$searchuser->PrincipalObj->GrantRight(Right => 'EditSavedSearches',
+ Object => $ingroup);
+$searchuser->PrincipalObj->GrantRight(Right => 'ShowSavedSearches',
+ Object => $ingroup);
+
+# This is the group whose searches searchuser should not be able to see.
+my $outgroup = RT::Group->new(RT->SystemUser);
+$outgroup->CreateUserDefinedGroup(Name => 'searchgroup2'.$$);
+$outgroup->AddMember(RT->SystemUser->Id);
+
+my $queue = RT::Queue->new(RT->SystemUser);
+$queue->Create(Name => 'SearchQueue'.$$);
+$searchuser->PrincipalObj->GrantRight(Right => 'SeeQueue', Object => $queue);
+$searchuser->PrincipalObj->GrantRight(Right => 'ShowTicket', Object => $queue);
+$searchuser->PrincipalObj->GrantRight(Right => 'OwnTicket', Object => $queue);
+
+
+my $ticket = RT::Ticket->new(RT->SystemUser);
+$ticket->Create(Queue => $queue->Id,
+ Requestor => [ $searchuser->Name ],
+ Owner => $searchuser,
+ Subject => 'saved search test');
+
+
+# Now start the search madness.
+my $curruser = RT::CurrentUser->new($searchuser);
+my $format = '\' <b><a href="/Ticket/Display.html?id=__id__">__id__</a></b>/TITLE:#\',
+\'<b><a href="/Ticket/Display.html?id=__id__">__Subject__</a></b>/TITLE:Subject\',
+\'__Status__\',
+\'__QueueName__\',
+\'__OwnerName__\',
+\'__Priority__\',
+\'__NEWLINE__\',
+\'\',
+\'<small>__Requestors__</small>\',
+\'<small>__CreatedRelative__</small>\',
+\'<small>__ToldRelative__</small>\',
+\'<small>__LastUpdatedRelative__</small>\',
+\'<small>__TimeLeft__</small>\'';
+
+my $mysearch = RT::SavedSearch->new($curruser);
+($ret, $msg) = $mysearch->Save(Privacy => 'RT::User-' . $searchuser->Id,
+ Type => 'Ticket',
+ Name => 'owned by me',
+ SearchParams => {'Format' => $format,
+ 'Query' => "Owner = '"
+ . $searchuser->Name
+ . "'"});
+ok($ret, "mysearch was created");
+
+
+my $groupsearch = RT::SavedSearch->new($curruser);
+($ret, $msg) = $groupsearch->Save(Privacy => 'RT::Group-' . $ingroup->Id,
+ Type => 'Ticket',
+ Name => 'search queue',
+ SearchParams => {'Format' => $format,
+ 'Query' => "Queue = '"
+ . $queue->Name . "'"});
+ok($ret, "groupsearch was created");
+
+my $othersearch = RT::SavedSearch->new($curruser);
+($ret, $msg) = $othersearch->Save(Privacy => 'RT::Group-' . $outgroup->Id,
+ Type => 'Ticket',
+ Name => 'searchuser requested',
+ SearchParams => {'Format' => $format,
+ 'Query' =>
+ "Requestor.Name LIKE 'search'"});
+ok(!$ret, "othersearch NOT created");
+like($msg, qr/Failed to load object for/, "...for the right reason");
+
+$othersearch = RT::SavedSearch->new(RT->SystemUser);
+($ret, $msg) = $othersearch->Save(Privacy => 'RT::Group-' . $outgroup->Id,
+ Type => 'Ticket',
+ Name => 'searchuser requested',
+ SearchParams => {'Format' => $format,
+ 'Query' =>
+ "Requestor.Name LIKE 'search'"});
+ok($ret, "othersearch created by systemuser");
+
+# Now try to load some searches.
+
+# This should work.
+my $loadedsearch1 = RT::SavedSearch->new($curruser);
+$loadedsearch1->Load('RT::User-'.$curruser->Id, $mysearch->Id);
+is($loadedsearch1->Id, $mysearch->Id, "Loaded mysearch");
+like($loadedsearch1->GetParameter('Query'), qr/Owner/,
+ "Retrieved query of mysearch");
+# Check through the other accessor methods.
+is($loadedsearch1->Privacy, 'RT::User-' . $curruser->Id,
+ "Privacy of mysearch correct");
+is($loadedsearch1->Name, 'owned by me', "Name of mysearch correct");
+is($loadedsearch1->Type, 'Ticket', "Type of mysearch correct");
+
+# See if it can be used to search for tickets.
+my $tickets = RT::Tickets->new($curruser);
+$tickets->FromSQL($loadedsearch1->GetParameter('Query'));
+is($tickets->Count, 1, "Found a ticket");
+
+# This should fail -- wrong object.
+# my $loadedsearch2 = RT::SavedSearch->new($curruser);
+# $loadedsearch2->Load('RT::User-'.$curruser->Id, $groupsearch->Id);
+# isnt($loadedsearch2->Id, $othersearch->Id, "Didn't load groupsearch as mine");
+# ...but this should succeed.
+my $loadedsearch3 = RT::SavedSearch->new($curruser);
+$loadedsearch3->Load('RT::Group-'.$ingroup->Id, $groupsearch->Id);
+is($loadedsearch3->Id, $groupsearch->Id, "Loaded groupsearch");
+like($loadedsearch3->GetParameter('Query'), qr/Queue/,
+ "Retrieved query of groupsearch");
+# Can it get tickets?
+$tickets = RT::Tickets->new($curruser);
+$tickets->FromSQL($loadedsearch3->GetParameter('Query'));
+is($tickets->Count, 1, "Found a ticket");
+
+# This should fail -- no permission.
+my $loadedsearch4 = RT::SavedSearch->new($curruser);
+
+warning_like {
+ $loadedsearch4->Load($othersearch->Privacy, $othersearch->Id);
+} qr/Could not load object RT::Group-\d+ when loading search/;
+
+isnt($loadedsearch4->Id, $othersearch->Id, "Did not load othersearch");
+
+# Try to update an existing search.
+$loadedsearch1->Update( SearchParams => {'Format' => $format,
+ 'Query' => "Queue = '" . $queue->Name . "'" } );
+like($loadedsearch1->GetParameter('Query'), qr/Queue/,
+ "Updated mysearch parameter");
+is($loadedsearch1->Type, 'Ticket', "mysearch is still for tickets");
+is($loadedsearch1->Privacy, 'RT::User-'.$curruser->Id,
+ "mysearch still belongs to searchuser");
+like($mysearch->GetParameter('Query'), qr/Queue/, "other mysearch object updated");
+
+
+## Right ho. Test the pseudo-collection object.
+
+my $genericsearch = RT::SavedSearch->new($curruser);
+$genericsearch->Save(Name => 'generic search',
+ Type => 'all',
+ SearchParams => {'Query' => "Queue = 'General'"});
+
+my $ticketsearches = RT::SavedSearches->new($curruser);
+$ticketsearches->LimitToPrivacy('RT::User-'.$curruser->Id, 'Ticket');
+is($ticketsearches->Count, 1, "Found searchuser's ticket searches");
+
+my $allsearches = RT::SavedSearches->new($curruser);
+$allsearches->LimitToPrivacy('RT::User-'.$curruser->Id);
+is($allsearches->Count, 2, "Found all searchuser's searches");
+
+# Delete a search.
+($ret, $msg) = $genericsearch->Delete;
+ok($ret, "Deleted genericsearch");
+$allsearches->LimitToPrivacy('RT::User-'.$curruser->Id);
+is($allsearches->Count, 1, "Found all searchuser's searches after deletion");
+
diff --git a/rt/t/api/scrip.t b/rt/t/api/scrip.t
index 9d97e7344..eb543476b 100644
--- a/rt/t/api/scrip.t
+++ b/rt/t/api/scrip.t
@@ -10,11 +10,11 @@ use RT::Test tests => 25;
ok (require RT::Scrip);
-my $q = RT::Queue->new($RT::SystemUser);
+my $q = RT::Queue->new(RT->SystemUser);
$q->Create(Name => 'ScripTest');
ok($q->Id, "Created a scriptest queue");
-my $s1 = RT::Scrip->new($RT::SystemUser);
+my $s1 = RT::Scrip->new(RT->SystemUser);
my ($val, $msg) =$s1->Create( Queue => $q->Id,
ScripAction => 'User Defined',
ScripCondition => 'User Defined',
@@ -25,7 +25,7 @@ my ($val, $msg) =$s1->Create( Queue => $q->Id,
);
ok($val,$msg);
-my $ticket = RT::Ticket->new($RT::SystemUser);
+my $ticket = RT::Ticket->new(RT->SystemUser);
my ($tv,$ttv,$tm) = $ticket->Create(Queue => $q->Id,
Subject => "hair on fire",
);
@@ -34,7 +34,7 @@ ok($tv, $tm);
is ($ticket->Priority , '87', "Ticket priority is set right");
-my $ticket2 = RT::Ticket->new($RT::SystemUser);
+my $ticket2 = RT::Ticket->new(RT->SystemUser);
my ($t2v,$t2tv,$t2m) = $ticket2->Create(Queue => $q->Id,
Subject => "hair in water",
);
@@ -117,5 +117,3 @@ isnt ($ticket2->Priority , '87', "Ticket priority is set right");
ok( $scrip->Delete, 'delete the scrip' );
}
-
-1;
diff --git a/rt/t/api/scrip_order.t b/rt/t/api/scrip_order.t
index 9738db9bc..22d3f21d1 100644
--- a/rt/t/api/scrip_order.t
+++ b/rt/t/api/scrip_order.t
@@ -6,14 +6,13 @@ use RT;
use RT::Test tests => 7;
-# {{{ test scrip ordering based on description
-my $scrip_queue = RT::Queue->new($RT::SystemUser);
+my $scrip_queue = RT::Queue->new(RT->SystemUser);
my ($queue_id, $msg) = $scrip_queue->Create( Name => "ScripOrdering-$$",
Description => 'Test scrip ordering by description' );
ok($queue_id, "Created scrip-ordering test queue? ".$msg);
-my $priority_ten_scrip = RT::Scrip->new($RT::SystemUser);
+my $priority_ten_scrip = RT::Scrip->new(RT->SystemUser);
(my $id, $msg) = $priority_ten_scrip->Create(
Description => "10 set priority $$",
Queue => $queue_id,
@@ -26,7 +25,7 @@ my $priority_ten_scrip = RT::Scrip->new($RT::SystemUser);
);
ok($id, "Created priority-10 scrip? ".$msg);
-my $priority_five_scrip = RT::Scrip->new($RT::SystemUser);
+my $priority_five_scrip = RT::Scrip->new(RT->SystemUser);
($id, $msg) = $priority_ten_scrip->Create(
Description => "05 set priority $$",
Queue => $queue_id,
@@ -39,7 +38,7 @@ my $priority_five_scrip = RT::Scrip->new($RT::SystemUser);
);
ok($id, "Created priority-5 scrip? ".$msg);
-my $ticket = RT::Ticket->new($RT::SystemUser);
+my $ticket = RT::Ticket->new(RT->SystemUser);
($id, $msg) = $ticket->Create(
Queue => $queue_id,
Requestor => 'order@example.com',
@@ -51,6 +50,4 @@ isnt($ticket->Priority , 0, "Ticket shouldn't be priority 0");
isnt($ticket->Priority , 5, "Ticket shouldn't be priority 5");
is ($ticket->Priority , 10, "Ticket should be priority 10");
-# }}}
-1;
diff --git a/rt/t/api/searchbuilder.t b/rt/t/api/searchbuilder.t
index cb118906c..8562bfc2b 100644
--- a/rt/t/api/searchbuilder.t
+++ b/rt/t/api/searchbuilder.t
@@ -15,7 +15,7 @@ ok (require RT::SearchBuilder);
{
use_ok('RT::Queues');
-ok(my $queues = RT::Queues->new($RT::SystemUser), 'Created a queues object');
+ok(my $queues = RT::Queues->new(RT->SystemUser), 'Created a queues object');
ok( $queues->UnLimit(),'Unlimited the result set of the queues object');
my $items = $queues->ItemsArrayRef();
my @items = @{$items};
@@ -37,4 +37,3 @@ is_deeply(\@items_ids, \@sorted_ids, "ItemsArrayRef sorts alphabetically by name
}
-1;
diff --git a/rt/t/api/squish.t b/rt/t/api/squish.t
new file mode 100644
index 000000000..59615368f
--- /dev/null
+++ b/rt/t/api/squish.t
@@ -0,0 +1,16 @@
+use strict;
+use warnings;
+use RT;
+use RT::Test nodb => 1, tests => 7;
+
+use RT::Squish;
+
+my $squish = RT::Squish->new();
+for my $method ( qw/Content ModifiedTime ModifiedTimeString Key/ ) {
+ can_ok($squish, $method);
+}
+like( $squish->Key, qr/[a-f0-9]{32}/, 'Key is like md5' );
+ok( (time()-$squish->ModifiedTime) <= 2, 'ModifiedTime' );
+
+use RT::Squish::CSS;
+can_ok('RT::Squish::CSS', 'Style');
diff --git a/rt/t/api/system.t b/rt/t/api/system.t
index 3077115c7..f1100d332 100644
--- a/rt/t/api/system.t
+++ b/rt/t/api/system.t
@@ -2,12 +2,12 @@
use strict;
use warnings;
use RT;
-use RT::Test tests => 7;
+use RT::Test nodata => 1, tests => 7;
{
-my $s = RT::System->new($RT::SystemUser);
+my $s = RT::System->new(RT->SystemUser);
my $rights = $s->AvailableRights;
ok ($rights, "Rights defined");
ok ($rights->{'AdminUsers'},"AdminUsers right found");
@@ -30,4 +30,3 @@ is ($sys->id, 1);
}
-1;
diff --git a/rt/t/api/template-insert.t b/rt/t/api/template-insert.t
index 47bbd790c..1bf5fc390 100644
--- a/rt/t/api/template-insert.t
+++ b/rt/t/api/template-insert.t
@@ -12,7 +12,7 @@ use RT::Test tests => 7;
# This tiny little test script triggers an interaction bug between DBD::Oracle 1.16, SB 1.15 and RT 3.4
use_ok('RT::Template');
-my $template = RT::Template->new($RT::SystemUser);
+my $template = RT::Template->new(RT->SystemUser);
isa_ok($template, 'RT::Template');
my ($val,$msg) = $template->Create(Queue => 1,
diff --git a/rt/t/api/template-simple.t b/rt/t/api/template-simple.t
new file mode 100644
index 000000000..bbdebb31f
--- /dev/null
+++ b/rt/t/api/template-simple.t
@@ -0,0 +1,275 @@
+use strict;
+use warnings;
+use RT;
+use RT::Test tests => 231;
+use Test::Warn;
+
+my $queue = RT::Queue->new(RT->SystemUser);
+$queue->Load("General");
+
+my $ticket_cf = RT::CustomField->new(RT->SystemUser);
+$ticket_cf->Create(
+ Name => 'Department',
+ Queue => '0',
+ Type => 'FreeformSingle',
+);
+
+my $txn_cf = RT::CustomField->new(RT->SystemUser);
+$txn_cf->Create(
+ Name => 'Category',
+ LookupType => RT::Transaction->CustomFieldLookupType,
+ Type => 'FreeformSingle',
+);
+$txn_cf->AddToObject($queue);
+
+my $ticket = RT::Ticket->new(RT->SystemUser);
+my ($id, $msg) = $ticket->Create(
+ Subject => "template testing",
+ Queue => "General",
+ Owner => 'root@localhost',
+ Requestor => ["dom\@example.com"],
+ "CustomField-" . $txn_cf->id => "Special",
+);
+ok($id, "Created ticket: $msg");
+my $txn = $ticket->Transactions->First;
+
+$ticket->AddCustomFieldValue(
+ Field => 'Department',
+ Value => 'Coolio',
+);
+
+TemplateTest(
+ Content => "\ntest",
+ PerlOutput => "test",
+ SimpleOutput => "test",
+);
+
+TemplateTest(
+ Content => "\ntest { 5 * 5 }",
+ PerlOutput => "test 25",
+ SimpleOutput => "test { 5 * 5 }",
+);
+
+TemplateTest(
+ Content => "\ntest { \$Requestor }",
+ PerlOutput => "test dom\@example.com",
+ SimpleOutput => "test dom\@example.com",
+);
+
+TemplateTest(
+ Content => "\ntest { \$TicketSubject }",
+ PerlOutput => "test ",
+ SimpleOutput => "test template testing",
+);
+
+SimpleTemplateTest(
+ Content => "\ntest { \$TicketQueueId }",
+ Output => "test 1",
+);
+
+SimpleTemplateTest(
+ Content => "\ntest { \$TicketQueueName }",
+ Output => "test General",
+);
+
+SimpleTemplateTest(
+ Content => "\ntest { \$TicketOwnerId }",
+ Output => "test 12",
+);
+
+SimpleTemplateTest(
+ Content => "\ntest { \$TicketOwnerName }",
+ Output => "test root",
+);
+
+SimpleTemplateTest(
+ Content => "\ntest { \$TicketOwnerEmailAddress }",
+ Output => "test root\@localhost",
+);
+
+SimpleTemplateTest(
+ Content => "\ntest { \$TicketStatus }",
+ Output => "test new",
+);
+
+SimpleTemplateTest(
+ Content => "\ntest #{ \$TicketId }",
+ Output => "test #" . $ticket->id,
+);
+
+SimpleTemplateTest(
+ Content => "\ntest { \$TicketCFDepartment }",
+ Output => "test Coolio",
+);
+
+SimpleTemplateTest(
+ Content => "\ntest #{ \$TransactionId }",
+ Output => "test #" . $txn->id,
+);
+
+SimpleTemplateTest(
+ Content => "\ntest { \$TransactionType }",
+ Output => "test Create",
+);
+
+SimpleTemplateTest(
+ Content => "\ntest { \$TransactionCFCategory }",
+ Output => "test Special",
+);
+
+SimpleTemplateTest(
+ Content => "\ntest { \$TicketDelete }",
+ Output => "test { \$TicketDelete }",
+);
+
+SimpleTemplateTest(
+ Content => "\ntest { \$Nonexistent }",
+ Output => "test { \$Nonexistent }",
+);
+
+warning_like {
+ TemplateTest(
+ Content => "\ntest { \$Ticket->Nonexistent }",
+ PerlOutput => undef,
+ SimpleOutput => "test { \$Ticket->Nonexistent }",
+ );
+} qr/RT::Ticket::Nonexistent Unimplemented/;
+
+warning_like {
+ TemplateTest(
+ Content => "\ntest { \$Nonexistent->Nonexistent }",
+ PerlOutput => undef,
+ SimpleOutput => "test { \$Nonexistent->Nonexistent }",
+ );
+} qr/Can't call method "Nonexistent" on an undefined value/;
+
+TemplateTest(
+ Content => "\ntest { \$Ticket->OwnerObj->Name }",
+ PerlOutput => "test root",
+ SimpleOutput => "test { \$Ticket->OwnerObj->Name }",
+);
+
+warning_like {
+ TemplateTest(
+ Content => "\ntest { *!( }",
+ SyntaxError => 1,
+ PerlOutput => undef,
+ SimpleOutput => "test { *!( }",
+ );
+} qr/Template parsing error: syntax error/;
+
+TemplateTest(
+ Content => "\ntest { \$rtname ",
+ SyntaxError => 1,
+ PerlOutput => undef,
+ SimpleOutput => undef,
+);
+
+is($ticket->Status, 'new', "test setup");
+SimpleTemplateTest(
+ Content => "\ntest { \$Ticket->SetStatus('resolved') }",
+ Output => "test { \$Ticket->SetStatus('resolved') }",
+);
+is($ticket->Status, 'new', "simple templates can't call ->SetStatus");
+
+# Make sure changing the template's type works
+my $template = RT::Template->new(RT->SystemUser);
+$template->Create(
+ Name => "type chameleon",
+ Type => "Perl",
+ Content => "\ntest { 10 * 7 }",
+);
+ok($id = $template->id, "Created template");
+$template->Parse;
+is($template->MIMEObj->stringify_body, "test 70", "Perl output");
+
+$template = RT::Template->new(RT->SystemUser);
+$template->Load($id);
+is($template->Name, "type chameleon");
+
+$template->SetType('Simple');
+$template->Parse;
+is($template->MIMEObj->stringify_body, "test { 10 * 7 }", "Simple output");
+
+$template = RT::Template->new(RT->SystemUser);
+$template->Load($id);
+is($template->Name, "type chameleon");
+
+$template->SetType('Perl');
+$template->Parse;
+is($template->MIMEObj->stringify_body, "test 70", "Perl output");
+
+undef $ticket;
+
+my $counter = 0;
+sub IndividualTemplateTest {
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+
+ my %args = (
+ Name => "Test-" . ++$counter,
+ Type => "Perl",
+ @_,
+ );
+
+ my $t = RT::Template->new(RT->SystemUser);
+ $t->Create(
+ Name => $args{Name},
+ Type => $args{Type},
+ Content => $args{Content},
+ );
+
+ ok($t->id, "Created $args{Type} template");
+ is($t->Name, $args{Name}, "$args{Type} template name");
+ is($t->Content, $args{Content}, "$args{Type} content");
+ is($t->Type, $args{Type}, "template type");
+
+ # this should never blow up!
+ my ($ok, $msg) = $t->CompileCheck;
+
+ # we don't need to syntax check simple templates since if you mess them up
+ # it's safe to just use the input directly as the template's output
+ if ($args{SyntaxError} && $args{Type} eq 'Perl') {
+ ok(!$ok, "got a syntax error");
+ }
+ else {
+ ok($ok, $msg);
+ }
+
+ ($ok, $msg) = $t->Parse(
+ TicketObj => $ticket,
+ TransactionObj => $txn,
+ );
+ if (defined $args{Output}) {
+ ok($ok, $msg);
+ is($t->MIMEObj->stringify_body, $args{Output}, "$args{Type} template's output");
+ }
+ else {
+ ok(!$ok, "expected a failure");
+ }
+}
+
+sub TemplateTest {
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+ my %args = @_;
+
+ for my $type ('Perl', 'Simple') {
+ next if $args{"Skip$type"};
+
+ IndividualTemplateTest(
+ %args,
+ Type => $type,
+ Output => $args{$type . 'Output'},
+ );
+ }
+}
+
+sub SimpleTemplateTest {
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+ my %args = @_;
+
+ IndividualTemplateTest(
+ %args,
+ Type => 'Simple',
+ );
+}
+
diff --git a/rt/t/api/template.t b/rt/t/api/template.t
index 1612b8ffd..2fadede38 100644
--- a/rt/t/api/template.t
+++ b/rt/t/api/template.t
@@ -14,13 +14,12 @@ ok(require RT::Template);
{
-my $t = RT::Template->new($RT::SystemUser);
+my $t = RT::Template->new(RT->SystemUser);
$t->Create(Name => "Foo", Queue => 1);
-my $t2 = RT::Template->new($RT::Nobody);
+my $t2 = RT::Template->new(RT->Nobody);
$t2->Load($t->Id);
ok($t2->QueueObj->id, "Got the template's queue objet");
}
-1;
diff --git a/rt/t/api/ticket.t b/rt/t/api/ticket.t
index 2ca0997bd..92c8a85df 100644
--- a/rt/t/api/ticket.t
+++ b/rt/t/api/ticket.t
@@ -8,11 +8,11 @@ use RT::Test tests => 87;
{
use_ok ('RT::Queue');
-ok(my $testqueue = RT::Queue->new($RT::SystemUser));
+ok(my $testqueue = RT::Queue->new(RT->SystemUser));
ok($testqueue->Create( Name => 'ticket tests'));
isnt($testqueue->Id , 0);
use_ok('RT::CustomField');
-ok(my $testcf = RT::CustomField->new($RT::SystemUser));
+ok(my $testcf = RT::CustomField->new(RT->SystemUser));
my ($ret, $cmsg) = $testcf->Create( Name => 'selectmulti',
Queue => $testqueue->id,
Type => 'SelectMultiple');
@@ -34,10 +34,10 @@ is($testcf->Values->Count , 3);
use_ok('RT::Ticket');
-my $u = RT::User->new($RT::SystemUser);
+my $u = RT::User->new(RT->SystemUser);
$u->Load("root");
ok ($u->Id, "Found the root user");
-ok(my $t = RT::Ticket->new($RT::SystemUser));
+ok(my $t = RT::Ticket->new(RT->SystemUser));
ok(my ($id, $msg) = $t->Create( Queue => $testqueue->Id,
Subject => 'Testing',
Owner => $u->Id
@@ -56,13 +56,13 @@ ok(my ($cfdv, $cfdm) = $t->DeleteCustomFieldValue(Field => $testcf->Id,
isnt ($cfdv , 0, "Deleted a custom field value: $cfdm");
is($t->CustomFieldValues($testcf->Id)->Count , 0);
-ok(my $t2 = RT::Ticket->new($RT::SystemUser));
+ok(my $t2 = RT::Ticket->new(RT->SystemUser));
ok($t2->Load($id));
is($t2->Subject, 'Testing');
is($t2->QueueObj->Id, $testqueue->id);
is($t2->OwnerObj->Id, $u->Id);
-my $t3 = RT::Ticket->new($RT::SystemUser);
+my $t3 = RT::Ticket->new(RT->SystemUser);
my ($id3, $msg3) = $t3->Create( Queue => $testqueue->Id,
Subject => 'Testing',
Owner => $u->Id);
@@ -93,7 +93,7 @@ ok(require RT::Ticket, "Loading the RT::Ticket library");
{
-my $t = RT::Ticket->new($RT::SystemUser);
+my $t = RT::Ticket->new(RT->SystemUser);
ok( $t->Create(Queue => 'General', Due => '2002-05-21 00:00:00', ReferredToBy => 'http://www.cpan.org', RefersTo => 'http://fsck.com', Subject => 'This is a subject'), "Ticket Created");
@@ -107,19 +107,19 @@ is ($t->ResolvedObj->Unix, 0, "It hasn't been resolved - ". $t->ResolvedObj->Uni
{
-my $ticket = RT::Ticket->new($RT::SystemUser);
+my $ticket = RT::Ticket->new(RT->SystemUser);
my ($id, $msg) = $ticket->Create(Subject => "Foo",
- Owner => $RT::SystemUser->Id,
+ Owner => RT->SystemUser->Id,
Status => 'open',
Requestor => ['jesse@example.com'],
Queue => '1'
);
ok ($id, "Ticket $id was created");
-ok(my $group = RT::Group->new($RT::SystemUser));
+ok(my $group = RT::Group->new(RT->SystemUser));
ok($group->LoadTicketRoleGroup(Ticket => $id, Type=> 'Requestor'));
ok ($group->Id, "Found the requestors object for this ticket");
-ok(my $jesse = RT::User->new($RT::SystemUser), "Creating a jesse rt::user");
+ok(my $jesse = RT::User->new(RT->SystemUser), "Creating a jesse rt::user");
$jesse->LoadByEmail('jesse@example.com');
ok($jesse->Id, "Found the jesse rt user");
@@ -127,7 +127,7 @@ ok($jesse->Id, "Found the jesse rt user");
ok ($ticket->IsWatcher(Type => 'Requestor', PrincipalId => $jesse->PrincipalId), "The ticket actually has jesse at fsck.com as a requestor");
ok (my ($add_id, $add_msg) = $ticket->AddWatcher(Type => 'Requestor', Email => 'bob@fsck.com'), "Added bob at fsck.com as a requestor");
ok ($add_id, "Add succeeded: ($add_msg)");
-ok(my $bob = RT::User->new($RT::SystemUser), "Creating a bob rt::user");
+ok(my $bob = RT::User->new(RT->SystemUser), "Creating a bob rt::user");
$bob->LoadByEmail('bob@fsck.com');
ok($bob->Id, "Found the bob rt user");
ok ($ticket->IsWatcher(Type => 'Requestor', PrincipalId => $bob->PrincipalId), "The ticket actually has bob at fsck.com as a requestor");
@@ -135,23 +135,23 @@ ok ( ($add_id, $add_msg) = $ticket->DeleteWatcher(Type =>'Requestor', Email => '
ok (!$ticket->IsWatcher(Type => 'Requestor', PrincipalId => $bob->PrincipalId), "The ticket no longer has bob at fsck.com as a requestor");
-$group = RT::Group->new($RT::SystemUser);
+$group = RT::Group->new(RT->SystemUser);
ok($group->LoadTicketRoleGroup(Ticket => $id, Type=> 'Cc'));
ok ($group->Id, "Found the cc object for this ticket");
-$group = RT::Group->new($RT::SystemUser);
+$group = RT::Group->new(RT->SystemUser);
ok($group->LoadTicketRoleGroup(Ticket => $id, Type=> 'AdminCc'));
ok ($group->Id, "Found the AdminCc object for this ticket");
-$group = RT::Group->new($RT::SystemUser);
+$group = RT::Group->new(RT->SystemUser);
ok($group->LoadTicketRoleGroup(Ticket => $id, Type=> 'Owner'));
ok ($group->Id, "Found the Owner object for this ticket");
-ok($group->HasMember($RT::SystemUser->UserObj->PrincipalObj), "the owner group has the member 'RT_System'");
+ok($group->HasMember(RT->SystemUser->UserObj->PrincipalObj), "the owner group has the member 'RT_System'");
}
{
-my $t = RT::Ticket->new($RT::SystemUser);
+my $t = RT::Ticket->new(RT->SystemUser);
ok($t->Create(Queue => 'general', Subject => 'SquelchTest', SquelchMailTo => 'nobody@example.com'));
my @returned = $t->SquelchMailTo();
@@ -189,15 +189,15 @@ is($#returned, -1, "The ticket has no squelched recipients". join(',',@returned)
{
-my $t1 = RT::Ticket->new($RT::SystemUser);
+my $t1 = RT::Ticket->new(RT->SystemUser);
$t1->Create ( Subject => 'Merge test 1', Queue => 'general', Requestor => 'merge1@example.com');
my $t1id = $t1->id;
-my $t2 = RT::Ticket->new($RT::SystemUser);
+my $t2 = RT::Ticket->new(RT->SystemUser);
$t2->Create ( Subject => 'Merge test 2', Queue => 'general', Requestor => 'merge2@example.com');
my $t2id = $t2->id;
my ($msg, $val) = $t1->MergeInto($t2->id);
ok ($msg,$val);
-$t1 = RT::Ticket->new($RT::SystemUser);
+$t1 = RT::Ticket->new(RT->SystemUser);
is ($t1->id, undef, "ok. we've got a blank ticket1");
$t1->Load($t1id);
@@ -211,16 +211,16 @@ is ($t1->Requestors->MembersObj->Count, 2);
{
-my $root = RT::User->new($RT::SystemUser);
+my $root = RT::User->new(RT->SystemUser);
$root->Load('root');
ok ($root->Id, "Loaded the root user");
-my $t = RT::Ticket->new($RT::SystemUser);
+my $t = RT::Ticket->new(RT->SystemUser);
$t->Load(1);
$t->SetOwner('root');
is ($t->OwnerObj->Name, 'root' , "Root owns the ticket");
$t->Steal();
-is ($t->OwnerObj->id, $RT::SystemUser->id , "SystemUser owns the ticket");
-my $txns = RT::Transactions->new($RT::SystemUser);
+is ($t->OwnerObj->id, RT->SystemUser->id , "SystemUser owns the ticket");
+my $txns = RT::Transactions->new(RT->SystemUser);
$txns->OrderBy(FIELD => 'id', ORDER => 'DESC');
$txns->Limit(FIELD => 'ObjectId', VALUE => '1');
$txns->Limit(FIELD => 'ObjectType', VALUE => 'RT::Ticket');
@@ -228,14 +228,14 @@ $txns->Limit(FIELD => 'Type', OPERATOR => '!=', VALUE => 'EmailRecord');
my $steal = $txns->First;
is($steal->OldValue , $root->Id , "Stolen from root");
-is($steal->NewValue , $RT::SystemUser->Id , "Stolen by the systemuser");
+is($steal->NewValue , RT->SystemUser->Id , "Stolen by the systemuser");
}
{
-my $tt = RT::Ticket->new($RT::SystemUser);
+my $tt = RT::Ticket->new(RT->SystemUser);
my ($id, $tid, $msg)= $tt->Create(Queue => 'general',
Subject => 'test');
ok($id, $msg);
@@ -254,4 +254,3 @@ ok(!$id,$msg);
}
-1;
diff --git a/rt/t/api/tickets.t b/rt/t/api/tickets.t
index 9148a8899..cabb00e50 100644
--- a/rt/t/api/tickets.t
+++ b/rt/t/api/tickets.t
@@ -8,7 +8,7 @@ use RT::Test tests => 16;
{
ok (require RT::Tickets);
-ok( my $testtickets = RT::Tickets->new( $RT::SystemUser ) );
+ok( my $testtickets = RT::Tickets->new( RT->SystemUser ) );
ok( $testtickets->LimitStatus( VALUE => 'deleted' ) );
# Should be zero until 'allow_deleted_search'
is( $testtickets->Count , 0 );
@@ -22,45 +22,45 @@ is( $testtickets->Count , 0 );
# by requestor name.
my ($id,$msg);
-my $u1 = RT::User->new($RT::SystemUser);
+my $u1 = RT::User->new(RT->SystemUser);
($id, $msg) = $u1->Create( Name => 'RequestorTestOne', EmailAddress => 'rqtest1@example.com');
ok ($id,$msg);
-my $u2 = RT::User->new($RT::SystemUser);
+my $u2 = RT::User->new(RT->SystemUser);
($id, $msg) = $u2->Create( Name => 'RequestorTestTwo', EmailAddress => 'rqtest2@example.com');
ok ($id,$msg);
-my $t1 = RT::Ticket->new($RT::SystemUser);
+my $t1 = RT::Ticket->new(RT->SystemUser);
my ($trans);
($id,$trans,$msg) =$t1->Create (Queue => 'general', Subject => 'Requestor test one', Requestor => [$u1->EmailAddress]);
ok ($id, $msg);
-my $t2 = RT::Ticket->new($RT::SystemUser);
+my $t2 = RT::Ticket->new(RT->SystemUser);
($id,$trans,$msg) =$t2->Create (Queue => 'general', Subject => 'Requestor test one', Requestor => [$u2->EmailAddress]);
ok ($id, $msg);
-my $t3 = RT::Ticket->new($RT::SystemUser);
+my $t3 = RT::Ticket->new(RT->SystemUser);
($id,$trans,$msg) =$t3->Create (Queue => 'general', Subject => 'Requestor test one', Requestor => [$u2->EmailAddress, $u1->EmailAddress]);
ok ($id, $msg);
-my $tix1 = RT::Tickets->new($RT::SystemUser);
+my $tix1 = RT::Tickets->new(RT->SystemUser);
$tix1->FromSQL('Requestor.EmailAddress LIKE "rqtest1" OR Requestor.EmailAddress LIKE "rqtest2"');
is ($tix1->Count, 3);
-my $tix2 = RT::Tickets->new($RT::SystemUser);
+my $tix2 = RT::Tickets->new(RT->SystemUser);
$tix2->FromSQL('Requestor.Name LIKE "TestOne" OR Requestor.Name LIKE "TestTwo"');
is ($tix2->Count, 3);
-my $tix3 = RT::Tickets->new($RT::SystemUser);
+my $tix3 = RT::Tickets->new(RT->SystemUser);
$tix3->FromSQL('Requestor.EmailAddress LIKE "rqtest1"');
is ($tix3->Count, 2);
-my $tix4 = RT::Tickets->new($RT::SystemUser);
+my $tix4 = RT::Tickets->new(RT->SystemUser);
$tix4->FromSQL('Requestor.Name LIKE "TestOne" ');
is ($tix4->Count, 2);
@@ -69,12 +69,12 @@ is ($tix4->Count, 2);
# There's no way to differentiate "one requestor name that matches foo and bar"
# and "two requestors, one matching foo and one matching bar"
-# my $tix5 = RT::Tickets->new($RT::SystemUser);
+# my $tix5 = RT::Tickets->new(RT->SystemUser);
# $tix5->FromSQL('Requestor.Name LIKE "TestOne" AND Requestor.Name LIKE "TestTwo"');
#
# is ($tix5->Count, 1);
#
-# my $tix6 = RT::Tickets->new($RT::SystemUser);
+# my $tix6 = RT::Tickets->new(RT->SystemUser);
# $tix6->FromSQL('Requestor.EmailAddress LIKE "rqtest1" AND Requestor.EmailAddress LIKE "rqtest2"');
#
# is ($tix6->Count, 1);
@@ -85,7 +85,7 @@ is ($tix4->Count, 2);
{
-my $t1 = RT::Ticket->new($RT::SystemUser);
+my $t1 = RT::Ticket->new(RT->SystemUser);
$t1->Create(Queue => 'general', Subject => "LimitWatchers test", Requestors => \['requestor1@example.com']);
@@ -94,11 +94,10 @@ $t1->Create(Queue => 'general', Subject => "LimitWatchers test", Requestors => \
{
# We assume that we've got some tickets hanging around from before.
-ok( my $unlimittickets = RT::Tickets->new( $RT::SystemUser ) );
+ok( my $unlimittickets = RT::Tickets->new( RT->SystemUser ) );
ok( $unlimittickets->UnLimit );
ok( $unlimittickets->Count > 0, "UnLimited tickets object should return tickets" );
}
-1;
diff --git a/rt/t/api/tickets_overlay_sql.t b/rt/t/api/tickets_overlay_sql.t
index 5bc614077..9f91111df 100644
--- a/rt/t/api/tickets_overlay_sql.t
+++ b/rt/t/api/tickets_overlay_sql.t
@@ -1,13 +1,9 @@
-
-use RT;
-use RT::Test tests => 19;
-
-{
-
-use RT::Tickets;
use strict;
+use warnings;
+use RT::Test tests => 20, config => 'Set( %FullTextSearch, Enable => 1 );';
+use Test::Warn;
-my $tix = RT::Tickets->new($RT::SystemUser);
+my $tix = RT::Tickets->new(RT->SystemUser);
{
my $query = "Status = 'open'";
my ($status, $msg) = $tix->FromSQL($query);
@@ -18,7 +14,7 @@ my $tix = RT::Tickets->new($RT::SystemUser);
my (@created,%created);
my $string = 'subject/content SQL test';
{
- my $t = RT::Ticket->new($RT::SystemUser);
+ my $t = RT::Ticket->new(RT->SystemUser);
ok( $t->Create(Queue => 'General', Subject => $string), "Ticket Created");
$created{ $t->Id }++; push @created, $t->Id;
}
@@ -30,7 +26,7 @@ my $string = 'subject/content SQL test';
Data => [ $string ],
);
- my $t = RT::Ticket->new($RT::SystemUser);
+ my $t = RT::Ticket->new(RT->SystemUser);
ok( $t->Create( Queue => 'General',
Requestor => 'jesse@example.com',
Subject => 'another ticket',
@@ -74,7 +70,7 @@ diag "Make sure we don't barf on invalid input for IS / IS NOT";
unlike $tix->BuildSelectQuery, qr/foobar/, "didn't find foobar in the select";
like $tix->BuildSelectQuery, qr/Subject IS NULL/, "found right clause";
- my ($status, $msg) = $tix->FromSQL("Subject IS NOT 'foobar'");
+ ($status, $msg) = $tix->FromSQL("Subject IS NOT 'foobar'");
ok ($status, "valid query") or diag("error: $msg");
is $tix->Count, 2, "found two tickets";
unlike $tix->BuildSelectQuery, qr/foobar/, "didn't find foobar in the select";
@@ -82,15 +78,16 @@ diag "Make sure we don't barf on invalid input for IS / IS NOT";
}
{
- my ($status, $msg) = $tix->FromSQL("Requestor.Signature LIKE 'foo'");
- ok (!$status, "invalid query - Signature not valid") or diag("error: $msg");
+ my ($status, $msg);
- my ($status, $msg) = $tix->FromSQL("Requestor.EmailAddress LIKE 'jesse'");
+ warning_like {
+ ($status, $msg) = $tix->FromSQL("Requestor.Signature LIKE 'foo'");
+ } qr/Invalid watcher subfield: 'Signature'/;
+ ok(!$status, "invalid query - Signature not valid") or diag("error: $msg");
+
+ ($status, $msg) = $tix->FromSQL("Requestor.EmailAddress LIKE 'jesse'");
ok ($status, "valid query") or diag("error: $msg");
is $tix->Count, 1, "found one ticket";
like $tix->First->Subject, qr/another ticket/, "found the right ticket";
}
-}
-
-1;
diff --git a/rt/t/api/txn_content.t b/rt/t/api/txn_content.t
index 0f5d78ca9..392b6a73b 100644
--- a/rt/t/api/txn_content.t
+++ b/rt/t/api/txn_content.t
@@ -3,7 +3,7 @@ use strict;
use RT::Test tests => 3;
use MIME::Entity;
-my $ticket = RT::Ticket->new($RT::SystemUser);
+my $ticket = RT::Ticket->new(RT->SystemUser);
my $mime = MIME::Entity->build(
From => 'test@example.com',
Type => 'text/html',
diff --git a/rt/t/api/uri-fsck_com_rt.t b/rt/t/api/uri-fsck_com_rt.t
index d62e58022..18bee7db2 100644
--- a/rt/t/api/uri-fsck_com_rt.t
+++ b/rt/t/api/uri-fsck_com_rt.t
@@ -4,9 +4,9 @@ use RT;
use RT::Test tests => 8;
use_ok("RT::URI::fsck_com_rt");
-my $uri = RT::URI::fsck_com_rt->new($RT::SystemUser);
+my $uri = RT::URI::fsck_com_rt->new(RT->SystemUser);
-my $t1 = RT::Ticket->new($RT::SystemUser);
+my $t1 = RT::Ticket->new(RT->SystemUser);
my ($id,$trans,$msg) =$t1->Create (Queue => 'general', Subject => 'Requestor test one', );
ok ($id, $msg);
@@ -20,9 +20,8 @@ ok ($uri->isa('RT::Base'), "It's an RT::Base");
is ($uri->LocalURIPrefix , 'fsck.com-rt://'.RT->Config->Get('Organization'));
-my $ticket = RT::Ticket->new($RT::SystemUser);
+my $ticket = RT::Ticket->new(RT->SystemUser);
$ticket->Load(1);
$uri = RT::URI::fsck_com_rt->new($ticket->CurrentUser);
is($uri->LocalURIPrefix. "/ticket/1" , $uri->URIForObject($ticket));
-1;
diff --git a/rt/t/api/uri-t.t b/rt/t/api/uri-t.t
index 4695629bb..61b3e1761 100644
--- a/rt/t/api/uri-t.t
+++ b/rt/t/api/uri-t.t
@@ -3,12 +3,12 @@ use warnings;
use RT;
use RT::Test tests => 6;
-my $t1 = RT::Ticket->new($RT::SystemUser);
+my $t1 = RT::Ticket->new(RT->SystemUser);
my ($id,$trans,$msg) =$t1->Create (Queue => 'general', Subject => 'Requestor test one', );
ok ($id, $msg);
use_ok("RT::URI::t");
-my $uri = RT::URI::t->new($RT::SystemUser);
+my $uri = RT::URI::t->new(RT->SystemUser);
ok(ref($uri), "URI object exists");
my $uristr = "t:1";
@@ -18,4 +18,3 @@ is($uri->Object->Id, 1, "Object loaded has correct ID");
is($uri->URI, 'fsck.com-rt://'.RT->Config->Get('Organization').'/ticket/1',
"URI object has correct URI string");
-1;
diff --git a/rt/t/api/user.t b/rt/t/api/user.t
index 25cf74773..e6b891f73 100644
--- a/rt/t/api/user.t
+++ b/rt/t/api/user.t
@@ -2,7 +2,7 @@
use strict;
use warnings;
use RT;
-use RT::Test tests => 108;
+use RT::Test tests => 111;
{
@@ -16,38 +16,38 @@ ok(require RT::User);
# Make sure we can create a user
-my $u1 = RT::User->new($RT::SystemUser);
+my $u1 = RT::User->new(RT->SystemUser);
is(ref($u1), 'RT::User');
my ($id, $msg) = $u1->Create(Name => 'CreateTest1'.$$, EmailAddress => $$.'create-test-1@example.com');
ok ($id, "Creating user CreateTest1 - " . $msg );
# Make sure we can't create a second user with the same name
-my $u2 = RT::User->new($RT::SystemUser);
+my $u2 = RT::User->new(RT->SystemUser);
($id, $msg) = $u2->Create(Name => 'CreateTest1'.$$, EmailAddress => $$.'create-test-2@example.com');
ok (!$id, $msg);
# Make sure we can't create a second user with the same EmailAddress address
-my $u3 = RT::User->new($RT::SystemUser);
+my $u3 = RT::User->new(RT->SystemUser);
($id, $msg) = $u3->Create(Name => 'CreateTest2'.$$, EmailAddress => $$.'create-test-1@example.com');
ok (!$id, $msg);
# Make sure we can create a user with no EmailAddress address
-my $u4 = RT::User->new($RT::SystemUser);
+my $u4 = RT::User->new(RT->SystemUser);
($id, $msg) = $u4->Create(Name => 'CreateTest3'.$$);
ok ($id, $msg);
# make sure we can create a second user with no EmailAddress address
-my $u5 = RT::User->new($RT::SystemUser);
+my $u5 = RT::User->new(RT->SystemUser);
($id, $msg) = $u5->Create(Name => 'CreateTest4'.$$);
ok ($id, $msg);
# make sure we can create a user with a blank EmailAddress address
-my $u6 = RT::User->new($RT::SystemUser);
+my $u6 = RT::User->new(RT->SystemUser);
($id, $msg) = $u6->Create(Name => 'CreateTest6'.$$, EmailAddress => '');
ok ($id, $msg);
# make sure we can create a second user with a blankEmailAddress address
-my $u7 = RT::User->new($RT::SystemUser);
+my $u7 = RT::User->new(RT->SystemUser);
($id, $msg) = $u7->Create(Name => 'CreateTest7'.$$, EmailAddress => '');
ok ($id, $msg);
@@ -59,19 +59,27 @@ ok ($id, $msg);
ok ($id, $msg);
is_empty ($u7->EmailAddress);
+# back to something, so we can set undef next successfully
+($id,$msg) = $u7->SetEmailAddress('foo@bar'.$$);
+ok ($id, $msg);
+
+($id,$msg) = $u7->SetEmailAddress(undef);
+ok ($id, $msg);
+is_empty ($u7->EmailAddress);
+
RT->Config->Set('ValidateUserEmailAddresses' => 1);
# Make sur we can't create a user with multiple email adresses separated by comma
-my $u8 = RT::User->new($RT::SystemUser);
+my $u8 = RT::User->new(RT->SystemUser);
($id, $msg) = $u8->Create(Name => 'CreateTest8'.$$, EmailAddress => $$.'create-test-81@example.com, '.$$.'create-test-82@example.com');
ok (!$id, $msg);
# Make sur we can't create a user with multiple email adresses separated by space
-my $u9 = RT::User->new($RT::SystemUser);
+my $u9 = RT::User->new(RT->SystemUser);
($id, $msg) = $u9->Create(Name => 'CreateTest9'.$$, EmailAddress => $$.'create-test-91@example.com '.$$.'create-test-92@example.com');
ok (!$id, $msg);
# Make sur we can't create a user with invalid email address
-my $u10 = RT::User->new($RT::SystemUser);
+my $u10 = RT::User->new(RT->SystemUser);
($id, $msg) = $u10->Create(Name => 'CreateTest10'.$$, EmailAddress => $$.'create-test10}@[.com');
ok (!$id, $msg);
RT->Config->Set('ValidateUserEmailAddresses' => undef);
@@ -81,7 +89,7 @@ RT->Config->Set('ValidateUserEmailAddresses' => undef);
{
-ok(my $user = RT::User->new($RT::SystemUser));
+ok(my $user = RT::User->new(RT->SystemUser));
ok($user->Load('root'), "Loaded user 'root'");
ok($user->Privileged, "User 'root' is privileged");
ok(my ($v,$m) = $user->SetPrivileged(0));
@@ -96,7 +104,7 @@ ok($user->Privileged, "User 'root' is privileged again");
{
-ok(my $u = RT::User->new($RT::SystemUser));
+ok(my $u = RT::User->new(RT->SystemUser));
ok($u->Load(1), "Loaded the first user");
is($u->PrincipalObj->ObjectId , 1, "user 1 is the first principal");
is($u->PrincipalObj->PrincipalType, 'User' , "Principal 1 is a user, not a group");
@@ -106,7 +114,7 @@ is($u->PrincipalObj->PrincipalType, 'User' , "Principal 1 is a user, not a group
{
-my $root = RT::User->new($RT::SystemUser);
+my $root = RT::User->new(RT->SystemUser);
$root->Load('root');
ok($root->Id, "Found the root user");
my $rootq = RT::Queue->new($root);
@@ -115,7 +123,7 @@ ok($rootq->Id, "Loaded the first queue");
ok ($rootq->CurrentUser->HasRight(Right=> 'CreateTicket', Object => $rootq), "Root can create tickets");
-my $new_user = RT::User->new($RT::SystemUser);
+my $new_user = RT::User->new(RT->SystemUser);
my ($id, $msg) = $new_user->Create(Name => 'ACLTest'.$$);
ok ($id, "Created a new user for acl test $msg");
@@ -140,13 +148,13 @@ ok (!$q->CurrentUser->HasRight(Right => 'CreateTicket', Object => $q), "The user
# Create a ticket in the queue
-my $new_tick = RT::Ticket->new($RT::SystemUser);
+my $new_tick = RT::Ticket->new(RT->SystemUser);
my ($tickid, $tickmsg) = $new_tick->Create(Subject=> 'ACL Test', Queue => 'General');
ok($tickid, "Created ticket: $tickid");
# Make sure the user doesn't have the right to modify tickets in the queue
ok (!$new_user->HasRight( Object => $new_tick, Right => 'ModifyTicket'), "User can't modify the ticket without group membership");
# Create a new group
-my $group = RT::Group->new($RT::SystemUser);
+my $group = RT::Group->new(RT->SystemUser);
$group->CreateUserDefinedGroup(Name => 'ACLTest'.$$);
ok($group->Id, "Created a new group Ok");
# Grant a group the right to modify tickets in a queue
@@ -166,12 +174,12 @@ ok ($did,"Deleted the group member: $dmsg");
ok (!$new_user->HasRight( Object => $new_tick, Right => 'ModifyTicket'), "User can't modify the ticket without group membership");
-my $q_as_system = RT::Queue->new($RT::SystemUser);
+my $q_as_system = RT::Queue->new(RT->SystemUser);
$q_as_system->Load(1);
ok($q_as_system->Id, "Loaded the first queue");
# Create a ticket in the queue
-my $new_tick2 = RT::Ticket->new($RT::SystemUser);
+my $new_tick2 = RT::Ticket->new(RT->SystemUser);
(my $tick2id, $tickmsg) = $new_tick2->Create(Subject=> 'ACL Test 2', Queue =>$q_as_system->Id);
ok($tick2id, "Created ticket: $tick2id");
is($new_tick2->QueueObj->id, $q_as_system->Id, "Created a new ticket in queue 1");
@@ -181,7 +189,7 @@ is($new_tick2->QueueObj->id, $q_as_system->Id, "Created a new ticket in queue 1"
ok (!$new_user->HasRight( Object => $new_tick2, Right => 'ModifyTicket'), "User can't modify the ticket without group membership");
# Create a subgroup
-my $subgroup = RT::Group->new($RT::SystemUser);
+my $subgroup = RT::Group->new(RT->SystemUser);
$subgroup->CreateUserDefinedGroup(Name => 'Subgrouptest'.$$);
ok($subgroup->Id, "Created a new group ".$subgroup->Id."Ok");
#Add the subgroup as a subgroup of the group
@@ -210,7 +218,6 @@ ok (!$new_user->HasRight( Object => $new_tick2, Right => 'ModifyTicket'), "User
ok ($id,$msg);
ok ($new_user->HasRight( Object => $new_tick2, Right => 'ModifyTicket'), "User can modify the ticket without group membership");
-# }}}
my ($usrid, $usrmsg) = $subgroup->DeleteMember($new_user->PrincipalId);
@@ -222,7 +229,6 @@ ok (!$new_user->HasRight( Object => $new_tick2, Right => 'ModifyTicket'), "User
ok(($gv,$gm) = $group->PrincipalObj->RevokeRight( Object => $q, Right => 'ModifyTicket'),"Granted the group the right to modify tickets");
ok($gv,"revoke succeeed - $gm");
-# {{{ Test the user's right to modify a ticket as a _queue_ admincc for a right granted at the _queue_ level
# Grant queue admin cc the right to modify ticket in the queue
ok(my ($qv,$qm) = $q_as_system->AdminCc->PrincipalObj->GrantRight( Object => $q_as_system, Right => 'ModifyTicket'),"Granted the queue adminccs the right to modify tickets");
@@ -240,9 +246,7 @@ ok (my ($del_id, $del_msg) = $q_as_system->DeleteWatcher(Type => 'AdminCc', Prin
# Make sure the user doesn't have the right to modify tickets in the queue
ok (!$new_user->HasRight( Object => $new_tick2, Right => 'ModifyTicket'), "User can't modify the ticket without group membership");
-# }}}
-# {{{ Test the user's right to modify a ticket as a _ticket_ admincc with the right granted at the _queue_ level
# Add the user as a ticket admincc
ok (my( $uadd_id, $uadd_msg) = $new_tick2->AddWatcher(Type => 'AdminCc', PrincipalId => $new_user->PrincipalId) , "Added the new user as a queue admincc");
@@ -262,11 +266,9 @@ ok (!$new_user->HasRight( Object => $new_tick2, Right => 'ModifyTicket'), "User
ok(my ($rqv,$rqm) = $q_as_system->AdminCc->PrincipalObj->RevokeRight( Object => $q_as_system, Right => 'ModifyTicket'),"Revokeed the queue adminccs the right to modify tickets");
ok($rqv, "Revoked the right successfully - $rqm");
-# }}}
-# {{{ Test the user's right to modify a ticket as a _queue_ admincc for a right granted at the _system_ level
# Before we start Make sure the user does not have the right to modify tickets in the queue
ok (!$new_user->HasRight( Object => $new_tick2, Right => 'ModifyTicket'), "User can not modify the ticket without it being granted");
@@ -294,9 +296,7 @@ ok (($del_id, $del_msg) = $q_as_system->DeleteWatcher(Type => 'AdminCc', Princip
ok (!$new_user->HasRight( Object => $new_tick2, Right => 'ModifyTicket'), "User can't modify the ticket without group membership");
ok (!$new_user->HasRight( Object => $new_tick2->QueueObj, Right => 'ModifyTicket'), "User can't modify tickets in the queue without group membership");
-# }}}
-# {{{ Test the user's right to modify a ticket as a _ticket_ admincc with the right granted at the _queue_ level
ok (!$new_user->HasRight( Object => $new_tick2, Right => 'ModifyTicket'), "User can not modify the ticket without being an admincc");
ok (!$new_user->HasRight( Object => $new_tick2->QueueObj, Right => 'ModifyTicket'), "User can not modify tickets in the queue obj without being an admincc");
@@ -322,7 +322,6 @@ ok (!$new_user->HasRight( Object => $new_tick2->QueueObj, Right => 'ModifyTicket
ok(($rqv,$rqm) = $q_as_system->AdminCc->PrincipalObj->RevokeRight( Object => $RT::System, Right => 'ModifyTicket'),"Revokeed the queue adminccs the right to modify tickets");
ok($rqv, "Revoked the right successfully - $rqm");
-# }}}
@@ -336,4 +335,3 @@ ok($rqv, "Revoked the right successfully - $rqm");
}
-1;
diff --git a/rt/t/api/users.t b/rt/t/api/users.t
index d1ff174e1..1f3a48770 100644
--- a/rt/t/api/users.t
+++ b/rt/t/api/users.t
@@ -1,37 +1,31 @@
-
use strict;
use warnings;
-use RT;
-use RT::Test tests => 11;
-
-
-{
+use RT::Test tests => 10;
-ok(require RT::Users);
-
-
-}
+RT::System->AddRights(
+ 'RTxUserRight' => 'Just a right for testing rights',
+);
{
no warnings qw(redefine once);
-ok(my $users = RT::Users->new($RT::SystemUser));
-$users->WhoHaveRight(Object =>$RT::System, Right =>'SuperUser');
+ok(my $users = RT::Users->new(RT->SystemUser));
+$users->WhoHaveRight(Object => RT->System, Right =>'SuperUser');
is($users->Count , 1, "There is one privileged superuser - Found ". $users->Count );
# TODO: this wants more testing
-my $RTxUser = RT::User->new($RT::SystemUser);
+my $RTxUser = RT::User->new(RT->SystemUser);
my ($id, $msg) = $RTxUser->Create( Name => 'RTxUser', Comments => "RTx extension user", Privileged => 1);
ok ($id,$msg);
-my $group = RT::Group->new($RT::SystemUser);
+my $group = RT::Group->new(RT->SystemUser);
$group->LoadACLEquivalenceGroup($RTxUser->PrincipalObj);
my $RTxSysObj = {};
bless $RTxSysObj, 'RTx::System';
*RTx::System::Id = sub { 1; };
*RTx::System::id = *RTx::System::Id;
-my $ace = RT::Record->new($RT::SystemUser);
+my $ace = RT::Record->new(RT->SystemUser);
$ace->Table('ACL');
$ace->_BuildTableAttributes unless ($RT::Record::_TABLE_ATTR->{ref($ace)});
($id, $msg) = $ace->Create( PrincipalId => $group->id, PrincipalType => 'Group', RightName => 'RTxUserRight', ObjectType => 'RTx::System', ObjectId => 1 );
@@ -42,19 +36,19 @@ bless $RTxObj, 'RTx::System::Record';
*RTx::System::Record::Id = sub { 4; };
*RTx::System::Record::id = *RTx::System::Record::Id;
-$users = RT::Users->new($RT::SystemUser);
+$users = RT::Users->new(RT->SystemUser);
$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxSysObj);
is($users->Count, 1, "RTxUserRight found for RTxSysObj");
-$users = RT::Users->new($RT::SystemUser);
+$users = RT::Users->new(RT->SystemUser);
$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj);
is($users->Count, 0, "RTxUserRight not found for RTxObj");
-$users = RT::Users->new($RT::SystemUser);
+$users = RT::Users->new(RT->SystemUser);
$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj, EquivObjects => [ $RTxSysObj ]);
is($users->Count, 1, "RTxUserRight found for RTxObj using EquivObjects");
-$ace = RT::Record->new($RT::SystemUser);
+$ace = RT::Record->new(RT->SystemUser);
$ace->Table('ACL');
$ace->_BuildTableAttributes unless ($RT::Record::_TABLE_ATTR->{ref($ace)});
($id, $msg) = $ace->Create( PrincipalId => $group->id, PrincipalType => 'Group', RightName => 'RTxUserRight', ObjectType => 'RTx::System::Record', ObjectId => 5 );
@@ -65,11 +59,11 @@ bless $RTxObj2, 'RTx::System::Record';
*RTx::System::Record::Id = sub { 5; };
*RTx::System::Record::id = sub { 5; };
-$users = RT::Users->new($RT::SystemUser);
+$users = RT::Users->new(RT->SystemUser);
$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj2);
is($users->Count, 1, "RTxUserRight found for RTxObj2");
-$users = RT::Users->new($RT::SystemUser);
+$users = RT::Users->new(RT->SystemUser);
$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj2, EquivObjects => [ $RTxSysObj ]);
is($users->Count, 1, "RTxUserRight found for RTxObj2");
@@ -77,4 +71,3 @@ is($users->Count, 1, "RTxUserRight found for RTxObj2");
}
-1;
diff --git a/rt/t/api/versions_sorter.t b/rt/t/api/versions_sorter.t
new file mode 100644
index 000000000..b2ec547a0
--- /dev/null
+++ b/rt/t/api/versions_sorter.t
@@ -0,0 +1,22 @@
+#!/usr/bin/perl -w
+
+use RT::Test nodata => 1, tests => 3;
+
+use strict;
+use warnings;
+
+sub is_right_sorting {
+ my @order = @_;
+ my @tmp = sort { int(rand(3)) - 1 } @order;
+
+ is_deeply(
+ [ sort RT::Handle::cmp_version @tmp ],
+ \@order,
+ 'test sorting of ('. join(' ', @tmp) .')'
+ );
+}
+
+is_right_sorting(qw(1 2 3));
+is_right_sorting(qw(1.1 1.2 1.3 2.0 2.1));
+is_right_sorting(qw(4.0.0a1 4.0.0alpha2 4.0.0b1 4.0.0beta2 4.0.0pre1 4.0.0pre2 4.0.0rc1 4.0.0rc2 4.0.0));
+
diff --git a/rt/t/api/web-config.t b/rt/t/api/web-config.t
new file mode 100644
index 000000000..fb2b36242
--- /dev/null
+++ b/rt/t/api/web-config.t
@@ -0,0 +1,163 @@
+use strict;
+use warnings;
+use RT;
+use RT::Test nodb => 1, tests => 89;
+
+sub no_warnings_ok {
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+
+ my $option = shift;
+ my $value = shift;
+ my $name = shift;
+
+ is(warnings_from($option => $value), 0, $name);
+}
+
+sub one_warning_like {
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+
+ my $option = shift;
+ my $value = shift;
+ my $regex = shift;
+ my $name = shift;
+
+ my @w = warnings_from($option => $value);
+ is(@w, 1);
+ like($w[0], $regex, $name);
+}
+
+
+sub warnings_from {
+ my $option = shift;
+ my $value = shift;
+
+ my @warnings;
+ local $SIG{__WARN__} = sub {
+ push @warnings, $_[0];
+ };
+
+ RT->Config->Set($option => $value);
+ RT->Config->PostLoadCheck;
+
+ return @warnings;
+}
+
+# WebPath
+no_warnings_ok(WebPath => '');
+no_warnings_ok(WebPath => '/foo');
+no_warnings_ok(WebPath => '/foo/bar');
+
+one_warning_like(WebPath => '/foo/', qr/The WebPath config option requires no trailing slash/);
+
+one_warning_like(WebPath => 'foo', qr/The WebPath config option requires a leading slash/);
+
+my @w = warnings_from(WebPath => 'foo/');
+is(@w, 2);
+like($w[0], qr/The WebPath config option requires no trailing slash/);
+like($w[1], qr/The WebPath config option requires a leading slash/);
+
+one_warning_like(WebPath => '/foo/bar/', qr/The WebPath config option requires no trailing slash/);
+
+one_warning_like(WebPath => 'foo/bar', qr/The WebPath config option requires a leading slash/);
+
+@w = warnings_from(WebPath => 'foo/bar/');
+is(@w, 2);
+like($w[0], qr/The WebPath config option requires no trailing slash/);
+like($w[1], qr/The WebPath config option requires a leading slash/);
+
+one_warning_like(WebPath => '/', qr{For the WebPath config option, use the empty string instead of /});
+
+# reinstate a valid WebPath for other tests
+no_warnings_ok(WebPath => '/rt');
+
+# WebDomain
+no_warnings_ok(WebDomain => 'example.com');
+no_warnings_ok(WebDomain => 'rt.example.com');
+no_warnings_ok(WebDomain => 'localhost');
+
+one_warning_like(WebDomain => '', qr{You must set the WebDomain config option});
+
+one_warning_like(WebDomain => 'http://rt.example.com', qr{The WebDomain config option must not contain a scheme \(http://\)});
+
+one_warning_like(WebDomain => 'https://rt.example.com', qr{The WebDomain config option must not contain a scheme \(https://\)});
+
+one_warning_like(WebDomain => 'rt.example.com/path', qr{The WebDomain config option must not contain a path \(/path\)});
+
+one_warning_like(WebDomain => 'rt.example.com/path/more', qr{The WebDomain config option must not contain a path \(/path/more\)});
+
+one_warning_like(WebDomain => 'rt.example.com:80', qr{The WebDomain config option must not contain a port \(80\)});
+
+# reinstate a valid WebDomain for other tests
+no_warnings_ok(WebDomain => 'rt.example.com');
+
+# WebPort
+no_warnings_ok(WebDomain => 80);
+no_warnings_ok(WebDomain => 443);
+no_warnings_ok(WebDomain => 8888);
+
+one_warning_like(WebPort => '', qr{You must set the WebPort config option});
+
+one_warning_like(WebPort => 3.14, qr{The WebPort config option must be an integer});
+
+one_warning_like(WebPort => 'wha?', qr{The WebPort config option must be an integer});
+
+# reinstate a valid WebDomain for other tests
+no_warnings_ok(WebPort => 443);
+
+# WebBaseURL
+no_warnings_ok(WebBaseURL => 'http://rt.example.com');
+no_warnings_ok(WebBaseURL => 'HTTP://rt.example.com', 'uppercase scheme is okay');
+no_warnings_ok(WebBaseURL => 'http://rt.example.com:8888', 'nonstandard port is okay');
+no_warnings_ok(WebBaseURL => 'https://rt.example.com:8888', 'nonstandard port with https is okay');
+
+one_warning_like(WebBaseURL => '', qr{You must set the WebBaseURL config option});
+
+one_warning_like(WebBaseURL => 'rt.example.com', qr{The WebBaseURL config option must contain a scheme});
+
+one_warning_like(WebBaseURL => 'xtp://rt.example.com', qr{The WebBaseURL config option must contain a scheme \(http or https\)});
+
+one_warning_like(WebBaseURL => 'http://rt.example.com/', qr{The WebBaseURL config option requires no trailing slash});
+
+one_warning_like(WebBaseURL => 'http://rt.example.com/rt', qr{The WebBaseURL config option must not contain a path \(/rt\)});
+
+@w = warnings_from(WebBaseURL => 'http://rt.example.com/rt/');
+is(@w, 2);
+like($w[0], qr{The WebBaseURL config option requires no trailing slash});
+like($w[1], qr{The WebBaseURL config option must not contain a path \(/rt/\)});
+
+one_warning_like(WebBaseURL => 'http://rt.example.com/rt/ir', qr{The WebBaseURL config option must not contain a path \(/rt/ir\)});
+
+@w = warnings_from(WebBaseURL => 'http://rt.example.com/rt/ir/');
+is(@w, 2);
+like($w[0], qr{The WebBaseURL config option requires no trailing slash});
+like($w[1], qr{The WebBaseURL config option must not contain a path \(/rt/ir/\)});
+
+# reinstate a valid WebBaseURL for other tests
+no_warnings_ok(WebBaseURL => 'http://rt.example.com');
+
+# WebURL
+no_warnings_ok(WebURL => 'http://rt.example.com/');
+no_warnings_ok(WebURL => 'HTTP://rt.example.com/', 'uppercase scheme is okay');
+no_warnings_ok(WebURL => 'http://example.com/rt/');
+no_warnings_ok(WebURL => 'http://example.com/rt/ir/');
+no_warnings_ok(WebURL => 'http://rt.example.com:8888/', 'nonstandard port is okay');
+no_warnings_ok(WebURL => 'https://rt.example.com:8888/', 'nonstandard port with https is okay');
+
+one_warning_like(WebURL => '', qr{You must set the WebURL config option});
+
+@w = warnings_from(WebURL => 'rt.example.com');
+is(@w, 2);
+like($w[0], qr{The WebURL config option must contain a scheme});
+like($w[1], qr{The WebURL config option requires a trailing slash});
+
+one_warning_like(WebURL => 'http://rt.example.com', qr{The WebURL config option requires a trailing slash});
+
+one_warning_like(WebURL => 'xtp://example.com/rt/', qr{The WebURL config option must contain a scheme \(http or https\)});
+
+one_warning_like(WebURL => 'http://rt.example.com/rt', qr{The WebURL config option requires a trailing slash});
+
+one_warning_like(WebURL => 'http://rt.example.com/rt/ir', qr{The WebURL config option requires a trailing slash});
+
+# reinstate a valid WebURL for other tests
+no_warnings_ok(WebURL => 'http://rt.example.com/rt/');
+
diff --git a/rt/t/articles/article.t b/rt/t/articles/article.t
new file mode 100644
index 000000000..33becb023
--- /dev/null
+++ b/rt/t/articles/article.t
@@ -0,0 +1,230 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 67;
+
+use_ok 'RT::Articles';
+use_ok 'RT::Classes';
+use_ok 'RT::Class';
+
+my $CLASS = 'ArticleTest-'.$$;
+
+my $user = RT::CurrentUser->new('root');
+
+my $class = RT::Class->new($user);
+
+
+my ($id, $msg) = $class->Create(Name =>$CLASS);
+ok ($id, $msg);
+
+
+
+my $article = RT::Article->new($user);
+ok (UNIVERSAL::isa($article, 'RT::Article'));
+ok (UNIVERSAL::isa($article, 'RT::Record'));
+ok (UNIVERSAL::isa($article, 'RT::Record'));
+ok (UNIVERSAL::isa($article, 'DBIx::SearchBuilder::Record') , "It's a searchbuilder record!");
+
+
+($id, $msg) = $article->Create( Class => $CLASS, Summary => $CLASS);
+ok ($id, $msg);
+$article->Load($id);
+is ($article->Summary, $CLASS, "The summary is set correct");
+my $at = RT::Article->new($RT::SystemUser);
+$at->Load($id);
+is ($at->id , $id);
+is ($at->Summary, $article->Summary);
+
+
+
+
+my $a1 = RT::Article->new($RT::SystemUser);
+ ($id, $msg) = $a1->Create(Class => $class->id, Name => 'ValidateNameTest'.$$);
+ok ($id, $msg);
+
+
+
+my $a2 = RT::Article->new($RT::SystemUser);
+($id, $msg) = $a2->Create(Class => $class->id, Name => 'ValidateNameTest'.$$);
+ok (!$id, $msg);
+
+my $a3 = RT::Article->new($RT::SystemUser);
+($id, $msg) = $a3->Create(Class => $class->id, Name => 'ValidateNameTest2'.$$);
+ok ($id, $msg);
+($id, $msg) =$a3->SetName('ValidateNameTest'.$$);
+
+ok (!$id, $msg);
+
+($id, $msg) =$a3->SetName('ValidateNametest2'.$$);
+
+ok ($id, $msg);
+
+
+
+
+
+my $newart = RT::Article->new($RT::SystemUser);
+$newart->Create(Name => 'DeleteTest'.$$, Class => '1');
+$id = $newart->Id;
+
+ok($id, "New article has an id");
+
+
+ $article = RT::Article->new($RT::SystemUser);
+$article->Load($id);
+ok ($article->Id, "Found the article");
+my $val;
+ ($val, $msg) = $article->Delete();
+ok ($val, "Article Deleted: $msg");
+
+ $a2 = RT::Article->new($RT::SystemUser);
+$a2->Load($id);
+ok (!$a2->Id, "Did not find the article");
+
+# NOT OK
+#$RT::Handle->SimpleQuery("DELETE FROM Links");
+
+my $article_a = RT::Article->new($RT::SystemUser);
+($id, $msg) = $article_a->Create( Class => $CLASS, Summary => "ArticleTestlink1".$$);
+ok($id,$msg);
+
+my $article_b = RT::Article->new($RT::SystemUser);
+($id, $msg) = $article_b->Create( Class => $CLASS, Summary => "ArticleTestlink2".$$);
+ok($id,$msg);
+
+# Create a link between two articles
+($id, $msg) = $article_a->AddLink( Type => 'RefersTo', Target => $article_b->URI);
+ok($id,$msg);
+
+# Make sure that Article Bs "ReferredToBy" links object refers to to this article
+my $refers_to_b = $article_b->ReferredToBy;
+is($refers_to_b->Count, 1, "Found one thing referring to b");
+my $first = $refers_to_b->First;
+ok ($first->isa('RT::Link'), "IT's an RT link - ref ".ref($first) );
+is($first->TargetObj->Id, $article_b->Id, "Its target is B");
+
+ok($refers_to_b->First->BaseObj->isa('RT::Article'), "Yep. its an article");
+
+
+# Make sure that Article A's "RefersTo" links object refers to this article"
+my $referred_To_by_a = $article_a->RefersTo;
+is($referred_To_by_a->Count, 1, "Found one thing referring to b ".$referred_To_by_a->Count. "-".$referred_To_by_a->First->id . " - ".$referred_To_by_a->Last->id);
+ $first = $referred_To_by_a->First;
+ok ($first->isa('RT::Link'), "IT's an RT link - ref ".ref($first) );
+is ($first->TargetObj->Id, $article_b->Id, "Its target is B - " . $first->TargetObj->Id);
+is ($first->BaseObj->Id, $article_a->Id, "Its base is A");
+
+ok($referred_To_by_a->First->BaseObj->isa('RT::Article'), "Yep. its an article");
+
+# Delete the link
+($id, $msg) = $article_a->DeleteLink(Type => 'RefersTo', Target => $article_b->URI);
+ok($id,$msg);
+
+
+# Create an Article A RefersTo Ticket 1 from the Articles side
+use RT::Ticket;
+
+
+my $tick = RT::Ticket->new($RT::SystemUser);
+$tick->Create(Subject => "Article link test ", Queue => 'General');
+$tick->Load($tick->Id);
+ok ($tick->Id, "Found ticket ".$tick->id);
+($id, $msg) = $article_a->AddLink(Type => 'RefersTo', Target => $tick->URI);
+ok($id,$msg);
+
+# Find all tickets whhich refer to Article A
+
+use RT::Tickets;
+use RT::Links;
+
+my $tix = RT::Tickets->new($RT::SystemUser);
+ok ($tix, "Got an RT::Tickets object");
+ok ($tix->LimitReferredToBy($article_a->URI));
+is ($tix->Count, 1, "Found one ticket linked to that article");
+is ($tix->First->Id, $tick->id, "It's even the right one");
+
+
+
+# Find all articles which refer to Ticket 1
+use RT::Articles;
+
+my $articles = RT::Articles->new($RT::SystemUser);
+ok($articles->isa('RT::Articles'), "Created an article collection");
+ok($articles->isa('RT::SearchBuilder'), "Created an article collection");
+ok($articles->isa('DBIx::SearchBuilder'), "Created an article collection");
+ok($tick->URI, "The ticket does still have a URI");
+$articles->LimitRefersTo($tick->URI);
+
+is($articles->Count(), 1);
+is ($articles->First->Id, $article_a->Id);
+is ($articles->First->URI, $article_a->URI);
+
+
+
+# Find all things which refer to ticket 1 using the RT API.
+
+my $tix2 = RT::Links->new($RT::SystemUser);
+ok ($tix2->isa('RT::Links'));
+ok($tix2->LimitRefersTo($tick->URI));
+is ($tix2->Count, 1);
+is ($tix2->First->BaseObj->URI ,$article_a->URI);
+
+
+
+# Delete the link from the RT side.
+my $t2 = RT::Ticket->new($RT::SystemUser);
+$t2->Load($tick->Id);
+($id, $msg)= $t2->DeleteLink( Base => $article_a->URI, Type => 'RefersTo');
+ok ($id, $msg . " - $id - $msg");
+
+# it is actually deleted
+my $tix3 = RT::Links->new($RT::SystemUser);
+$tix3->LimitReferredToBy($tick->URI);
+is ($tix3->Count, 0);
+
+# Recreate the link from teh RT site
+($id, $msg) = $t2->AddLink( Base => $article_a->URI, Type => 'RefersTo');
+ok ($id, $msg);
+
+# Find all tickets whhich refer to Article A
+
+# Find all articles which refer to Ticket 1
+
+
+
+
+my $art = RT::Article->new($RT::SystemUser);
+($id, $msg) = $art->Create (Class => $CLASS);
+ok ($id,$msg);
+
+ok($art->URI);
+ok($art->__Value('URI') eq $art->URI, "The uri in the db is set correctly");
+
+
+
+
+ $art = RT::Article->new($RT::SystemUser);
+($id, $msg) = $art->Create (Class => $CLASS);
+ok ($id,$msg);
+
+ok($art->URIObj);
+ok($art->__Value('URI') eq $art->URIObj->URI, "The uri in the db is set correctly");
+
+
+my $art_id = $art->id;
+$art = RT::Article->new($RT::SystemUser);
+$art->Load($art_id);
+is ($art->Id, $art_id, "Loaded article 1");
+my $s =$art->Summary;
+($val, $msg) = $art->SetSummary("testFoo");
+ok ($val, $msg);
+ok ($art->Summary eq 'testFoo', "The Summary was set to foo");
+my $t = $art->Transactions();
+my $trans = $t->Last;
+ok ($trans->Type eq 'Set', "It's a Set transaction");
+ok ($trans->Field eq 'Summary', "it is about setting the Summary");
+is ($trans->NewValue , 'testFoo', "The new content is 'foo'");
+is ($trans->OldValue,$s, "the old value was preserved");
+
diff --git a/rt/t/articles/articles.t b/rt/t/articles/articles.t
new file mode 100644
index 000000000..c6fe65106
--- /dev/null
+++ b/rt/t/articles/articles.t
@@ -0,0 +1,137 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 29;
+
+use_ok 'RT::Articles';
+use_ok 'RT::Classes';
+use_ok 'RT::Class';
+
+my $class = RT::Class->new($RT::SystemUser);
+my ( $id, $msg ) = $class->Create( Name => 'CollectionTest-' . $$ );
+ok( $id, $msg );
+
+# Add a custom field to our class
+use_ok('RT::CustomField');
+my $cf = RT::CustomField->new($RT::SystemUser);
+isa_ok($cf, 'RT::CustomField');
+
+($id,$msg) = $cf->Create( Name => 'Articles::Sample-'.$$,
+ Description => 'Test text cf',
+ LookupType => RT::Article->CustomFieldLookupType,
+ Type => 'Freeform'
+ );
+
+
+
+ok($id,$msg);
+
+
+($id,$msg) = $cf->AddToObject($class);
+ok ($id,$msg);
+
+
+
+my $art = RT::Article->new($RT::SystemUser);
+( $id, $msg ) = $art->Create(
+ Class => $class->id,
+ Name => 'Collection-1-' . $$,
+ Summary => 'Coll-1-' . $$,
+ 'CustomField-'.$cf->Name => 'Test-'.$$
+);
+
+ok( $id, $msg );
+
+
+
+
+
+
+my $arts = RT::Articles->new($RT::SystemUser);
+$arts->LimitName( VALUE => 'Collection-1-' . $$ . 'fake' );
+is( $arts->Count, 0,
+ "Found no artlcles with names matching something that is not there" );
+
+my $arts2 = RT::Articles->new($RT::SystemUser);
+$arts2->LimitName( VALUE => 'Collection-1-' . $$ );
+is( $arts2->Count, 1, 'Found one with names matching the word "test"' );
+
+$arts = RT::Articles->new($RT::SystemUser);
+$arts->LimitSummary( VALUE => 'Coll-1-' . $$ . 'fake' );
+is( $arts->Count, 0,
+ 'Found no artlcles with summarys matching something that is not there' );
+
+$arts2 = RT::Articles->new($RT::SystemUser);
+$arts2->LimitSummary( VALUE => 'Coll-1-' . $$ );
+is( $arts2->Count, 1, 'Found one with summarys matching the word "Coll-1"' );
+
+my $new_art = RT::Article->new($RT::SystemUser);
+( $id, $msg ) = $new_art->Create(
+ Class => $class->id,
+ Name => 'CFSearchTest1' . $$,
+ 'CustomField-'.$cf->Name => 'testing' . $$
+);
+
+ok( $id, $msg . " Created a second testable article" );
+
+
+$arts = RT::Articles->new($RT::SystemUser);
+$arts->LimitCustomField( OPERATOR => 'LIKE', VALUE => "esting".$$ );
+is( $arts->Count, 1, "Found 1 cf values matching 'esting" . $$ . "' for an unspecified field");
+
+$arts = RT::Articles->new($RT::SystemUser);
+$arts->LimitCustomField( OPERATOR => '=', VALUE => "esting".$$ );
+is( $arts->Count, 0, "Found 0 cf values EXACTLY matching 'esting" . $$ . "' for an unspecified field");
+
+$arts = RT::Articles->new($RT::SystemUser);
+$arts->LimitCustomField( OPERATOR => '=', VALUE => "testing".$$ );
+is( $arts->Count, 1, "Found 0 cf values EXACTLY matching 'testing" . $$ . "' for an unspecified field");
+
+
+$arts = RT::Articles->new($RT::SystemUser);
+$arts->LimitCustomField( OPERATOR => 'LIKE', VALUE => $$ );
+is( $arts->Count, 2, "Found 1 cf values matching '" . $$ . "' for an unspecified field");
+
+
+# Test searching on named custom fields
+$arts = RT::Articles->new($RT::SystemUser);
+$arts->LimitCustomField( OPERATOR => 'LIKE', VALUE => $$, FIELD => $cf->Name );
+is( $arts->Count, 2, "Found 1 Article with cf values matching '".$$."' for CF named " .$cf->Name);
+
+$arts = RT::Articles->new($RT::SystemUser);
+$arts->LimitCustomField( OPERATOR => 'LIKE', VALUE => $$, FIELD => 'NO-SUCH-CF' );
+is( $arts->Count,0, "Found no cf values matching '".$$."' for CF 'NO-SUCH-CF' " );
+
+$arts = RT::Articles->new($RT::SystemUser);
+$arts->Limit(FIELD =>'Class', VALUE => $class->id);
+
+$arts->LimitCustomField(
+ OPERATOR => 'NOT LIKE',
+ VALUE => 'blah',
+ FIELD => $cf->id
+);
+is(
+ $arts->Count ,2,
+ "Found 1 articles with custom field values not matching blah");
+
+$arts = RT::Articles->new($RT::SystemUser);
+$arts->Limit(FIELD =>'Class', VALUE => $class->id);
+$arts->LimitCustomField( OPERATOR => 'NOT LIKE', VALUE => 'est', FIELD => $cf->id );
+is( $arts->Count , 0, "Found 0 cf values not matching 'est' for CF ".$cf->id. " " . join(',', map {$_->id} @{$arts->ItemsArrayRef}));
+$arts = RT::Articles->new($RT::SystemUser);
+$arts->Limit(FIELD =>'Class', VALUE => $class->id);
+$arts->LimitCustomField( OPERATOR => 'NOT LIKE', VALUE => 'BOGUS', FIELD => $cf->id );
+is( $arts->Count , 2, "Found 2 articles not matching 'BOGUS' for CF ".$cf->id);
+
+my $ac = RT::Articles->new($RT::SystemUser);
+ok( $ac->isa('RT::Articles') );
+ok( $ac->isa('DBIx::SearchBuilder') );
+ok( $ac->LimitRefersTo('http://dead.link') );
+is( $ac->Count, 0 );
+
+$ac = RT::Articles->new($RT::SystemUser);
+ok( $ac->LimitReferredToBy('http://dead.link') );
+is( $ac->Count, 0 );
+
diff --git a/rt/t/articles/basic-api.t b/rt/t/articles/basic-api.t
new file mode 100644
index 000000000..f9f9f89f4
--- /dev/null
+++ b/rt/t/articles/basic-api.t
@@ -0,0 +1,114 @@
+#!/usr/bin/perl
+
+use warnings;
+use strict;
+
+use RT::Test tests => 37;
+
+use_ok('RT::Class');
+
+my $class = RT::Class->new($RT::SystemUser);
+isa_ok($class, 'RT::Class');
+isa_ok($class, 'RT::Record');
+isa_ok($class, 'RT::Record');
+
+
+my $name = 'test-'.$$;
+my ($id,$msg) = $class->Create( Name =>$name, Description => 'Test class');
+ok($id,$msg);
+is ($class->Name, $name);
+is ($class->Description, 'Test class');
+
+
+
+# Test custom fields.
+
+can_ok($class, 'CustomFields');
+can_ok($class, 'AddCustomFieldValue');
+can_ok($class, 'DeleteCustomFieldValue');
+can_ok($class, 'FirstCustomFieldValue');
+can_ok($class, 'CustomFieldValues');
+can_ok($class, 'CurrentUserHasRight');
+
+
+# Add a custom field to our class
+my $cf = RT::CustomField->new($RT::SystemUser);
+isa_ok($cf, 'RT::CustomField');
+
+($id,$msg) = $cf->Create( Name => 'Articles::Sample-'.$$,
+ Description => 'Test text cf',
+ LookupType => RT::Article->CustomFieldLookupType,
+ Type => 'Text'
+ );
+
+
+
+ok($id,$msg);
+
+
+($id,$msg) = $cf->AddToObject($class);
+ok ($id,$msg);
+
+
+# Does our class have a custom field?
+
+my $cfs = $class->ArticleCustomFields;
+isa_ok($cfs, 'RT::CustomFields');
+is($cfs->Count, 1, "We only have one custom field");
+my $found_cf = $cfs->First;
+is ($cf->id, $found_cf->id, "it's the right one");
+
+($id,$msg) = $cf->RemoveFromObject($class);
+
+is($class->ArticleCustomFields->Count, 0, "All gone!");
+
+# Put it back. we want to go forward.
+
+($id,$msg) = $cf->AddToObject($class);
+ok ($id,$msg);
+
+
+
+
+use_ok('RT::Article');
+
+my $art = RT::Article->new($RT::SystemUser);
+($id,$msg) =$art->Create(Class => $class->id,
+ Name => 'Sample'.$$,
+ Description => 'A sample article');
+
+ok($id,"Created article ".$id." - " .$msg);
+
+# make sure there is one transaction.
+
+my $txns = $art->Transactions;
+
+is($txns->Count, 1, "One txn");
+my $txn = $txns->First;
+is ($txn->ObjectType, 'RT::Article');
+is ($txn->ObjectId , $id , "It's the right article");
+is ($txn->Type, 'Create', "It's a create!");
+
+
+my $art_cfs = $art->CustomFields();
+is ($art_cfs->Count, 1, "It has a custom field");
+my $values = $art->CustomFieldValues($art_cfs->First);
+is ($values->Count, 0);
+
+$art->AddCustomFieldValue(Field => $cf->id, Value => 'Testing');
+$values = $art->CustomFieldValues($art_cfs->First->id);
+
+# We added the custom field
+is ($values->Count, 1);
+is ($values->First->Content, 'Testing', "We added the CF");
+
+is ($art->Transactions->Count,2, "We added a second transaction for the custom field addition");
+my $txn2 = $art->Transactions->Last;
+is ($txn2->ObjectId, $art->id);
+is ($txn2->id, ($txn->id +1));
+is ($txn2->Type, 'CustomField');
+is($txn2->NewValue, 'Testing');
+ok (!$txn2->OldValue, "It had no old value");
+
+1;
+
diff --git a/rt/t/articles/cfsearch.t b/rt/t/articles/cfsearch.t
new file mode 100644
index 000000000..49420e581
--- /dev/null
+++ b/rt/t/articles/cfsearch.t
@@ -0,0 +1,94 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 11;
+
+my $suffix = '-'. $$;
+
+use_ok 'RT::Class';
+use_ok 'RT::Article';
+use_ok 'RT::CustomField';
+
+my $classname = 'TestClass';
+my $class = RT::Class->new( $RT::SystemUser );
+{
+ $class->Load( $classname );
+ unless ( $class->Id ) {
+ my ($id, $msg) = $class->Create(
+ Name => $classname,
+ Description => 'class for cf tests',
+ );
+ ok $id, "created class '$classname' #$id"
+ or diag "error: $msg";
+ } else {
+ ok 1, "class '$classname' exists";
+ }
+}
+
+# create cf
+my $cfname = 'TestCF'. $suffix;
+my $cf = RT::CustomField->new( $RT::SystemUser );
+{
+ my ($id, $msg) = $cf->Create(
+ Name => $cfname,
+ LookupType => 'RT::Class-RT::Article',
+ Type => 'Select', MaxValues => 1,
+ Description => 'singleselect cf for tests',
+ );
+ ok $id, "created cf '$cfname' #$id"
+ or diag "error: $msg";
+}
+
+# attach cf to class
+{
+ my ($status, $msg) = $cf->AddToObject( $class );
+ ok $status, "attached the cf to the class"
+ or diag "error: $msg";
+}
+
+# create two cf-values
+{
+ my ($status, $msg) = $cf->AddValue( Name => 'Value1' );
+ ok $status, "added a value to the cf" or diag "error: $msg";
+
+ ($status, $msg) = $cf->AddValue( Name => 'Value2' );
+ ok $status, "added a value to the cf" or diag "error: $msg";
+}
+
+my $article1name = 'TestArticle1'.$suffix;
+my $article1 = RT::Article->new($RT::SystemUser);
+$article1->Create( Name => $article1name, Summary => 'Test', Class => $class->Id);
+$article1->AddCustomFieldValue(Field => $cf->Id, Value => 'Value1');
+
+my $article2name = 'TestArticle2'.$suffix;
+my $article2 = RT::Article->new($RT::SystemUser);
+$article2->Create( Name => $article2name, Summary => 'Test', Class => $class->Id);
+$article2->AddCustomFieldValue(Field => $cf->Id, Value => 'Value2');
+
+# search for articles containing 1st value
+{
+ my $articles = RT::Articles->new( $RT::SystemUser );
+ $articles->UnLimit;
+ $articles->Limit( FIELD => "Class", SUBCLAUSE => 'ClassMatch', VALUE => $class->Id);
+ $articles->LimitCustomField( FIELD => $cf->Id, VALUE => 'Value1' );
+ is $articles->Count, 1, 'found correct number of articles';
+}
+
+{
+ my $articles = RT::Articles->new($RT::SystemUser);
+ $articles->UnLimit;
+ $articles->Limit( FIELD => "Class", SUBCLAUSE => 'ClassMatch', VALUE => $class->Id);
+ $articles->LimitCustomField( FIELD => $cf, VALUE => 'Value1' );
+ is $articles->Count, 1, 'found correct number of articles';
+}
+
+{
+ my $articles = RT::Articles->new($RT::SystemUser);
+ $articles->UnLimit( );
+ $articles->Limit( FIELD => "Class", SUBCLAUSE => 'ClassMatch', VALUE => $class->Id);
+ $articles->LimitCustomField( FIELD => $cf->Name, VALUE => 'Value1' );
+ is $articles->Count, 1, 'found correct number of articles';
+}
+
diff --git a/rt/t/articles/class.t b/rt/t/articles/class.t
new file mode 100644
index 000000000..84d6e23be
--- /dev/null
+++ b/rt/t/articles/class.t
@@ -0,0 +1,76 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 24;
+
+use_ok 'RT::Articles';
+use_ok 'RT::Classes';
+use_ok 'RT::Class';
+
+my $root = RT::CurrentUser->new('root');
+ok ($root->Id, "Loaded root");
+my $cl = RT::Class->new($root);
+ok (UNIVERSAL::isa($cl, 'RT::Class'), "the new class is a class");
+
+my ($id, $msg) = $cl->Create(Name => 'Test-'.$$, Description => 'A test class');
+
+ok ($id, $msg);
+
+# no duplicate class names should be allowed
+($id, $msg) = $cl->Create(Name => 'Test-'.$$, Description => 'A test class');
+
+ok (!$id, $msg);
+
+#class name should be required
+
+($id, $msg) = $cl->Create(Name => '', Description => 'A test class');
+
+ok (!$id, $msg);
+
+
+
+$cl->Load('Test-'.$$);
+ok($cl->id, "Loaded the class we want");
+
+
+
+# Create a new user. make sure they can't create a class
+
+my $u= RT::User->new(RT->SystemUser);
+$u->Create(Name => "ArticlesTest".time, Privileged => 1);
+ok ($u->Id, "Created a new user");
+
+# Make sure you can't create a group with no acls
+$cl = RT::Class->new($u);
+ok (UNIVERSAL::isa($cl, 'RT::Class'), "the new class is a class");
+
+($id, $msg) = $cl->Create(Name => 'Test-nobody'.$$, Description => 'A test class');
+
+
+ok (!$id, $msg. "- Can not create classes as a random new user - " .$u->Id);
+$u->PrincipalObj->GrantRight(Right =>'AdminClass', Object => RT->System);
+($id, $msg) = $cl->Create(Name => 'Test-nobody-'.$$, Description => 'A test class');
+
+ok ($id, $msg. "- Can create classes as a random new user after ACL grant");
+
+# now check the Web UI
+
+my ($url, $m) = RT::Test->started_ok;
+ok($m->login);
+$m->get_ok("$url/Admin/Articles/Classes/Modify.html?Create=1");
+$m->content_contains('Create a Class', 'found title');
+$m->submit_form_ok({
+ form_number => 3,
+ fields => { Name => 'Test Redirect' },
+});
+$m->content_contains('Object created', 'found results');
+$m->content_contains('Modify the Class Test Redirect', 'found title');
+$m->form_number(3);
+$m->untick( 'Include-Name', 1 );
+$m->field( 'Description', 'Test Description' );
+$m->submit();
+$m->content_like(qr/Description changed from.*no value.*to .*Test Description/,'description changed');
+$m->form_number(3);
+is($m->current_form->find_input('Include-Name')->value,undef,'Disabled Including Names for this Class');
diff --git a/rt/t/articles/interface.t b/rt/t/articles/interface.t
new file mode 100644
index 000000000..d04be8b88
--- /dev/null
+++ b/rt/t/articles/interface.t
@@ -0,0 +1,221 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 53;
+
+use RT::CustomField;
+use RT::EmailParser;
+use RT::Queue;
+use RT::Ticket;
+use_ok 'RT::Class';
+use_ok 'RT::Topic';
+use_ok 'RT::Article';
+
+my ($url, $m) = RT::Test->started_ok;
+
+# Variables to test return values
+my ($ret, $msg);
+
+# Create a test class
+my $class = RT::Class->new($RT::SystemUser);
+($ret, $msg) = $class->Create('Name' => 'tlaTestClass-'.$$,
+ 'Description' => 'A general-purpose test class');
+ok($ret, "Test class created");
+my $class2 = RT::Class->new($RT::SystemUser);
+($ret, $msg) = $class2->Create('Name' => 'tlaTestClass2-'.$$,
+ 'Description' => 'Another general-purpose test class');
+ok($ret, "Test class 2 created");
+
+
+# Create a hierarchy of test topics
+my $topic1 = RT::Topic->new($RT::SystemUser);
+my $topic11 = RT::Topic->new($RT::SystemUser);
+my $topic12 = RT::Topic->new($RT::SystemUser);
+my $topic2 = RT::Topic->new($RT::SystemUser);
+my $topic_class2= RT::Topic->new($RT::SystemUser);
+my $gtopic = RT::Topic->new($RT::SystemUser);
+($ret, $msg) = $topic1->Create('Parent' => 0,
+ 'Name' => 'tlaTestTopic1-'.$$,
+ 'ObjectType' => 'RT::Class',
+ 'ObjectId' => $class->Id);
+ok($ret, "Topic 1 created");
+($ret, $msg) = $topic11->Create('Parent' => $topic1->Id,
+ 'Name' => 'tlaTestTopic1.1-'.$$,
+ 'ObjectType' => 'RT::Class',
+ 'ObjectId' => $class->Id);
+ok($ret, "Topic 1.1 created");
+($ret, $msg) = $topic12->Create('Parent' => $topic1->Id,
+ 'Name' => 'tlaTestTopic1.2-'.$$,
+ 'ObjectType' => 'RT::Class',
+ 'ObjectId' => $class->Id);
+ok($ret, "Topic 1.2 created");
+($ret, $msg) = $topic2->Create('Parent' => 0,
+ 'Name' => 'tlaTestTopic2-'.$$,
+ 'ObjectType' => 'RT::Class',
+ 'ObjectId' => $class->Id);
+ok($ret, "Topic 2 created");
+($ret, $msg) = $topic_class2->Create('Parent' => 0,
+ 'Name' => 'tlaTestTopicClass2-'.$$,
+ 'ObjectType' => 'RT::Class',
+ 'ObjectId' => $class2->Id);
+ok($ret, "Topic Class2 created");
+($ret, $msg) = $gtopic->Create('Parent' => 0,
+ 'Name' => 'tlaTestTopicGlobal-'.$$,
+ 'ObjectType' => 'RT::System',
+ 'ObjectId' => $RT::System->Id );
+ok($ret, "Global Topic created");
+
+# Create some article custom fields
+
+my $questionCF = RT::CustomField->new($RT::SystemUser);
+my $answerCF = RT::CustomField->new($RT::SystemUser);
+($ret, $msg) = $questionCF->Create('Name' => 'Question-'.$$,
+ 'Type' => 'Text',
+ 'MaxValues' => 1,
+ 'LookupType' => 'RT::Class-RT::Article',
+ 'Description' => 'The question to be answered',
+ 'Disabled' => 0);
+ok($ret, "Question CF created: $msg");
+($ret, $msg) = $answerCF->Create('Name' => 'Answer-'.$$,
+ 'Type' => 'Text',
+ 'MaxValues' => 1,
+ 'LookupType' => 'RT::Class-RT::Article',
+ 'Description' => 'The answer to the question',
+ 'Disabled' => 0);
+ok($ret, "Answer CF created: $msg");
+
+# Attach the custom fields to our class
+($ret, $msg) = $questionCF->AddToObject($class);
+ok($ret, "Question CF added to class: $msg");
+($ret, $msg) = $answerCF->AddToObject($class);
+ok($ret, "Answer CF added to class: $msg");
+my ($qid, $aid) = ($questionCF->Id, $answerCF->Id);
+
+my %cvals = ('article1q' => 'Some question about swallows',
+ 'article1a' => 'Some answer about Europe and Africa',
+ 'article2q' => 'Another question about Monty Python',
+ 'article2a' => 'Romani ite domum',
+ 'article3q' => 'Why should I eat my supper?',
+ 'article3a' => 'There are starving children in Africa',
+ 'article4q' => 'What did Brian originally write?',
+ 'article4a' => 'Romanes eunt domus');
+
+# Create an article or two with our custom field values.
+
+my $article1 = RT::Article->new($RT::SystemUser);
+my $article2 = RT::Article->new($RT::SystemUser);
+my $article3 = RT::Article->new($RT::SystemUser);
+my $article4 = RT::Article->new($RT::SystemUser);
+($ret, $msg) = $article1->Create(Name => 'First article '.$$,
+ Summary => 'blah blah 1',
+ Class => $class->Id,
+ Topics => [$topic1->Id],
+ "CustomField-$qid" => $cvals{'article1q'},
+ "CustomField-$aid" => $cvals{'article1a'},
+ );
+ok($ret, "article 1 created");
+($ret, $msg) = $article2->Create(Name => 'Second article '.$$,
+ Summary => 'foo bar 2',
+ Class => $class->Id,
+ Topics => [$topic11->Id],
+ "CustomField-$qid" => $cvals{'article2q'},
+ "CustomField-$aid" => $cvals{'article2a'},
+ );
+ok($ret, "article 2 created");
+($ret, $msg) = $article3->Create(Name => 'Third article '.$$,
+ Summary => 'ping pong 3',
+ Class => $class->Id,
+ Topics => [$topic12->Id],
+ "CustomField-$qid" => $cvals{'article3q'},
+ "CustomField-$aid" => $cvals{'article3a'},
+ );
+ok($ret, "article 3 created");
+($ret, $msg) = $article4->Create(Name => 'Fourth article '.$$,
+ Summary => 'hoi polloi 4',
+ Class => $class->Id,
+ Topics => [$topic2->Id],
+ "CustomField-$qid" => $cvals{'article4q'},
+ "CustomField-$aid" => $cvals{'article4a'},
+ );
+ok($ret, "article 4 created");
+
+# Create a ticket.
+my $parser = RT::EmailParser->new();
+$parser->ParseMIMEEntityFromScalar('From: root@localhost
+To: rt@example.com
+Subject: test ticket for articles
+
+This is some form of new request.
+May as well say something about Africa.');
+
+my $ticket = RT::Ticket->new($RT::SystemUser);
+my $obj;
+($ret, $obj, $msg) = $ticket->Create(Queue => 'General',
+ Subject => 'test ticket for articles '.$$,
+ MIMEObj => $parser->Entity);
+ok($ret, "Test ticket for articles created: $msg");
+
+
+#### Right. That's our data. Now begin the real testing.
+
+isa_ok($m, 'Test::WWW::Mechanize');
+ok($m->login, 'logged in');
+$m->follow_link_ok( { text => 'Articles', url_regex => qr!^/Articles/! },
+ 'UI -> Articles' );
+
+$m->content_contains($article3->Name);
+$m->follow_link_ok( {text => $article3->Name}, 'Articles -> '. $article3->Name );
+$m->title_is("Article #" . $article3->Id . ": " . $article3->Name);
+$m->follow_link_ok( { text => 'Modify'}, 'Article -> Modify' );
+
+{
+$m->content_like(qr/Refers to/, "found links edit box");
+my $ticket_id = $ticket->Id;
+my $turi = "t:$ticket_id";
+my $a1uri = 'a:'.$article1->Id;
+$m->submit_form(form_name => 'EditArticle',
+ fields => { $article3->Id.'-RefersTo' => $turi,
+ 'RefersTo-'.$article3->Id => $a1uri }
+ );
+
+$m->content_like(qr/Ticket.*$ticket_id/, "Ticket linkto was created");
+$m->content_like(qr/URI.*$a1uri/, "Article linkfrom was created");
+}
+
+# Now try to extract an article from a link.
+$m->get_ok($url."/Ticket/Display.html?id=".$ticket->Id,
+ "Loaded ticket display");
+$m->content_like(qr/Extract Article/, "Article extraction link shows up");
+$m->follow_link_ok( { text => 'Extract Article' }, '-> Extract Article' );
+$m->content_contains($class->Name);
+$m->follow_link_ok( { text => $class->Name }, 'Extract Article -> '. $class->Name );
+$m->content_like(qr/Select topics for this article/i, 'selecting topic');
+$m->form_number(3);
+$m->set_visible([option => $topic1->Name]);
+$m->submit;
+$m->form_number(3);
+$m->set_visible([option => $answerCF->Name]);
+$m->click();
+$m->title_like(qr/Create a new article/, "got edit page from extraction");
+$m->submit_form(form_name => 'EditArticle');
+$m->title_like(qr/Modify article/);
+$m->follow_link_ok( { text => 'Display' }, '-> Display' );
+$m->content_like(qr/Africa/, "Article content exist");
+$m->content_contains($ticket->Subject,
+ "Article references originating ticket");
+
+diag("Test creating a ticket in Class2 and make sure we don't see Class1 Topics") if $ENV{TEST_VERBOSE};
+{
+$m->follow_link_ok( { text => 'Articles', url_regex => qr!^/Articles/! },
+ 'UI -> Articles' );
+$m->follow_link_ok( {text => 'New Article' }, 'Articles -> New Article' );
+$m->follow_link_ok( {text => 'in class '.$class2->Name }, 'New Article -> in class '.$class2->Name );
+$m->content_lacks( $topic1->Name, "Topic1 from Class1 isn't shown" );
+$m->content_lacks( $topic11->Name, "Topic11 from Class1 isn't shown" );
+$m->content_lacks( $topic12->Name, "Topic12 from Class1 isn't shown" );
+$m->content_lacks( $topic2->Name, "Topic2 from Class1 isn't shown" );
+$m->content_contains( $gtopic->Name, "Global Topic is shown" );
+$m->content_contains( $topic_class2->Name, "Class2 topic is shown" );
+}
diff --git a/rt/t/articles/queue-specific-class.t b/rt/t/articles/queue-specific-class.t
new file mode 100644
index 000000000..a73d583c3
--- /dev/null
+++ b/rt/t/articles/queue-specific-class.t
@@ -0,0 +1,218 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 56;
+
+my ( $url, $m ) = RT::Test->started_ok;
+$m->login;
+
+my %class = map { $_ => '' } qw/foo bar/;
+
+diag "create classes foo and bar" if $ENV{TEST_VERBOSE};
+
+for my $name ( keys %class ) {
+ $m->get_ok( '/Admin/Articles/Classes/Modify.html?Create=1',
+ 'class create page' );
+
+ $m->submit_form(
+ form_number => 3,
+ fields => { Name => $name, HotList => 1 },
+ );
+
+ $m->content_contains( "Modify the Class $name",
+ 'created class $name' );
+ my ($id) = ( $m->content =~ /name="id" value="(\d+)"/ );
+ ok( $id, "id of $name" );
+ $class{$name} = $id;
+}
+
+diag "create articles in foo and bar" if $ENV{TEST_VERBOSE};
+
+for my $name ( keys %class ) {
+ $m->get_ok( '/Articles/Article/Edit.html?Class=' . $class{$name},
+ 'article create page' );
+
+ $m->submit_form(
+ form_number => 3,
+ fields => { Name => "article $name" }
+ );
+
+ $m->content_like( qr/Article \d+ created/, "created article $name" );
+}
+
+diag "apply foo to queue General" if $ENV{TEST_VERBOSE};
+{
+ $m->get_ok( '/Admin/Articles/Classes/Objects.html?id=' . $class{foo},
+ 'apply page' );
+ $m->submit_form(
+ form_number => 3,
+ fields => { 'AddClass-' . $class{foo} => 1 },
+ button => 'UpdateObjs',
+ );
+ $m->content_contains( 'Object created', 'applied foo to General' );
+}
+
+my $ticket_id;
+
+diag "create ticket in General" if $ENV{TEST_VERBOSE};
+
+{
+ $m->get_ok( '/Ticket/Create.html?Queue=1', 'ticket create page' );
+ $m->submit_form(
+ form_number => 3,
+ fields => { 'Subject' => 'test article', Content => 'test article' },
+ );
+ ($ticket_id) = ( $m->content =~ /Ticket \d+ created/ );
+ ok( $ticket_id, "id of ticket: $ticket_id" );
+}
+
+diag "update ticket to see if there is article foo"
+ if $ENV{TEST_VERBOSE};
+
+{
+ $m->get_ok( '/Ticket/Update.html?Action=Comment&id=' . $ticket_id,
+ 'ticket update page' );
+ $m->content_contains( 'article foo:', 'got article foo in hotlist' );
+ $m->content_lacks( 'article bar:', 'no article bar in hotlist' );
+
+ $m->submit_form(
+ form_number => 3,
+ fields => { 'Articles_Content' => 'article' },
+ button => 'Go',
+ );
+ $m->content_like( qr/article foo.*article foo/s, 'selected article foo' );
+ $m->content_lacks( 'article bar', 'no article bar' );
+
+ $m->get_ok( '/Ticket/Update.html?Action=Comment&id=' . $ticket_id,
+ 'ticket update page' );
+ $m->submit_form(
+ form_number => 3,
+ fields => { 'Articles-Include-Article-Named' => 'article foo' },
+ button => 'Go',
+ );
+ $m->content_like( qr/article foo.*article foo/s, 'selected article foo' );
+ $m->content_lacks( 'article bar', 'no article bar' );
+
+ $m->get_ok( '/Ticket/Update.html?Action=Comment&id=' . $ticket_id,
+ 'ticket update page' );
+ $m->submit_form(
+ form_number => 3,
+ fields => { 'Articles-Include-Article-Named' => 'articlei bar' },
+ button => 'Go',
+ );
+ $m->content_unlike( qr/article foo.*article foo/s, 'no article foo' );
+ $m->content_lacks( 'article bar', 'no article bar' );
+}
+
+diag "apply bar to globally" if $ENV{TEST_VERBOSE};
+{
+ $m->get_ok( '/Admin/Articles/Classes/Objects.html?id=' . $class{bar},
+ 'apply page' );
+ $m->submit_form(
+ form_number => 3,
+ fields => { 'AddClass-' . $class{bar} => 0 },
+ button => 'UpdateObjs',
+ );
+ $m->content_contains( 'Object created', 'applied bar globally' );
+}
+
+diag "update ticket to see if there are both article foo and bar"
+ if $ENV{TEST_VERBOSE};
+
+{
+ $m->get_ok( '/Ticket/Update.html?Action=Comment&id=' . $ticket_id,
+ 'ticket update page' );
+ $m->content_contains( 'article foo:', 'got article foo in hotlist' );
+ $m->content_contains( 'article bar:', 'got article bar in hotlist' );
+
+ $m->submit_form(
+ form_number => 3,
+ fields => { 'Articles_Content' => 'article' },
+ button => 'Go',
+ );
+ $m->content_like( qr/article foo.*article foo/s, 'selected article foo' );
+ $m->content_like( qr/article bar.*article bar/s, 'selected article bar' );
+
+ $m->get_ok( '/Ticket/Update.html?Action=Comment&id=' . $ticket_id,
+ 'ticket update page' );
+ $m->submit_form(
+ form_number => 3,
+ fields => { 'Articles-Include-Article-Named' => 'article foo' },
+ button => 'Go',
+ );
+ $m->content_like( qr/article foo.*article foo/s, 'selected article foo' );
+ $m->content_unlike( qr/article bar.*article bar/s, 'no article bar' );
+
+ $m->get_ok( '/Ticket/Update.html?Action=Comment&id=' . $ticket_id,
+ 'ticket update page' );
+ $m->submit_form(
+ form_number => 3,
+ fields => { 'Articles-Include-Article-Named' => 'article bar' },
+ button => 'Go',
+ );
+ $m->content_like( qr/article bar.*article bar/s, 'selected article bar' );
+ $m->content_unlike( qr/article foo.*article foo/s, 'no article foo' );
+}
+
+
+diag "remove both foo and bar" if $ENV{TEST_VERBOSE};
+{
+ $m->get_ok( '/Admin/Articles/Classes/Objects.html?id=' . $class{foo},
+ 'apply page' );
+ $m->submit_form(
+ form_number => 3,
+ fields => { 'RemoveClass-' . $class{foo} => 1 },
+ button => 'UpdateObjs',
+ );
+ $m->content_contains( 'Object deleted', 'removed foo' );
+
+ $m->get_ok( '/Admin/Articles/Classes/Objects.html?id=' . $class{bar},
+ 'apply page' );
+ $m->submit_form(
+ form_number => 3,
+ fields => { 'RemoveClass-' . $class{bar} => 0 },
+ button => 'UpdateObjs',
+ );
+ $m->content_contains( 'Object deleted', 'remoked bar' );
+}
+
+diag "update ticket to see if there are both article foo and bar"
+ if $ENV{TEST_VERBOSE};
+
+{
+ $m->get_ok( '/Ticket/Update.html?Action=Comment&id=' . $ticket_id,
+ 'ticket update page' );
+ $m->content_lacks( 'article foo:', 'no article foo in hotlist' );
+ $m->content_lacks( 'article bar:', 'no article bar in hotlist' );
+
+ $m->submit_form(
+ form_number => 3,
+ fields => { 'Articles_Content' => 'article' },
+ button => 'Go',
+ );
+ $m->content_lacks( 'article foo', 'no article foo' );
+ $m->content_lacks( 'article bar', 'no article bar' );
+
+ $m->get_ok( '/Ticket/Update.html?Action=Comment&id=' . $ticket_id,
+ 'ticket update page' );
+ $m->submit_form(
+ form_number => 3,
+ fields => { 'Articles-Include-Article-Named' => 'article foo' },
+ button => 'Go',
+ );
+ $m->content_lacks( 'article foo', 'no article foo' );
+ $m->content_lacks( 'article bar', 'no article bar' );
+
+ $m->get_ok( '/Ticket/Update.html?Action=Comment&id=' . $ticket_id,
+ 'ticket update page' );
+ $m->submit_form(
+ form_number => 3,
+ fields => { 'Articles-Include-Article-Named' => 'article bar' },
+ button => 'Go',
+ );
+ $m->content_lacks( 'article foo', 'no article foo' );
+ $m->content_lacks( 'article bar', 'no article bar' );
+}
+
diff --git a/rt/t/articles/search-interface.t b/rt/t/articles/search-interface.t
new file mode 100644
index 000000000..eb3a4f763
--- /dev/null
+++ b/rt/t/articles/search-interface.t
@@ -0,0 +1,113 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 23;
+
+use RT::CustomField;
+use RT::Queue;
+use RT::Ticket;
+use_ok 'RT::Class';
+use_ok 'RT::Topic';
+use_ok 'RT::Article';
+
+my ($url, $m) = RT::Test->started_ok;
+
+# Variables to test return values
+my ($ret, $msg);
+
+# Create a test class
+my $class = RT::Class->new($RT::SystemUser);
+($ret, $msg) = $class->Create('Name' => 'tlaTestClass-'.$$,
+ 'Description' => 'A general-purpose test class');
+ok($ret, "Test class created");
+
+
+my $questionCF = RT::CustomField->new($RT::SystemUser);
+my $answerCF = RT::CustomField->new($RT::SystemUser);
+my $ticketCF = RT::CustomField->new($RT::SystemUser);
+($ret, $msg) = $questionCF->Create('Name' => 'Question-'.$$,
+ 'Type' => 'Text',
+ 'MaxValues' => 1,
+ 'LookupType' => 'RT::Class-RT::Article',
+ 'Description' => 'The question to be answered',
+ 'Disabled' => 0);
+ok($ret, "Question CF created: $msg");
+($ret, $msg) = $answerCF->Create('Name' => 'Answer-'.$$,
+ 'Type' => 'Text',
+ 'MaxValues' => 1,
+ 'LookupType' => 'RT::Class-RT::Article',
+ 'Description' => 'The answer to the question',
+ 'Disabled' => 0);
+ok($ret, "Answer CF created: $msg");
+
+($ret, $msg) = $ticketCF->Create('Name' => 'Class',
+ 'Type' => 'Text',
+ 'MaxValues' => 1,
+ 'LookupType' => 'RT::Queue-RT::Ticket',
+ 'Disabled' => 0);
+ok($ret, "Ticket CF 'Class' created: $msg");
+
+# Attach the custom fields to our class
+($ret, $msg) = $questionCF->AddToObject($class);
+ok($ret, "Question CF added to class: $msg");
+($ret, $msg) = $answerCF->AddToObject($class);
+ok($ret, "Answer CF added to class: $msg");
+my ($qid, $aid) = ($questionCF->Id, $answerCF->Id);
+
+my $global_queue = RT::Queue->new($RT::SystemUser);
+($ret, $msg) = $ticketCF->AddToObject($global_queue);
+ok($ret, "Ticket CF added globally: $msg");
+
+my %cvals = ('article1q' => 'Some question about swallows',
+ 'article1a' => 'Some answer about Europe and Africa',
+ 'article2q' => 'Another question about Monty Python',
+ 'article2a' => 'Romani ite domum',
+ 'article3q' => 'Why should I eat my supper?',
+ 'article3a' => 'There are starving children in Africa',
+ 'article4q' => 'What did Brian originally write?',
+ 'article4a' => 'Romanes eunt domus');
+
+# Create an article or two with our custom field values.
+
+my $article1 = RT::Article->new($RT::SystemUser);
+my $article2 = RT::Article->new($RT::SystemUser);
+my $article3 = RT::Article->new($RT::SystemUser);
+my $article4 = RT::Article->new($RT::SystemUser);
+($ret, $msg) = $article1->Create(Name => 'First article '.$$,
+ Summary => 'blah blah 1',
+ Class => $class->Id,
+ "CustomField-$qid" => $cvals{'article1q'},
+ "CustomField-$aid" => $cvals{'article1a'},
+ );
+ok($ret, "article 1 created");
+($ret, $msg) = $article2->Create(Name => 'Second article '.$$,
+ Summary => 'foo bar 2',
+ Class => $class->Id,
+ "CustomField-$qid" => $cvals{'article2q'},
+ "CustomField-$aid" => $cvals{'article2a'},
+ );
+ok($ret, "article 2 created");
+($ret, $msg) = $article3->Create(Name => 'Third article '.$$,
+ Summary => 'ping pong 3',
+ Class => $class->Id,
+ "CustomField-$qid" => $cvals{'article3q'},
+ "CustomField-$aid" => $cvals{'article3a'},
+ );
+ok($ret, "article 3 created");
+($ret, $msg) = $article4->Create(Name => 'Fourth article '.$$,
+ Summary => 'hoi polloi 4',
+ Class => $class->Id,
+ "CustomField-$qid" => $cvals{'article4q'},
+ "CustomField-$aid" => $cvals{'article4a'},
+ );
+ok($ret, "article 4 created");
+
+isa_ok($m, 'Test::WWW::Mechanize');
+ok($m->login, 'logged in');
+$m->follow_link_ok( { text => 'Articles', url_regex => qr!^/Articles/! },
+ 'UI -> Articles' );
+$m->follow_link_ok( {text => 'Search'}, 'Articles -> Search');
+$m->follow_link_ok( {text => 'in class '.$class->Name}, 'Articles in class '.$class->Name);
+$m->content_contains($article1->Name);
diff --git a/rt/t/articles/upload-customfields.t b/rt/t/articles/upload-customfields.t
new file mode 100644
index 000000000..912c23ded
--- /dev/null
+++ b/rt/t/articles/upload-customfields.t
@@ -0,0 +1,90 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 20;
+
+use RT;
+my $logo;
+BEGIN {
+ $logo =
+ -e $RT::MasonComponentRoot . '/NoAuth/images/bpslogo.png'
+ ? 'bpslogo.png'
+ : 'bplogo.gif';
+}
+
+use constant ImageFile => $RT::MasonComponentRoot . "/NoAuth/images/$logo";
+
+use constant ImageFileContent => do {
+ local $/;
+ open my $fh, '<', ImageFile or die ImageFile.$!;
+ binmode($fh);
+ scalar <$fh>;
+};
+
+use RT::Class;
+my $class = RT::Class->new($RT::SystemUser);
+my ($ret, $msg) = $class->Create('Name' => 'tlaTestClass-'.$$,
+ 'Description' => 'A general-purpose test class');
+ok($ret, "Test class created");
+
+
+my ($url, $m) = RT::Test->started_ok;
+isa_ok($m, 'Test::WWW::Mechanize');
+ok($m->login, 'logged in');
+$m->follow_link_ok( { text => 'Configuration' } );
+$m->title_is(q/RT Administration/, 'admin screen');
+$m->follow_link_ok( { text => 'Custom Fields' } );
+$m->title_is(q/Select a Custom Field/, 'admin-cf screen');
+$m->follow_link_ok( { text => 'Create', url_regex => qr{^/Admin/CustomFields/} } );
+$m->submit_form(
+ form_name => "ModifyCustomField",
+ fields => {
+ TypeComposite => 'Image-0',
+ LookupType => 'RT::Class-RT::Article',
+ Name => 'img'.$$,
+ Description => 'img',
+ },
+);
+$m->title_is(qq/Editing CustomField img$$/, 'admin-cf created');
+$m->follow_link( text => 'Applies to' );
+$m->title_is(qq/Modify associated objects for img$$/, 'pick cf screenadmin screen');
+$m->form_number(3);
+
+my $tcf = (grep { /AddCustomField-/ } map { $_->name } $m->current_form->inputs )[0];
+$m->tick( $tcf, 0 ); # Associate the new CF with this queue
+$m->click('UpdateObjs');
+$m->content_like( qr/Object created/, 'TCF added to the queue' );
+
+$m->follow_link_ok( { text => 'Articles', url_regex => qr!^/Articles/! },
+ 'UI -> Articles' );
+$m->follow_link( text => 'New Article');
+
+$m->follow_link( url_regex => qr/Edit.html\?Class=1/ );
+$m->title_is(qq/Create a new article/);
+
+$m->content_like(qr/Upload multiple images/, 'has a upload image field');
+
+$tcf =~ /(\d+)$/ or die "Hey this is impossible dude";
+my $upload_field = "Object-RT::Article--CustomField-$1-Upload";
+
+diag("Uploading an image to $upload_field") if $ENV{TEST_VERBOSE};
+
+$m->submit_form(
+ form_name => "EditArticle",
+ fields => {
+ $upload_field => ImageFile,
+ Name => 'Image Test '.$$,
+ Summary => 'testing img cf creation',
+ },
+);
+
+$m->content_like(qr/Article \d+ created/, "an article was created succesfully");
+
+my $id = $1 if $m->content =~ /Article (\d+) created/;
+
+$m->title_like(qr/Modify article #$id/, "Editing article $id");
+
+$m->follow_link( text => $logo );
+$m->content_is(ImageFileContent, "it links to the uploaded image");
diff --git a/rt/t/articles/uri-a.t b/rt/t/articles/uri-a.t
new file mode 100644
index 000000000..82d0f1b01
--- /dev/null
+++ b/rt/t/articles/uri-a.t
@@ -0,0 +1,28 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 7;
+
+use_ok("RT::URI::a");
+my $uri = RT::URI::a->new($RT::SystemUser);
+ok(ref($uri), "URI object exists");
+
+my $class = RT::Class->new( $RT::SystemUser );
+$class->Create( Name => 'URItest - '. $$ );
+ok $class->id, 'created a class';
+my $article = RT::Article->new( $RT::SystemUser );
+my ($id, $msg) = $article->Create(
+ Name => 'Testing URI parsing - '. $$,
+ Summary => 'In which this should load',
+ Class => $class->Id
+);
+ok($id,$msg);
+
+my $uristr = "a:" . $article->Id;
+$uri->ParseURI($uristr);
+is(ref($uri->Object), "RT::Article", "Object loaded is an article");
+is($uri->Object->Id, $article->Id, "Object loaded has correct ID");
+is($article->URI, 'fsck.com-article://example.com/article/'.$article->Id,
+ "URI object has correct URI string");
diff --git a/rt/t/articles/uri-articles.t b/rt/t/articles/uri-articles.t
new file mode 100644
index 000000000..4124b1942
--- /dev/null
+++ b/rt/t/articles/uri-articles.t
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 9;
+
+use_ok "RT::URI::fsck_com_article";
+my $uri = RT::URI::fsck_com_article->new( $RT::SystemUser );
+
+ok $uri;
+isa_ok $uri, 'RT::URI::fsck_com_article';
+isa_ok $uri, 'RT::URI::base';
+isa_ok $uri, 'RT::Base';
+
+is $uri->LocalURIPrefix, 'fsck.com-article://example.com/article/';
+
+my $class = RT::Class->new( $RT::SystemUser );
+$class->Create( Name => 'URItest - '. $$ );
+ok $class->id, 'created a class';
+my $article = RT::Article->new( $RT::SystemUser );
+my ($id, $msg) = $article->Create(
+ Name => 'Testing URI parsing - '. $$,
+ Summary => 'In which this should load',
+ Class => $class->Id
+);
+ok($id,$msg);
+
+$uri = RT::URI::fsck_com_article->new( $article->CurrentUser );
+is $uri->LocalURIPrefix . $article->id, $uri->URIForObject( $article );
+
diff --git a/rt/t/customfields/access_via_queue.t b/rt/t/customfields/access_via_queue.t
index c291860ea..690e177df 100644
--- a/rt/t/customfields/access_via_queue.t
+++ b/rt/t/customfields/access_via_queue.t
@@ -3,7 +3,7 @@
use strict;
use warnings;
-use RT::Test tests => 35;
+use RT::Test nodata => 1, tests => 37;
use RT::Ticket;
use RT::CustomField;
@@ -11,11 +11,11 @@ my $queue_name = "CFSortQueue-$$";
my $queue = RT::Test->load_or_create_queue( Name => $queue_name );
ok($queue && $queue->id, "$queue_name - test queue creation");
-diag "create a CF\n" if $ENV{TEST_VERBOSE};
+diag "create a CF";
my $cf_name = "Rights$$";
my $cf;
{
- $cf = RT::CustomField->new( $RT::SystemUser );
+ $cf = RT::CustomField->new( RT->SystemUser );
my ($ret, $msg) = $cf->Create(
Name => $cf_name,
Queue => $queue->id,
@@ -98,7 +98,7 @@ ok( RT::Test->set_rights(
my ($baseurl, $m) = RT::Test->started_ok;
ok $m->login( tester => 'password' ), 'logged in';
-diag "check that we have no the CF on the create" if $ENV{'TEST_VERBOSE'};
+diag "check that we don't have the cf on create";
{
$m->submit_form(
form_name => "CreateTicketInQueue",
@@ -115,46 +115,46 @@ diag "check that we have no the CF on the create" if $ENV{'TEST_VERBOSE'};
);
my ($tid) = ($m->content =~ /Ticket (\d+) created/i);
ok $tid, "created a ticket succesfully";
- $m->content_unlike(qr/$cf_name/, "don't see CF");
+ $m->content_lacks($cf_name, "don't see CF");
- $m->follow_link( text => 'Custom Fields' );
- $form = $m->form_number(3);
+ $m->follow_link( id => 'page-basics');
+ $form = $m->form_name('TicketModify');
$cf_field = "Object-RT::Ticket-$tid-CustomField-". $cf->id ."-Value";
ok !$form->find_input( $cf_field ), 'no form field on the page';
}
-diag "check that we see CF as Cc" if $ENV{'TEST_VERBOSE'};
+diag "check that we see CF as Cc";
{
my $ticket = RT::Ticket->new( $tester );
my ($tid, $msg) = $ticket->Create( Queue => $queue, Subject => 'test', Cc => $tester->id );
ok $tid, "created ticket";
ok $m->goto_ticket( $tid ), "opened ticket";
- $m->content_like(qr/$cf_name/, "see CF");
+ $m->content_contains($cf_name, "see CF");
}
-diag "check that owner can see and edit CF" if $ENV{'TEST_VERBOSE'};
+diag "check that owner can see and edit CF";
{
my $ticket = RT::Ticket->new( $tester );
my ($tid, $msg) = $ticket->Create( Queue => $queue, Subject => 'test', Cc => $tester->id, Owner => $tester->id );
ok $tid, "created ticket";
ok $m->goto_ticket( $tid ), "opened ticket";
- $m->content_like(qr/$cf_name/, "see CF");
+ $m->content_contains($cf_name, "see CF");
- $m->follow_link( text => 'Custom Fields' );
- my $form = $m->form_number(3);
+ $m->follow_link( id => 'page-basics');
+ my $form = $m->form_name('TicketModify');
my $cf_field = "Object-RT::Ticket-$tid-CustomField-". $cf->id ."-Value";
ok $form->find_input( $cf_field ), 'form field on the page';
$m->submit_form(
- form_number => 3,
+ form_name => 'TicketModify',
fields => {
$cf_field => "changed cf",
},
);
ok $m->goto_ticket( $tid ), "opened ticket";
- $m->content_like(qr/$cf_name/, "changed cf");
+ $m->content_contains($cf_name, "changed cf");
}
diff --git a/rt/t/customfields/api.t b/rt/t/customfields/api.t
new file mode 100644
index 000000000..d739a572d
--- /dev/null
+++ b/rt/t/customfields/api.t
@@ -0,0 +1,221 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings FATAL => 'all';
+
+use RT::Test nodata => 1, tests => 139;
+
+# Before we get going, ditch all object_cfs; this will remove
+# all custom fields systemwide;
+my $object_cfs = RT::ObjectCustomFields->new(RT->SystemUser);
+$object_cfs->UnLimit();
+while (my $ocf = $object_cfs->Next) {
+ $ocf->Delete();
+}
+
+
+my $queue = RT::Queue->new( RT->SystemUser );
+$queue->Create( Name => 'RecordCustomFields-'.$$ );
+ok ($queue->id, "Created the queue");
+
+my $queue2 = RT::Queue->new( RT->SystemUser );
+$queue2->Create( Name => 'RecordCustomFields2' );
+
+my $ticket = RT::Ticket->new( RT->SystemUser );
+$ticket->Create(
+ Queue => $queue->Id,
+ Requestor => 'root@localhost',
+ Subject => 'RecordCustomFields1',
+);
+
+my $cfs = $ticket->CustomFields;
+is( $cfs->Count, 0 );
+
+# Check that record has no any CF values yet {{{
+my $cfvs = $ticket->CustomFieldValues;
+is( $cfvs->Count, 0 );
+is( $ticket->FirstCustomFieldValue, undef );
+
+my $local_cf1 = RT::CustomField->new( RT->SystemUser );
+$local_cf1->Create( Name => 'RecordCustomFields1-'.$$, Type => 'SelectSingle', Queue => $queue->id );
+$local_cf1->AddValue( Name => 'RecordCustomFieldValues11' );
+$local_cf1->AddValue( Name => 'RecordCustomFieldValues12' );
+
+my $local_cf2 = RT::CustomField->new( RT->SystemUser );
+$local_cf2->Create( Name => 'RecordCustomFields2-'.$$, Type => 'SelectSingle', Queue => $queue->id );
+$local_cf2->AddValue( Name => 'RecordCustomFieldValues21' );
+$local_cf2->AddValue( Name => 'RecordCustomFieldValues22' );
+
+my $global_cf3 = RT::CustomField->new( RT->SystemUser );
+$global_cf3->Create( Name => 'RecordCustomFields3-'.$$, Type => 'SelectSingle', Queue => 0 );
+$global_cf3->AddValue( Name => 'RecordCustomFieldValues31' );
+$global_cf3->AddValue( Name => 'RecordCustomFieldValues32' );
+
+my $local_cf4 = RT::CustomField->new( RT->SystemUser );
+$local_cf4->Create( Name => 'RecordCustomFields4', Type => 'SelectSingle', Queue => $queue2->id );
+$local_cf4->AddValue( Name => 'RecordCustomFieldValues41' );
+$local_cf4->AddValue( Name => 'RecordCustomFieldValues42' );
+
+
+my @custom_fields = ($local_cf1, $local_cf2, $global_cf3);
+
+
+$cfs = $ticket->CustomFields;
+is( $cfs->Count, 3 );
+
+# Check that record has no any CF values yet {{{
+$cfvs = $ticket->CustomFieldValues;
+is( $cfvs->Count, 0 );
+is( $ticket->FirstCustomFieldValue, undef );
+
+# CF with ID -1 shouldnt exist at all
+$cfvs = $ticket->CustomFieldValues( -1 );
+is( $cfvs->Count, 0 );
+is( $ticket->FirstCustomFieldValue( -1 ), undef );
+
+$cfvs = $ticket->CustomFieldValues( 'SomeUnexpedCustomFieldName' );
+is( $cfvs->Count, 0 );
+is( $ticket->FirstCustomFieldValue( 'SomeUnexpedCustomFieldName' ), undef );
+
+for (@custom_fields) {
+ $cfvs = $ticket->CustomFieldValues( $_->id );
+ is( $cfvs->Count, 0 );
+
+ $cfvs = $ticket->CustomFieldValues( $_->Name );
+ is( $cfvs->Count, 0 );
+ is( $ticket->FirstCustomFieldValue( $_->id ), undef );
+ is( $ticket->FirstCustomFieldValue( $_->Name ), undef );
+}
+
+# try to add field value with fields that do not exist {{{
+my ($status, $msg) = $ticket->AddCustomFieldValue( Field => -1 , Value => 'foo' );
+ok(!$status, "shouldn't add value" );
+($status, $msg) = $ticket->AddCustomFieldValue( Field => 'SomeUnexpedCustomFieldName' , Value => 'foo' );
+ok(!$status, "shouldn't add value" );
+
+SKIP: {
+
+ skip "TODO: We want fields that are not allowed to set unexpected values", 10;
+ for (@custom_fields) {
+ ($status, $msg) = $ticket->AddCustomFieldValue( Field => $_ , Value => 'SomeUnexpectedCFValue' );
+ ok( !$status, 'value doesn\'t exist');
+
+ ($status, $msg) = $ticket->AddCustomFieldValue( Field => $_->id , Value => 'SomeUnexpectedCFValue' );
+ ok( !$status, 'value doesn\'t exist');
+
+ ($status, $msg) = $ticket->AddCustomFieldValue( Field => $_->Name , Value => 'SomeUnexpectedCFValue' );
+ ok( !$status, 'value doesn\'t exist');
+ }
+
+ # Let check that we did not add value to be sure
+ # using only FirstCustomFieldValue sub because
+ # we checked other variants allready
+ for (@custom_fields) {
+ is( $ticket->FirstCustomFieldValue( $_->id ), undef );
+ }
+
+}
+# Add some values to our custom fields
+for (@custom_fields) {
+ # this should be tested elsewhere
+ $_->AddValue( Name => 'Foo' );
+ $_->AddValue( Name => 'Bar' );
+}
+
+my $test_add_delete_cycle = sub {
+ my $cb = shift;
+ for (@custom_fields) {
+ ($status, $msg) = $ticket->AddCustomFieldValue( Field => $cb->($_) , Value => 'Foo' );
+ ok( $status, "message: $msg");
+ }
+
+ # does it exist?
+ $cfvs = $ticket->CustomFieldValues;
+ is( $cfvs->Count, 3, "We found all three custom fields on our ticket" );
+ for (@custom_fields) {
+ $cfvs = $ticket->CustomFieldValues( $_->id );
+ is( $cfvs->Count, 1 , "we found one custom field when searching by id");
+
+ $cfvs = $ticket->CustomFieldValues( $_->Name );
+ is( $cfvs->Count, 1 , " We found one custom field when searching by name for " . $_->Name);
+ is( $ticket->FirstCustomFieldValue( $_->id ), 'Foo' , "first value by id is foo");
+ is( $ticket->FirstCustomFieldValue( $_->Name ), 'Foo' , "first value by name is foo");
+ }
+ # because our CFs are SingleValue then new value addition should override
+ for (@custom_fields) {
+ ($status, $msg) = $ticket->AddCustomFieldValue( Field => $_ , Value => 'Bar' );
+ ok( $status, "message: $msg");
+ }
+ $cfvs = $ticket->CustomFieldValues;
+ is( $cfvs->Count, 3 );
+ for (@custom_fields) {
+ $cfvs = $ticket->CustomFieldValues( $_->id );
+ is( $cfvs->Count, 1 );
+
+ $cfvs = $ticket->CustomFieldValues( $_->Name );
+ is( $cfvs->Count, 1 );
+ is( $ticket->FirstCustomFieldValue( $_->id ), 'Bar' );
+ is( $ticket->FirstCustomFieldValue( $_->Name ), 'Bar' );
+ }
+ # delete it
+ for (@custom_fields ) {
+ ($status, $msg) = $ticket->DeleteCustomFieldValue( Field => $_ , Value => 'Bar' );
+ ok( $status, "Deleted a custom field value 'Bar' for field ".$_->id.": $msg");
+ }
+ $cfvs = $ticket->CustomFieldValues;
+ is( $cfvs->Count, 0, "The ticket (".$ticket->id.") no longer has any custom field values" );
+ for (@custom_fields) {
+ $cfvs = $ticket->CustomFieldValues( $_->id );
+ is( $cfvs->Count, 0, $ticket->id." has no values for cf ".$_->id );
+
+ $cfvs = $ticket->CustomFieldValues( $_->Name );
+ is( $cfvs->Count, 0 , $ticket->id." has no values for cf '".$_->Name. "'" );
+ is( $ticket->FirstCustomFieldValue( $_->id ), undef , "There is no first custom field value when loading by id" );
+ is( $ticket->FirstCustomFieldValue( $_->Name ), undef, "There is no first custom field value when loading by Name" );
+ }
+};
+
+# lets test cycle via CF id
+$test_add_delete_cycle->( sub { return $_[0]->id } );
+# lets test cycle via CF object reference
+$test_add_delete_cycle->( sub { return $_[0] } );
+
+$ticket->AddCustomFieldValue( Field => $local_cf2->id , Value => 'Baz' );
+$ticket->AddCustomFieldValue( Field => $global_cf3->id , Value => 'Baz' );
+# now if we ask for cf values on RecordCustomFields4 we should not get any
+$cfvs = $ticket->CustomFieldValues( 'RecordCustomFields4' );
+is( $cfvs->Count, 0, "No custom field values for non-Queue cf" );
+is( $ticket->FirstCustomFieldValue( 'RecordCustomFields4' ), undef, "No first custom field value for non-Queue cf" );
+
+{
+ my $cfname = $global_cf3->Name;
+ ($status, $msg) = $global_cf3->SetDisabled(1);
+ ok($status, "Disabled CF named $cfname");
+
+ my $load = RT::CustomField->new( RT->SystemUser );
+ $load->LoadByName( Name => $cfname);
+ ok($load->Id, "Loaded CF named $cfname");
+ is($load->Id, $global_cf3->Id, "Can load disabled CFs");
+
+ my $dup = RT::CustomField->new( RT->SystemUser );
+ $dup->Create( Name => $cfname, Type => 'SelectSingle', Queue => 0 );
+ ok($dup->Id, "Created CF with duplicate name");
+
+ $load->LoadByName( Name => $cfname);
+ is($load->Id, $dup->Id, "Loading by name gets non-disabled first");
+
+ $dup->SetDisabled(1);
+ $global_cf3->SetDisabled(0);
+
+ $load->LoadByName( Name => $cfname);
+ is($load->Id, $global_cf3->Id, "Loading by name gets non-disabled first, even with order swapped");
+}
+
+#SKIP: {
+# skip "TODO: should we add CF values to objects via CF Name?", 48;
+# names are not unique
+ # lets test cycle via CF Name
+# $test_add_delete_cycle->( sub { return $_[0]->Name } );
+#}
+
+
diff --git a/rt/t/customfields/combo_cascade.t b/rt/t/customfields/combo_cascade.t
new file mode 100644
index 000000000..28eee4527
--- /dev/null
+++ b/rt/t/customfields/combo_cascade.t
@@ -0,0 +1,37 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+
+use RT::Test nodata => 1, tests => 11;
+
+my $q = RT::Queue->new($RT::SystemUser);
+works($q->Create(Name => "CF-Pattern-".$$));
+
+my $cf = RT::CustomField->new($RT::SystemUser);
+my @cf_args = (Name => $q->Name, Type => 'Combobox', Queue => $q->id);
+
+works($cf->Create(@cf_args));
+
+# Set some CFVs with Category markers
+
+my $t = RT::Ticket->new($RT::SystemUser);
+my ($id,undef,$msg) = $t->Create(Queue => $q->id, Subject => 'CF Test');
+works($id,$msg);
+
+sub add_works {
+ works(
+ $cf->AddValue(Name => $_[0], Description => $_[0], Category => $_[1])
+ );
+};
+
+add_works('value1', '1. Category A');
+add_works('value2');
+add_works('value3', '1.1. A-sub one');
+add_works('value4', '1.2. A-sub two');
+add_works('value5', '');
+
+my $cfv = $cf->Values->First;
+is($cfv->Category, '1. Category A');
+works($cfv->SetCategory('1. Category AAA'));
+is($cfv->Category, '1. Category AAA');
+
diff --git a/rt/t/customfields/date_search.t b/rt/t/customfields/date_search.t
new file mode 100644
index 000000000..b425b9e36
--- /dev/null
+++ b/rt/t/customfields/date_search.t
@@ -0,0 +1,119 @@
+#!/usr/bin/perl
+
+use warnings;
+use strict;
+
+use RT::Test nodata => 1, tests => 13;
+
+my $q = RT::Queue->new(RT->SystemUser);
+ok( $q->Create( Name => 'DateCFTest' . $$ ), 'create queue' );
+
+my $cf = RT::CustomField->new(RT->SystemUser);
+ok(
+ $cf->Create(
+ Name => 'date-' . $$,
+ Type => 'Date',
+ MaxValues => 1,
+ LookupType => RT::Ticket->CustomFieldLookupType,
+ ),
+ 'create cf date'
+);
+ok( $cf->AddToObject($q), 'date cf apply to queue' );
+
+my $ticket = RT::Ticket->new(RT->SystemUser);
+
+ok(
+ $ticket->Create(
+ Queue => $q->id,
+ Subject => 'Test',
+ 'CustomField-' . $cf->id => '2010-05-04',
+ ),
+ 'create ticket with cf set to 2010-05-04'
+);
+
+is( $ticket->CustomFieldValues->First->Content, '2010-05-04', 'date in db is' );
+
+{
+
+ my $tickets = RT::Tickets->new(RT->SystemUser);
+ $tickets->LimitCustomField(
+ CUSTOMFIELD => $cf->id,
+ OPERATOR => '=',
+ VALUE => '2010-05-04',
+ );
+ is( $tickets->Count, 1, 'found the ticket with exact date: 2010-05-04' );
+
+}
+
+{
+ my $tickets = RT::Tickets->new(RT->SystemUser);
+ $tickets->LimitCustomField(
+ CUSTOMFIELD => $cf->id,
+ OPERATOR => '>',
+ VALUE => '2010-05-03',
+ );
+
+ is( $tickets->Count, 1, 'found ticket with > 2010-05-03' );
+}
+
+{
+ my $tickets = RT::Tickets->new(RT->SystemUser);
+ $tickets->LimitCustomField(
+ CUSTOMFIELD => $cf->id,
+ OPERATOR => '<',
+ VALUE => '2010-05-05',
+ );
+
+ is( $tickets->Count, 1, 'found ticket with < 2010-05-05' );
+}
+
+{
+
+ my $tickets = RT::Tickets->new(RT->SystemUser);
+ $tickets->LimitCustomField(
+ CUSTOMFIELD => $cf->id,
+ OPERATOR => '=',
+ VALUE => '2010-05-05',
+ );
+
+ is( $tickets->Count, 0, 'did not find the ticket with = 2010-05-05' );
+}
+
+{
+
+ my $tickets = RT::Tickets->new(RT->SystemUser);
+ $tickets->LimitCustomField(
+ CUSTOMFIELD => $cf->id,
+ OPERATOR => '<',
+ VALUE => '2010-05-03',
+ );
+
+ is( $tickets->Count, 0, 'did not find the ticket with < 2010-05-03' );
+}
+
+{
+
+ my $tickets = RT::Tickets->new(RT->SystemUser);
+ $tickets->LimitCustomField(
+ CUSTOMFIELD => $cf->id,
+ OPERATOR => '>',
+ VALUE => '2010-05-05',
+ );
+
+ is( $tickets->Count, 0, 'did not find the ticket with > 2010-05-05' );
+}
+
+$ticket = RT::Ticket->new(RT->SystemUser);
+
+ok(
+ $ticket->Create(
+ Queue => $q->id,
+ Subject => 'Test',
+ 'CustomField-' . $cf->id => '2010-05-04 11:34:56',
+ ),
+ 'create ticket with cf set to 2010-05-04 11:34:56'
+);
+
+is( $ticket->CustomFieldValues->First->Content,
+ '2010-05-04', 'date in db only has date' );
+
diff --git a/rt/t/customfields/datetime_search.t b/rt/t/customfields/datetime_search.t
new file mode 100644
index 000000000..11fe3bc57
--- /dev/null
+++ b/rt/t/customfields/datetime_search.t
@@ -0,0 +1,141 @@
+#!/usr/bin/perl
+
+use warnings;
+use strict;
+
+use RT::Test nodata => 1, tests => 14;
+RT->Config->Set( 'Timezone' => 'EST5EDT' ); # -04:00
+
+my $q = RT::Queue->new(RT->SystemUser);
+ok( $q->Create( Name => 'DateTimeCFTest' . $$ ), 'create queue' );
+
+my $cf = RT::CustomField->new(RT->SystemUser);
+ok(
+ $cf->Create(
+ Name => 'datetime-' . $$,
+ Type => 'DateTime',
+ MaxValues => 1,
+ LookupType => RT::Ticket->CustomFieldLookupType,
+ ),
+ 'create cf datetime'
+);
+ok( $cf->AddToObject($q), 'date cf apply to queue' );
+
+my $ticket = RT::Ticket->new(RT->SystemUser);
+
+ok(
+ $ticket->Create(
+ Queue => $q->id,
+ Subject => 'Test',
+ 'CustomField-' . $cf->id => '2010-05-04 07:00:00',
+ ),
+ 'create ticket with cf set to 2010-05-04 07:00:00( 2010-05-04 11:00:00 with UTC )'
+);
+
+is(
+ $ticket->CustomFieldValues->First->Content,
+ '2010-05-04 11:00:00',
+ 'date in db is in timezone UTC'
+);
+
+{
+
+ my $tickets = RT::Tickets->new(RT->SystemUser);
+ $tickets->LimitCustomField(
+ CUSTOMFIELD => $cf->id,
+ OPERATOR => '=',
+ VALUE => '2010-05-04 07:00:00', # this timezone is server
+ );
+
+ is( $tickets->Count, 1, 'found the ticket with exact date: 2010-05-04 07:00:00' );
+}
+
+{
+
+ # TODO according to the code, if OPERATOR is '=', it means on that day
+ # this will test this behavior
+ my $tickets = RT::Tickets->new(RT->SystemUser);
+ $tickets->LimitCustomField(
+ CUSTOMFIELD => $cf->id,
+ OPERATOR => '=',
+ VALUE => '2010-05-04',
+ );
+
+ is( $tickets->Count, 1, 'found the ticket with rough date: 2010-05-04' );
+}
+
+{
+
+ # TODO according to the code, if OPERATOR is '=', it means on that day
+ # this will test this behavior
+ my $tickets = RT::Tickets->new(RT->SystemUser);
+ $tickets->LimitCustomField(
+ CUSTOMFIELD => $cf->id,
+ OPERATOR => '=',
+ VALUE => '2010-05-05',
+ );
+
+ is( $tickets->Count, 0, 'did not find the ticket with wrong datetime: 2010-05-05' );
+}
+
+my $tickets = RT::Tickets->new( RT->SystemUser );
+$tickets->UnLimit;
+while( my $ticket = $tickets->Next ) {
+ $ticket->Delete();
+}
+
+{
+ ok(
+ $ticket->Create(
+ Queue => $q->id,
+ Subject => 'Test',
+ 'CustomField-' . $cf->id => '2010-06-21 17:00:01',
+ ),
+'create ticket with cf set to 2010-06-21 17:00:01( 2010-06-21 21:00:01 with UTC )'
+ );
+
+ my $shanghai = RT::Test->load_or_create_user(
+ Name => 'shanghai',
+ Timezone => 'Asia/Shanghai',
+ );
+
+ ok(
+ $shanghai->PrincipalObj->GrantRight(
+ Right => 'SuperUser',
+ Object => $RT::System,
+ )
+ );
+
+ my $current_user = RT::CurrentUser->new($shanghai);
+ my $tickets = RT::Tickets->new($current_user);
+ $tickets->LimitCustomField(
+ CUSTOMFIELD => $cf->id,
+ OPERATOR => '=',
+ VALUE => '2010-06-22',
+ );
+ is( $tickets->Count, 1, 'found the ticket with rough datetime: 2010-06-22' );
+
+ $tickets->UnLimit;
+ $tickets->LimitCustomField(
+ CUSTOMFIELD => $cf->id,
+ OPERATOR => '>',
+ VALUE => '2010-06-21',
+ );
+ is( $tickets->Count, 1, 'found the ticket with > 2010-06-21' );
+
+ $tickets->UnLimit;
+ $tickets->LimitCustomField(
+ CUSTOMFIELD => $cf->id,
+ OPERATOR => '<',
+ VALUE => '2010-06-23',
+ );
+ is( $tickets->Count, 1, 'found the ticket with < 2010-06-23' );
+
+ $tickets->UnLimit;
+ $tickets->LimitCustomField(
+ CUSTOMFIELD => $cf->id,
+ OPERATOR => '=',
+ VALUE => '2010-06-22 05:00:01',
+ );
+ is( $tickets->Count, 1, 'found the ticket with = 2010-06-22 01:00:01' );
+}
diff --git a/rt/t/customfields/external.t b/rt/t/customfields/external.t
new file mode 100644
index 000000000..0abf6eca1
--- /dev/null
+++ b/rt/t/customfields/external.t
@@ -0,0 +1,56 @@
+#!/usr/bin/perl
+
+use warnings;
+use strict;
+
+use RT;
+use RT::Test nodata => 1, tests => 11;
+
+sub new (*) {
+ my $class = shift;
+ return $class->new(RT->SystemUser);
+}
+
+use constant VALUES_CLASS => 'RT::CustomFieldValues::Groups';
+RT->Config->Set(CustomFieldValuesSources => VALUES_CLASS);
+
+my $q = new( RT::Queue );
+isa_ok( $q, 'RT::Queue' );
+my ($qid) = $q->Create( Name => "CF-External-". $$ );
+ok( $qid, "created queue" );
+my %arg = ( Name => $q->Name,
+ Type => 'Select',
+ Queue => $q->id,
+ MaxValues => 1,
+ ValuesClass => VALUES_CLASS );
+
+my $cf = new( RT::CustomField );
+isa_ok( $cf, 'RT::CustomField' );
+
+{
+ my ($cfid, $msg) = $cf->Create( %arg );
+ ok( $cfid, "created cf" ) or diag "error: $msg";
+ is( $cf->ValuesClass, VALUES_CLASS, "right values class" );
+ ok( $cf->IsExternalValues, "custom field has external values" );
+}
+
+{
+ # create at least on group for the tests
+ my $group = RT::Group->new( RT->SystemUser );
+ my ($ret, $msg) = $group->CreateUserDefinedGroup( Name => $q->Name );
+ ok $ret, 'created group' or diag "error: $msg";
+}
+
+{
+ my $values = $cf->Values;
+ isa_ok( $values, VALUES_CLASS );
+ ok( $values->Count, "we have values" );
+ my ($failure, $count) = (0, 0);
+ while( my $value = $values->Next ) {
+ $count++;
+ $failure = 1 unless $value->Name;
+ }
+ ok( !$failure, "all values have name" );
+ is( $values->Count, $count, "count is correct" );
+}
+
diff --git a/rt/t/customfields/ip.t b/rt/t/customfields/ip.t
new file mode 100644
index 000000000..f73e63fa5
--- /dev/null
+++ b/rt/t/customfields/ip.t
@@ -0,0 +1,285 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 73;
+
+my ( $baseurl, $agent ) = RT::Test->started_ok;
+ok( $agent->login, 'log in' );
+
+my $q = RT::Queue->new($RT::SystemUser);
+$q->Load('General');
+my $ip_cf = RT::CustomField->new($RT::SystemUser);
+
+my ( $val, $msg ) = $ip_cf->Create(
+ Name => 'IP',
+ Type => 'IPAddress',
+ LookupType => 'RT::Queue-RT::Ticket'
+);
+ok( $val, $msg );
+my $cf_id = $val;
+$ip_cf->AddToObject($q);
+use_ok('RT');
+
+my $cf;
+diag "load and check basic properties of the IP CF" if $ENV{'TEST_VERBOSE'};
+{
+ my $cfs = RT::CustomFields->new($RT::SystemUser);
+ $cfs->Limit( FIELD => 'Name', VALUE => 'IP' );
+ is( $cfs->Count, 1, "found one CF with name 'IP'" );
+
+ $cf = $cfs->First;
+ is( $cf->Type, 'IPAddress', 'type check' );
+ is( $cf->LookupType, 'RT::Queue-RT::Ticket', 'lookup type check' );
+ ok( !$cf->MaxValues, "unlimited number of values" );
+ ok( !$cf->Disabled, "not disabled" );
+}
+
+diag "check that CF applies to queue General" if $ENV{'TEST_VERBOSE'};
+{
+ my $cfs = $q->TicketCustomFields;
+ $cfs->Limit( FIELD => 'id', VALUE => $cf->id, ENTRYAGGREGATOR => 'AND' );
+ is( $cfs->Count, 1, 'field applies to queue' );
+}
+
+diag "create a ticket via web and set IP" if $ENV{'TEST_VERBOSE'};
+{
+ my $val = '192.168.20.1';
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $val,
+ }
+ );
+
+ $agent->content_contains( $val, "IP on the page" );
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created ticket $id" );
+
+ my $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+ is( $ticket->FirstCustomFieldValue('IP'), $val, 'correct value' );
+}
+
+diag "create a ticket and edit IP field using Edit page"
+ if $ENV{'TEST_VERBOSE'};
+{
+ my $val = '172.16.0.1';
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => { Subject => 'test ip', }
+ );
+
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created ticket $id" );
+ my $cf_field = "Object-RT::Ticket-$id-CustomField-$cf_id-Values";
+
+ $agent->follow_link_ok( { text => 'Basics', n => "1" },
+ "Followed 'Basics' link" );
+ $agent->form_name('TicketModify');
+
+ is( $agent->value($cf_field), '', 'IP is empty' );
+ $agent->field( $cf_field => $val );
+ $agent->click('SubmitTicket');
+
+ $agent->content_contains( $val, "IP on the page" );
+
+ my $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+ is( $ticket->FirstCustomFieldValue('IP'), '172.16.0.1' );
+
+ diag "set IP with spaces around" if $ENV{'TEST_VERBOSE'};
+ $val = " 172.16.0.2 \n ";
+ $agent->follow_link_ok( { text => 'Basics', n => "1" },
+ "Followed 'Basics' link" );
+ $agent->form_name('TicketModify');
+ is( $agent->value($cf_field), '172.16.0.1', 'IP is in input box' );
+ $agent->field( $cf_field => $val );
+ $agent->click('SubmitTicket');
+
+ $agent->content_contains( '172.16.0.2', "IP on the page" );
+
+ $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+ is( $ticket->FirstCustomFieldValue('IP'),
+ '172.16.0.2', 'correct value' );
+}
+
+diag "check that we parse correct IPs only" if $ENV{'TEST_VERBOSE'};
+{
+
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ for my $valid (qw/1.0.0.0 255.255.255.255/) {
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $valid,
+ }
+ );
+
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created ticket $id" );
+ my $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ is( $ticket->id, $id, 'loaded ticket' );
+
+ is( $ticket->FirstCustomFieldValue('IP'),
+ $valid, 'correct value' );
+ }
+
+ for my $invalid (qw{255.255.255.256 355.255.255.255 8.13.8/8.13.0/1.0}) {
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $invalid,
+ }
+ );
+
+ $agent->content_contains( 'can not be parsed as an IP address',
+ 'ticket fails to create' );
+ }
+
+}
+
+diag "search tickets by IP" if $ENV{'TEST_VERBOSE'};
+{
+ my $val = '172.16.1.1';
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $val,
+ }
+ );
+
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created ticket $id" );
+
+ my $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+
+ my $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets->FromSQL("id = $id AND CF.{IP} = '172.16.1.1'");
+ ok( $tickets->Count, "found tickets" );
+}
+
+diag "create two tickets with different IPs and check several searches"
+ if $ENV{'TEST_VERBOSE'};
+{
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => '192.168.21.10',
+ }
+ );
+
+ my ($id1) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id1, "created first ticket $id1" );
+
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => '192.168.22.10',
+ }
+ );
+
+ my ($id2) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id2, "created second ticket $id2" );
+
+ my $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets->FromSQL("id = $id1 OR id = $id2");
+ is( $tickets->Count, 2, "found both tickets by 'id = x OR y'" );
+
+ # IP
+ $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.21.10'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'),
+ '192.168.21.10', "correct value" );
+ $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.22.10'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'),
+ '192.168.22.10', "correct value" );
+
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} <= '192.168.21.10'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'),
+ '192.168.21.10', "correct value" );
+ $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} >= '192.168.22.10'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'),
+ '192.168.22.10', "correct value" );
+
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} > '192.168.22.10'");
+ is( $tickets->Count, 0, "no tickets found" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} < '192.168.21.10'");
+ is( $tickets->Count, 0, "no tickets found" );
+
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} < '192.168.22.10'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'),
+ '192.168.21.10', "correct value" );
+
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} > '192.168.21.10'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'),
+ '192.168.22.10', "correct value" );
+}
+
+diag "create a ticket with an IP of 10.0.0.1 and search for doesn't match '10.0.0.'."
+ if $ENV{'TEST_VERBOSE'};
+{
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'local',
+ $cf_field => '10.0.0.1',
+ }
+ );
+
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created first ticket $id" );
+
+ my $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets->FromSQL("id=$id AND CF.{IP} NOT LIKE '10.0.0.'");
+
+ SKIP: {
+ skip "partical ip parse causes ambiguity", 1;
+ is( $tickets->Count, 0, "should not have found the ticket" );
+ }
+}
+
+
+diag "test the operators in search page" if $ENV{'TEST_VERBOSE'};
+{
+ $agent->get_ok( $baseurl . "/Search/Build.html?Query=Queue='General'" );
+ $agent->content_contains('CF.{IP}', 'got CF.{IP}');
+ my $form = $agent->form_name('BuildQuery');
+ my $op = $form->find_input("'CF.{IP}'Op");
+ ok( $op, "found 'CF.{IP}'Op" );
+ is_deeply( [ $op->possible_values ], [ '=', '!=', '<', '>' ], 'op values' );
+}
diff --git a/rt/t/customfields/iprange.t b/rt/t/customfields/iprange.t
new file mode 100644
index 000000000..118d23c88
--- /dev/null
+++ b/rt/t/customfields/iprange.t
@@ -0,0 +1,469 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 133;
+
+my ($baseurl, $agent) =RT::Test->started_ok;
+ok( $agent->login, 'log in' );
+
+my $q = RT::Queue->new($RT::SystemUser);
+$q->Load('General');
+my $ip_cf = RT::CustomField->new($RT::SystemUser);
+
+my ($val,$msg) = $ip_cf->Create(Name => 'IP', Type =>'IPAddressRange', LookupType => 'RT::Queue-RT::Ticket');
+ok($val,$msg);
+my $cf_id = $val;
+$ip_cf->AddToObject($q);
+use_ok('RT');
+
+my $cf;
+diag "load and check basic properties of the IP CF" if $ENV{'TEST_VERBOSE'};
+{
+ my $cfs = RT::CustomFields->new( $RT::SystemUser );
+ $cfs->Limit( FIELD => 'Name', VALUE => 'IP' );
+ is( $cfs->Count, 1, "found one CF with name 'IP'" );
+
+ $cf = $cfs->First;
+ is( $cf->Type, 'IPAddressRange', 'type check' );
+ is( $cf->LookupType, 'RT::Queue-RT::Ticket', 'lookup type check' );
+ ok( !$cf->MaxValues, "unlimited number of values" );
+ ok( !$cf->Disabled, "not disabled" );
+}
+
+diag "check that CF applies to queue General" if $ENV{'TEST_VERBOSE'};
+{
+ my $cfs = $q->TicketCustomFields;
+ $cfs->Limit( FIELD => 'id', VALUE => $cf->id, ENTRYAGGREGATOR => 'AND' );
+ is( $cfs->Count, 1, 'field applies to queue' );
+}
+
+diag "create a ticket via web and set IP" if $ENV{'TEST_VERBOSE'};
+{
+ my $val = '192.168.20.1';
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $val,
+ }
+ );
+
+ $agent->content_like( qr/\Q$val/, "IP on the page" );
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created ticket $id" );
+
+ my $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+ is( $ticket->FirstCustomFieldValue('IP'), $val, 'correct value' );
+}
+
+diag "create a ticket via web with CIDR" if $ENV{'TEST_VERBOSE'};
+{
+ my $val = '172.16.20/31';
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $val,
+ }
+ );
+
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created ticket $id" );
+
+ my $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+ is( $ticket->FirstCustomFieldValue('IP'), '172.16.20.0-172.16.20.1', 'correct value' );
+}
+
+diag "create a ticket and edit IP field using Edit page" if $ENV{'TEST_VERBOSE'};
+{
+ my $val = '172.16.0.1';
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => { Subject => 'test ip', }
+ );
+
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created ticket $id" );
+ my $cf_field = "Object-RT::Ticket-$id-CustomField-$cf_id-Values";
+
+ $agent->follow_link_ok( { text => 'Basics', n => "1" },
+ "Followed 'Basics' link" );
+ $agent->form_name('TicketModify');
+
+ like( $agent->value($cf_field), qr/^\s*$/, 'IP is empty' );
+ $agent->field( $cf_field => $val );
+ $agent->click('SubmitTicket');
+
+ $agent->content_like( qr/\Q$val/, "IP on the page" );
+
+ my $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+ is( $ticket->FirstCustomFieldValue('IP'), $val, 'correct value' );
+
+ diag "set IP with spaces around" if $ENV{'TEST_VERBOSE'};
+ $val = " 172.16.0.2 \n ";
+ $agent->follow_link_ok( { text => 'Basics', n => "1" },
+ "Followed 'Basics' link" );
+ $agent->form_name('TicketModify');
+ like( $agent->value($cf_field),
+ qr/^\s*\Q172.16.0.1\E\s*$/, 'IP is in input box' );
+ $agent->field( $cf_field => $val );
+ $agent->click('SubmitTicket');
+
+ $agent->content_like( qr/\Q172.16.0.2/, "IP on the page" );
+
+ $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+ is( $ticket->FirstCustomFieldValue('IP'), '172.16.0.2', 'correct value' );
+
+ diag "replace IP with a range" if $ENV{'TEST_VERBOSE'};
+ $val = '172.16.0.0-172.16.0.255';
+ $agent->follow_link_ok( { text => 'Basics', n => "1" },
+ "Followed 'Basics' link" );
+ $agent->form_name('TicketModify');
+ like( $agent->value($cf_field),
+ qr/^\s*\Q172.16.0.2\E\s*$/, 'IP is in input box' );
+ $agent->field( $cf_field => $val );
+ $agent->click('SubmitTicket');
+
+ $agent->content_like( qr/\Q$val/, "IP on the page" );
+
+ $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+ is( $ticket->FirstCustomFieldValue('IP'), $val, 'correct value' );
+
+ diag "delete range, add another range using CIDR" if $ENV{'TEST_VERBOSE'};
+ $val = '172.16/16';
+ $agent->follow_link_ok( { text => 'Basics', n => "1" },
+ "Followed 'Basics' link" );
+ $agent->form_name('TicketModify');
+ is( $agent->value($cf_field),
+ '172.16.0.0-172.16.0.255', 'IP is in input box' );
+ $agent->field( $cf_field => $val );
+ $agent->click('SubmitTicket');
+
+ $agent->content_like( qr/\Q$val/, "IP on the page" );
+
+ $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+ is( $ticket->FirstCustomFieldValue('IP'),
+ '172.16.0.0-172.16.255.255', 'correct value' );
+}
+
+diag "check that we parse correct IPs only" if $ENV{'TEST_VERBOSE'};
+{
+
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ for my $valid (qw/1.0.0.0 255.255.255.255/) {
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $valid,
+ }
+ );
+
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created ticket $id" );
+ my $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ is( $ticket->id, $id, 'loaded ticket' );
+
+ is( $ticket->FirstCustomFieldValue('IP'), $valid, 'correct value' );
+ }
+
+ for my $invalid (qw{255.255.255.256 355.255.255.255 8.13.8/8.13.0/1.0}) {
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $invalid,
+ }
+ );
+
+ $agent->content_like( qr/can not be parsed as an IP address range/, 'ticket fails to create' );
+ }
+
+}
+
+diag "search tickets by IP" if $ENV{'TEST_VERBOSE'};
+{
+ my $val = '172.16.1/31';
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $val,
+ }
+ );
+
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created ticket $id" );
+
+ my $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+
+ my $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets->FromSQL("id = $id AND CF.{IP} = '172.16.1.1'");
+ ok( $tickets->Count, "found tickets" );
+
+ is( $ticket->FirstCustomFieldValue('IP'),
+ '172.16.1.0-172.16.1.1', 'correct value' );
+}
+
+diag "search tickets by IP range" if $ENV{'TEST_VERBOSE'};
+{
+ my $val = '172.16.2/26';
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $val,
+ }
+ );
+
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created ticket $id" );
+
+ my $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+
+ my $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("id = $id AND CF.{IP} = '172.16.2.0-172.16.2.255'");
+ ok( $tickets->Count, "found tickets" );
+
+ is( $ticket->FirstCustomFieldValue('IP'),
+ '172.16.2.0-172.16.2.63', 'correct value' );
+}
+
+diag "create two tickets with different IPs and check several searches" if $ENV{'TEST_VERBOSE'};
+{
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => '192.168.21.10',
+ }
+ );
+
+ my ($id1) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id1, "created first ticket $id1" );
+
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => '192.168.22.10',
+ }
+ );
+
+ my ($id2) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id2, "created second ticket $id2" );
+
+ my $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("id = $id1 OR id = $id2");
+ is( $tickets->Count, 2, "found both tickets by 'id = x OR y'" );
+
+ # IP
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.21.10'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), '192.168.21.10', "correct value" );
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.22.10'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), '192.168.22.10', "correct value" );
+
+ # IP/32 - one address
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.21.10/32'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), '192.168.21.10', "correct value" );
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.22.10/32'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), '192.168.22.10', "correct value" );
+
+ # IP range
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.21.0-192.168.21.255'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), '192.168.21.10', "correct value" );
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.22.0-192.168.22.255'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), '192.168.22.10', "correct value" );
+
+ # IP range, with start IP greater than end
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.21.255-192.168.21.0'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), '192.168.21.10', "correct value" );
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.22.255-192.168.22.0'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), '192.168.22.10', "correct value" );
+
+ # CIDR/24
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.21.0/24'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), '192.168.21.10', "correct value" );
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.22.0/24'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), '192.168.22.10', "correct value" );
+
+ # IP is not in CIDR/24
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} != '192.168.21.0/24'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), '192.168.22.10', "correct value" );
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} != '192.168.22.0/24'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), '192.168.21.10', "correct value" );
+
+ # CIDR or CIDR
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND "
+ ."(CF.{IP} = '192.168.21.0/24' OR CF.{IP} = '192.168.22.0/24')");
+ is( $tickets->Count, 2, "found both tickets" );
+}
+
+diag "create two tickets with different IP ranges and check several searches" if $ENV{'TEST_VERBOSE'};
+{
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => '192.168.21.0-192.168.21.127',
+ }
+ );
+
+ my ($id1) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id1, "created first ticket $id1" );
+
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => '192.168.21.128-192.168.21.255',
+ }
+ );
+
+ my ($id2) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id2, "created ticket $id2" );
+
+ my $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("id = $id1 OR id = $id2");
+ is( $tickets->Count, 2, "found both tickets by 'id = x OR y'" );
+
+ # IP
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.21.0'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.21.64'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.21.127'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.21.128'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id2, "correct value" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.21.191'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id2, "correct value" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.21.255'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id2, "correct value" );
+
+ # IP/32 - one address
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.21.63/32'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.21.191/32'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id2, "correct value" );
+
+ # IP range, lower than both
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.20.0-192.168.20.255'");
+ is( $tickets->Count, 0, "didn't finnd ticket" ) or diag "but found ". $tickets->First->id;
+
+ # IP range, intersect with the first range
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.20.0-192.168.21.63'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+
+ # IP range, equal to the first range
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.21.0-192.168.21.127'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+
+ # IP range, lay inside the first range
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.21.31-192.168.21.63'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+
+ # IP range, intersect with the ranges
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.21.31-192.168.21.191'");
+ is( $tickets->Count, 2, "found both tickets" );
+
+ # IP range, equal to range from the starting IP of the first ticket to the ending IP of the second
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.21.0-192.168.21.255'");
+ is( $tickets->Count, 2, "found both tickets" );
+
+ # IP range, has the both ranges inside it
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168/16'");
+ is( $tickets->Count, 2, "found both tickets" );
+
+ # IP range, greater than both
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '192.168.22/24'");
+ is( $tickets->Count, 0, "didn't find ticket" ) or diag "but found ". $tickets->First->id;
+}
+
+
+diag "test the operators in search page" if $ENV{'TEST_VERBOSE'};
+{
+ $agent->get_ok( $baseurl . "/Search/Build.html?Query=Queue='General'" );
+ $agent->content_contains('CF.{IP}', 'got CF.{IP}');
+ my $form = $agent->form_name('BuildQuery');
+ my $op = $form->find_input("'CF.{IP}'Op");
+ ok( $op, "found 'CF.{IP}'Op" );
+ is_deeply( [ $op->possible_values ], [ '=', '!=', '<', '>' ], 'op values' );
+}
+
diff --git a/rt/t/customfields/iprangev6.t b/rt/t/customfields/iprangev6.t
new file mode 100644
index 000000000..d823dd6e3
--- /dev/null
+++ b/rt/t/customfields/iprangev6.t
@@ -0,0 +1,474 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 158;
+
+my ($baseurl, $agent) =RT::Test->started_ok;
+ok( $agent->login, 'log in' );
+
+my $q = RT::Queue->new($RT::SystemUser);
+$q->Load('General');
+my $ip_cf = RT::CustomField->new($RT::SystemUser);
+
+my ($val,$msg) = $ip_cf->Create(Name => 'IP', Type =>'IPAddressRange', LookupType => 'RT::Queue-RT::Ticket');
+ok($val,$msg);
+my $cf_id = $val;
+$ip_cf->AddToObject($q);
+use_ok('RT');
+
+my $cf;
+diag "load and check basic properties of the IP CF" if $ENV{'TEST_VERBOSE'};
+{
+ my $cfs = RT::CustomFields->new( $RT::SystemUser );
+ $cfs->Limit( FIELD => 'Name', VALUE => 'IP' );
+ is( $cfs->Count, 1, "found one CF with name 'IP'" );
+
+ $cf = $cfs->First;
+ is( $cf->Type, 'IPAddressRange', 'type check' );
+ is( $cf->LookupType, 'RT::Queue-RT::Ticket', 'lookup type check' );
+ ok( !$cf->MaxValues, "unlimited number of values" );
+ ok( !$cf->Disabled, "not disabled" );
+}
+
+diag "check that CF applies to queue General" if $ENV{'TEST_VERBOSE'};
+{
+ my $cfs = $q->TicketCustomFields;
+ $cfs->Limit( FIELD => 'id', VALUE => $cf->id, ENTRYAGGREGATOR => 'AND' );
+ is( $cfs->Count, 1, 'field applies to queue' );
+}
+
+my %valid = (
+ 'abcd:' x 7 . 'abcd' => 'abcd:' x 7 . 'abcd',
+ '034:' x 7 . '034' => '0034:' x 7 . '0034',
+ 'abcd::' => 'abcd:' . '0000:' x 6 . '0000',
+ '::abcd' => '0000:' x 7 . 'abcd',
+ 'abcd::034' => 'abcd:' . '0000:' x 6 . '0034',
+ 'abcd::192.168.1.1' => 'abcd:' . '0000:' x 5 . 'c0a8:0101',
+ '::192.168.1.1' => '0000:' x 6 . 'c0a8:0101',
+ '::' => '0000:' x 7 . '0000',
+);
+
+diag "create a ticket via web and set IP" if $ENV{'TEST_VERBOSE'};
+{
+ for my $ip ( keys %valid ) {
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $ip,
+ }
+ );
+
+ $agent->content_like( qr/$valid{$ip}/, "IP on the page" );
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created ticket $id" );
+
+ my $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+ is( $ticket->FirstCustomFieldValue('IP'), $valid{$ip},
+ 'correct value' );
+ }
+}
+
+diag "create a ticket via web with CIDR" if $ENV{'TEST_VERBOSE'};
+{
+ my $val = 'abcd:034::/31';
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $val,
+ }
+ );
+
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created ticket $id" );
+
+ my $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+ is(
+ $ticket->FirstCustomFieldValue('IP'),
+'abcd:0034:0000:0000:0000:0000:0000:0000-abcd:0035:ffff:ffff:ffff:ffff:ffff:ffff',
+ 'correct value'
+ );
+}
+
+diag "create a ticket and edit IP field using Edit page" if $ENV{'TEST_VERBOSE'};
+{
+ my $val = 'abcd' . ':abcd' x 7;
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => { Subject => 'test ip', }
+ );
+
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created ticket $id" );
+ my $cf_field = "Object-RT::Ticket-$id-CustomField-$cf_id-Values";
+
+ $agent->follow_link_ok( { text => 'Basics', n => "1" },
+ "Followed 'Basics' link" );
+ $agent->form_name('TicketModify');
+
+ is( $agent->value($cf_field), '', 'IP is empty' );
+ $agent->field( $cf_field => $val );
+ $agent->click('SubmitTicket');
+
+ $agent->content_contains( $val, "IP on the page" );
+
+ my $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+ is( $ticket->FirstCustomFieldValue('IP'), $val, 'correct value' );
+
+ diag "set IP with spaces around" if $ENV{'TEST_VERBOSE'};
+ $agent->follow_link_ok( { text => 'Basics', n => "1" },
+ "Followed 'Basics' link" );
+ $agent->form_name('TicketModify');
+ is( $agent->value($cf_field), $val, 'IP is in input box' );
+ $val = 'bbcd' . ':abcd' x 7;
+ $agent->field( $cf_field => " $val " );
+ $agent->click('SubmitTicket');
+
+ $agent->content_contains( $val, "IP on the page" );
+
+ $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+ is( $ticket->FirstCustomFieldValue('IP'), $val, 'correct value' );
+
+ diag "replace IP with a range" if $ENV{'TEST_VERBOSE'};
+ $agent->follow_link_ok( { text => 'Basics', n => "1" },
+ "Followed 'Basics' link" );
+ $agent->form_name('TicketModify');
+ is( $agent->value($cf_field), $val, 'IP is in input box' );
+ $val = 'abcd' . ':0000' x 7 . '-' . 'abcd' . ':ffff' x 7;
+ $agent->field( $cf_field => 'abcd::/16' );
+ $agent->click('SubmitTicket');
+
+ $agent->content_contains( $val, "IP on the page" );
+
+ $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+ is( $ticket->FirstCustomFieldValue('IP'), $val, 'correct value' );
+
+ diag "delete range, add another range using CIDR" if $ENV{'TEST_VERBOSE'};
+ $agent->follow_link_ok( { text => 'Basics', n => "1" },
+ "Followed 'Basics' link" );
+ $agent->form_name('TicketModify');
+ is( $agent->value($cf_field), $val, 'IP is in input box' );
+ $val = 'bb00' . ':0000' x 7 . '-' . 'bbff' . ':ffff' x 7;
+ $agent->field( $cf_field => $val );
+ $agent->click('SubmitTicket');
+
+ $agent->content_contains( $val, "IP on the page" );
+
+ $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+ is( $ticket->FirstCustomFieldValue('IP'), $val, 'correct value' );
+}
+
+diag "check that we parse correct IPs only" if $ENV{'TEST_VERBOSE'};
+{
+
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ my @invalid =
+ ( 'abcd:', 'efgh', 'abcd:' x 8 . 'abcd', 'abcd::abcd::abcd' );
+ for my $invalid (@invalid) {
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $invalid,
+ }
+ );
+
+ $agent->content_like( qr/can not be parsed as an IP address range/,
+ 'ticket fails to create' );
+ }
+
+}
+
+diag "search tickets by IP" if $ENV{'TEST_VERBOSE'};
+{
+ my $val = 'abcd::/16';
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $val,
+ }
+ );
+
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created ticket $id" );
+
+ my $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+
+ my $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets->FromSQL("id = $id AND CF.{IP} = 'abcd::/16'");
+ ok( $tickets->Count, "found tickets" );
+ is(
+ $ticket->FirstCustomFieldValue('IP'),
+'abcd:0000:0000:0000:0000:0000:0000:0000-abcd:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
+ 'correct value'
+ );
+}
+
+diag "search tickets by IP range" if $ENV{'TEST_VERBOSE'};
+{
+ my $val = 'abcd:ef00::/24';
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $val,
+ }
+ );
+
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created ticket $id" );
+
+ my $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+
+ my $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("id = $id AND CF.{IP} =
+ 'abcd:ef::-abcd:efff:ffff:ffff:ffff:ffff:ffff:ffff'");
+ ok( $tickets->Count, "found tickets" );
+
+ is(
+ $ticket->FirstCustomFieldValue('IP'),
+'abcd:ef00:0000:0000:0000:0000:0000:0000-abcd:efff:ffff:ffff:ffff:ffff:ffff:ffff',
+ 'correct value'
+ );
+}
+
+diag "create two tickets with different IPs and check several searches" if $ENV{'TEST_VERBOSE'};
+{
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ my $first_ip = 'cbcd' . ':0000' x 7;
+ my $second_ip = 'cbdd' . ':0000' x 7;
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $first_ip,
+ }
+ );
+
+ my ($id1) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id1, "created first ticket $id1" );
+
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $second_ip,
+ }
+ );
+
+ my ($id2) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id2, "created second ticket $id2" );
+
+ my $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("id = $id1 OR id = $id2");
+ is( $tickets->Count, 2, "found both tickets by 'id = x OR y'" );
+
+ # IP
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '$first_ip'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), $first_ip, "correct value" );
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '$second_ip'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), $second_ip, "correct value" );
+
+ # IP/32 - one address
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'cbcd::/16'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), $first_ip, "correct value" );
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'cbdd::/16'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), $second_ip, "correct value" );
+
+ # IP range
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL(
+ "(id = $id1 OR id = $id2) AND CF.{IP} = '$first_ip-cbcf::'"
+ );
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), $first_ip, "correct value" );
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL(
+ "(id = $id1 OR id = $id2) AND CF.{IP} = '$second_ip-cbdf::'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), $second_ip, "correct value" );
+
+ # IP range, with start IP greater than end
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} =
+ 'cbcf::-$first_ip'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), $first_ip,, "correct value" );
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'cbdf::-$second_ip'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), $second_ip, "correct value" );
+
+ # CIDR/12
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'cbcd::/12'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), $first_ip, "correct value" );
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'cbdd::/12'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), $second_ip, "correct value" );
+
+ # IP is not in CIDR/24
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} != 'cbcd::/12'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), $second_ip,, "correct value" );
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} != 'cbdd::/12'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'), $first_ip, "correct value" );
+
+ # CIDR or CIDR
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND "
+ ."(CF.{IP} = 'cbcd::/12' OR CF.{IP} = 'cbdd::/12')");
+ is( $tickets->Count, 2, "found both tickets" );
+}
+
+diag "create two tickets with different IP ranges and check several searches" if $ENV{'TEST_VERBOSE'};
+{
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => 'ddcd::/16',
+ }
+ );
+
+ my ($id1) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id1, "created first ticket $id1" );
+
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => 'edcd::/16',
+ }
+ );
+
+ my ($id2) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id2, "created ticket $id2" );
+
+ my $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("id = $id1 OR id = $id2");
+ is( $tickets->Count, 2, "found both tickets by 'id = x OR y'" );
+
+ # IP
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'ddcd::'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'ddcd:abcd::'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'ddcd:ffff::'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'edcd::abcd'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id2, "correct value" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'edcd::ffff'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id2, "correct value" );
+ $tickets->FromSQL(
+"(id = $id1 OR id = $id2) AND CF.{IP} = 'edcd:ffff:ffff:ffff:ffff:ffff:ffff:ffff'"
+ );
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id2, "correct value" );
+
+ # IP/32 - one address
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'ddcd::/32'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'edcd::/32'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id2, "correct value" );
+
+ # IP range, lower than both
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'abcd::/32'");
+ is( $tickets->Count, 0, "didn't finnd ticket" ) or diag "but found ". $tickets->First->id;
+
+ # IP range, intersect with the first range
+ $tickets->FromSQL(
+ "(id = $id1 OR id = $id2) AND CF.{IP} = 'ddcc::-ddcd:ab::'"
+ );
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+
+ # IP range, equal to the first range
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'ddcd::/16'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+
+ # IP range, lay inside the first range
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'ddcd:ab::'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+
+ # IP range, intersect with the ranges
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'ddcc::-edcd:ab::'");
+ is( $tickets->Count, 2, "found both tickets" );
+
+ # IP range, equal to range from the starting IP of the first ticket to the ending IP of the second
+ $tickets->FromSQL(
+ "(id = $id1 OR id = $id2) AND CF.{IP} = 'ddcd::-edcd:ffff:ffff:ffff:ffff:ffff:ffff:ffff'"
+ );
+ is( $tickets->Count, 2, "found both tickets" );
+
+ # IP range, has the both ranges inside it
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'd000::/2'");
+ is( $tickets->Count, 2, "found both tickets" );
+
+ # IP range, greater than both
+ $tickets = RT::Tickets->new( $RT::SystemUser );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'ffff::/16'");
+ is( $tickets->Count, 0, "didn't find ticket" ) or diag "but found ". $tickets->First->id;
+}
+
+
diff --git a/rt/t/customfields/ipv6.t b/rt/t/customfields/ipv6.t
new file mode 100644
index 000000000..09c4d30d0
--- /dev/null
+++ b/rt/t/customfields/ipv6.t
@@ -0,0 +1,252 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 102;
+
+my ( $baseurl, $agent ) = RT::Test->started_ok;
+ok( $agent->login, 'log in' );
+
+my $q = RT::Queue->new($RT::SystemUser);
+$q->Load('General');
+my $ip_cf = RT::CustomField->new($RT::SystemUser);
+
+my ( $val, $msg ) = $ip_cf->Create(
+ Name => 'IP',
+ Type => 'IPAddress',
+ LookupType => 'RT::Queue-RT::Ticket'
+);
+ok( $val, $msg );
+my $cf_id = $val;
+$ip_cf->AddToObject($q);
+use_ok('RT');
+
+my $cf;
+diag "load and check basic properties of the IP CF" if $ENV{'TEST_VERBOSE'};
+{
+ my $cfs = RT::CustomFields->new($RT::SystemUser);
+ $cfs->Limit( FIELD => 'Name', VALUE => 'IP' );
+ is( $cfs->Count, 1, "found one CF with name 'IP'" );
+
+ $cf = $cfs->First;
+ is( $cf->Type, 'IPAddress', 'type check' );
+ is( $cf->LookupType, 'RT::Queue-RT::Ticket', 'lookup type check' );
+ ok( !$cf->MaxValues, "unlimited number of values" );
+ ok( !$cf->Disabled, "not disabled" );
+}
+
+diag "check that CF applies to queue General" if $ENV{'TEST_VERBOSE'};
+{
+ my $cfs = $q->TicketCustomFields;
+ $cfs->Limit( FIELD => 'id', VALUE => $cf->id, ENTRYAGGREGATOR => 'AND' );
+ is( $cfs->Count, 1, 'field applies to queue' );
+}
+
+my %valid = (
+ 'abcd:' x 7 . 'abcd' => 'abcd:' x 7 . 'abcd',
+ '034:' x 7 . '034' => '0034:' x 7 . '0034',
+ 'abcd::' => 'abcd:' . '0000:' x 6 . '0000',
+ '::abcd' => '0000:' x 7 . 'abcd',
+ 'abcd::034' => 'abcd:' . '0000:' x 6 . '0034',
+ 'abcd::192.168.1.1' => 'abcd:' . '0000:' x 5 . 'c0a8:0101',
+ '::192.168.1.1' => '0000:' x 6 . 'c0a8:0101',
+ '::' => '0000:' x 7 . '0000',
+);
+
+diag "create a ticket via web and set IP" if $ENV{'TEST_VERBOSE'};
+{
+ for my $ip ( keys %valid ) {
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $ip,
+ }
+ );
+
+ $agent->content_contains( $valid{$ip}, "IP on the page" );
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created ticket $id" );
+
+ my $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+ is( $ticket->FirstCustomFieldValue('IP'), $valid{$ip},
+ 'correct value' );
+
+ my $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets->FromSQL("id = $id AND CF.{IP} = '$ip'");
+ ok( $tickets->Count, "found tickets" );
+ }
+}
+
+diag "create a ticket and edit IP field using Edit page"
+ if $ENV{'TEST_VERBOSE'};
+
+{
+ my $ip = 'abcd::034';
+
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => { Subject => 'test ip', }
+ );
+
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created ticket $id" );
+ my $cf_field = "Object-RT::Ticket-$id-CustomField-$cf_id-Values";
+
+ $agent->follow_link_ok( { text => 'Basics', n => "1" },
+ "Followed 'Basics' link" );
+ $agent->form_name('TicketModify');
+
+ is( $agent->value($cf_field), '', 'IP is empty' );
+ $agent->field( $cf_field => $valid{$ip} );
+ $agent->click('SubmitTicket');
+
+ $agent->content_contains( $valid{$ip}, "IP on the page" );
+
+ my $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+ my $values = $ticket->CustomFieldValues('IP');
+ is( $ticket->FirstCustomFieldValue('IP'), $valid{$ip}, 'correct value' );
+
+ diag "set IP with spaces around" if $ENV{'TEST_VERBOSE'};
+ my $new_ip = '::3141';
+ my $new_value = '0000:' x 7 . '3141';
+
+ $agent->follow_link_ok( { text => 'Basics', n => "1" },
+ "Followed 'Basics' link" );
+ $agent->form_name('TicketModify');
+ is( $agent->value($cf_field), $valid{$ip}, 'IP is in input box' );
+ $agent->field( $cf_field => $new_ip );
+ $agent->click('SubmitTicket');
+
+ $agent->content_contains( $new_value, "IP on the page" );
+
+ $ticket = RT::Ticket->new($RT::SystemUser);
+ $ticket->Load($id);
+ ok( $ticket->id, 'loaded ticket' );
+ is( $ticket->FirstCustomFieldValue('IP'), $new_value, 'correct value' );
+}
+
+diag "check that we parse correct IPs only" if $ENV{'TEST_VERBOSE'};
+{
+
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ my @invalid =
+ ( 'abcd:', 'efgh', 'abcd:' x 8 . 'abcd', 'abcd::abcd::abcd' );
+ for my $invalid (@invalid) {
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => $invalid,
+ }
+ );
+
+ $agent->content_contains( 'can not be parsed as an IP address',
+ 'ticket fails to create' );
+ }
+}
+
+diag "create two tickets with different IPs and check several searches"
+ if $ENV{'TEST_VERBOSE'};
+{
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => 'abcd::',
+ }
+ );
+
+ my ($id1) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id1, "created first ticket $id1" );
+
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test ip',
+ $cf_field => 'bbcd::',
+ }
+ );
+
+ my ($id2) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id2, "created second ticket $id2" );
+
+ my $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets->FromSQL("id = $id1 OR id = $id2");
+ is( $tickets->Count, 2, "found both tickets by 'id = x OR y'" );
+
+ # IP
+ $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'abcd::'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'),
+ 'abcd' . ':0000' x 7, "correct value" );
+ $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = 'bbcd::'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'),
+ 'bbcd' . ':0000' x 7, "correct value" );
+
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} <= 'abcd::'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'),
+ 'abcd' . ':0000' x 7, "correct value" );
+ $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} >= 'bbcd::'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'),
+ 'bbcd' . ':0000' x 7, "correct value" );
+
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} > 'bbcd::'");
+ is( $tickets->Count, 0, "no tickets found" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} < 'abcd::'");
+ is( $tickets->Count, 0, "no tickets found" );
+
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} < 'bbcd::'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'),
+ 'abcd' . ':0000' x 7, "correct value" );
+
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} > 'abcd::'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->FirstCustomFieldValue('IP'),
+ 'bbcd' . ':0000' x 7, "correct value" );
+}
+
+diag "create a ticket with an IP of abcd:23:: and search for doesn't match 'abcd:23'."
+ if $ENV{'TEST_VERBOSE'};
+{
+ ok $agent->goto_create_ticket($q), "go to create ticket";
+ my $cf_field = "Object-RT::Ticket--CustomField-$cf_id-Values";
+ $agent->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'local',
+ $cf_field => 'abcd:23::',
+ }
+ );
+
+ my ($id) = $agent->content =~ /Ticket (\d+) created/;
+ ok( $id, "created first ticket $id" );
+
+ my $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets->FromSQL("id=$id AND CF.{IP} NOT LIKE 'abcd:23'");
+
+ SKIP: {
+ skip "partical ip parse can causes ambiguity", 1;
+ is( $tickets->Count, 0, "should not have found the ticket" );
+ }
+}
+
diff --git a/rt/t/customfields/pattern.t b/rt/t/customfields/pattern.t
new file mode 100644
index 000000000..7d1090fa7
--- /dev/null
+++ b/rt/t/customfields/pattern.t
@@ -0,0 +1,44 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+
+use RT;
+use RT::Test nodata => 1, tests => 17;
+
+my $q = RT::Queue->new($RT::SystemUser);
+works($q->Create(Name => "CF-Pattern-".$$));
+
+my $cf = RT::CustomField->new($RT::SystemUser);
+my @cf_args = (Name => $q->Name, Type => 'Freeform', Queue => $q->id, MaxValues => 1);
+
+fails($cf->Create(@cf_args, Pattern => ')))bad!regex((('));
+works($cf->Create(@cf_args, Pattern => 'good regex'));
+
+my $t = RT::Ticket->new($RT::SystemUser);
+my ($id,undef,$msg) = $t->Create(Queue => $q->id, Subject => 'CF Test');
+works($id,$msg);
+
+# OK, I'm thoroughly brain washed by HOP at this point now...
+sub cnt { $t->CustomFieldValues($cf->id)->Count };
+sub add { $t->AddCustomFieldValue(Field => $cf->id, Value => $_[0]) };
+sub del { $t->DeleteCustomFieldValue(Field => $cf->id, Value => $_[0]) };
+
+is(cnt(), 0, "No values yet");
+fails(add('not going to match'));
+is(cnt(), 0, "No values yet");
+works(add('here is a good regex'));
+is(cnt(), 1, "Value filled");
+fails(del('here is a good regex'));
+is(cnt(), 1, "Single CF - Value _not_ deleted");
+
+$cf->SetMaxValues(0); # Unlimited MaxValues
+
+works(del('here is a good regex'));
+is(cnt(), 0, "Multiple CF - Value deleted");
+
+fails($cf->SetPattern('(?{ "insert evil code here" })'));
+works($cf->SetPattern('(?!)')); # reject everything
+fails(add(''));
+fails(add('...'));
+
+undef $t;
diff --git a/rt/t/customfields/single_values.t b/rt/t/customfields/single_values.t
new file mode 100644
index 000000000..15a00163c
--- /dev/null
+++ b/rt/t/customfields/single_values.t
@@ -0,0 +1,37 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+
+use RT;
+use RT::Test nodata => 1, tests => 8;
+
+
+
+my $q = RT::Queue->new(RT->SystemUser);
+my ($id,$msg) =$q->Create(Name => "CF-Single-".$$);
+ok($id,$msg);
+
+my $cf = RT::CustomField->new(RT->SystemUser);
+($id,$msg) = $cf->Create(Name => 'Single-'.$$, Type => 'Select', MaxValues => '1', Queue => $q->id);
+ok($id,$msg);
+
+
+($id,$msg) =$cf->AddValue(Name => 'First');
+ok($id,$msg);
+
+($id,$msg) =$cf->AddValue(Name => 'Second');
+ok($id,$msg);
+
+
+my $t = RT::Ticket->new(RT->SystemUser);
+($id,undef,$msg) = $t->Create(Queue => $q->id,
+ Subject => 'CF Test');
+
+ok($id,$msg);
+is($t->CustomFieldValues($cf->id)->Count, 0, "No values yet");
+$t->AddCustomFieldValue(Field => $cf->id, Value => 'First');
+is($t->CustomFieldValues($cf->id)->Count, 1, "One now");
+
+$t->AddCustomFieldValue(Field => $cf->id, Value => 'Second');
+is($t->CustomFieldValues($cf->id)->Count, 1, "Still one");
+
diff --git a/rt/t/customfields/sort_order.t b/rt/t/customfields/sort_order.t
index c5c808ceb..2453a7cc8 100644
--- a/rt/t/customfields/sort_order.t
+++ b/rt/t/customfields/sort_order.t
@@ -3,7 +3,7 @@
use strict;
use warnings;
-use RT::Test tests => 18;
+use RT::Test tests => 20;
use RT::Ticket;
use RT::CustomField;
@@ -11,10 +11,10 @@ my $queue_name = "CFSortQueue-$$";
my $queue = RT::Test->load_or_create_queue( Name => $queue_name );
ok($queue && $queue->id, "$queue_name - test queue creation");
-diag "create multiple CFs: B, A and C" if $ENV{TEST_VERBOSE};
+diag "create multiple CFs: B, A and C";
my @cfs = ();
{
- my $cf = RT::CustomField->new( $RT::SystemUser );
+ my $cf = RT::CustomField->new( RT->SystemUser );
my ($ret, $msg) = $cf->Create(
Name => "CF B",
Queue => $queue->id,
@@ -24,7 +24,7 @@ my @cfs = ();
push @cfs, $cf;
}
{
- my $cf = RT::CustomField->new( $RT::SystemUser );
+ my $cf = RT::CustomField->new( RT->SystemUser );
my ($ret, $msg) = $cf->Create(
Name => "CF A",
Queue => $queue->id,
@@ -34,7 +34,7 @@ my @cfs = ();
push @cfs, $cf;
}
{
- my $cf = RT::CustomField->new( $RT::SystemUser );
+ my $cf = RT::CustomField->new( RT->SystemUser );
my ($ret, $msg) = $cf->Create(
Name => "CF C",
Queue => $queue->id,
@@ -47,12 +47,11 @@ my @cfs = ();
my ($baseurl, $m) = RT::Test->started_ok;
ok $m->login( root => 'password' ), 'logged in';
-diag "reorder CFs: C, A and B" if $ENV{TEST_VERBOSE};
+diag "reorder CFs: C, A and B";
{
$m->get( '/Admin/Queues/' );
$m->follow_link_ok( {text => $queue->id} );
- $m->follow_link_ok( {text => 'Ticket Custom Fields'} );
-
+ $m->follow_link_ok( {id => 'page-ticket-custom-fields'} );
my @tmp = ($m->content =~ /(CF [ABC])/g);
is_deeply(\@tmp, ['CF B', 'CF A', 'CF C']);
@@ -64,7 +63,7 @@ diag "reorder CFs: C, A and B" if $ENV{TEST_VERBOSE};
is_deeply(\@tmp, ['CF C', 'CF A', 'CF B']);
}
-diag "check ticket create, display and edit pages" if $ENV{TEST_VERBOSE};
+diag "check ticket create, display and edit pages";
{
$m->submit_form(
form_name => "CreateTicketInQueue",
@@ -83,8 +82,7 @@ diag "check ticket create, display and edit pages" if $ENV{TEST_VERBOSE};
@tmp = ($m->content =~ /(CF [ABC])/g);
is_deeply(\@tmp, ['CF C', 'CF A', 'CF B']);
-
- $m->follow_link_ok( {text => 'Custom Fields'} );
+ $m->follow_link_ok( {id => 'page-basics'});
@tmp = ($m->content =~ /(CF [ABC])/g);
is_deeply(\@tmp, ['CF C', 'CF A', 'CF B']);
diff --git a/rt/t/customfields/transaction.t b/rt/t/customfields/transaction.t
new file mode 100644
index 000000000..22f8459eb
--- /dev/null
+++ b/rt/t/customfields/transaction.t
@@ -0,0 +1,60 @@
+#!/usr/bin/perl
+
+use warnings;
+use strict;
+use Data::Dumper;
+
+use RT::Test nodata => 1, tests => 14;
+use_ok('RT');
+use_ok('RT::Transactions');
+
+
+my $q = RT::Queue->new(RT->SystemUser);
+my ($id,$msg) = $q->Create( Name => 'TxnCFTest'.$$);
+ok($id,$msg);
+
+my $cf = RT::CustomField->new(RT->SystemUser);
+($id,$msg) = $cf->Create(Name => 'Txnfreeform-'.$$, Type => 'Freeform', MaxValues => '0', LookupType => RT::Transaction->CustomFieldLookupType );
+
+ok($id,$msg);
+
+($id,$msg) = $cf->AddToObject($q);
+
+ok($id,$msg);
+
+
+my $ticket = RT::Ticket->new(RT->SystemUser);
+
+my $transid;
+($id,$transid, $msg) = $ticket->Create(Queue => $q->id,
+ Subject => 'TxnCF test',
+ );
+ok($id,$msg);
+
+my $trans = RT::Transaction->new(RT->SystemUser);
+$trans->Load($transid);
+
+is($trans->ObjectId,$id);
+is ($trans->ObjectType, 'RT::Ticket');
+is ($trans->Type, 'Create');
+my $txncfs = $trans->CustomFields;
+is ($txncfs->Count, 1, "We have one custom field");
+my $txn_cf = $txncfs->First;
+is ($txn_cf->id, $cf->id, "It's the right custom field");
+my $values = $trans->CustomFieldValues($txn_cf->id);
+is ($values->Count, 0, "It has no values");
+
+# Old API
+my %cf_updates = ( 'CustomField-'.$cf->id => 'Testing');
+$trans->UpdateCustomFields( ARGSRef => \%cf_updates);
+
+ $values = $trans->CustomFieldValues($txn_cf->id);
+is ($values->Count, 1, "It has one value");
+
+# New API
+
+$trans->UpdateCustomFields( 'CustomField-'.$cf->id => 'Test two');
+ $values = $trans->CustomFieldValues($txn_cf->id);
+is ($values->Count, 2, "it has two values");
+
+# TODO ok(0, "Should updating custom field values remove old values?");
diff --git a/rt/t/data/configs/passwords b/rt/t/data/configs/passwords
new file mode 100644
index 000000000..2ea72d166
--- /dev/null
+++ b/rt/t/data/configs/passwords
@@ -0,0 +1,2 @@
+# root / password
+root:8NbrT44Shvnco
diff --git a/rt/t/fts/indexed_mysql.t b/rt/t/fts/indexed_mysql.t
new file mode 100644
index 000000000..8966f1cd4
--- /dev/null
+++ b/rt/t/fts/indexed_mysql.t
@@ -0,0 +1,134 @@
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+
+use RT::Test tests => undef;
+plan skip_all => 'Not mysql' unless RT->Config->Get('DatabaseType') eq 'mysql';
+plan skip_all => "No SphinxSE in mysql" unless $RT::Handle->CheckSphinxSE;
+
+my %sphinx;
+$sphinx{'searchd'} = RT::Test->find_executable('searchd');
+$sphinx{'indexer'} = RT::Test->find_executable('indexer');
+
+plan skip_all => "No searchd and indexer under PATH"
+ unless $sphinx{'searchd'} && $sphinx{'indexer'};
+
+plan tests => 15;
+
+RT->Config->Set( FullTextSearch => Enable => 1, Indexed => 1, Table => 'AttachmentsIndex', MaxMatches => 1000 );
+
+setup_indexing();
+
+my $q = RT::Test->load_or_create_queue( Name => 'General' );
+ok $q && $q->id, 'loaded or created queue';
+my $queue = $q->Name;
+
+sub setup_indexing {
+ # Since we're not running a webserver in this test, use the
+ # known-safe port we determined at test setup
+ my $port = $RT::Test::port;
+ my ($exit_code, $output) = RT::Test->run_and_capture(
+ 'no-ask' => 1,
+ command => $RT::SbinPath .'/rt-setup-fulltext-index',
+ dba => $ENV{'RT_DBA_USER'},
+ 'dba-password' => $ENV{'RT_DBA_PASSWORD'},
+ url => "sphinx://localhost:$port/rt",
+ );
+ ok(!$exit_code, "setted up index");
+ diag "output: $output" if $ENV{'TEST_VERBOSE'};
+
+ my $tmp = $sphinx{'directory'} = File::Spec->catdir( RT::Test->temp_directory, 'sphinx' );
+ mkdir $tmp;
+
+ my $sphinx_conf = $output;
+ $sphinx_conf =~ s/.*?source rt {/source rt {/ms;
+ $sphinx_conf =~ s{\Q$RT::VarPath\E/sphinx/}{$tmp/}g;
+
+ $sphinx{'config'} = File::Spec->catfile( $tmp, 'sphinx.conf' );
+ {
+ open my $fh, ">", $sphinx{'config'};
+ print $fh $sphinx_conf;
+ close $fh;
+ }
+
+ sync_index();
+
+ {
+ my ($exit_code, $output) = RT::Test->run_and_capture(
+ command => $sphinx{'searchd'},
+ config => $sphinx{'config'},
+ );
+ ok(!$exit_code, "setted up index") or diag "output: $output";
+ $sphinx{'started'} = 1 if !$exit_code;
+ }
+}
+
+sub sync_index {
+ local $SIG{'CHLD'} = 'DEFAULT';
+ local $SIG{'PIPE'} = 'DEFAULT';
+ open my $fh, '-|', $sphinx{'indexer'}, '--all',
+ '--config' => $sphinx{'config'},
+ $sphinx{'started'}? ('--rotate') : (),
+ ;
+ my $output = <$fh>;
+ close $fh;
+ my $exit_code = $?>>8;
+ ok(!$exit_code, "indexed") or diag "output: $output";
+
+ # We may need to wait a second for searchd to pick up the changes
+ sleep 1;
+}
+
+sub run_tests {
+ my @test = @_;
+ while ( my ($query, $checks) = splice @test, 0, 2 ) {
+ run_test( $query, %$checks );
+ }
+}
+
+my @tickets;
+sub run_test {
+ my ($query, %checks) = @_;
+ my $query_prefix = join ' OR ', map 'id = '. $_->id, @tickets;
+
+ my $tix = RT::Tickets->new(RT->SystemUser);
+ $tix->FromSQL( "( $query_prefix ) AND ( $query )" );
+
+ my $error = 0;
+
+ my $count = 0;
+ $count++ foreach grep $_, values %checks;
+ is($tix->Count, $count, "found correct number of ticket(s) by '$query'") or $error = 1;
+
+ my $good_tickets = ($tix->Count == $count);
+ while ( my $ticket = $tix->Next ) {
+ next if $checks{ $ticket->Subject };
+ diag $ticket->Subject ." ticket has been found when it's not expected";
+ $good_tickets = 0;
+ }
+ ok( $good_tickets, "all tickets are good with '$query'" ) or $error = 1;
+
+ diag "Wrong SQL query for '$query':". $tix->BuildSelectQuery if $error;
+}
+
+@tickets = RT::Test->create_tickets(
+ { Queue => $q->id },
+ { Subject => 'book', Content => 'book' },
+ { Subject => 'bar', Content => 'bar' },
+);
+sync_index();
+
+run_tests(
+ "Content LIKE 'book'" => { book => 1, bar => 0 },
+ "Content LIKE 'bar'" => { book => 0, bar => 1 },
+);
+
+END {
+ my $Test = RT::Test->builder;
+ return if $Test->{Original_Pid} != $$;
+ return unless $sphinx{'started'};
+
+ my $pid = int RT::Test->file_content([$sphinx{'directory'}, 'searchd.pid']);
+ kill TERM => $pid if $pid;
+}
diff --git a/rt/t/fts/indexed_oracle.t b/rt/t/fts/indexed_oracle.t
new file mode 100644
index 000000000..5d71712d0
--- /dev/null
+++ b/rt/t/fts/indexed_oracle.t
@@ -0,0 +1,82 @@
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+
+use RT::Test tests => undef;
+plan skip_all => 'Not Oracle' unless RT->Config->Get('DatabaseType') eq 'Oracle';
+plan tests => 13;
+
+RT->Config->Set( FullTextSearch => Enable => 1, Indexed => 1 );
+
+setup_indexing();
+
+my $q = RT::Test->load_or_create_queue( Name => 'General' );
+ok $q && $q->id, 'loaded or created queue';
+my $queue = $q->Name;
+
+sub setup_indexing {
+ my %args = (
+ 'no-ask' => 1,
+ command => $RT::SbinPath .'/rt-setup-fulltext-index',
+ dba => $ENV{'RT_DBA_USER'},
+ 'dba-password' => $ENV{'RT_DBA_PASSWORD'},
+ );
+ my ($exit_code, $output) = RT::Test->run_and_capture( %args );
+ ok(!$exit_code, "setted up index") or diag "output: $output";
+}
+
+sub sync_index {
+ my %args = (
+ command => $RT::SbinPath .'/rt-fulltext-indexer',
+ );
+ my ($exit_code, $output) = RT::Test->run_and_capture( %args );
+ ok(!$exit_code, "synced the index") or diag "output: $output";
+}
+
+sub run_tests {
+ my @test = @_;
+ while ( my ($query, $checks) = splice @test, 0, 2 ) {
+ run_test( $query, %$checks );
+ }
+}
+
+my @tickets;
+sub run_test {
+ my ($query, %checks) = @_;
+ my $query_prefix = join ' OR ', map 'id = '. $_->id, @tickets;
+
+ my $tix = RT::Tickets->new(RT->SystemUser);
+ $tix->FromSQL( "( $query_prefix ) AND ( $query )" );
+
+ my $error = 0;
+
+ my $count = 0;
+ $count++ foreach grep $_, values %checks;
+ is($tix->Count, $count, "found correct number of ticket(s) by '$query'") or $error = 1;
+
+ my $good_tickets = ($tix->Count == $count);
+ while ( my $ticket = $tix->Next ) {
+ next if $checks{ $ticket->Subject };
+ diag $ticket->Subject ." ticket has been found when it's not expected";
+ $good_tickets = 0;
+ }
+ ok( $good_tickets, "all tickets are good with '$query'" ) or $error = 1;
+
+ diag "Wrong SQL query for '$query':". $tix->BuildSelectQuery if $error;
+}
+
+@tickets = RT::Test->create_tickets(
+ { Queue => $q->id },
+ { Subject => 'book', Content => 'book' },
+ { Subject => 'bar', Content => 'bar' },
+);
+sync_index();
+
+run_tests(
+ "Content LIKE 'book'" => { book => 1, bar => 0 },
+ "Content LIKE 'bar'" => { book => 0, bar => 1 },
+);
+
+@tickets = ();
+
diff --git a/rt/t/fts/indexed_pg.t b/rt/t/fts/indexed_pg.t
new file mode 100644
index 000000000..c437c1f4f
--- /dev/null
+++ b/rt/t/fts/indexed_pg.t
@@ -0,0 +1,119 @@
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+
+use RT::Test tests => undef;
+plan skip_all => 'Not Pg' unless RT->Config->Get('DatabaseType') eq 'Pg';
+
+my ($major, $minor) = $RT::Handle->dbh->get_info(18) =~ /^0*(\d+)\.0*(\d+)/;
+plan skip_all => "Need Pg 8.2 or higher; we have $major.$minor"
+ if "$major.$minor" < 8.2;
+
+plan tests => 36;
+
+RT->Config->Set( FullTextSearch => Enable => 1, Indexed => 1, Column => 'ContentIndex', Table => 'Attachments' );
+
+setup_indexing();
+
+my $q = RT::Test->load_or_create_queue( Name => 'General' );
+ok $q && $q->id, 'loaded or created queue';
+my $queue = $q->Name;
+
+sub setup_indexing {
+ my %args = (
+ 'no-ask' => 1,
+ command => $RT::SbinPath .'/rt-setup-fulltext-index',
+ dba => $ENV{'RT_DBA_USER'},
+ 'dba-password' => $ENV{'RT_DBA_PASSWORD'},
+ );
+ my ($exit_code, $output) = RT::Test->run_and_capture( %args );
+ ok(!$exit_code, "setted up index") or diag "output: $output";
+}
+
+sub sync_index {
+ my %args = (
+ command => $RT::SbinPath .'/rt-fulltext-indexer',
+ );
+ my ($exit_code, $output) = RT::Test->run_and_capture( %args );
+ ok(!$exit_code, "setted up index") or diag "output: $output";
+}
+
+sub run_tests {
+ my @test = @_;
+ while ( my ($query, $checks) = splice @test, 0, 2 ) {
+ run_test( $query, %$checks );
+ }
+}
+
+my @tickets;
+sub run_test {
+ my ($query, %checks) = @_;
+ my $query_prefix = join ' OR ', map 'id = '. $_->id, @tickets;
+
+ my $tix = RT::Tickets->new(RT->SystemUser);
+ $tix->FromSQL( "( $query_prefix ) AND ( $query )" );
+
+ my $error = 0;
+
+ my $count = 0;
+ $count++ foreach grep $_, values %checks;
+ is($tix->Count, $count, "found correct number of ticket(s) by '$query'") or $error = 1;
+
+ my $good_tickets = ($tix->Count == $count);
+ while ( my $ticket = $tix->Next ) {
+ next if $checks{ $ticket->id };
+ diag $ticket->Subject ." ticket has been found when it's not expected";
+ $good_tickets = 0;
+ }
+ ok( $good_tickets, "all tickets are good with '$query'" ) or $error = 1;
+
+ diag "Wrong SQL query for '$query':". $tix->BuildSelectQuery if $error;
+}
+
+@tickets = RT::Test->create_tickets(
+ { Queue => $q->id },
+ { Subject => 'fts test 1', Content => 'book' },
+ { Subject => 'fts test 2', Content => 'bars' },
+);
+sync_index();
+
+my $book = $tickets[0];
+my $bars = $tickets[1];
+
+run_tests(
+ "Content LIKE 'book'" => { $book->id => 1, $bars->id => 0 },
+ "Content LIKE 'bars'" => { $book->id => 0, $bars->id => 1 },
+
+ # make sure that Pg stemming works
+ "Content LIKE 'books'" => { $book->id => 1, $bars->id => 0 },
+ "Content LIKE 'bar'" => { $book->id => 0, $bars->id => 1 },
+
+ # no matches
+ "Content LIKE 'baby'" => { $book->id => 0, $bars->id => 0 },
+ "Content LIKE 'pubs'" => { $book->id => 0, $bars->id => 0 },
+);
+
+# Test the "ts_vector too long" skip
+my $content = "";
+$content .= "$_\n" for 1..200_000;
+@tickets = RT::Test->create_tickets(
+ { Queue => $q->id },
+ { Subject => 'Short content', Content => '50' },
+ { Subject => 'Long content', Content => $content },
+ { Subject => 'More short', Content => '50' },
+);
+
+my ($exit_code, $output) = RT::Test->run_and_capture(
+ command => $RT::SbinPath .'/rt-fulltext-indexer'
+);
+like($output, qr/string is too long for tsvector/, "Got a warning for the ticket");
+ok(!$exit_code, "set up index");
+
+# The long content is skipped entirely
+run_tests(
+ "Content LIKE '1'" => { $tickets[0]->id => 0, $tickets[1]->id => 0, $tickets[2]->id => 0 },
+ "Content LIKE '50'" => { $tickets[0]->id => 1, $tickets[1]->id => 0, $tickets[2]->id => 1 },
+);
+
+@tickets = ();
diff --git a/rt/t/fts/not_indexed.t b/rt/t/fts/not_indexed.t
new file mode 100644
index 000000000..0a1abd081
--- /dev/null
+++ b/rt/t/fts/not_indexed.t
@@ -0,0 +1,61 @@
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+
+use RT::Test tests => 20;
+
+RT->Config->Set( FullTextSearch => Enable => 1, Indexed => 0 );
+
+my $q = RT::Test->load_or_create_queue( Name => 'General' );
+ok $q && $q->id, 'loaded or created queue';
+my $queue = $q->Name;
+
+sub run_tests {
+ my @test = @_;
+ while ( my ($query, $checks) = splice @test, 0, 2 ) {
+ run_test( $query, %$checks );
+ }
+}
+
+my @tickets;
+sub run_test {
+ my ($query, %checks) = @_;
+ my $query_prefix = join ' OR ', map 'id = '. $_->id, @tickets;
+
+ my $tix = RT::Tickets->new(RT->SystemUser);
+ $tix->FromSQL( "( $query_prefix ) AND ( $query )" );
+
+ my $error = 0;
+
+ my $count = 0;
+ $count++ foreach grep $_, values %checks;
+ is($tix->Count, $count, "found correct number of ticket(s) by '$query'") or $error = 1;
+
+ my $good_tickets = ($tix->Count == $count);
+ while ( my $ticket = $tix->Next ) {
+ next if $checks{ $ticket->Subject };
+ diag $ticket->Subject ." ticket has been found when it's not expected";
+ $good_tickets = 0;
+ }
+ ok( $good_tickets, "all tickets are good with '$query'" ) or $error = 1;
+
+ diag "Wrong SQL query for '$query':". $tix->BuildSelectQuery if $error;
+}
+
+@tickets = RT::Test->create_tickets(
+ { Queue => $q->id },
+ { Subject => 'book', Content => 'book' },
+ { Subject => 'bar', Content => 'bar' },
+ { Subject => 'no content', Content => undef },
+);
+
+run_tests(
+ "Content LIKE 'book'" => { book => 1, bar => 0 },
+ "Content LIKE 'bar'" => { book => 0, bar => 1 },
+ "(Content LIKE 'baz' OR Subject LIKE 'con')" => { 'no content' => 1 },
+ "(Content LIKE 'bar' OR Subject LIKE 'con')" => { 'no content' => 1, bar => 1 },
+ "(Content LIKE 'bar' OR Subject LIKE 'missing')" => { bar => 1 },
+);
+
+
diff --git a/rt/t/i18n/caching.t b/rt/t/i18n/caching.t
new file mode 100644
index 000000000..ebb29423f
--- /dev/null
+++ b/rt/t/i18n/caching.t
@@ -0,0 +1,33 @@
+#!/usr/bin/perl -w
+use strict;
+use warnings;
+
+use RT::Test;
+
+{
+ my $french = RT::User->new(RT->SystemUser);
+ $french->LoadOrCreateByEmail('french@example.com');
+ $french->SetName('french');
+ $french->SetLang('fr');
+ $french->SetPrivileged(1);
+ $french->SetPassword('password');
+ $french->PrincipalObj->GrantRight(Right => 'SuperUser');
+}
+
+
+my ($baseurl, $m) = RT::Test->started_ok;
+$m->login( root => "password" );
+$m->get_ok('/Prefs/Other.html');
+$m->content_lacks('Ne pas','Lacks translated french');
+$m->get_ok( "/NoAuth/Logout.html" );
+
+$m->login( french => "password" );
+$m->get_ok('/Prefs/Other.html');
+$m->content_contains('Ne pas','Has translated french');
+$m->get_ok( "/NoAuth/Logout.html" ); # ->logout fails because it's translated
+
+$m->login( root => "password" );
+$m->get_ok('/Prefs/Other.html');
+$m->content_lacks('Ne pas','Lacks translated french');
+
+undef $m;
diff --git a/rt/t/i18n/footer.t b/rt/t/i18n/footer.t
new file mode 100644
index 000000000..e0d09058c
--- /dev/null
+++ b/rt/t/i18n/footer.t
@@ -0,0 +1,29 @@
+#!/usr/bin/perl -w
+use strict;
+use warnings;
+
+use RT::Test;
+
+{
+ my $chinese = RT::User->new(RT->SystemUser);
+ $chinese->LoadOrCreateByEmail('chinese@example.com');
+ $chinese->SetName('chinese');
+ $chinese->SetLang('zh_tw');
+ $chinese->SetPrivileged(1);
+ $chinese->SetPassword('password');
+ $chinese->PrincipalObj->GrantRight(Right => 'SuperUser');
+}
+
+my ($baseurl, $m) = RT::Test->started_ok;
+$m->login( root => "password" );
+$m->content_contains('Copyright','Has english coypright');
+$m->get_ok( "/NoAuth/Logout.html" );
+
+$m->login( chinese => "password" );
+$m->content_lacks('Copyright','Lacks english copyright');
+$m->get_ok( "/NoAuth/Logout.html" ); # ->logout fails because it's translated
+
+$m->login( root => "password" );
+$m->content_contains('Copyright','Still has english copyright');
+
+undef $m;
diff --git a/rt/t/lifecycles/basics.t b/rt/t/lifecycles/basics.t
new file mode 100644
index 000000000..40e239186
--- /dev/null
+++ b/rt/t/lifecycles/basics.t
@@ -0,0 +1,247 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use Data::Dumper;
+
+BEGIN {require 't/lifecycles/utils.pl'};
+
+my $general = RT::Test->load_or_create_queue(
+ Name => 'General',
+);
+ok $general && $general->id, 'loaded or created a queue';
+
+my $tstatus = sub {
+ DBIx::SearchBuilder::Record::Cachable->FlushCache;
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ $ticket->Load( $_[0] );
+ return $ticket->Status;
+};
+
+diag "check basic API";
+{
+ my $schema = $general->Lifecycle;
+ isa_ok($schema, 'RT::Lifecycle');
+ is $schema->Name, 'default', "it's a default schema";
+ is_deeply [$schema->Valid],
+ [qw(new open stalled resolved rejected deleted)],
+ 'this is the default set from our config file';
+
+ foreach my $s ( qw(new open stalled resolved rejected deleted) ) {
+ ok $schema->IsValid($s), "valid";
+ }
+ ok !$schema->IsValid(), 'invalid';
+ ok !$schema->IsValid(''), 'invalid';
+ ok !$schema->IsValid(undef), 'invalid';
+ ok !$schema->IsValid('foo'), 'invalid';
+
+ is_deeply [$schema->Initial], ['new'], 'initial set';
+ ok $schema->IsInitial('new'), "initial";
+ ok !$schema->IsInitial('open'), "not initial";
+ ok !$schema->IsInitial, "not initial";
+ ok !$schema->IsInitial(''), "not initial";
+ ok !$schema->IsInitial(undef), "not initial";
+ ok !$schema->IsInitial('foo'), "not initial";
+
+ is_deeply [$schema->Active], [qw(open stalled)], 'active set';
+ ok( $schema->IsActive($_), "active" )
+ foreach qw(open stalled);
+ ok !$schema->IsActive('new'), "not active";
+ ok !$schema->IsActive, "not active";
+ ok !$schema->IsActive(''), "not active";
+ ok !$schema->IsActive(undef), "not active";
+ ok !$schema->IsActive('foo'), "not active";
+
+ is_deeply [$schema->Inactive], [qw(resolved rejected deleted)], 'inactive set';
+ ok( $schema->IsInactive($_), "inactive" )
+ foreach qw(resolved rejected deleted);
+ ok !$schema->IsInactive('new'), "not inactive";
+ ok !$schema->IsInactive, "not inactive";
+ ok !$schema->IsInactive(''), "not inactive";
+ ok !$schema->IsInactive(undef), "not inactive";
+ ok !$schema->IsInactive('foo'), "not inactive";
+
+ is_deeply [$schema->Transitions('')], [qw(new open resolved)], 'on create transitions';
+ ok $schema->IsTransition('' => $_), 'good transition'
+ foreach qw(new open resolved);
+}
+
+my ($baseurl, $m) = RT::Test->started_ok;
+ok $m->login, 'logged in';
+
+diag "check status input on create";
+{
+ $m->goto_create_ticket( $general );
+
+ my $form = $m->form_name('TicketCreate');
+ ok my $input = $form->find_input('Status'), 'found status selector';
+
+ my @form_values = $input->possible_values;
+ ok scalar @form_values, 'some options in the UI';
+
+ my $valid = 1;
+ foreach ( @form_values ) {
+ next if $general->Lifecycle->IsValid($_);
+ $valid = 0;
+ diag("$_ doesn't appear to be a valid status, but it was in the form");
+ }
+
+
+ ok $valid, 'all statuses in the form are valid';
+}
+
+diag "create a ticket";
+my $tid;
+{
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ ($tid) = $ticket->Create( Queue => $general->id, Subject => 'test' );
+ ok $tid, "created a ticket #$tid";
+ is $ticket->Status, 'new', 'correct status';
+}
+
+diag "new ->(open it)-> open";
+{
+ ok $m->goto_ticket( $tid ), 'opened a ticket';
+ $m->check_links(
+ has => ['Open It', 'Resolve', 'Reject', 'Delete'],
+ has_no => ['Stall', 'Re-open', 'Undelete'],
+ );
+
+ $m->follow_link_ok({text => 'Open It'});
+ $m->form_name('TicketUpdate');
+ $m->click('SubmitTicket');
+
+ is $tstatus->($tid), 'open', 'changed status';
+}
+
+diag "open ->(stall)-> stalled";
+{
+ is $tstatus->($tid), 'open', 'ticket is open';
+
+ ok $m->goto_ticket( $tid ), 'opened a ticket';
+
+ $m->check_links(
+ has => ['Stall', 'Resolve', 'Reject'],
+ has_no => ['Open It', 'Delete', 'Re-open', 'Undelete'],
+ );
+
+ $m->follow_link_ok({text => 'Stall'});
+ $m->form_name('TicketUpdate');
+ $m->click('SubmitTicket');
+
+ is $tstatus->($tid), 'stalled', 'changed status';
+}
+
+diag "stall ->(open it)-> open";
+{
+ is $tstatus->($tid), 'stalled', 'ticket is stalled';
+
+ ok $m->goto_ticket( $tid ), 'opened a ticket';
+ $m->check_links(
+ has => ['Open It'],
+ has_no => ['Delete', 'Re-open', 'Undelete', 'Stall', 'Resolve', 'Reject'],
+ );
+
+ $m->follow_link_ok({text => 'Open It'});
+
+ is $tstatus->($tid), 'open', 'changed status';
+}
+
+diag "open -> deleted, only via modify";
+{
+ is $tstatus->($tid), 'open', 'ticket is open';
+
+ $m->get_ok( '/Ticket/Modify.html?id='. $tid );
+ my $form = $m->form_name('TicketModify');
+ ok my $input = $form->find_input('Status'), 'found status selector';
+
+ my @form_values = $input->possible_values;
+ ok scalar @form_values, 'some options in the UI';
+
+ ok grep($_ eq 'deleted', @form_values), "has deleted";
+
+ $m->select( Status => 'deleted' );
+ $m->submit;
+
+ is $tstatus->($tid), 'deleted', 'deleted ticket';
+}
+
+diag "deleted -> X via modify, only open is available";
+{
+ is $tstatus->($tid), 'deleted', 'ticket is deleted';
+
+ $m->get_ok( '/Ticket/Modify.html?id='. $tid );
+ my $form = $m->form_name('TicketModify');
+ ok my $input = $form->find_input('Status'), 'found status selector';
+
+ my @form_values = $input->possible_values;
+ ok scalar @form_values, 'some options in the UI';
+
+ is join('-', @form_values), '-open', 'only open and default available';
+}
+
+diag "check illegal values and transitions";
+{
+ {
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $general->id,
+ Subject => 'test',
+ Status => 'illegal',
+ );
+ ok !$id, 'have not created a ticket';
+ }
+ {
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $general->id,
+ Subject => 'test',
+ Status => 'new',
+ );
+ ok $id, 'created a ticket';
+ }
+ {
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $general->id,
+ Subject => 'test',
+ Status => 'new',
+ );
+ ok $id, 'created a ticket';
+
+ (my $status, $msg) = $ticket->SetStatus( 'illeagal' );
+ ok !$status, "couldn't set illeagal status";
+ is $ticket->Status, 'new', 'status is steal the same';
+
+ ($status, $msg) = $ticket->SetStatus( 'stalled' );
+ ok !$status, "couldn't set status, transition is illeagal";
+ is $ticket->Status, 'new', 'status is steal the same';
+ }
+}
+
+diag "'!inactive -> inactive' actions are shown even if ticket has unresolved dependencies";
+{
+ my $child_ticket = RT::Test->create_ticket(
+ Queue => $general->id,
+ Subject => 'child',
+ );
+ my $cid = $child_ticket->id;
+ my $parent_ticket = RT::Test->create_ticket(
+ Queue => $general->id,
+ Subject => 'parent',
+ DependsOn => $child_ticket->id,
+ );
+ my $pid = $parent_ticket->id;
+
+ ok $m->goto_ticket( $pid ), 'opened a ticket';
+ $m->check_links(
+ has => ['Open It', 'Resolve', 'Reject', 'Delete' ],
+ has_no => ['Stall', 'Re-open', 'Undelete', ],
+ );
+ ok $m->goto_ticket( $cid ), 'opened a ticket';
+ $m->check_links(
+ has => ['Open It', 'Resolve', 'Reject', 'Delete'],
+ has_no => ['Stall', 'Re-open', 'Undelete'],
+ );
+}
+
diff --git a/rt/t/lifecycles/dates.t b/rt/t/lifecycles/dates.t
new file mode 100644
index 000000000..d8a27f613
--- /dev/null
+++ b/rt/t/lifecycles/dates.t
@@ -0,0 +1,317 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use Data::Dumper;
+
+BEGIN {require 't/lifecycles/utils.pl'};
+
+my $general = RT::Test->load_or_create_queue(
+ Name => 'General',
+);
+ok $general && $general->id, 'loaded or created a queue';
+
+my $delivery = RT::Test->load_or_create_queue(
+ Name => 'delivery',
+ Lifecycle => 'delivery',
+);
+ok $delivery && $delivery->id, 'loaded or created a queue';
+
+my $tstatus = sub {
+ DBIx::SearchBuilder::Record::Cachable->FlushCache;
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ $ticket->Load( $_[0] );
+ return $ticket->Status;
+};
+
+my ($baseurl, $m) = RT::Test->started_ok;
+ok $m->login, 'logged in';
+
+diag "check basic API";
+{
+ my $schema = $general->Lifecycle;
+ isa_ok($schema, 'RT::Lifecycle');
+ is $schema->Name, 'default', "it's a default schema";
+
+ $schema = $delivery->Lifecycle;
+ isa_ok($schema, 'RT::Lifecycle');
+ is $schema->Name, 'delivery', "it's a delivery schema";
+}
+
+diag "dates on create for default schema";
+{
+ {
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $general->id,
+ Subject => 'test',
+ Status => 'new',
+ );
+ ok $id, 'created a ticket';
+ ok $ticket->StartedObj->Unix <= 0, 'started is not set';
+ ok $ticket->ResolvedObj->Unix <= 0, 'resolved is not set';
+ }
+ {
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $general->id,
+ Subject => 'test',
+ Status => 'open',
+ );
+ ok $id, 'created a ticket';
+ ok $ticket->StartedObj->Unix > 0, 'started is set';
+ ok $ticket->ResolvedObj->Unix <= 0, 'resolved is not set';
+ }
+ {
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $general->id,
+ Subject => 'test',
+ Status => 'resolved',
+ );
+ ok $id, 'created a ticket';
+ ok $ticket->StartedObj->Unix > 0, 'started is set';
+ ok $ticket->ResolvedObj->Unix > 0, 'resolved is set';
+ }
+
+ my $test_date = '2008-11-28 12:00:00';
+ {
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $general->id,
+ Subject => 'test',
+ Status => 'new',
+ Started => $test_date,
+ Resolved => $test_date,
+ );
+ ok $id, 'created a ticket';
+ is $ticket->StartedObj->ISO, $test_date, 'started is set';
+ is $ticket->ResolvedObj->ISO, $test_date, 'resolved is set';
+ }
+ {
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $general->id,
+ Subject => 'test',
+ Status => 'open',
+ Started => $test_date,
+ Resolved => $test_date,
+ );
+ ok $id, 'created a ticket';
+ is $ticket->StartedObj->ISO, $test_date, 'started is set';
+ is $ticket->ResolvedObj->ISO, $test_date, 'resolved is set';
+ }
+ {
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $general->id,
+ Subject => 'test',
+ Status => 'resolved',
+ Started => $test_date,
+ Resolved => $test_date,
+ );
+ ok $id, 'created a ticket';
+ is $ticket->StartedObj->ISO, $test_date, 'started is set';
+ is $ticket->ResolvedObj->ISO, $test_date, 'resolved is set';
+ }
+}
+
+diag "dates on create for delivery schema";
+{
+ {
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $delivery->id,
+ Subject => 'test',
+ Status => 'ordered',
+ );
+ ok $id, 'created a ticket';
+ is $ticket->StartedObj->Unix , 0, 'started is not set';
+ is $ticket->ResolvedObj->Unix, 0, 'resolved is not set';
+
+ }
+ {
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $txn, $msg) = $ticket->Create(
+ Queue => $delivery->id,
+ Subject => 'test',
+ );
+ ok $id, 'created a ticket';
+ diag($msg);
+ is $ticket->Status, 'ordered', "Status is ordered";
+ my ($statusval,$statusmsg) = $ticket->SetStatus('on way');
+ ok($statusval,$statusmsg);
+ ok $ticket->StartedObj->Unix > 0, 'started is set to ' .$ticket->StartedObj->AsString ;
+ is $ticket->ResolvedObj->Unix, 0, 'resolved is not set';
+ }
+ {
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $delivery->id,
+ Subject => 'test',
+ );
+ ok $id, 'created a ticket';
+
+ my ($statusval,$statusmsg) = $ticket->SetStatus('on way');
+ ok($statusval,$statusmsg);
+
+ ($statusval,$statusmsg) = $ticket->SetStatus('delivered');
+ ok($statusval,$statusmsg);
+
+ ok $ticket->StartedObj->Unix > 0, 'started is set';
+ ok $ticket->ResolvedObj->Unix > 0, 'resolved is set';
+ }
+
+ my $test_date = '2008-11-28 12:00:00';
+ {
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $statusmsg) = $ticket->Create(
+ Queue => $delivery->id,
+ Subject => 'test',
+ Status => 'ordered',
+ Started => $test_date,
+ Resolved => $test_date,
+ );
+ ok $id, 'created a ticket';
+ is $ticket->StartedObj->ISO, $test_date, 'started is set';
+ is $ticket->ResolvedObj->ISO, $test_date, 'resolved is set';
+ }
+ {
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $delivery->id,
+ Subject => 'test',
+ Status => 'ordered',
+ Started => $test_date,
+ Resolved => $test_date,
+ );
+ ok $id, 'created a ticket';
+ my ($statusval,$statusmsg) = $ticket->SetStatus('on way');
+ ok($statusval,$statusmsg);
+ is $ticket->StartedObj->ISO, $test_date, 'started is set';
+ is $ticket->ResolvedObj->ISO, $test_date, 'resolved is set';
+ }
+ {
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $delivery->id,
+ Subject => 'test',
+ Started => $test_date,
+ Resolved => $test_date,
+ );
+ ok $id, 'created a ticket';
+ my ($statusval,$statusmsg) = $ticket->SetStatus('on way');
+ ok($statusval,$statusmsg);
+ ($statusval,$statusmsg) = $ticket->SetStatus('delivered');
+ ok($statusval,$statusmsg);
+ is $ticket->StartedObj->ISO, $test_date, 'started is set';
+ TODO: {
+ local $TODO = "we should decide if we set resolved repeatedly";
+ is $ticket->ResolvedObj->ISO, $test_date, 'resolved is set';
+ };
+ }
+}
+
+diag "dates on status change for default schema";
+{
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $general->id,
+ Subject => 'test',
+ Status => 'new',
+ );
+ ok $id, 'created a ticket';
+ ok $ticket->StartedObj->Unix <= 0, 'started is not set';
+ ok $ticket->ResolvedObj->Unix <= 0, 'resolved is not set';
+
+ (my $status, $msg) = $ticket->SetStatus('open');
+ ok $status, 'changed status' or diag "error: $msg";
+ ok $ticket->StartedObj->Unix > 0, 'started is set';
+ ok $ticket->ResolvedObj->Unix <= 0, 'resolved is not set';
+
+ my $started = $ticket->StartedObj->Unix;
+
+ ($status, $msg) = $ticket->SetStatus('stalled');
+ ok $status, 'changed status' or diag "error: $msg";
+ is $ticket->StartedObj->Unix, $started, 'started is set and the same';
+ ok $ticket->ResolvedObj->Unix <= 0, 'resolved is not set';
+
+ ($status, $msg) = $ticket->SetStatus('open');
+ ok $status, 'changed status' or diag "error: $msg";
+ is $ticket->StartedObj->Unix, $started, 'started is set and the same';
+ ok $ticket->ResolvedObj->Unix <= 0, 'resolved is not set';
+
+ ($status, $msg) = $ticket->SetStatus('resolved');
+ ok $status, 'changed status' or diag "error: $msg";
+ is $ticket->StartedObj->Unix, $started, 'started is set and the same';
+ ok $ticket->ResolvedObj->Unix > 0, 'resolved is set';
+}
+
+diag "dates on status change for delivery schema";
+{
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $delivery->id,
+ Subject => 'test',
+ Status => 'ordered',
+ );
+ ok $id, 'created a ticket';
+ ok $ticket->StartedObj->Unix <= 0, 'started is not set';
+ ok $ticket->ResolvedObj->Unix <= 0, 'resolved is not set';
+
+ (my $status, $msg) = $ticket->SetStatus('delayed');
+ ok $status, 'changed status' or diag "error: $msg";
+ ok $ticket->StartedObj->Unix > 0, 'started is set';
+ ok $ticket->ResolvedObj->Unix <= 0, 'resolved is not set';
+
+ my $started = $ticket->StartedObj->Unix;
+
+ ($status, $msg) = $ticket->SetStatus('on way');
+ ok $status, 'changed status' or diag "error: $msg";
+ is $ticket->StartedObj->Unix, $started, 'started is set and the same';
+ ok $ticket->ResolvedObj->Unix <= 0, 'resolved is not set';
+
+ ($status, $msg) = $ticket->SetStatus('delivered');
+ ok $status, 'changed status' or diag "error: $msg";
+ is $ticket->StartedObj->Unix, $started, 'started is set and the same';
+ ok $ticket->ResolvedObj->Unix > 0, 'resolved is set';
+}
+
+diag "add partial map between general->delivery";
+{
+ my $schemas = RT->Config->Get('Lifecycles');
+ $schemas->{'__maps__'} = {
+ 'default -> delivery' => {
+ new => 'on way',
+ },
+ 'delivery -> default' => {
+ 'on way' => 'resolved',
+ },
+ };
+ RT::Lifecycle->FillCache;
+}
+
+diag "check date changes on moving a ticket";
+{
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $general->id,
+ Subject => 'test',
+ Status => 'new',
+ );
+ ok $id, 'created a ticket';
+ ok $ticket->StartedObj->Unix <= 0, 'started is not set';
+ ok $ticket->ResolvedObj->Unix <= 0, 'resolved is not set';
+
+ (my $status, $msg) = $ticket->SetQueue( $delivery->id );
+ ok $status, "moved ticket between queues with different schemas";
+ is $ticket->Status, 'on way', 'status has been changed';
+ ok $ticket->StartedObj->Unix > 0, 'started is set';
+ ok $ticket->ResolvedObj->Unix <= 0, 'resolved is not set';
+
+ ($status, $msg) = $ticket->SetQueue( $general->id );
+ ok $status, "moved ticket between queues with different schemas";
+ is $ticket->Status, 'resolved', 'status has been changed';
+ ok $ticket->StartedObj->Unix > 0, 'started is set';
+ ok $ticket->ResolvedObj->Unix > 0, 'resolved is set';
+}
diff --git a/rt/t/lifecycles/moving.t b/rt/t/lifecycles/moving.t
new file mode 100644
index 000000000..6e0d64bbf
--- /dev/null
+++ b/rt/t/lifecycles/moving.t
@@ -0,0 +1,97 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use Data::Dumper;
+
+BEGIN {require 't/lifecycles/utils.pl'};
+
+my $general = RT::Test->load_or_create_queue(
+ Name => 'General',
+);
+ok $general && $general->id, 'loaded or created a queue';
+
+my $delivery = RT::Test->load_or_create_queue(
+ Name => 'delivery',
+ Lifecycle => 'delivery',
+);
+ok $delivery && $delivery->id, 'loaded or created a queue';
+
+my $tstatus = sub {
+ DBIx::SearchBuilder::Record::Cachable->FlushCache;
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ $ticket->Load( $_[0] );
+ return $ticket->Status;
+};
+
+diag "check moving without a map";
+{
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $general->id,
+ Subject => 'test',
+ Status => 'new',
+ );
+ ok $id, 'created a ticket';
+ (my $status, $msg) = $ticket->SetQueue( $delivery->id );
+ ok !$status, "couldn't change queue when there is no maps between schemas";
+ is $ticket->Queue, $general->id, 'queue is steal the same';
+ is $ticket->Status, 'new', 'status is steal the same';
+}
+
+diag "add partial map";
+{
+ my $schemas = RT->Config->Get('Lifecycles');
+ $schemas->{'__maps__'} = {
+ 'default -> delivery' => {
+ new => 'ordered',
+ },
+ };
+ RT::Lifecycle->FillCache;
+}
+
+diag "check moving with a partial map";
+{
+ {
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $general->id,
+ Subject => 'test',
+ Status => 'new',
+ );
+ ok $id, 'created a ticket';
+ (my $status, $msg) = $ticket->SetQueue( $delivery->id );
+ ok $status, "moved ticket between queues with different schemas";
+ is $ticket->Queue, $delivery->id, 'queue has been changed'
+ or diag "error: $msg";
+ is $ticket->Status, 'ordered', 'status has been changed';
+ }
+ {
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $general->id,
+ Subject => 'test',
+ Status => 'open',
+ );
+ ok $id, 'created a ticket';
+ (my $status, $msg) = $ticket->SetQueue( $delivery->id );
+ ok !$status, "couldn't change queue when map is not complete";
+ is $ticket->Queue, $general->id, 'queue is steal the same';
+ is $ticket->Status, 'open', 'status is steal the same';
+ }
+}
+
+diag "one way map doesn't work backwards";
+{
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id, $msg) = $ticket->Create(
+ Queue => $delivery->id,
+ Subject => 'test',
+ Status => 'ordered',
+ );
+ ok $id, 'created a ticket';
+ (my $status, $msg) = $ticket->SetQueue( $general->id );
+ ok !$status, "couldn't change queue when there is no maps between schemas";
+ is $ticket->Queue, $delivery->id, 'queue is steal the same';
+ is $ticket->Status, 'ordered', 'status is steal the same';
+}
diff --git a/rt/t/lifecycles/unresolved-deps.t b/rt/t/lifecycles/unresolved-deps.t
new file mode 100644
index 000000000..aff9a1a56
--- /dev/null
+++ b/rt/t/lifecycles/unresolved-deps.t
@@ -0,0 +1,45 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use Data::Dumper;
+
+use Test::More tests => 15;
+BEGIN {require 't/lifecycles/utils.pl'};
+
+my $general = RT::Test->load_or_create_queue(
+ Name => 'General',
+);
+ok $general && $general->id, 'loaded or created a queue';
+
+# different value tested in basics
+RT->Config->Set('HideResolveActionsWithDependencies' => 1);
+
+my ($baseurl, $m) = RT::Test->started_ok;
+ok $m->login, 'logged in';
+
+{
+ my $child_ticket = RT::Test->create_ticket(
+ Queue => $general->id,
+ Subject => 'child',
+ );
+ my $cid = $child_ticket->id;
+ my $parent_ticket = RT::Test->create_ticket(
+ Queue => $general->id,
+ Subject => 'parent',
+ DependsOn => $child_ticket->id,
+ );
+ my $pid = $parent_ticket->id;
+
+ ok $m->goto_ticket( $pid ), 'opened a ticket';
+ $m->check_links(
+ has => ['Open It'],
+ has_no => ['Stall', 'Re-open', 'Undelete', 'Resolve', 'Reject', 'Delete'],
+ );
+ ok $m->goto_ticket( $cid ), 'opened a ticket';
+ $m->check_links(
+ has => ['Open It', 'Resolve', 'Reject', 'Delete'],
+ has_no => ['Stall', 'Re-open', 'Undelete'],
+ );
+}
+
diff --git a/rt/t/lifecycles/utils.pl b/rt/t/lifecycles/utils.pl
new file mode 100644
index 000000000..6fb229390
--- /dev/null
+++ b/rt/t/lifecycles/utils.pl
@@ -0,0 +1,73 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+
+my $config;
+BEGIN {
+$config = <<END;
+Set(\%Lifecycles,
+ default => {
+ initial => [qw(new)],
+ active => [qw(open stalled)],
+ inactive => [qw(resolved rejected deleted)],
+ defaults => {
+ on_create => 'new',
+ on_merge => 'resolved',
+ },
+ transitions => {
+ '' => [qw(new open resolved)],
+ new => [qw(open resolved rejected deleted)],
+ open => [qw(stalled resolved rejected deleted)],
+ stalled => [qw(open)],
+ resolved => [qw(open)],
+ rejected => [qw(open)],
+ deleted => [qw(open)],
+ },
+ actions => {
+ 'new -> open' => {label => 'Open It', update => 'Respond'},
+ 'new -> resolved' => {label => 'Resolve', update => 'Comment'},
+ 'new -> rejected' => {label => 'Reject', update => 'Respond'},
+ 'new -> deleted' => {label => 'Delete', update => ''},
+
+ 'open -> stalled' => {label => 'Stall', update => 'Comment'},
+ 'open -> resolved' => {label => 'Resolve', update => 'Comment'},
+ 'open -> rejected' => {label => 'Reject', update => 'Respond'},
+
+ 'stalled -> open' => {label => 'Open It', update => ''},
+ 'resolved -> open' => {label => 'Re-open', update => 'Comment'},
+ 'rejected -> open' => {label => 'Re-open', update => 'Comment'},
+ 'deleted -> open' => {label => 'Undelete', update => ''},
+ },
+ },
+ delivery => {
+ initial => ['ordered'],
+ active => ['on way', 'delayed'],
+ inactive => ['delivered'],
+ defaults => {
+ on_create => 'ordered',
+ on_merge => 'delivered',
+ },
+ transitions => {
+ '' => ['ordered'],
+ ordered => ['on way', 'delayed'],
+ 'on way' => ['delivered'],
+ delayed => ['on way'],
+ delivered => [],
+ },
+ actions => {
+ 'ordered -> on way' => {label => 'Put On Way', update => 'Respond'},
+ 'ordered -> delayed' => {label => 'Delay', update => 'Respond'},
+
+ 'on way -> delivered' => {label => 'Done', update => 'Respond'},
+ 'delayed -> on way' => {label => 'Put On Way', update => 'Respond'},
+ },
+ },
+);
+END
+}
+
+use RT::Test config => $config;
+
+1;
diff --git a/rt/t/mail/bounce.t b/rt/t/mail/bounce.t
new file mode 100644
index 000000000..703e86d67
--- /dev/null
+++ b/rt/t/mail/bounce.t
@@ -0,0 +1,42 @@
+use strict;
+use warnings;
+
+use RT::Test tests => undef;
+
+RT->Config->Set( MailCommand => 'sendmailpipe' );
+RT->Config->Set( SetOutgoingMailFrom => 1 );
+RT->Config->Set( OverrideOutgoingMailFrom => { Default => 'queue@example.invalid' } );
+
+# Ensure that the fake sendmail knows where to write to
+$ENV{RT_MAILLOGFILE} = RT::Test->temp_directory . "/sendmailpipe.log";
+my $fake = File::Spec->rel2abs( File::Spec->catfile(
+ 't', 'mail', 'fake-sendmail' ) );
+RT->Config->Set( SendmailPath => $fake);
+
+my $message = <<EOM;
+From: doesnotexist\@willbounce.invalid
+Subject: This is a test of new ticket creation
+
+Bounce bounce bounce
+EOM
+
+{
+ # by default, MailError wants to crit or error the email message
+ # out to Screen, which scribbles all over the test output
+ no warnings 'redefine';
+ my $orig_mail_error = RT::Interface::Email->can('MailError');
+ local *RT::Interface::Email::MailError = sub { $orig_mail_error->( @_, LogLevel => undef ) };
+ RT::Test->send_via_mailgate($message);
+}
+
+
+open(LOG, "<", $ENV{RT_MAILLOGFILE}) or die "Can't open log file: $!";
+my $fcount;
+while (my $line = <LOG>) {
+ $fcount++ if $line =~ /^-f/;
+}
+close(LOG);
+# RT_MAILLOGFILE will contain all the command line flags if you need them
+is($fcount,1,"Only one -f specified to sendmail command");
+
+done_testing;
diff --git a/rt/t/mail/charsets-outgoing.t b/rt/t/mail/charsets-outgoing.t
index e3f13fb6c..e17dd983d 100644
--- a/rt/t/mail/charsets-outgoing.t
+++ b/rt/t/mail/charsets-outgoing.t
@@ -18,8 +18,6 @@ my %string = (
},
);
-RT::Test->set_mail_catcher;
-
my $queue = RT::Test->load_or_create_queue(
Name => 'Regression',
CorrespondAddress => 'rt-recipient@example.com',
@@ -27,15 +25,15 @@ my $queue = RT::Test->load_or_create_queue(
);
ok $queue && $queue->id, 'loaded or created queue';
-diag "make sure queue has no subject tag" if $ENV{'TEST_VERBOSE'};
+diag "make sure queue has no subject tag";
{
my ($status, $msg) = $queue->SetSubjectTag( undef );
ok $status, "set subject tag for the queue" or diag "error: $msg";
}
-diag "set intial simple autoreply template" if $ENV{'TEST_VERBOSE'};
+diag "set intial simple autoreply template";
{
- my $template = RT::Template->new( $RT::SystemUser );
+ my $template = RT::Template->new( RT->SystemUser );
$template->Load('Autoreply');
ok $template->id, "loaded autoreply tempalte";
@@ -49,9 +47,9 @@ diag "set intial simple autoreply template" if $ENV{'TEST_VERBOSE'};
or diag "error: $msg";
}
-diag "basic test of autoreply" if $ENV{'TEST_VERBOSE'};
+diag "basic test of autoreply";
{
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ my $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Create(
Queue => $queue->id,
Subject => 'test',
@@ -61,10 +59,9 @@ diag "basic test of autoreply" if $ENV{'TEST_VERBOSE'};
ok @mails, "got some outgoing emails";
}
-diag "non-ascii Subject with ascii prefix set in the template"
- if $ENV{'TEST_VERBOSE'};
+diag "non-ascii Subject with ascii prefix set in the template";
foreach my $set ( 'ru', 'latin1' ) {
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ my $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Create(
Queue => $queue->id,
Subject => $string{$set}{test},
@@ -85,15 +82,15 @@ foreach my $set ( 'ru', 'latin1' ) {
foreach my $tag_set ( 'ru', 'latin1' ) {
-diag "set non-ascii subject tag for the queue" if $ENV{'TEST_VERBOSE'};
+diag "set non-ascii subject tag for the queue";
{
my ($status, $msg) = $queue->SetSubjectTag( $string{$tag_set}{support} );
ok $status, "set subject tag for the queue" or diag "error: $msg";
}
-diag "ascii subject with non-ascii subject tag" if $ENV{'TEST_VERBOSE'};
+diag "ascii subject with non-ascii subject tag";
{
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ my $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Create(
Queue => $queue->id,
Subject => 'test',
@@ -112,9 +109,9 @@ diag "ascii subject with non-ascii subject tag" if $ENV{'TEST_VERBOSE'};
ok $status, "all mails have correct data";
}
-diag "non-ascii subject with non-ascii subject tag" if $ENV{'TEST_VERBOSE'};
+diag "non-ascii subject with non-ascii subject tag";
foreach my $set ( 'ru', 'latin1' ) {
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ my $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Create(
Queue => $queue->id,
Subject => $string{$set}{test},
@@ -137,7 +134,7 @@ foreach my $set ( 'ru', 'latin1' ) {
} # subject tag
-diag "return back the empty subject tag" if $ENV{'TEST_VERBOSE'};
+diag "return back the empty subject tag";
{
my ($status, $msg) = $queue->SetSubjectTag( undef );
ok $status, "set subject tag for the queue" or diag "error: $msg";
@@ -146,9 +143,9 @@ diag "return back the empty subject tag" if $ENV{'TEST_VERBOSE'};
foreach my $prefix_set ( 'ru', 'latin1' ) {
-diag "add non-ascii subject prefix in the autoreply template" if $ENV{'TEST_VERBOSE'};
+diag "add non-ascii subject prefix in the autoreply template";
{
- my $template = RT::Template->new( $RT::SystemUser );
+ my $template = RT::Template->new( RT->SystemUser );
$template->Load('Autoreply');
ok $template->id, "loaded autoreply tempalte";
@@ -161,9 +158,9 @@ diag "add non-ascii subject prefix in the autoreply template" if $ENV{'TEST_VERB
ok $status, "changed content of the template" or diag "error: $msg";
}
-diag "ascii subject with non-ascii subject prefix in template" if $ENV{'TEST_VERBOSE'};
+diag "ascii subject with non-ascii subject prefix in template";
{
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ my $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Create(
Queue => $queue->id,
Subject => 'test',
@@ -182,10 +179,9 @@ diag "ascii subject with non-ascii subject prefix in template" if $ENV{'TEST_VER
ok $status, "all mails have correct data";
}
-diag "non-ascii subject with non-ascii subject prefix in template"
- if $ENV{'TEST_VERBOSE'};
+diag "non-ascii subject with non-ascii subject prefix in template";
foreach my $set ( 'ru', 'latin1' ) {
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ my $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Create(
Queue => $queue->id,
Subject => $string{$set}{test},
@@ -207,16 +203,15 @@ foreach my $set ( 'ru', 'latin1' ) {
}
foreach my $tag_set ( 'ru', 'latin1' ) {
-diag "set non-ascii subject tag for the queue" if $ENV{'TEST_VERBOSE'};
+diag "set non-ascii subject tag for the queue";
{
my ($status, $msg) = $queue->SetSubjectTag( $string{$tag_set}{support} );
ok $status, "set subject tag for the queue" or diag "error: $msg";
}
-diag "non-ascii subject, non-ascii prefix in template and non-ascii tag"
- if $ENV{'TEST_VERBOSE'};
+diag "non-ascii subject, non-ascii prefix in template and non-ascii tag";
foreach my $set ( 'ru', 'latin1' ) {
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ my $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Create(
Queue => $queue->id,
Subject => $string{$set}{test},
@@ -241,7 +236,7 @@ foreach my $set ( 'ru', 'latin1' ) {
} # subject tag
-diag "flush subject tag of the queue" if $ENV{'TEST_VERBOSE'};
+diag "flush subject tag of the queue";
{
my ($status, $msg) = $queue->SetSubjectTag( undef );
ok $status, "set subject tag for the queue" or diag "error: $msg";
@@ -250,11 +245,11 @@ diag "flush subject tag of the queue" if $ENV{'TEST_VERBOSE'};
} # prefix set
-diag "don't change subject via template" if $ENV{'TEST_VERBOSE'};
+diag "don't change subject via template";
# clean DB has autoreply that always changes subject in template,
# we should test situation when subject is not changed from template
{
- my $template = RT::Template->new( $RT::SystemUser );
+ my $template = RT::Template->new( RT->SystemUser );
$template->Load('Autoreply');
ok $template->id, "loaded autoreply tempalte";
@@ -267,9 +262,9 @@ diag "don't change subject via template" if $ENV{'TEST_VERBOSE'};
ok $status, "changed content of the template" or diag "error: $msg";
}
-diag "non-ascii Subject without changes in template" if $ENV{'TEST_VERBOSE'};
+diag "non-ascii Subject without changes in template";
foreach my $set ( 'ru', 'latin1' ) {
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ my $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Create(
Queue => $queue->id,
Subject => $string{$set}{test},
@@ -289,16 +284,15 @@ foreach my $set ( 'ru', 'latin1' ) {
}
foreach my $tag_set ( 'ru', 'latin1' ) {
-diag "set non-ascii subject tag for the queue" if $ENV{'TEST_VERBOSE'};
+diag "set non-ascii subject tag for the queue";
{
my ($status, $msg) = $queue->SetSubjectTag( $string{$tag_set}{support} );
ok $status, "set subject tag for the queue" or diag "error: $msg";
}
-diag "non-ascii Subject without changes in template and with non-ascii subject tag"
- if $ENV{'TEST_VERBOSE'};
+diag "non-ascii Subject without changes in template and with non-ascii subject tag";
foreach my $set ( 'ru', 'latin1' ) {
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ my $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Create(
Queue => $queue->id,
Subject => $string{$set}{test},
@@ -320,3 +314,4 @@ foreach my $set ( 'ru', 'latin1' ) {
}
} # subject tag set
+
diff --git a/rt/t/mail/crypt-gnupg.t b/rt/t/mail/crypt-gnupg.t
index cc52dd631..c0a875644 100644
--- a/rt/t/mail/crypt-gnupg.t
+++ b/rt/t/mail/crypt-gnupg.t
@@ -3,35 +3,20 @@
use strict;
use warnings;
-use RT::Test nodata => 1, tests => 92;
-plan skip_all => 'GnuPG required.'
- unless eval 'use GnuPG::Interface; 1';
-plan skip_all => 'gpg executable is required.'
- unless RT::Test->find_executable('gpg');
-
-
-use File::Spec ();
-use Cwd;
-
-my $homedir = RT::Test::get_abs_relocatable_dir(File::Spec->updir(),
- qw(data gnupg keyrings) );
+my $homedir;
+BEGIN {
+ require RT::Test;
+ $homedir =
+ RT::Test::get_abs_relocatable_dir( File::Spec->updir(),
+ qw/data gnupg keyrings/ );
+}
-mkdir $homedir;
+use RT::Test::GnuPG tests => 96, gnupg_options => { homedir => $homedir };
+use Test::Warn;
-use_ok('RT::Crypt::GnuPG');
use_ok('MIME::Entity');
-RT->Config->Set( 'GnuPG',
- Enable => 1,
- OutgoingMessagesFormat => 'RFC' );
-
-RT->Config->Set( 'GnuPGOptions',
- homedir => $homedir,
- 'no-permission-warning' => undef,
-);
-
-
-diag 'only signing. correct passphrase' if $ENV{'TEST_VERBOSE'};
+diag 'only signing. correct passphrase';
{
my $entity = MIME::Entity->build(
From => 'rt@example.com',
@@ -67,14 +52,21 @@ diag 'only signing. correct passphrase' if $ENV{'TEST_VERBOSE'};
is( $status[0]->{'Trust'}, 'ULTIMATE', 'have trust value');
}
-diag 'only signing. missing passphrase' if $ENV{'TEST_VERBOSE'};
+diag 'only signing. missing passphrase';
{
my $entity = MIME::Entity->build(
From => 'rt@example.com',
Subject => 'test',
Data => ['test'],
);
- my %res = RT::Crypt::GnuPG::SignEncrypt( Entity => $entity, Encrypt => 0, Passphrase => '' );
+ my %res;
+ warning_like {
+ %res = RT::Crypt::GnuPG::SignEncrypt(
+ Entity => $entity,
+ Encrypt => 0,
+ Passphrase => ''
+ );
+ } qr/can't query passphrase in batch mode/;
ok( $res{'exit_code'}, "couldn't sign without passphrase");
ok( $res{'error'} || $res{'logger'}, "error is here" );
@@ -84,14 +76,23 @@ diag 'only signing. missing passphrase' if $ENV{'TEST_VERBOSE'};
is( $status[0]->{'Status'}, 'MISSING', 'missing passphrase');
}
-diag 'only signing. wrong passphrase' if $ENV{'TEST_VERBOSE'};
+diag 'only signing. wrong passphrase';
{
my $entity = MIME::Entity->build(
From => 'rt@example.com',
Subject => 'test',
Data => ['test'],
);
- my %res = RT::Crypt::GnuPG::SignEncrypt( Entity => $entity, Encrypt => 0, Passphrase => 'wrong' );
+
+ my %res;
+ warning_like {
+ %res = RT::Crypt::GnuPG::SignEncrypt(
+ Entity => $entity,
+ Encrypt => 0,
+ Passphrase => 'wrong',
+ );
+ } qr/bad passphrase/;
+
ok( $res{'exit_code'}, "couldn't sign with bad passphrase");
ok( $res{'error'} || $res{'logger'}, "error is here" );
@@ -101,7 +102,7 @@ diag 'only signing. wrong passphrase' if $ENV{'TEST_VERBOSE'};
is( $status[0]->{'Status'}, 'BAD', 'wrong passphrase');
}
-diag 'encryption only' if $ENV{'TEST_VERBOSE'};
+diag 'encryption only';
{
my $entity = MIME::Entity->build(
From => 'rt@example.com',
@@ -127,7 +128,7 @@ diag 'encryption only' if $ENV{'TEST_VERBOSE'};
is( $parts[0]->{'Top'}, $entity, "it's the same entity" );
}
-diag 'encryption only, bad recipient' if $ENV{'TEST_VERBOSE'};
+diag 'encryption only, bad recipient';
{
my $entity = MIME::Entity->build(
From => 'rt@example.com',
@@ -135,7 +136,15 @@ diag 'encryption only, bad recipient' if $ENV{'TEST_VERBOSE'};
Subject => 'test',
Data => ['test'],
);
- my %res = RT::Crypt::GnuPG::SignEncrypt( Entity => $entity, Sign => 0 );
+
+ my %res;
+ warning_like {
+ %res = RT::Crypt::GnuPG::SignEncrypt(
+ Entity => $entity,
+ Sign => 0,
+ );
+ } qr/public key not found/;
+
ok( $res{'exit_code'}, 'no way to encrypt without keys of recipients');
ok( $res{'logger'}, "errors are in logger" );
@@ -144,7 +153,7 @@ diag 'encryption only, bad recipient' if $ENV{'TEST_VERBOSE'};
is( $status[0]->{'Keyword'}, 'INV_RECP', 'invalid recipient');
}
-diag 'encryption and signing with combined method' if $ENV{'TEST_VERBOSE'};
+diag 'encryption and signing with combined method';
{
my $entity = MIME::Entity->build(
From => 'rt@example.com',
@@ -174,7 +183,7 @@ diag 'encryption and signing with combined method' if $ENV{'TEST_VERBOSE'};
is( $parts[0]->{'Top'}, $entity, "it's the same entity" );
}
-diag 'encryption and signing with cascading, sign on encrypted' if $ENV{'TEST_VERBOSE'};
+diag 'encryption and signing with cascading, sign on encrypted';
{
my $entity = MIME::Entity->build(
From => 'rt@example.com',
@@ -196,7 +205,7 @@ diag 'encryption and signing with cascading, sign on encrypted' if $ENV{'TEST_VE
is( $parts[0]->{'Top'}, $entity, "it's the same entity" );
}
-diag 'find signed/encrypted part deep inside' if $ENV{'TEST_VERBOSE'};
+diag 'find signed/encrypted part deep inside';
{
my $entity = MIME::Entity->build(
From => 'rt@example.com',
@@ -219,7 +228,7 @@ diag 'find signed/encrypted part deep inside' if $ENV{'TEST_VERBOSE'};
is( $parts[0]->{'Top'}, $entity->parts(0), "it's the same entity" );
}
-diag 'wrong signed/encrypted parts: no protocol' if $ENV{'TEST_VERBOSE'};
+diag 'wrong signed/encrypted parts: no protocol';
{
my $entity = MIME::Entity->build(
From => 'rt@example.com',
@@ -227,15 +236,24 @@ diag 'wrong signed/encrypted parts: no protocol' if $ENV{'TEST_VERBOSE'};
Subject => 'test',
Data => ['test'],
);
- my %res = RT::Crypt::GnuPG::SignEncrypt( Entity => $entity, Sign => 0 );
+
+ my %res = RT::Crypt::GnuPG::SignEncrypt(
+ Entity => $entity,
+ Sign => 0,
+ );
+
ok( !$res{'exit_code'}, 'success' );
$entity->head->mime_attr( 'Content-Type.protocol' => undef );
- my @parts = RT::Crypt::GnuPG::FindProtectedParts( Entity => $entity );
+ my @parts;
+ warning_like {
+ @parts = RT::Crypt::GnuPG::FindProtectedParts( Entity => $entity );
+ } qr{Entity is 'multipart/encrypted', but has no protocol defined. Skipped};
+
is( scalar @parts, 0, 'no protected parts' );
}
-diag 'wrong signed/encrypted parts: not enought parts' if $ENV{'TEST_VERBOSE'};
+diag 'wrong signed/encrypted parts: not enought parts';
{
my $entity = MIME::Entity->build(
From => 'rt@example.com',
@@ -243,15 +261,23 @@ diag 'wrong signed/encrypted parts: not enought parts' if $ENV{'TEST_VERBOSE'};
Subject => 'test',
Data => ['test'],
);
- my %res = RT::Crypt::GnuPG::SignEncrypt( Entity => $entity, Sign => 0 );
+
+ my %res = RT::Crypt::GnuPG::SignEncrypt(
+ Entity => $entity,
+ Sign => 0,
+ );
+
ok( !$res{'exit_code'}, 'success' );
$entity->parts([ $entity->parts(0) ]);
- my @parts = RT::Crypt::GnuPG::FindProtectedParts( Entity => $entity );
+ my @parts;
+ warning_like {
+ @parts = RT::Crypt::GnuPG::FindProtectedParts( Entity => $entity );
+ } qr/Encrypted or signed entity must has two subparts. Skipped/;
is( scalar @parts, 0, 'no protected parts' );
}
-diag 'wrong signed/encrypted parts: wrong proto' if $ENV{'TEST_VERBOSE'};
+diag 'wrong signed/encrypted parts: wrong proto';
{
my $entity = MIME::Entity->build(
From => 'rt@example.com',
@@ -267,7 +293,7 @@ diag 'wrong signed/encrypted parts: wrong proto' if $ENV{'TEST_VERBOSE'};
is( scalar @parts, 0, 'no protected parts' );
}
-diag 'wrong signed/encrypted parts: wrong proto' if $ENV{'TEST_VERBOSE'};
+diag 'wrong signed/encrypted parts: wrong proto';
{
my $entity = MIME::Entity->build(
From => 'rt@example.com',
@@ -283,7 +309,7 @@ diag 'wrong signed/encrypted parts: wrong proto' if $ENV{'TEST_VERBOSE'};
is( scalar @parts, 0, 'no protected parts' );
}
-diag 'verify inline and in attachment signatures' if $ENV{'TEST_VERBOSE'};
+diag 'verify inline and in attachment signatures';
{
open( my $fh, '<', "$homedir/signed_old_style_with_attachment.eml" ) or die $!;
my $parser = new MIME::Parser;
diff --git a/rt/t/mail/dashboards.t b/rt/t/mail/dashboards.t
new file mode 100644
index 000000000..7a7a54ce6
--- /dev/null
+++ b/rt/t/mail/dashboards.t
@@ -0,0 +1,397 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use RT::Test tests => 187;
+use Test::Warn;
+use RT::Dashboard::Mailer;
+
+my ($baseurl, $m) = RT::Test->started_ok;
+ok($m->login, 'logged in');
+
+sub create_dashboard {
+ my ($baseurl, $m) = @_;
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+ $m->get_ok($baseurl . '/Dashboards/Modify.html?Create=1');
+ $m->form_name('ModifyDashboard');
+ $m->field('Name' => 'Testing!');
+ $m->click_button(value => 'Create');
+ $m->title_is('Modify the dashboard Testing!');
+
+ $m->follow_link_ok({text => 'Content'});
+ $m->title_is('Modify the content of dashboard Testing!');
+
+ my $form = $m->form_name('Dashboard-Searches-body');
+ my @input = $form->find_input('Searches-body-Available');
+ my ($dashboards_component) =
+ map { ( $_->possible_values )[1] }
+ grep { ( $_->value_names )[1] =~ /Dashboards/ } @input;
+ $form->value('Searches-body-Available' => $dashboards_component );
+ $m->click_button(name => 'add');
+ $m->content_contains('Dashboard updated');
+
+ $m->follow_link_ok({text => 'Show'});
+ $m->title_is('Testing! Dashboard');
+ $m->content_contains('My dashboards');
+ $m->content_like(qr{<a href="/Dashboards/\d+/Testing!">Testing!</a>});
+
+}
+
+sub create_subscription {
+ my ($baseurl, $m, %fields) = @_;
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+
+ # create a subscription
+ $m->follow_link_ok({text => 'Subscription'});
+ $m->title_is('Subscribe to dashboard Testing!');
+ $m->form_name('SubscribeDashboard');
+ $m->set_fields(%fields);
+ $m->click_button(name => 'Save');
+ $m->content_contains("Subscribed to dashboard Testing!");
+}
+
+sub get_dash_sub_ids {
+ my $user = RT::User->new(RT->SystemUser);
+ $user->Load('root');
+ ok($user->Id, 'loaded user');
+ my ($subscription) = $user->Attributes->Named('Subscription');
+ my $subscription_id = $subscription->Id;
+ ok($subscription_id, 'loaded subscription');
+ my $dashboard_id = $subscription->SubValue('DashboardId');
+ ok($dashboard_id, 'got dashboard id');
+
+
+ return ($dashboard_id, $subscription_id);
+}
+
+# first, create and populate a dashboard
+create_dashboard($baseurl, $m);
+
+# now test the mailer
+
+# without a subscription..
+RT::Dashboard::Mailer->MailDashboards();
+
+my @mails = RT::Test->fetch_caught_mails;
+is @mails, 0, 'no mail yet';
+
+RT::Dashboard::Mailer->MailDashboards(
+ All => 1,
+);
+
+@mails = RT::Test->fetch_caught_mails;
+is @mails, 0, "no mail yet since there's no subscription";
+
+create_subscription($baseurl, $m,
+ Frequency => 'daily',
+ Hour => '06:00',
+);
+
+my ($dashboard_id, $subscription_id) = get_dash_sub_ids();
+
+sub produces_dashboard_mail_ok { # {{{
+ my %args = @_;
+ my $subject = delete $args{Subject};
+
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+
+ RT::Dashboard::Mailer->MailDashboards(%args);
+
+ my @mails = RT::Test->fetch_caught_mails;
+ is @mails, 1, "got a dashboard mail";
+
+ my $mail = parse_mail( $mails[0] );
+ is($mail->head->get('Subject'), $subject);
+ is($mail->head->get('From'), "root\n");
+ is($mail->head->get('X-RT-Dashboard-Id'), "$dashboard_id\n");
+ is($mail->head->get('X-RT-Dashboard-Subscription-Id'), "$subscription_id\n");
+
+ SKIP: {
+ skip 'Weird MIME failure', 2;
+ my $body = $mail->stringify_body;
+ like($body, qr{My dashboards});
+ like($body, qr{<a href="http://[^/]+/Dashboards/\d+/Testing!">Testing!</a>});
+ };
+} # }}}
+
+sub produces_no_dashboard_mail_ok { # {{{
+ my %args = @_;
+ my $name = delete $args{Name};
+
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+
+ RT::Dashboard::Mailer->MailDashboards(%args);
+
+ @mails = RT::Test->fetch_caught_mails;
+ is @mails, 0, $name;
+} # }}}
+
+sub delete_dashboard { # {{{
+ my $dashboard_id = shift;
+ # delete the dashboard and make sure we get exactly one subscription failure
+ # notice
+ my $dashboard = RT::Dashboard->new(RT::CurrentUser->new('root'));
+ my ($ok, $msg) = $dashboard->LoadById($dashboard_id);
+ ok($ok, $msg);
+
+ ($ok, $msg) = $dashboard->Delete;
+ ok($ok, $msg);
+} # }}}
+
+sub delete_subscriptions { # {{{
+ my $subscription_id = shift;
+ # delete the dashboard and make sure we get exactly one subscription failure
+ # notice
+ my $user = RT::User->new(RT->SystemUser);
+ $user->Load('root');
+ for my $subscription ($user->Attributes->Named('Subscription')) {
+ $subscription->Delete;
+ }
+} # }}}
+
+my $good_time = 1290423660; # 6:01 EST on a monday
+my $bad_time = 1290427260; # 7:01 EST on a monday
+
+my $expected_subject = "[example.com] Daily Dashboard: Testing!\n";
+
+produces_dashboard_mail_ok(
+ Time => $good_time,
+ Subject => $expected_subject,
+);
+
+produces_dashboard_mail_ok(
+ All => 1,
+ Subject => $expected_subject,
+);
+
+produces_dashboard_mail_ok(
+ All => 1,
+ Time => $good_time,
+ Subject => $expected_subject,
+);
+
+produces_dashboard_mail_ok(
+ All => 1,
+ Time => $bad_time,
+ Subject => $expected_subject,
+);
+
+
+produces_no_dashboard_mail_ok(
+ Name => "no dashboard mail it's a dry run",
+ All => 1,
+ DryRun => 1,
+);
+
+produces_no_dashboard_mail_ok(
+ Name => "no dashboard mail it's a dry run",
+ Time => $good_time,
+ DryRun => 1,
+);
+
+produces_no_dashboard_mail_ok(
+ Name => "no mail because it's the wrong time",
+ Time => $bad_time,
+);
+
+@mails = RT::Test->fetch_caught_mails;
+is(@mails, 0, "no mail leftover");
+
+
+$m->no_warnings_ok;
+RT::Test->stop_server;
+RT->Config->Set('DashboardSubject' => 'a %s b %s c');
+RT->Config->Set('DashboardAddress' => 'dashboard@example.com');
+RT->Config->Set('EmailDashboardRemove' => (qr/My dashboards/, "Testing!"));
+($baseurl, $m) = RT::Test->started_ok;
+
+RT::Dashboard::Mailer->MailDashboards(All => 1);
+@mails = RT::Test->fetch_caught_mails;
+is(@mails, 1, "one mail");
+my $mail = parse_mail($mails[0]);
+is($mail->head->get('Subject'), "[example.com] a Daily b Testing! c\n");
+is($mail->head->get('From'), "dashboard\@example.com\n");
+is($mail->head->get('X-RT-Dashboard-Id'), "$dashboard_id\n");
+is($mail->head->get('X-RT-Dashboard-Subscription-Id'), "$subscription_id\n");
+
+SKIP: {
+ skip 'Weird MIME failure', 2;
+ my $body = $mail->stringify_body;
+ unlike($body, qr{My dashboards});
+ unlike($body, qr{Testing!});
+};
+
+delete_dashboard($dashboard_id);
+
+warning_like {
+ RT::Dashboard::Mailer->MailDashboards(All => 1);
+} qr/Unable to load dashboard $dashboard_id of subscription $subscription_id for user root/;
+
+@mails = RT::Test->fetch_caught_mails;
+is(@mails, 1, "one mail for subscription failure");
+$mail = parse_mail($mails[0]);
+is($mail->head->get('Subject'), "[example.com] Missing dashboard!\n");
+is($mail->head->get('From'), "dashboard\@example.com\n");
+is($mail->head->get('X-RT-Dashboard-Id'), "$dashboard_id\n");
+is($mail->head->get('X-RT-Dashboard-Subscription-Id'), "$subscription_id\n");
+
+RT::Dashboard::Mailer->MailDashboards(All => 1);
+@mails = RT::Test->fetch_caught_mails;
+is(@mails, 0, "no mail because the subscription notice happens only once");
+
+RT::Test->stop_server;
+RT::Test->clean_caught_mails;
+RT->Config->Set('EmailDashboardRemove' => ());
+RT->Config->Set('DashboardAddress' => 'root');
+($baseurl, $m) = RT::Test->started_ok;
+$m->login;
+create_dashboard($baseurl, $m);
+create_subscription($baseurl, $m,
+ Frequency => 'weekly',
+ Hour => '06:00',
+);
+
+($dashboard_id, $subscription_id) = get_dash_sub_ids();
+
+# bump $bad_time to Tuesday
+$bad_time = $good_time + 86400;
+
+produces_dashboard_mail_ok(
+ Time => $good_time,
+ Subject => "[example.com] a Weekly b Testing! c\n",
+);
+
+produces_no_dashboard_mail_ok(
+ Name => "no mail because it's the wrong time",
+ Time => $bad_time,
+);
+
+@mails = RT::Test->fetch_caught_mails;
+is(@mails, 0, "no mail leftover");
+
+$m->no_warnings_ok;
+RT::Test->stop_server;
+RT->Config->Set('DashboardSubject' => 'a %s b %s c');
+RT->Config->Set('DashboardAddress' => 'dashboard@example.com');
+RT->Config->Set('EmailDashboardRemove' => (qr/My dashboards/, "Testing!"));
+($baseurl, $m) = RT::Test->started_ok;
+
+delete_dashboard($dashboard_id);
+delete_subscriptions();
+
+RT::Test->clean_caught_mails;
+
+RT::Test->stop_server;
+
+RT->Config->Set('EmailDashboardRemove' => ());
+RT->Config->Set('DashboardAddress' => 'root');
+($baseurl, $m) = RT::Test->started_ok;
+$m->login;
+create_dashboard($baseurl, $m);
+create_subscription($baseurl, $m,
+ Frequency => 'm-f',
+ Hour => '06:00',
+);
+
+($dashboard_id, $subscription_id) = get_dash_sub_ids();
+
+# bump $bad_time back to Sunday
+$bad_time = $good_time - 86400;
+
+produces_dashboard_mail_ok(
+ Time => $good_time,
+ Subject => "[example.com] a Weekday b Testing! c\n",
+);
+
+produces_no_dashboard_mail_ok(
+ Name => "no mail because it's the wrong time",
+ Time => $bad_time,
+);
+
+produces_no_dashboard_mail_ok(
+ Name => "no mail because it's the wrong time",
+ Time => $bad_time - 86400, # saturday
+);
+
+produces_dashboard_mail_ok(
+ Time => $bad_time - 86400 * 2, # friday
+ Subject => "[example.com] a Weekday b Testing! c\n",
+);
+
+
+@mails = RT::Test->fetch_caught_mails;
+is(@mails, 0, "no mail leftover");
+
+$m->no_warnings_ok;
+RT::Test->stop_server;
+RT->Config->Set('DashboardSubject' => 'a %s b %s c');
+RT->Config->Set('DashboardAddress' => 'dashboard@example.com');
+RT->Config->Set('EmailDashboardRemove' => (qr/My dashboards/, "Testing!"));
+($baseurl, $m) = RT::Test->started_ok;
+
+delete_dashboard($dashboard_id);
+delete_subscriptions();
+
+RT::Test->clean_caught_mails;
+
+RT::Test->stop_server;
+
+RT->Config->Set('EmailDashboardRemove' => ());
+RT->Config->Set('DashboardAddress' => 'root');
+($baseurl, $m) = RT::Test->started_ok;
+$m->login;
+create_dashboard($baseurl, $m);
+create_subscription($baseurl, $m,
+ Frequency => 'monthly',
+ Hour => '06:00',
+);
+
+($dashboard_id, $subscription_id) = get_dash_sub_ids();
+
+$good_time = 1291201200; # dec 1
+$bad_time = $good_time - 86400; # day before (i.e. different month)
+
+produces_dashboard_mail_ok(
+ Time => $good_time,
+ Subject => "[example.com] a Monthly b Testing! c\n",
+);
+
+produces_no_dashboard_mail_ok(
+ Name => "no mail because it's the wrong time",
+ Time => $bad_time,
+);
+
+
+@mails = RT::Test->fetch_caught_mails;
+is(@mails, 0, "no mail leftover");
+
+$m->no_warnings_ok;
+RT::Test->stop_server;
+RT->Config->Set('DashboardSubject' => 'a %s b %s c');
+RT->Config->Set('DashboardAddress' => 'dashboard@example.com');
+RT->Config->Set('EmailDashboardRemove' => (qr/My dashboards/, "Testing!"));
+($baseurl, $m) = RT::Test->started_ok;
+
+delete_dashboard($dashboard_id);
+delete_subscriptions();
+
+RT::Test->clean_caught_mails;
+
+RT::Test->stop_server;
+
+RT->Config->Set('EmailDashboardRemove' => ());
+RT->Config->Set('DashboardAddress' => 'root');
+($baseurl, $m) = RT::Test->started_ok;
+$m->login;
+create_dashboard($baseurl, $m);
+create_subscription($baseurl, $m,
+ Frequency => 'never',
+);
+
+($dashboard_id, $subscription_id) = get_dash_sub_ids();
+
+produces_no_dashboard_mail_ok(
+ Name => "mail should never get sent",
+ Time => $bad_time,
+);
+
diff --git a/rt/t/mail/digest-attributes.t b/rt/t/mail/digest-attributes.t
new file mode 100644
index 000000000..5b4560621
--- /dev/null
+++ b/rt/t/mail/digest-attributes.t
@@ -0,0 +1,168 @@
+#!/usr/bin/perl -w
+
+use warnings;
+use strict;
+use RT;
+use RT::Test tests => 31;
+my @users = qw/ emailnormal@example.com emaildaily@example.com emailweekly@example.com emailsusp@example.com /;
+
+my( $ret, $msg );
+my $user_n = RT::User->new( RT->SystemUser );
+( $ret, $msg ) = $user_n->LoadOrCreateByEmail( $users[0] );
+ok( $ret, "user with default email prefs created: $msg" );
+$user_n->SetPrivileged( 1 );
+
+my $user_d = RT::User->new( RT->SystemUser );
+( $ret, $msg ) = $user_d->LoadOrCreateByEmail( $users[1] );
+ok( $ret, "user with daily digest email prefs created: $msg" );
+# Set a username & password for testing the interface.
+$user_d->SetPrivileged( 1 );
+$user_d->SetPreferences($RT::System => { %{ $user_d->Preferences( $RT::System ) || {}}, EmailFrequency => 'Daily digest'});
+
+
+
+my $user_w = RT::User->new( RT->SystemUser );
+( $ret, $msg ) = $user_w->LoadOrCreateByEmail( $users[2] );
+ok( $ret, "user with weekly digest email prefs created: $msg" );
+$user_w->SetPrivileged( 1 );
+$user_w->SetPreferences($RT::System => { %{ $user_w->Preferences( $RT::System ) || {}}, EmailFrequency => 'Weekly digest'});
+
+my $user_s = RT::User->new( RT->SystemUser );
+( $ret, $msg ) = $user_s->LoadOrCreateByEmail( $users[3] );
+ok( $ret, "user with suspended email prefs created: $msg" );
+$user_s->SetPreferences($RT::System => { %{ $user_s->Preferences( $RT::System ) || {}}, EmailFrequency => 'Suspended'});
+$user_s->SetPrivileged( 1 );
+
+
+is(RT::Config->Get('EmailFrequency' => $user_s), 'Suspended');
+
+# Make a testing queue for ourselves.
+my $testq = RT::Queue->new( RT->SystemUser );
+if( $testq->ValidateName( 'EmailDigest-testqueue' ) ) {
+ ( $ret, $msg ) = $testq->Create( Name => 'EmailDigest-testqueue' );
+ ok( $ret, "Our test queue is created: $msg" );
+} else {
+ $testq->Load( 'EmailDigest-testqueue' );
+ ok( $testq->id, "Our test queue is loaded" );
+}
+
+# Allow anyone to open a ticket on the test queue.
+my $everyone = RT::Group->new( RT->SystemUser );
+( $ret, $msg ) = $everyone->LoadSystemInternalGroup( 'Everyone' );
+ok( $ret, "Loaded 'everyone' group: $msg" );
+
+( $ret, $msg ) = $everyone->PrincipalObj->GrantRight( Right => 'CreateTicket',
+ Object => $testq );
+ok( $ret || $msg =~ /already has/, "Granted everyone CreateTicket on testq: $msg" );
+
+# Make user_d an admincc for the queue.
+( $ret, $msg ) = $user_d->PrincipalObj->GrantRight( Right => 'AdminQueue',
+ Object => $testq );
+ok( $ret || $msg =~ /already has/, "Granted dduser AdminQueue on testq: $msg" );
+( $ret, $msg ) = $testq->AddWatcher( Type => 'AdminCc',
+ PrincipalId => $user_d->PrincipalObj->id );
+ok( $ret || $msg =~ /already/, "dduser added as a queue watcher: $msg" );
+
+# Give the others queue rights.
+( $ret, $msg ) = $user_n->PrincipalObj->GrantRight( Right => 'AdminQueue',
+ Object => $testq );
+ok( $ret || $msg =~ /already has/, "Granted emailnormal right on testq: $msg" );
+( $ret, $msg ) = $user_w->PrincipalObj->GrantRight( Right => 'AdminQueue',
+ Object => $testq );
+ok( $ret || $msg =~ /already has/, "Granted emailweekly right on testq: $msg" );
+( $ret, $msg ) = $user_s->PrincipalObj->GrantRight( Right => 'AdminQueue',
+ Object => $testq );
+ok( $ret || $msg =~ /already has/, "Granted emailsusp right on testq: $msg" );
+
+# Create a ticket with To: Cc: Bcc: fields using our four users.
+my $id;
+my $ticket = RT::Ticket->new( RT->SystemUser );
+( $id, $ret, $msg ) = $ticket->Create( Queue => $testq->Name,
+ Requestor => [ $user_w->Name ],
+ Subject => 'Test ticket for RT::Extension::EmailDigest',
+ );
+ok( $ret, "Ticket $id created: $msg" );
+
+# Make the other users ticket watchers.
+( $ret, $msg ) = $ticket->AddWatcher( Type => 'Cc',
+ PrincipalId => $user_n->PrincipalObj->id );
+ok( $ret, "Added user_n as a ticket watcher: $msg" );
+( $ret, $msg ) = $ticket->AddWatcher( Type => 'Cc',
+ PrincipalId => $user_s->PrincipalObj->id );
+ok( $ret, "Added user_s as a ticket watcher: $msg" );
+
+my $obj;
+($id, $msg, $obj ) = $ticket->Correspond(
+ Content => "This is a ticket response for CC action" );
+ok( $ret, "Transaction created: $msg" );
+
+# Get the deferred notifications that should result. Should be two for
+# email daily, and one apiece for emailweekly and emailsusp.
+my @notifications;
+
+my $txns = RT::Transactions->new( RT->SystemUser );
+$txns->LimitToTicket( $ticket->id );
+my( $c_daily, $c_weekly, $c_susp ) = ( 0, 0, 0 );
+while( my $txn = $txns->Next ) {
+ my @daily_rcpt = $txn->DeferredRecipients( 'daily' );
+ my @weekly_rcpt = $txn->DeferredRecipients('weekly' );
+ my @susp_rcpt = $txn->DeferredRecipients( 'susp' );
+
+ $c_daily++ if @daily_rcpt;
+ $c_weekly++ if @weekly_rcpt;
+ $c_susp++ if @susp_rcpt;
+
+ # If the transaction has content...
+ if( $txn->ContentObj ) {
+ # ...none of the deferred folk should be in the header.
+ my $headerstr = $txn->ContentObj->Headers;
+ foreach my $rcpt( @daily_rcpt, @weekly_rcpt, @susp_rcpt ) {
+ ok( $headerstr !~ /$rcpt/, "Deferred recipient $rcpt not found in header" );
+ }
+ }
+}
+
+# Finally, check to see that we got the correct number of each sort of
+# deferred recipient.
+is( $c_daily, 2, "correct number of daily-sent messages" );
+is( $c_weekly, 2, "correct number of weekly-sent messages" );
+is( $c_susp, 1, "correct number of suspended messages" );
+
+
+
+
+
+# Now let's actually run the daily and weekly digest tool to make sure we generate those
+
+# the first time get the content
+email_digest_like( '--mode daily --print', qr/in the last day/ );
+# The second time run it for real so we make sure that we get RT to mark the txn as sent
+email_digest_like( '--mode daily', qr/maildaily\@/ );
+# now we should have nothing to do, so no content.
+email_digest_like( '--mode daily --print', '' );
+
+# the first time get the content
+email_digest_like( '--mode weekly --print', qr/in the last seven days/ );
+# The second time run it for real so we make sure that we get RT to mark the txn as sent
+email_digest_like( '--mode weekly', qr/mailweekly\@/ );
+# now we should have nothing to do, so no content.
+email_digest_like( '--mode weekly --print', '' );
+
+sub email_digest_like {
+ my $arg = shift;
+ my $pattern = shift;
+
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+
+ my $perl = $^X . ' ' . join ' ', map { "-I$_" } @INC;
+ open my $digester, "-|", "$perl $RT::SbinPath/rt-email-digest $arg";
+ my @results = <$digester>;
+ my $content = join '', @results;
+ if ( ref $pattern && ref $pattern eq 'Regexp' ) {
+ like($content, $pattern);
+ }
+ else {
+ is( $content, $pattern );
+ }
+ close $digester;
+}
diff --git a/rt/t/mail/disposition-outgoing.t b/rt/t/mail/disposition-outgoing.t
new file mode 100644
index 000000000..06295a09c
--- /dev/null
+++ b/rt/t/mail/disposition-outgoing.t
@@ -0,0 +1,69 @@
+use strict;
+use warnings;
+
+use RT::Test tests => undef;
+
+my $queue = RT::Test->load_or_create_queue( Name => 'General' );
+ok $queue->id, 'loaded queue';
+
+my ($ok, $msg) = $queue->AddWatcher(
+ Type => 'AdminCc',
+ Email => 'test@example.com',
+);
+ok $ok, $msg;
+
+my $mail = <<'.';
+From: root@localhost
+Subject: I like inline dispositions and I cannot lie
+Content-type: multipart/related; boundary="foo"
+
+--foo
+Content-type: text/plain; charset="UTF-8"
+
+ho hum just some text
+
+--foo
+Content-type: text/x-patch; name="filename.patch"
+Content-disposition: inline; filename="filename.patch"
+
+a fake patch
+
+--foo
+.
+
+# inline
+{
+ my $rt = send_and_receive($mail);
+ like $rt, qr/Content-Disposition:\s*inline.+?filename\.patch/is, 'found inline disposition';
+}
+
+# attachment
+{
+ $mail =~ s/(?<=Content-disposition: )inline/attachment/i;
+
+ my $rt = send_and_receive($mail);
+ like $rt, qr/Content-Disposition:\s*attachment.+?filename\.patch/is, 'found attachment disposition';
+}
+
+# no disposition
+{
+ $mail =~ s/^Content-disposition: .+?\n(?=\n)//ism;
+
+ my $rt = send_and_receive($mail);
+ like $rt, qr/Content-Disposition:\s*inline.+?filename\.patch/is, 'found default (inline) disposition';
+}
+
+sub send_and_receive {
+ my $mail = shift;
+ my ($stat, $id) = RT::Test->send_via_mailgate($mail);
+ is( $stat >> 8, 0, "The mail gateway exited normally" );
+ ok( $id, "created ticket" );
+
+ my @mails = RT::Test->fetch_caught_mails;
+ is @mails, 2, "got 2 outgoing emails";
+
+ # first is autoreply
+ pop @mails;
+}
+
+done_testing;
diff --git a/rt/t/mail/extractsubjecttag.t b/rt/t/mail/extractsubjecttag.t
index fcaba8c98..e76da6f82 100644
--- a/rt/t/mail/extractsubjecttag.t
+++ b/rt/t/mail/extractsubjecttag.t
@@ -3,11 +3,7 @@ use strict;
use warnings;
use utf8;
-use RT::Test tests => 14;
-
-
-my ($baseurl, $m) = RT::Test->started_ok;
-RT::Test->set_mail_catcher;
+use RT::Test tests => 13;
my $queue = RT::Test->load_or_create_queue(
Name => 'Regression',
@@ -17,7 +13,7 @@ my $queue = RT::Test->load_or_create_queue(
my $subject_tag = 'Windows/Servers-Desktops';
ok $queue && $queue->id, 'loaded or created queue';
-diag "Set Subject Tag" if $ENV{'TEST_VERBOSE'};
+diag "Set Subject Tag";
{
is(RT->System->SubjectTag($queue), undef, 'No Subject Tag yet');
my ($status, $msg) = $queue->SetSubjectTag( $subject_tag );
@@ -25,8 +21,8 @@ diag "Set Subject Tag" if $ENV{'TEST_VERBOSE'};
is(RT->System->SubjectTag($queue), $subject_tag, "Set Subject Tag to $subject_tag");
}
-my $original_ticket = RT::Ticket->new( $RT::SystemUser );
-diag "Create a ticket and make sure it has the subject tag" if $ENV{'TEST_VERBOSE'};
+my $original_ticket = RT::Ticket->new( RT->SystemUser );
+diag "Create a ticket and make sure it has the subject tag";
{
$original_ticket->Create(
Queue => $queue->id,
@@ -47,7 +43,7 @@ diag "Create a ticket and make sure it has the subject tag" if $ENV{'TEST_VERBOS
}
-diag "Test that a reply with a Subject Tag doesn't change the subject" if $ENV{'TEST_VERBOSE'};
+diag "Test that a reply with a Subject Tag doesn't change the subject";
{
my $ticketid = $original_ticket->Id;
my $text = <<EOF;
@@ -61,13 +57,13 @@ EOF
is ($status >> 8, 0, "The mail gateway exited normally");
is ($id, $ticketid, "Replied to ticket $id correctly");
- my $freshticket = RT::Ticket->new( $RT::SystemUser );
+ my $freshticket = RT::Ticket->new( RT->SystemUser );
$freshticket->LoadById($id);
is($original_ticket->Subject,$freshticket->Subject,'Stripped Queue Subject Tag correctly');
}
-diag "Test that a reply with another RT's subject tag changes the subject" if $ENV{'TEST_VERBOSE'};
+diag "Test that a reply with another RT's subject tag changes the subject";
{
my $ticketid = $original_ticket->Id;
my $text = <<EOF;
@@ -77,14 +73,14 @@ Subject: [$subject_tag #$ticketid] [remote-rt-system #79] test
reply with subject tag and remote rt subject tag
EOF
- diag($text);
my ($status, $id) = RT::Test->send_via_mailgate($text, queue => $queue->Name);
is ($status >> 8, 0, "The mail gateway exited normally");
is ($id, $ticketid, "Replied to ticket $id correctly");
- my $freshticket = RT::Ticket->new( $RT::SystemUser );
+ my $freshticket = RT::Ticket->new( RT->SystemUser );
$freshticket->LoadById($id);
like($freshticket->Subject,qr/\[remote-rt-system #79\]/,"Kept remote rt's subject tag");
unlike($freshticket->Subject,qr/\[\Q$subject_tag\E #$ticketid\]/,'Stripped Queue Subject Tag correctly');
}
+
diff --git a/rt/t/mail/fake-sendmail b/rt/t/mail/fake-sendmail
new file mode 100644
index 000000000..44c237746
--- /dev/null
+++ b/rt/t/mail/fake-sendmail
@@ -0,0 +1,27 @@
+#!/usr/bin/env perl
+
+# captures command line arguments so you can validate
+# what is being generated in sendmailpipe
+
+use strict;
+use warnings;
+
+die "No \$RT_MAILLOGFILE set in environment"
+ unless $ENV{RT_MAILLOGFILE};
+open LOG, ">", $ENV{RT_MAILLOGFILE}
+ or die "Can't write to $ENV{RT_MAILLOGFILE}: $!";
+
+my $needs_newline;
+for (@ARGV) {
+ if (/^-/) {
+ print LOG "\n" if $needs_newline++;
+ print LOG $_;
+ } else {
+ print LOG " $_";
+ }
+}
+print LOG "\n";
+
+1 while $_ = <STDIN>;
+
+exit 0;
diff --git a/rt/t/mail/gateway.t b/rt/t/mail/gateway.t
index d57b063a2..9f0e669a3 100644
--- a/rt/t/mail/gateway.t
+++ b/rt/t/mail/gateway.t
@@ -57,7 +57,7 @@ use strict;
use warnings;
-use RT::Test config => 'Set( $UnsafeEmailCommands, 1);', tests => 159;
+use RT::Test config => 'Set( $UnsafeEmailCommands, 1);', tests => 221, actual_server => 1;
my ($baseurl, $m) = RT::Test->started_ok;
use RT::Tickets;
@@ -70,7 +70,7 @@ use LWP::UserAgent;
my $url = $m->rt_base_url;
-diag "Make sure that when we call the mailgate without URL, it fails" if $ENV{'TEST_VERBOSE'};
+diag "Make sure that when we call the mailgate without URL, it fails";
{
my $text = <<EOF;
From: root\@localhost
@@ -79,12 +79,13 @@ Subject: This is a test of new ticket creation
Foob!
EOF
- my ($status, $id) = RT::Test->send_via_mailgate($text, url => undef);
+ my ($status, $id) = RT::Test->send_via_mailgate_and_http($text, url => undef);
is ($status >> 8, 1, "The mail gateway exited with a failure");
ok (!$id, "No ticket id") or diag "by mistake ticket #$id";
+ $m->no_warnings_ok;
}
-diag "Make sure that when we call the mailgate with wrong URL, it tempfails" if $ENV{'TEST_VERBOSE'};
+diag "Make sure that when we call the mailgate with wrong URL, it tempfails";
{
my $text = <<EOF;
From: root\@localhost
@@ -93,15 +94,16 @@ Subject: This is a test of new ticket creation
Foob!
EOF
- my ($status, $id) = RT::Test->send_via_mailgate($text, url => 'http://this.test.for.non-connection.is.expected.to.generate.an.error');
+ my ($status, $id) = RT::Test->send_via_mailgate_and_http($text, url => 'http://this.test.for.non-connection.is.expected.to.generate.an.error');
is ($status >> 8, 75, "The mail gateway exited with a failure");
ok (!$id, "No ticket id");
+ $m->no_warnings_ok;
}
my $everyone_group;
-diag "revoke rights tests depend on" if $ENV{'TEST_VERBOSE'};
+diag "revoke rights tests depend on";
{
- $everyone_group = RT::Group->new( $RT::SystemUser );
+ $everyone_group = RT::Group->new( RT->SystemUser );
$everyone_group->LoadSystemInternalGroup( 'Everyone' );
ok ($everyone_group->Id, "Found group 'everyone'");
@@ -110,7 +112,7 @@ diag "revoke rights tests depend on" if $ENV{'TEST_VERBOSE'};
}
}
-diag "Test new ticket creation by root who is privileged and superuser" if $ENV{'TEST_VERBOSE'};
+diag "Test new ticket creation by root who is privileged and superuser";
{
my $text = <<EOF;
From: root\@localhost
@@ -121,7 +123,7 @@ Blah!
Foob!
EOF
- my ($status, $id) = RT::Test->send_via_mailgate($text);
+ my ($status, $id) = RT::Test->send_via_mailgate_and_http($text);
is ($status >> 8, 0, "The mail gateway exited normally");
ok ($id, "Created ticket");
@@ -129,9 +131,10 @@ EOF
isa_ok ($tick, 'RT::Ticket');
is ($tick->Id, $id, "correct ticket id");
is ($tick->Subject , 'This is a test of new ticket creation', "Created the ticket");
+ $m->no_warnings_ok;
}
-diag "Test the 'X-RT-Mail-Extension' field in the header of a ticket" if $ENV{'TEST_VERBOSE'};
+diag "Test the 'X-RT-Mail-Extension' field in the header of a ticket";
{
my $text = <<EOF;
From: root\@localhost
@@ -141,7 +144,7 @@ Blah!
Foob!
EOF
local $ENV{'EXTENSION'} = "bad value with\nnewlines\n";
- my ($status, $id) = RT::Test->send_via_mailgate($text);
+ my ($status, $id) = RT::Test->send_via_mailgate_and_http($text);
is ($status >> 8, 0, "The mail gateway exited normally");
ok ($id, "Created ticket #$id");
@@ -165,9 +168,10 @@ EOF
"bad value with newlines",
'header is in place, without trailing newline char'
);
+ $m->no_warnings_ok;
}
-diag "Make sure that not standard --extension is passed" if $ENV{'TEST_VERBOSE'};
+diag "Make sure that not standard --extension is passed";
{
my $text = <<EOF;
From: root\@localhost
@@ -176,7 +180,7 @@ Subject: This is a test of new ticket creation
Foob!
EOF
- my ($status, $id) = RT::Test->send_via_mailgate($text, extension => 'some-extension-arg' );
+ my ($status, $id) = RT::Test->send_via_mailgate_and_http($text, extension => 'some-extension-arg' );
is ($status >> 8, 0, "The mail gateway exited normally");
ok ($id, "Created ticket #$id");
@@ -198,9 +202,10 @@ EOF
'some-extension-arg',
'header is in place'
);
+ $m->no_warnings_ok;
}
-diag "Test new ticket creation without --action argument" if $ENV{'TEST_VERBOSE'};
+diag "Test new ticket creation without --action argument";
{
my $text = <<EOF;
From: root\@localhost
@@ -210,7 +215,7 @@ Subject: using mailgate without --action arg
Blah!
Foob!
EOF
- my ($status, $id) = RT::Test->send_via_mailgate($text, extension => 'some-extension-arg' );
+ my ($status, $id) = RT::Test->send_via_mailgate_and_http($text, extension => 'some-extension-arg' );
is ($status >> 8, 0, "The mail gateway exited normally");
ok ($id, "Created ticket #$id");
@@ -218,9 +223,10 @@ EOF
isa_ok ($tick, 'RT::Ticket');
is ($tick->Id, $id, "correct ticket id");
is ($tick->Subject, 'using mailgate without --action arg', "using mailgate without --action arg");
+ $m->no_warnings_ok;
}
-diag "This is a test of new ticket creation as an unknown user" if $ENV{'TEST_VERBOSE'};
+diag "This is a test of new ticket creation as an unknown user";
{
my $text = <<EOF;
From: doesnotexist\@@{[RT->Config->Get('rtname')]}
@@ -230,7 +236,7 @@ Subject: This is a test of new ticket creation as an unknown user
Blah!
Foob!
EOF
- my ($status, $id) = RT::Test->send_via_mailgate($text);
+ my ($status, $id) = RT::Test->send_via_mailgate_and_http($text);
is ($status >> 8, 0, "The mail gateway exited normally");
ok (!$id, "no ticket created");
@@ -239,12 +245,19 @@ EOF
ok ($tick->Id, "found ticket ".$tick->Id);
isnt ($tick->Subject , 'This is a test of new ticket creation as an unknown user', "failed to create the new ticket from an unprivileged account");
- my $u = RT::User->new($RT::SystemUser);
+ my $u = RT::User->new(RT->SystemUser);
$u->Load("doesnotexist\@@{[RT->Config->Get('rtname')]}");
ok( !$u->Id, "user does not exist and was not created by failed ticket submission");
+
+ $m->next_warning_like(qr/RT's configuration does not allow\s+for the creation of a new user for this email/);
+ $m->next_warning_like(qr/RT could not load a valid user/);
+ TODO: {
+ local $TODO = "we're a bit noisy for this warning case";
+ $m->no_leftover_warnings_ok;
+ }
}
-diag "grant everybody with CreateTicket right" if $ENV{'TEST_VERBOSE'};
+diag "grant everybody with CreateTicket right";
{
ok( RT::Test->set_rights(
{ Principal => $everyone_group->PrincipalObj,
@@ -254,7 +267,7 @@ diag "grant everybody with CreateTicket right" if $ENV{'TEST_VERBOSE'};
}
my $ticket_id;
-diag "now everybody can create tickets. can a random unkown user create tickets?" if $ENV{'TEST_VERBOSE'};
+diag "now everybody can create tickets. can a random unkown user create tickets?";
{
my $text = <<EOF;
From: doesnotexist\@@{[RT->Config->Get('rtname')]}
@@ -264,7 +277,7 @@ Subject: This is a test of new ticket creation as an unknown user
Blah!
Foob!
EOF
- my ($status, $id) = RT::Test->send_via_mailgate($text);
+ my ($status, $id) = RT::Test->send_via_mailgate_and_http($text);
is ($status >> 8, 0, "The mail gateway exited normally");
ok ($id, "ticket created");
@@ -274,13 +287,14 @@ EOF
is ($tick->Id, $id, "correct ticket id");
is ($tick->Subject , 'This is a test of new ticket creation as an unknown user', "failed to create the new ticket from an unprivileged account");
- my $u = RT::User->new( $RT::SystemUser );
+ my $u = RT::User->new( RT->SystemUser );
$u->Load( "doesnotexist\@@{[RT->Config->Get('rtname')]}" );
ok ($u->Id, "user does not exist and was created by ticket submission");
$ticket_id = $id;
+ $m->no_warnings_ok;
}
-diag "can another random reply to a ticket without being granted privs? answer should be no." if $ENV{'TEST_VERBOSE'};
+diag "can another random reply to a ticket without being granted privs? answer should be no.";
{
my $text = <<EOF;
From: doesnotexist-2\@@{[RT->Config->Get('rtname')]}
@@ -290,16 +304,21 @@ Subject: [@{[RT->Config->Get('rtname')]} #$ticket_id] This is a test of a reply
Blah! (Should not work.)
Foob!
EOF
- my ($status, $id) = RT::Test->send_via_mailgate($text);
+ my ($status, $id) = RT::Test->send_via_mailgate_and_http($text);
is ($status >> 8, 0, "The mail gateway exited normally");
ok (!$id, "no way to reply to the ticket");
- my $u = RT::User->new($RT::SystemUser);
+ my $u = RT::User->new(RT->SystemUser);
$u->Load('doesnotexist-2@'.RT->Config->Get('rtname'));
ok( !$u->Id, " user does not exist and was not created by ticket correspondence submission");
+ $m->next_warning_like(qr/RT's configuration does not allow\s+for the creation of a new user for this email \(doesnotexist-2\@example\.com\)/);
+ TODO: {
+ local $TODO = "we're a bit noisy for this warning case";
+ $m->no_leftover_warnings_ok;
+ }
}
-diag "grant everyone 'ReplyToTicket' right" if $ENV{'TEST_VERBOSE'};
+diag "grant everyone 'ReplyToTicket' right";
{
ok( RT::Test->set_rights(
{ Principal => $everyone_group->PrincipalObj,
@@ -308,7 +327,7 @@ diag "grant everyone 'ReplyToTicket' right" if $ENV{'TEST_VERBOSE'};
), "Granted everybody the right to reply to tickets" );
}
-diag "can another random reply to a ticket after being granted privs? answer should be yes" if $ENV{'TEST_VERBOSE'};
+diag "can another random reply to a ticket after being granted privs? answer should be yes";
{
my $text = <<EOF;
From: doesnotexist-2\@@{[RT->Config->Get('rtname')]}
@@ -318,16 +337,17 @@ Subject: [@{[RT->Config->Get('rtname')]} #$ticket_id] This is a test of a reply
Blah!
Foob!
EOF
- my ($status, $id) = RT::Test->send_via_mailgate($text);
+ my ($status, $id) = RT::Test->send_via_mailgate_and_http($text);
is ($status >> 8, 0, "The mail gateway exited normally");
is ($id, $ticket_id, "replied to the ticket");
- my $u = RT::User->new($RT::SystemUser);
+ my $u = RT::User->new(RT->SystemUser);
$u->Load('doesnotexist-2@'.RT->Config->Get('rtname'));
ok ($u->Id, "user exists and was created by ticket correspondence submission");
+ $m->no_warnings_ok;
}
-diag "add a reply to the ticket using '--extension ticket' feature" if $ENV{'TEST_VERBOSE'};
+diag "add a reply to the ticket using '--extension ticket' feature";
{
my $text = <<EOF;
From: doesnotexist-2\@@{[RT->Config->Get('rtname')]}
@@ -338,7 +358,7 @@ Blah!
Foob!
EOF
local $ENV{'EXTENSION'} = $ticket_id;
- my ($status, $id) = RT::Test->send_via_mailgate($text, extension => 'ticket');
+ my ($status, $id) = RT::Test->send_via_mailgate_and_http($text, extension => 'ticket');
is ($status >> 8, 0, "The mail gateway exited normally");
is ($id, $ticket_id, "replied to the ticket");
@@ -357,9 +377,10 @@ EOF
my $attachment = $txn->Attachments->First;
isa_ok ($attachment, 'RT::Attachment');
is ($attachment->GetHeader('X-RT-Mail-Extension'), $id, 'header is in place');
+ $m->no_warnings_ok;
}
-diag "can another random comment on a ticket without being granted privs? answer should be no" if $ENV{'TEST_VERBOSE'};
+diag "can another random comment on a ticket without being granted privs? answer should be no";
{
my $text = <<EOF;
From: doesnotexist-3\@@{[RT->Config->Get('rtname')]}
@@ -369,17 +390,22 @@ Subject: [@{[RT->Config->Get('rtname')]} #$ticket_id] This is a test of a commen
Blah! (Should not work.)
Foob!
EOF
- my ($status, $id) = RT::Test->send_via_mailgate($text, action => 'comment');
+ my ($status, $id) = RT::Test->send_via_mailgate_and_http($text, action => 'comment');
is ($status >> 8, 0, "The mail gateway exited normally");
ok (!$id, "no way to comment on the ticket");
- my $u = RT::User->new($RT::SystemUser);
+ my $u = RT::User->new(RT->SystemUser);
$u->Load('doesnotexist-3@'.RT->Config->Get('rtname'));
ok( !$u->Id, " user does not exist and was not created by ticket comment submission");
+ $m->next_warning_like(qr/RT's configuration does not allow\s+for the creation of a new user for this email \(doesnotexist-3\@example\.com\)/);
+ TODO: {
+ local $TODO = "we're a bit noisy for this warning case";
+ $m->no_leftover_warnings_ok;
+ }
}
-diag "grant everyone 'CommentOnTicket' right" if $ENV{'TEST_VERBOSE'};
+diag "grant everyone 'CommentOnTicket' right";
{
ok( RT::Test->set_rights(
{ Principal => $everyone_group->PrincipalObj,
@@ -388,7 +414,7 @@ diag "grant everyone 'CommentOnTicket' right" if $ENV{'TEST_VERBOSE'};
), "Granted everybody the right to comment on tickets");
}
-diag "can another random reply to a ticket after being granted privs? answer should be yes" if $ENV{'TEST_VERBOSE'};
+diag "can another random reply to a ticket after being granted privs? answer should be yes";
{
my $text = <<EOF;
From: doesnotexist-3\@@{[RT->Config->Get('rtname')]}
@@ -398,16 +424,17 @@ Subject: [@{[RT->Config->Get('rtname')]} #$ticket_id] This is a test of a commen
Blah!
Foob!
EOF
- my ($status, $id) = RT::Test->send_via_mailgate($text, action => 'comment');
+ my ($status, $id) = RT::Test->send_via_mailgate_and_http($text, action => 'comment');
is ($status >> 8, 0, "The mail gateway exited normally");
is ($id, $ticket_id, "replied to the ticket");
- my $u = RT::User->new($RT::SystemUser);
+ my $u = RT::User->new(RT->SystemUser);
$u->Load('doesnotexist-3@'.RT->Config->Get('rtname'));
ok ($u->Id, " user exists and was created by ticket comment submission");
+ $m->no_warnings_ok;
}
-diag "add comment to the ticket using '--extension action' feature" if $ENV{'TEST_VERBOSE'};
+diag "add comment to the ticket using '--extension action' feature";
{
my $text = <<EOF;
From: doesnotexist-3\@@{[RT->Config->Get('rtname')]}
@@ -418,7 +445,7 @@ Blah!
Foob!
EOF
local $ENV{'EXTENSION'} = 'comment';
- my ($status, $id) = RT::Test->send_via_mailgate($text, extension => 'action');
+ my ($status, $id) = RT::Test->send_via_mailgate_and_http($text, extension => 'action');
is ($status >> 8, 0, "The mail gateway exited normally");
is ($id, $ticket_id, "added comment to the ticket");
@@ -442,12 +469,13 @@ EOF
my $attachment = $txn->Attachments->First;
isa_ok ($attachment, 'RT::Attachment');
is ($attachment->GetHeader('X-RT-Mail-Extension'), 'comment', 'header is in place');
+ $m->no_warnings_ok;
}
-diag "Testing preservation of binary attachments" if $ENV{'TEST_VERBOSE'};
+diag "Testing preservation of binary attachments";
{
# Get a binary blob (Best Practical logo)
- my $LOGO_FILE = $RT::MasonComponentRoot .'/NoAuth/images/bplogo.gif';
+ my $LOGO_FILE = $RT::MasonComponentRoot .'/NoAuth/images/bpslogo.png';
# Create a mime entity with an attachment
my $entity = MIME::Entity->build(
@@ -459,11 +487,11 @@ diag "Testing preservation of binary attachments" if $ENV{'TEST_VERBOSE'};
$entity->attach(
Path => $LOGO_FILE,
- Type => 'image/gif',
+ Type => 'image/png',
Encoding => 'base64',
);
# Create a ticket with a binary attachment
- my ($status, $id) = RT::Test->send_via_mailgate($entity);
+ my ($status, $id) = RT::Test->send_via_mailgate_and_http($entity);
is ($status >> 8, 0, "The mail gateway exited normally");
ok ($id, "created ticket");
@@ -475,11 +503,11 @@ diag "Testing preservation of binary attachments" if $ENV{'TEST_VERBOSE'};
my $file = `cat $LOGO_FILE`;
ok ($file, "Read in the logo image");
- diag "for the raw file the md5 hex is ". Digest::MD5::md5_hex($file) if $ENV{'TEST_VERBOSE'};
+ diag "for the raw file the md5 hex is ". Digest::MD5::md5_hex($file);
# Verify that the binary attachment is valid in the database
- my $attachments = RT::Attachments->new($RT::SystemUser);
- $attachments->Limit(FIELD => 'ContentType', VALUE => 'image/gif');
+ my $attachments = RT::Attachments->new(RT->SystemUser);
+ $attachments->Limit(FIELD => 'ContentType', VALUE => 'image/png');
my $txn_alias = $attachments->Join(
ALIAS1 => 'main',
FIELD1 => 'TransactionId',
@@ -488,25 +516,27 @@ diag "Testing preservation of binary attachments" if $ENV{'TEST_VERBOSE'};
);
$attachments->Limit( ALIAS => $txn_alias, FIELD => 'ObjectType', VALUE => 'RT::Ticket' );
$attachments->Limit( ALIAS => $txn_alias, FIELD => 'ObjectId', VALUE => $id );
- is ($attachments->Count, 1, 'Found only one gif attached to the ticket');
+ is ($attachments->Count, 1, 'Found only one png attached to the ticket');
my $attachment = $attachments->First;
ok ($attachment->Id, 'loaded attachment object');
my $acontent = $attachment->Content;
- diag "coming from the database, md5 hex is ".Digest::MD5::md5_hex($acontent) if $ENV{'TEST_VERBOSE'};
+ diag "coming from the database, md5 hex is ".Digest::MD5::md5_hex($acontent);
is ($acontent, $file, 'The attachment isn\'t screwed up in the database.');
# Grab the binary attachment via the web ui
my $ua = new LWP::UserAgent;
my $full_url = "$url/Ticket/Attachment/". $attachment->TransactionId
- ."/". $attachment->id. "/bplogo.gif?&user=root&pass=password";
+ ."/". $attachment->id. "/bpslogo.png?&user=root&pass=password";
my $r = $ua->get( $full_url );
# Verify that the downloaded attachment is the same as what we uploaded.
is ($file, $r->content, 'The attachment isn\'t screwed up in download');
+
+ $m->no_warnings_ok;
}
-diag "Simple I18N testing" if $ENV{'TEST_VERBOSE'};
+diag "Simple I18N testing";
{
my $text = <<EOF;
From: root\@localhost
@@ -519,7 +549,7 @@ Content-Type: text/plain; charset="utf-8"
\303\241\303\251\303\255\303\263\303\272
bye
EOF
- my ($status, $id) = RT::Test->send_via_mailgate($text);
+ my ($status, $id) = RT::Test->send_via_mailgate_and_http($text);
is ($status >> 8, 0, "The mail gateway exited normally");
ok ($id, "created ticket");
@@ -540,9 +570,11 @@ EOF
$tick->Transactions->First->Content =~ /$unistring/i,
$tick->Id." appears to be unicode ". $tick->Transactions->First->Attachments->First->Id
);
+
+ $m->no_warnings_ok;
}
-diag "supposedly I18N fails on the second message sent in." if $ENV{'TEST_VERBOSE'};
+diag "supposedly I18N fails on the second message sent in.";
{
my $text = <<EOF;
From: root\@localhost
@@ -555,7 +587,7 @@ Content-Type: text/plain; charset="utf-8"
\303\241\303\251\303\255\303\263\303\272
bye
EOF
- my ($status, $id) = RT::Test->send_via_mailgate($text);
+ my ($status, $id) = RT::Test->send_via_mailgate_and_http($text);
is ($status >> 8, 0, "The mail gateway exited normally");
ok ($id, "created ticket");
@@ -572,9 +604,11 @@ EOF
$tick->Transactions->First->Content =~ $unistring,
"It appears to be unicode - ". $tick->Transactions->First->Content
);
+
+ $m->no_warnings_ok;
}
-diag "check that mailgate doesn't suffer from empty Reply-To:" if $ENV{'TEST_VERBOSE'};
+diag "check that mailgate doesn't suffer from empty Reply-To:";
{
my $text = <<EOF;
From: root\@localhost
@@ -585,7 +619,7 @@ Content-Type: text/plain; charset="utf-8"
test
EOF
- my ($status, $id) = RT::Test->send_via_mailgate($text);
+ my ($status, $id) = RT::Test->send_via_mailgate_and_http($text);
is ($status >> 8, 0, "The mail gateway exited normally");
ok ($id, "created ticket");
@@ -595,6 +629,8 @@ EOF
is ($tick->Id, $id, "correct ticket");
like $tick->RequestorAddresses, qr/root\@localhost/, 'correct requestor';
+
+ $m->no_warnings_ok;
}
@@ -607,18 +643,17 @@ skip "Advanced mailgate actions require an unsafe configuration", 47
# create new queue to be shure we don't mess with rights
use RT::Queue;
-my $queue = RT::Queue->new($RT::SystemUser);
+my $queue = RT::Queue->new(RT->SystemUser);
my ($qid) = $queue->Create( Name => 'ext-mailgate');
ok( $qid, 'queue created for ext-mailgate tests' );
-# {{{ Check take and resolve actions
# create ticket that is owned by nobody
use RT::Ticket;
-my $tick = RT::Ticket->new($RT::SystemUser);
+my $tick = RT::Ticket->new(RT->SystemUser);
my ($id) = $tick->Create( Queue => 'ext-mailgate', Subject => 'test');
ok( $id, 'new ticket created' );
-is( $tick->Owner, $RT::Nobody->Id, 'owner of the new ticket is nobody' );
+is( $tick->Owner, RT->Nobody->Id, 'owner of the new ticket is nobody' );
$! = 0;
ok(open(MAIL, '|-', "$RT::BinPath/rt-mailgate --url $url --queue ext-mailgate --action take"), "Opened the mailgate - $!");
@@ -630,7 +665,7 @@ EOF
close (MAIL);
is ($? >> 8, 0, "The mail gateway exited normally");
-$tick = RT::Ticket->new($RT::SystemUser);
+$tick = RT::Ticket->new(RT->SystemUser);
$tick->Load( $id );
is( $tick->Id, $id, 'load correct ticket');
is( $tick->OwnerObj->EmailAddress, 'root@localhost', 'successfuly take ticket via email');
@@ -639,9 +674,11 @@ is( $tick->OwnerObj->EmailAddress, 'root@localhost', 'successfuly take ticket vi
is( $tick->Transactions->Count, 2, 'no superfluous transactions');
my $status;
-($status, $msg) = $tick->SetOwner( $RT::Nobody->Id, 'Force' );
+($status, $msg) = $tick->SetOwner( RT->Nobody->Id, 'Force' );
ok( $status, 'successfuly changed owner: '. ($msg||'') );
-is( $tick->Owner, $RT::Nobody->Id, 'set owner back to nobody');
+is( $tick->Owner, RT->Nobody->Id, 'set owner back to nobody');
+
+$m->no_warnings_ok;
$! = 0;
@@ -657,7 +694,7 @@ is ($? >> 8, 0, "The mail gateway exited normally");
DBIx::SearchBuilder::Record::Cachable->FlushCache;
-$tick = RT::Ticket->new($RT::SystemUser);
+$tick = RT::Ticket->new(RT->SystemUser);
$tick->Load( $id );
is( $tick->Id, $id, "load correct ticket #$id");
is( $tick->OwnerObj->EmailAddress, 'root@localhost', 'successfuly take ticket via email');
@@ -668,6 +705,9 @@ $txns->OrderBy( FIELD => 'id', ORDER => 'DESC' );
is( $tick->Transactions->Count, 6, 'no superfluous transactions');
is( $txns->First->Subject, "[$RT::rtname \#$id] correspondence", 'successfuly add correspond within take via email' );
+$m->no_warnings_ok;
+
+
$! = 0;
ok(open(MAIL, '|-', "$RT::BinPath/rt-mailgate --url $url --queue ext-mailgate --action resolve"), "Opened the mailgate - $!");
print MAIL <<EOF;
@@ -680,14 +720,14 @@ is ($? >> 8, 0, "The mail gateway exited normally");
DBIx::SearchBuilder::Record::Cachable->FlushCache;
-$tick = RT::Ticket->new($RT::SystemUser);
+$tick = RT::Ticket->new(RT->SystemUser);
$tick->Load( $id );
is( $tick->Id, $id, 'load correct ticket');
is( $tick->Status, 'resolved', 'successfuly resolved ticket via email');
is( $tick->Transactions->Count, 7, 'no superfluous transactions');
use RT::User;
-my $user = RT::User->new( $RT::SystemUser );
+my $user = RT::User->new( RT->SystemUser );
my ($uid) = $user->Create( Name => 'ext-mailgate',
EmailAddress => 'ext-mailgate@localhost',
Privileged => 1,
@@ -696,12 +736,14 @@ my ($uid) = $user->Create( Name => 'ext-mailgate',
ok( $uid, 'user created for ext-mailgate tests' );
ok( !$user->HasRight( Right => 'OwnTicket', Object => $queue ), "User can't own ticket" );
-$tick = RT::Ticket->new($RT::SystemUser);
+$tick = RT::Ticket->new(RT->SystemUser);
($id) = $tick->Create( Queue => $qid, Subject => 'test' );
ok( $id, 'create new ticket' );
my $rtname = RT->Config->Get('rtname');
+$m->no_warnings_ok;
+
$! = 0;
ok(open(MAIL, '|-', "$RT::BinPath/rt-mailgate --url $url --queue ext-mailgate --action take"), "Opened the mailgate - $!");
print MAIL <<EOF;
@@ -720,6 +762,10 @@ ok( $status, "successfuly granted right: $msg" );
my $ace_id = $status;
ok( $user->HasRight( Right => 'ReplyToTicket', Object => $tick ), "User can reply to ticket" );
+$m->next_warning_like(qr/Permission Denied/);
+$m->next_warning_like(qr/Could not record email: Ticket not taken/);
+$m->no_leftover_warnings_ok;
+
$! = 0;
ok(open(MAIL, '|-', "$RT::BinPath/rt-mailgate --url $url --queue ext-mailgate --action correspond-take"), "Opened the mailgate - $!");
print MAIL <<EOF;
@@ -735,6 +781,10 @@ DBIx::SearchBuilder::Record::Cachable->FlushCache;
cmp_ok( $tick->Owner, '!=', $user->id, "we didn't change owner" );
is( $tick->Transactions->Count, 3, "one transactions added" );
+$m->next_warning_like(qr/Permission Denied/);
+$m->next_warning_like(qr/Could not record email: Ticket not taken/);
+$m->no_leftover_warnings_ok;
+
$! = 0;
ok(open(MAIL, '|-', "$RT::BinPath/rt-mailgate --url $url --queue ext-mailgate --action take-correspond"), "Opened the mailgate - $!");
print MAIL <<EOF;
@@ -750,12 +800,16 @@ DBIx::SearchBuilder::Record::Cachable->FlushCache;
cmp_ok( $tick->Owner, '!=', $user->id, "we didn't change owner" );
is( $tick->Transactions->Count, 3, "no transactions added, user can't take ticket first" );
+$m->next_warning_like(qr/Permission Denied/);
+$m->next_warning_like(qr/Could not record email: Ticket not taken/);
+$m->no_leftover_warnings_ok;
+
# revoke ReplyToTicket right
use RT::ACE;
-my $ace = RT::ACE->new($RT::SystemUser);
+my $ace = RT::ACE->new(RT->SystemUser);
$ace->Load( $ace_id );
$ace->Delete;
-my $acl = RT::ACL->new($RT::SystemUser);
+my $acl = RT::ACL->new(RT->SystemUser);
$acl->Limit( FIELD => 'RightName', VALUE => 'ReplyToTicket' );
$acl->LimitToObject( $RT::System );
while( my $ace = $acl->Next ) {
@@ -765,9 +819,9 @@ while( my $ace = $acl->Next ) {
ok( !$user->HasRight( Right => 'ReplyToTicket', Object => $tick ), "User can't reply to ticket any more" );
-my $group = RT::Group->new( $RT::SystemUser );
+my $group = RT::Group->new( RT->SystemUser );
ok( $group->LoadQueueRoleGroup( Queue => $qid, Type=> 'Owner' ), "load queue owners role group" );
-$ace = RT::ACE->new( $RT::SystemUser );
+$ace = RT::ACE->new( RT->SystemUser );
($ace_id, $msg) = $group->PrincipalObj->GrantRight( Right => 'ReplyToTicket', Object => $queue );
ok( $ace_id, "Granted queue owners role group with ReplyToTicket right" );
@@ -793,10 +847,7 @@ is( $tick->Owner, $user->id, "we changed owner" );
ok( $user->HasRight( Right => 'ReplyToTicket', Object => $tick ), "owner can reply to ticket" );
is( $tick->Transactions->Count, 5, "transactions added" );
+$m->no_warnings_ok;
-# }}}
};
-
-1;
-
diff --git a/rt/t/mail/gnupg-bad.t b/rt/t/mail/gnupg-bad.t
index 2d8e03575..c9b28c902 100644
--- a/rt/t/mail/gnupg-bad.t
+++ b/rt/t/mail/gnupg-bad.t
@@ -2,57 +2,43 @@
use strict;
use warnings;
-use RT::Test tests => 6;
-
-plan skip_all => 'GnuPG required.'
- unless eval 'use GnuPG::Interface; 1';
-plan skip_all => 'gpg executable is required.'
- unless RT::Test->find_executable('gpg');
-
-
-use Cwd 'getcwd';
-
-my $homedir = RT::Test::get_abs_relocatable_dir(File::Spec->updir(),
- qw(data gnupg keyrings));
-
-RT->Config->Set( 'GnuPG',
- Enable => 1,
- OutgoingMessagesFormat => 'RFC' );
-
-RT->Config->Set( 'GnuPGOptions',
- homedir => $homedir,
- passphrase => 'test',
- 'no-permission-warning' => undef);
+use RT::Test::GnuPG
+ tests => 7,
+ gnupg_options => {
+ passphrase => 'rt-test',
+ homedir => RT::Test::get_abs_relocatable_dir(
+ File::Spec->updir(), qw/data gnupg keyrings/
+ ),
+ };
RT->Config->Set( 'MailPlugins' => 'Auth::MailFrom', 'Auth::GnuPG' );
my ($baseurl, $m) = RT::Test->started_ok;
-$m->get( $baseurl."?user=root;pass=password" );
-$m->content_like(qr/Logout/, 'we did log in');
+$m->login;
$m->get( $baseurl.'/Admin/Queues/');
$m->follow_link_ok( {text => 'General'} );
$m->submit_form( form_number => 3,
fields => { CorrespondAddress => 'rt@example.com' } );
$m->content_like(qr/rt\@example.com.* - never/, 'has key info.');
-ok(my $user = RT::User->new($RT::SystemUser));
+ok(my $user = RT::User->new(RT->SystemUser));
ok($user->Load('root'), "Loaded user 'root'");
$user->SetEmailAddress('rt@example.com');
if (0) {
# XXX: need to generate these mails
- diag "no signature" if $ENV{TEST_VERBOSE};
- diag "no encryption on encrypted queue" if $ENV{TEST_VERBOSE};
- diag "mismatched signature" if $ENV{TEST_VERBOSE};
- diag "unknown public key" if $ENV{TEST_VERBOSE};
- diag "unknown private key" if $ENV{TEST_VERBOSE};
- diag "signer != sender" if $ENV{TEST_VERBOSE};
- diag "encryption to user whose pubkey is not signed" if $ENV{TEST_VERBOSE};
- diag "no encryption of attachment on encrypted queue" if $ENV{TEST_VERBOSE};
- diag "no signature of attachment" if $ENV{TEST_VERBOSE};
- diag "revoked key" if $ENV{TEST_VERBOSE};
- diag "expired key" if $ENV{TEST_VERBOSE};
- diag "unknown algorithm" if $ENV{TEST_VERBOSE};
+ diag "no signature";
+ diag "no encryption on encrypted queue";
+ diag "mismatched signature";
+ diag "unknown public key";
+ diag "unknown private key";
+ diag "signer != sender";
+ diag "encryption to user whose pubkey is not signed";
+ diag "no encryption of attachment on encrypted queue";
+ diag "no signature of attachment";
+ diag "revoked key";
+ diag "expired key";
+ diag "unknown algorithm";
}
diff --git a/rt/t/mail/gnupg-incoming.t b/rt/t/mail/gnupg-incoming.t
index 230aa9c58..e591add6c 100644
--- a/rt/t/mail/gnupg-incoming.t
+++ b/rt/t/mail/gnupg-incoming.t
@@ -2,35 +2,25 @@
use strict;
use warnings;
-use RT::Test tests => 39;
-
-plan skip_all => 'GnuPG required.'
- unless eval 'use GnuPG::Interface; 1';
-plan skip_all => 'gpg executable is required.'
- unless RT::Test->find_executable('gpg');
+my $homedir;
+BEGIN {
+ require RT::Test;
+ $homedir =
+ RT::Test::get_abs_relocatable_dir( File::Spec->updir(),
+ qw/data gnupg keyrings/ );
+}
+use RT::Test::GnuPG
+ tests => 41,
+ actual_server => 1,
+ gnupg_options => {
+ passphrase => 'rt-test',
+ homedir => $homedir,
+ };
-use File::Temp;
-use Cwd 'getcwd';
use String::ShellQuote 'shell_quote';
use IPC::Run3 'run3';
-my $homedir = RT::Test::get_abs_relocatable_dir(File::Spec->updir(),
- qw(data gnupg keyrings));
-
-# catch any outgoing emails
-RT::Test->set_mail_catcher;
-
-RT->Config->Set( 'GnuPG',
- Enable => 1,
- OutgoingMessagesFormat => 'RFC' );
-
-RT->Config->Set( 'GnuPGOptions',
- homedir => $homedir,
- 'no-permission-warning' => undef);
-
-RT->Config->Set( 'MailPlugins' => 'Auth::MailFrom', 'Auth::GnuPG' );
-
my ($baseurl, $m) = RT::Test->started_ok;
# configure key for General queue
@@ -41,7 +31,7 @@ $m->submit_form( form_number => 3,
fields => { CorrespondAddress => 'general@example.com' } );
$m->content_like(qr/general\@example.com.* - never/, 'has key info.');
-ok(my $user = RT::User->new($RT::SystemUser));
+ok(my $user = RT::User->new(RT->SystemUser));
ok($user->Load('root'), "Loaded user 'root'");
$user->SetEmailAddress('recipient@example.com');
@@ -71,7 +61,7 @@ RT::Test->close_mailgate_ok($mail);
qr/^X-RT-Incoming-Encryption: Not encrypted/m,
'recorded incoming mail that is not encrypted'
);
- like( $txn->Attachments->First->Content, qr'Blah');
+ like( $txn->Attachments->First->Content, qr/Blah/);
}
# test for signed mail
@@ -79,7 +69,7 @@ my $buf = '';
run3(
shell_quote(
- qw(gpg --armor --sign),
+ qw(gpg --batch --no-tty --armor --sign),
'--default-key' => 'recipient@example.com',
'--homedir' => $homedir,
'--passphrase' => 'recipient',
@@ -113,7 +103,7 @@ RT::Test->close_mailgate_ok($mail);
'recorded incoming mail that is encrypted'
);
# test for some kind of PGP-Signed-By: Header
- like( $attach->Content, qr'fnord');
+ like( $attach->Content, qr/fnord/);
}
# test for clear-signed mail
@@ -121,7 +111,7 @@ $buf = '';
run3(
shell_quote(
- qw(gpg --armor --sign --clearsign),
+ qw(gpg --batch --no-tty --armor --sign --clearsign),
'--default-key' => 'recipient@example.com',
'--homedir' => $homedir,
'--passphrase' => 'recipient',
@@ -154,7 +144,7 @@ RT::Test->close_mailgate_ok($mail);
'recorded incoming mail that is encrypted'
);
# test for some kind of PGP-Signed-By: Header
- like( $attach->Content, qr'clearfnord');
+ like( $attach->Content, qr/clearfnord/);
}
# test for signed and encrypted mail
@@ -162,7 +152,7 @@ $buf = '';
run3(
shell_quote(
- qw(gpg --encrypt --armor --sign),
+ qw(gpg --batch --no-tty --encrypt --armor --sign),
'--recipient' => 'general@example.com',
'--default-key' => 'recipient@example.com',
'--homedir' => $homedir,
@@ -200,7 +190,7 @@ RT::Test->close_mailgate_ok($mail);
'PGP',
'recorded incoming mail that is encrypted'
);
- like( $attach->Content, qr'orz');
+ like( $attach->Content, qr/orz/);
is( $orig->GetHeader('Content-Type'), 'application/x-rt-original-message');
ok(index($orig->Content, $buf) != -1, 'found original msg');
@@ -211,7 +201,7 @@ $buf = '';
run3(
shell_quote(
- qw(gpg --armor --sign),
+ qw(gpg --batch --no-tty --armor --sign),
'--default-key' => 'rt@example.com',
'--homedir' => $homedir,
'--passphrase' => 'test',
@@ -247,7 +237,7 @@ $buf = '';
run3(
shell_quote(
- qw(gpg --armor --encrypt),
+ qw(gpg --batch --no-tty --armor --encrypt),
'--recipient' => 'random@localhost',
'--homedir' => $homedir,
),
@@ -274,7 +264,7 @@ RT::Test->close_mailgate_ok($mail);
TODO:
{
local $TODO = "this test requires keys associated with queues";
- unlike( $attach->Content, qr'should not be there either');
+ unlike( $attach->Content, qr/should not be there either/);
}
}
@@ -284,7 +274,7 @@ $buf = '';
run3(
shell_quote(
- qw(gpg --armor --encrypt),
+ qw(gpg --batch --no-tty --armor --encrypt),
'--recipient' => 'rt@example.com',
'--homedir' => $homedir,
),
@@ -314,6 +304,6 @@ is(@mail, 1, 'caught outgoing mail.');
my $tick = RT::Test->last_ticket;
my $txn = $tick->Transactions->First;
my ($msg, $attach) = @{$txn->Attachments->ItemsArrayRef};
- unlike( ($attach ? $attach->Content : ''), qr'really should not be there either');
+ unlike( ($attach ? $attach->Content : ''), qr/really should not be there either/);
}
diff --git a/rt/t/mail/gnupg-outgoing-encrypted.t b/rt/t/mail/gnupg-outgoing-encrypted.t
new file mode 100644
index 000000000..4f2a28f55
--- /dev/null
+++ b/rt/t/mail/gnupg-outgoing-encrypted.t
@@ -0,0 +1,27 @@
+#!/usr/bin/perl -w
+use strict;
+use warnings;
+
+use RT::Test::GnuPG
+ tests => 103,
+ gnupg_options => {
+ passphrase => 'rt-test',
+ 'trust-model' => 'always',
+ };
+
+RT::Test->import_gnupg_key('rt-recipient@example.com');
+RT::Test->import_gnupg_key( 'rt-test@example.com', 'public' );
+
+my $queue = RT::Test->load_or_create_queue(
+ Name => 'Regression',
+ CorrespondAddress => 'rt-recipient@example.com',
+ CommentAddress => 'rt-recipient@example.com',
+ Encrypt => 1,
+);
+ok $queue && $queue->id, 'loaded or created queue';
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in';
+
+create_and_test_outgoing_emails( $queue, $m );
+
diff --git a/rt/t/mail/gnupg-outgoing-plain.t b/rt/t/mail/gnupg-outgoing-plain.t
new file mode 100644
index 000000000..ee9a8ac81
--- /dev/null
+++ b/rt/t/mail/gnupg-outgoing-plain.t
@@ -0,0 +1,25 @@
+#!/usr/bin/perl -w
+use strict;
+use warnings;
+
+use RT::Test::GnuPG
+ tests => 103,
+ gnupg_options => {
+ passphrase => 'rt-test',
+ 'trust-model' => 'always',
+ };
+
+RT::Test->import_gnupg_key('rt-recipient@example.com');
+RT::Test->import_gnupg_key( 'rt-test@example.com', 'public' );
+
+my $queue = RT::Test->load_or_create_queue(
+ Name => 'Regression',
+ CorrespondAddress => 'rt-recipient@example.com',
+ CommentAddress => 'rt-recipient@example.com',
+);
+ok $queue && $queue->id, 'loaded or created queue';
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in';
+
+create_and_test_outgoing_emails( $queue, $m );
diff --git a/rt/t/mail/gnupg-outgoing-signed.t b/rt/t/mail/gnupg-outgoing-signed.t
new file mode 100644
index 000000000..2ea20a2d7
--- /dev/null
+++ b/rt/t/mail/gnupg-outgoing-signed.t
@@ -0,0 +1,27 @@
+#!/usr/bin/perl -w
+use strict;
+use warnings;
+
+use RT::Test::GnuPG
+ tests => 103,
+ gnupg_options => {
+ passphrase => 'rt-test',
+ 'trust-model' => 'always',
+ };
+
+RT::Test->import_gnupg_key('rt-recipient@example.com');
+RT::Test->import_gnupg_key( 'rt-test@example.com', 'public' );
+
+my $queue = RT::Test->load_or_create_queue(
+ Name => 'Regression',
+ CorrespondAddress => 'rt-recipient@example.com',
+ CommentAddress => 'rt-recipient@example.com',
+ Sign => 1,
+);
+ok $queue && $queue->id, 'loaded or created queue';
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in';
+
+create_and_test_outgoing_emails( $queue, $m );
+
diff --git a/rt/t/mail/gnupg-outgoing-signed_encrypted.t b/rt/t/mail/gnupg-outgoing-signed_encrypted.t
new file mode 100644
index 000000000..0b82cf1ca
--- /dev/null
+++ b/rt/t/mail/gnupg-outgoing-signed_encrypted.t
@@ -0,0 +1,28 @@
+#!/usr/bin/perl -w
+use strict;
+use warnings;
+
+use RT::Test::GnuPG
+ tests => 103,
+ gnupg_options => {
+ passphrase => 'rt-test',
+ 'trust-model' => 'always',
+ };
+
+RT::Test->import_gnupg_key('rt-recipient@example.com');
+RT::Test->import_gnupg_key( 'rt-test@example.com', 'public' );
+
+my $queue = RT::Test->load_or_create_queue(
+ Name => 'Regression',
+ CorrespondAddress => 'rt-recipient@example.com',
+ CommentAddress => 'rt-recipient@example.com',
+ Sign => 1,
+ Encrypt => 1,
+);
+ok $queue && $queue->id, 'loaded or created queue';
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in';
+
+create_and_test_outgoing_emails( $queue, $m );
+
diff --git a/rt/t/mail/gnupg-realmail.t b/rt/t/mail/gnupg-realmail.t
index 198402b23..7d1dbcab5 100644
--- a/rt/t/mail/gnupg-realmail.t
+++ b/rt/t/mail/gnupg-realmail.t
@@ -2,32 +2,13 @@
use strict;
use warnings;
-use RT::Test tests => 196;
-
-plan skip_all => 'GnuPG required.'
- unless eval 'use GnuPG::Interface; 1';
-plan skip_all => 'gpg executable is required.'
- unless RT::Test->find_executable('gpg');
-
+use RT::Test::GnuPG tests => 198, gnupg_options => { passphrase => 'rt-test' };
use Digest::MD5 qw(md5_hex);
-use File::Temp qw(tempdir);
-my $homedir = tempdir( CLEANUP => 1 );
-
-RT->Config->Set( 'GnuPG',
- Enable => 1,
- OutgoingMessagesFormat => 'RFC' );
-
-RT->Config->Set( 'GnuPGOptions',
- homedir => $homedir,
- passphrase => 'rt-test',
- 'no-permission-warning' => undef);
-
-RT->Config->Set( 'MailPlugins' => 'Auth::MailFrom', 'Auth::GnuPG' );
-
RT::Test->import_gnupg_key('rt-recipient@example.com');
RT::Test->import_gnupg_key('rt-test@example.com', 'public');
+RT::Test->trust_gnupg_key('rt-test@example.com');
my ($baseurl, $m) = RT::Test->started_ok;
ok $m->login, 'we did log in';
@@ -37,17 +18,12 @@ $m->submit_form( form_number => 3,
fields => { CorrespondAddress => 'rt-recipient@example.com' } );
$m->content_like(qr/rt-recipient\@example.com.* - never/, 'has key info.');
-RT::Test->set_rights(
- Principal => 'Everyone',
- Right => ['CreateTicket'],
-);
-
my $eid = 0;
for my $usage (qw/signed encrypted signed&encrypted/) {
for my $format (qw/MIME inline/) {
for my $attachment (qw/plain text-attachment binary-attachment/) {
++$eid;
- diag "Email $eid: $usage, $attachment email with $format format" if $ENV{TEST_VERBOSE};
+ diag "Email $eid: $usage, $attachment email with $format format";
eval { email_ok($eid, $usage, $format, $attachment) };
}
}
@@ -57,13 +33,13 @@ $eid = 18;
{
my ($usage, $format, $attachment) = ('signed', 'inline', 'plain');
++$eid;
- diag "Email $eid: $usage, $attachment email with $format format" if $ENV{TEST_VERBOSE};
+ diag "Email $eid: $usage, $attachment email with $format format";
eval { email_ok($eid, $usage, $format, $attachment) };
}
sub email_ok {
my ($eid, $usage, $format, $attachment) = @_;
- diag "email_ok $eid: $usage, $format, $attachment" if $ENV{'TEST_VERBOSE'};
+ diag "email_ok $eid: $usage, $format, $attachment";
my $emaildatadir = RT::Test::get_relocatable_dir(File::Spec->updir(),
qw(data gnupg emails));
@@ -74,7 +50,7 @@ sub email_ok {
is ($status >> 8, 0, "$eid: The mail gateway exited normally");
ok ($id, "$eid: got id of a newly created ticket - $id");
- my $tick = RT::Ticket->new( $RT::SystemUser );
+ my $tick = RT::Ticket->new( RT->SystemUser );
$tick->Load( $id );
ok ($tick->id, "$eid: loaded ticket #$id");
diff --git a/rt/t/mail/gnupg-reverification.t b/rt/t/mail/gnupg-reverification.t
index f116d9380..96a37a080 100644
--- a/rt/t/mail/gnupg-reverification.t
+++ b/rt/t/mail/gnupg-reverification.t
@@ -2,43 +2,16 @@
use strict;
use warnings;
-use RT::Test tests => 120;
+use RT::Test::GnuPG tests => 216, gnupg_options => { passphrase => 'rt-test' };
-plan skip_all => 'GnuPG required.'
- unless eval 'use GnuPG::Interface; 1';
-plan skip_all => 'gpg executable is required.'
- unless RT::Test->find_executable('gpg');
-
-
-use File::Temp qw(tempdir);
-my $homedir = tempdir( CLEANUP => 1 );
-
-RT->Config->Set( 'GnuPG',
- Enable => 1,
- OutgoingMessagesFormat => 'RFC' );
-
-RT->Config->Set( 'GnuPGOptions',
- homedir => $homedir,
- passphrase => 'rt-test',
- 'no-permission-warning' => undef);
-
-RT->Config->Set( 'MailPlugins' => 'Auth::MailFrom', 'Auth::GnuPG' );
-
-
-diag "load Everyone group" if $ENV{'TEST_VERBOSE'};
+diag "load Everyone group";
my $everyone;
{
- $everyone = RT::Group->new( $RT::SystemUser );
+ $everyone = RT::Group->new( RT->SystemUser );
$everyone->LoadSystemInternalGroup('Everyone');
ok $everyone->id, "loaded 'everyone' group";
}
-RT::Test->set_rights(
- Principal => $everyone,
- Right => ['CreateTicket'],
-);
-
-
my ($baseurl, $m) = RT::Test->started_ok;
ok $m->login, 'we get log in';
@@ -50,7 +23,7 @@ my $emaildatadir = RT::Test::get_relocatable_dir(File::Spec->updir(),
qw(data gnupg emails));
my @files = glob("$emaildatadir/*-signed-*");
foreach my $file ( @files ) {
- diag "testing $file" if $ENV{'TEST_VERBOSE'};
+ diag "testing $file";
my ($eid) = ($file =~ m{(\d+)[^/\\]+$});
ok $eid, 'figured id of a file';
@@ -58,35 +31,61 @@ foreach my $file ( @files ) {
my $email_content = RT::Test->file_content( $file );
ok $email_content, "$eid: got content of email";
- my ($status, $id) = RT::Test->send_via_mailgate( $email_content );
+ my $warnings;
+ my ($status, $id);
+
+ {
+ # We don't use Test::Warn here because we get multi-line
+ # warnings, which Test::Warn only records the first line of.
+ local $SIG{__WARN__} = sub {
+ $warnings .= "@_";
+ };
+
+ ($status, $id) = RT::Test->send_via_mailgate( $email_content );
+ }
+
is $status >> 8, 0, "$eid: the mail gateway exited normally";
ok $id, "$eid: got id of a newly created ticket - $id";
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ like($warnings, qr/Had a problem during decrypting and verifying/);
+ like($warnings, qr/public key not found/);
+
+ my $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Load( $id );
ok $ticket->id, "$eid: loaded ticket #$id";
is $ticket->Subject, "Test Email ID:$eid", "$eid: correct subject";
$m->goto_ticket( $id );
- $m->content_like(
- qr/Not possible to check the signature, the reason is missing public key/is,
+ $m->content_contains(
+ "Not possible to check the signature, the reason is missing public key",
"$eid: signature is not verified",
);
$m->content_like(qr/This is .*ID:$eid/ims, "$eid: content is there and message is decrypted");
+ $m->next_warning_like(qr/public key not found/);
+
+ # some mails contain multiple signatures
+ if ($eid == 5 || $eid == 17 || $eid == 18) {
+ $m->next_warning_like(qr/public key not found/);
+ }
+
+ $m->no_leftover_warnings_ok;
+
push @ticket_ids, $id;
}
-diag "import key into keyring" if $ENV{'TEST_VERBOSE'};
+diag "import key into keyring";
RT::Test->import_gnupg_key('rt-test@example.com', 'public');
foreach my $id ( @ticket_ids ) {
- diag "testing ticket #$id" if $ENV{'TEST_VERBOSE'};
+ diag "testing ticket #$id";
$m->goto_ticket( $id );
- $m->content_like(
- qr/The signature is good/is,
+ $m->content_contains(
+ "The signature is good",
"signature is re-verified and now good",
);
+
+ $m->no_warnings_ok;
}
diff --git a/rt/t/mail/gnupg-special.t b/rt/t/mail/gnupg-special.t
index 6a31ef131..7dd63478a 100644
--- a/rt/t/mail/gnupg-special.t
+++ b/rt/t/mail/gnupg-special.t
@@ -2,32 +2,10 @@
use strict;
use warnings;
-use RT::Test tests => 23;
-
-plan skip_all => 'GnuPG required.'
- unless eval 'use GnuPG::Interface; 1';
-plan skip_all => 'gpg executable is required.'
- unless RT::Test->find_executable('gpg');
+use RT::Test::GnuPG tests => 25, gnupg_options => { passphrase => 'rt-test' };
use Digest::MD5 qw(md5_hex);
-use File::Temp qw(tempdir);
-my $homedir = tempdir( CLEANUP => 1 );
-
-# catch any outgoing emails
-RT::Test->set_mail_catcher;
-
-RT->Config->Set( 'GnuPG',
- Enable => 1,
- OutgoingMessagesFormat => 'RFC' );
-
-RT->Config->Set( 'GnuPGOptions',
- homedir => $homedir,
- 'passphrase' => 'rt-test',
- 'no-permission-warning' => undef);
-
-RT->Config->Set( 'MailPlugins' => 'Auth::MailFrom', 'Auth::GnuPG' );
-
RT::Test->import_gnupg_key('rt-recipient@example.com');
RT::Test->import_gnupg_key('rt-test@example.com', 'public');
@@ -46,19 +24,14 @@ ok( $m->login, 'we did log in' );
$m->content_like(qr/rt-recipient\@example.com.* - never/, 'has key info.');
}
-ok(my $user = RT::User->new($RT::SystemUser));
+ok(my $user = RT::User->new(RT->SystemUser));
ok($user->Load('root'), "Loaded user 'root'");
$user->SetEmailAddress('recipient@example.com');
-RT::Test->set_rights(
- Principal => 'Everyone',
- Right => ['CreateTicket'],
-);
-
{
my $id = send_via_mailgate('quoted_inline_signature.txt');
- my $tick = RT::Ticket->new( $RT::SystemUser );
+ my $tick = RT::Ticket->new( RT->SystemUser );
$tick->Load( $id );
ok ($tick->id, "loaded ticket #$id");
diff --git a/rt/t/mail/mime_decoding.t b/rt/t/mail/mime_decoding.t
index 8257aee80..b02f9795f 100644
--- a/rt/t/mail/mime_decoding.t
+++ b/rt/t/mail/mime_decoding.t
@@ -1,11 +1,11 @@
#!/usr/bin/perl
use strict;
use warnings;
-use RT::Test nodata => 1, tests => 6;
+use RT::Test nodb => 1, tests => 8;
use_ok('RT::I18N');
-diag q{'=' char in a leading part before an encoded part} if $ENV{TEST_VERBOSE};
+diag q{'=' char in a leading part before an encoded part};
{
my $str = 'key="plain"; key="=?UTF-8?B?0LzQvtC5X9GE0LDQudC7LmJpbg==?="';
is(
@@ -15,8 +15,7 @@ diag q{'=' char in a leading part before an encoded part} if $ENV{TEST_VERBOSE};
);
}
-diag q{not compliant with standards, but MUAs send such field when attachment has non-ascii in name}
- if $ENV{TEST_VERBOSE};
+diag q{not compliant with standards, but MUAs send such field when attachment has non-ascii in name};
{
my $str = 'attachment; filename="=?UTF-8?B?0LzQvtC5X9GE0LDQudC7LmJpbg==?="';
is(
@@ -26,7 +25,7 @@ diag q{not compliant with standards, but MUAs send such field when attachment ha
);
}
-diag q{'=' char in a trailing part after an encoded part} if $ENV{TEST_VERBOSE};
+diag q{'=' char in a trailing part after an encoded part};
{
my $str = 'attachment; filename="=?UTF-8?B?0LzQvtC5X9GE0LDQudC7LmJpbg==?="; some_prop="value"';
is(
@@ -36,7 +35,7 @@ diag q{'=' char in a trailing part after an encoded part} if $ENV{TEST_VERBOSE};
);
}
-diag q{regression test for #5248 from rt3.fsck.com} if $ENV{TEST_VERBOSE};
+diag q{regression test for #5248 from rt3.fsck.com};
{
my $str = qq{Subject: =?ISO-8859-1?Q?Re=3A_=5BXXXXXX=23269=5D_=5BComment=5D_Frag?=}
. qq{\n =?ISO-8859-1?Q?e_zu_XXXXXX--xxxxxx_/_Xxxxx=FCxxxxxxxxxx?=};
@@ -47,7 +46,7 @@ diag q{regression test for #5248 from rt3.fsck.com} if $ENV{TEST_VERBOSE};
);
}
-diag q{newline and encoded file name} if $ENV{TEST_VERBOSE};
+diag q{newline and encoded file name};
{
my $str = qq{application/vnd.ms-powerpoint;\n\tname="=?ISO-8859-1?Q?Main_presentation.ppt?="};
is(
@@ -57,3 +56,26 @@ diag q{newline and encoded file name} if $ENV{TEST_VERBOSE};
);
}
+diag q{rfc2231};
+{
+ my $str =
+"filename*=ISO-8859-1''%74%E9%73%74%2E%74%78%74 filename*=ISO-8859-1''%74%E9%73%74%2E%74%78%74";
+ is(
+ RT::I18N::DecodeMIMEWordsToEncoding( $str, 'utf-8' ),
+ 'filename=tést.txt filename=tést.txt',
+ 'right decodig'
+ );
+}
+
+diag q{canonicalize mime word encodings like gb2312};
+{
+ my $str = qq{Subject: =?gb2312?B?1NrKwL3nuPe12Lmy09CzrN9eX1NpbXBsaWZpZWRfQ05fR0IyMzEyYQ==?=
+ =?gb2312?B?dHRhY2hlbWVudCB0ZXN0IGluIENOIHNpbXBsaWZpZWQ=?=};
+
+ is(
+ RT::I18N::DecodeMIMEWordsToUTF8($str),
+ qq{Subject: 在世界各地共有超過_Simplified_CN_GB2312attachement test in CN simplified},
+ "right decoding"
+ );
+}
+
diff --git a/rt/t/mail/multipart.t b/rt/t/mail/multipart.t
index dc97b266f..a68710a75 100644
--- a/rt/t/mail/multipart.t
+++ b/rt/t/mail/multipart.t
@@ -46,19 +46,11 @@
# those contributions and any derivatives thereof.
#
# END BPS TAGGED BLOCK }}}
-
-=head1 NAME
-
-rt-mailgate - Mail interface to RT3.
-
-=cut
-
use strict;
use warnings;
-use RT::Test tests => 5;
+use RT::Test tests => 4;
use RT::Test::Email;
-my ($baseurl, $m) = RT::Test->started_ok;
my $queue = RT::Test->load_or_create_queue( Name => 'General' );
my $user = RT::Test->load_or_create_user( Name => 'bob', EmailAddress => 'bob@example.com' );
diff --git a/rt/t/mail/one-time-recipients.t b/rt/t/mail/one-time-recipients.t
new file mode 100644
index 000000000..985f95562
--- /dev/null
+++ b/rt/t/mail/one-time-recipients.t
@@ -0,0 +1,209 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use utf8;
+
+use RT::Test tests => 38;
+
+my $queue = RT::Test->load_or_create_queue(
+ Name => 'General',
+ CorrespondAddress => 'rt-recipient@example.com',
+ CommentAddress => 'rt-recipient@example.com',
+);
+ok $queue && $queue->id, 'loaded or created queue';
+
+my $user = RT::Test->load_or_create_user(
+ Name => 'root',
+ EmailAddress => 'root@localhost',
+);
+ok $user && $user->id, 'loaded or created user';
+
+diag "Reply to ticket with actor as one time cc";
+{
+ my $ticket = RT::Ticket->new( RT::CurrentUser->new( $user ) );
+ my ($status, undef, $msg) = $ticket->Create(
+ Queue => $queue->id,
+ Subject => 'test',
+ Requestor => 'root@localhost',
+ );
+ ok $status, "created ticket";
+
+ my @mails = RT::Test->fetch_caught_mails;
+ ok @mails, "got some outgoing emails";
+ foreach my $mail ( @mails ) {
+ my $entity = parse_mail( $mail );
+ my $to = $entity->head->get('To');
+ $to =~ s/^\s+|\s+$//;
+ is $to, 'root@localhost', 'got mail'
+ }
+
+ RT->Config->Set( NotifyActor => 1 );
+ ($status, $msg) = $ticket->Correspond(
+ Content => 'test mail',
+ );
+ ok $status, "replied to a ticket";
+
+ @mails = RT::Test->fetch_caught_mails;
+ ok @mails, "got some outgoing emails";
+ foreach my $mail ( @mails ) {
+ my $entity = parse_mail( $mail );
+ my $to = $entity->head->get('To');
+ $to =~ s/^\s+|\s+$//;
+ is $to, 'root@localhost', 'got mail'
+ }
+
+ RT->Config->Set( NotifyActor => 0 );
+ ($status, $msg) = $ticket->Correspond(
+ Content => 'test mail',
+ );
+ ok $status, "replied to a ticket";
+
+ @mails = RT::Test->fetch_caught_mails;
+ ok !@mails, "no mail - don't notify actor";
+
+ ($status, $msg) = $ticket->Correspond(
+ Content => 'test mail',
+ CcMessageTo => 'root@localhost',
+ );
+ ok $status, "replied to a ticket";
+
+ @mails = RT::Test->fetch_caught_mails;
+ ok @mails, "got some outgoing emails";
+ foreach my $mail ( @mails ) {
+ my $entity = parse_mail( $mail );
+ my $to = $entity->head->get('Cc');
+ $to =~ s/^\s+|\s+$//;
+ is $to, 'root@localhost', 'got mail'
+ }
+}
+
+diag "Reply to ticket with requestor squelched";
+{
+ my $ticket = RT::Ticket->new( RT::CurrentUser->new( $user ) );
+ my ($status, undef, $msg) = $ticket->Create(
+ Queue => $queue->id,
+ Subject => 'test',
+ Requestor => 'test@localhost',
+ );
+ ok $status, "created ticket";
+
+ my @mails = RT::Test->fetch_caught_mails;
+ ok @mails, "got some outgoing emails";
+ foreach my $mail ( @mails ) {
+ my $entity = parse_mail( $mail );
+ my $to = $entity->head->get('To');
+ $to =~ s/^\s+|\s+$//;
+ is $to, 'test@localhost', 'got mail'
+ }
+
+ ($status, $msg) = $ticket->Correspond(
+ Content => 'test mail',
+ );
+ ok $status, "replied to a ticket";
+
+ @mails = RT::Test->fetch_caught_mails;
+ ok @mails, "got some outgoing emails";
+ foreach my $mail ( @mails ) {
+ my $entity = parse_mail( $mail );
+ my $to = $entity->head->get('To');
+ $to =~ s/^\s+|\s+$//;
+ is $to, 'test@localhost', 'got mail'
+ }
+
+ $ticket->SquelchMailTo('test@localhost');
+ ($status, $msg) = $ticket->Correspond(
+ Content => 'test mail',
+ );
+ ok $status, "replied to a ticket";
+
+ @mails = RT::Test->fetch_caught_mails;
+ ok !@mails, "no mail - squelched";
+
+ ($status, $msg) = $ticket->Correspond(
+ Content => 'test mail',
+ CcMessageTo => 'test@localhost',
+ );
+ ok $status, "replied to a ticket";
+
+ @mails = RT::Test->fetch_caught_mails;
+ ok @mails, "got some outgoing emails";
+ foreach my $mail ( @mails ) {
+ my $entity = parse_mail( $mail );
+ my $to = $entity->head->get('Cc');
+ $to =~ s/^\s+|\s+$//;
+ is $to, 'test@localhost', 'got mail'
+ }
+}
+
+diag "Reply to ticket with requestor squelched";
+{
+ my $ticket = RT::Ticket->new( RT::CurrentUser->new( $user ) );
+ my ($status, undef, $msg) = $ticket->Create(
+ Queue => $queue->id,
+ Subject => 'test',
+ Requestor => 'test@localhost',
+ );
+ ok $status, "created ticket";
+
+ my @mails = RT::Test->fetch_caught_mails;
+ ok @mails, "got some outgoing emails";
+ foreach my $mail ( @mails ) {
+ my $entity = parse_mail( $mail );
+ my $to = $entity->head->get('To');
+ $to =~ s/^\s+|\s+$//;
+ is $to, 'test@localhost', 'got mail'
+ }
+
+ ($status, $msg) = $ticket->Correspond(
+ Content => 'test mail',
+ );
+ ok $status, "replied to a ticket";
+
+ @mails = RT::Test->fetch_caught_mails;
+ ok @mails, "got some outgoing emails";
+ foreach my $mail ( @mails ) {
+ my $entity = parse_mail( $mail );
+ my $to = $entity->head->get('To');
+ $to =~ s/^\s+|\s+$//;
+ is $to, 'test@localhost', 'got mail'
+ }
+
+ ($status, $msg) = $ticket->Correspond(
+ Content => 'test mail',
+ SquelchMailTo => ['test@localhost'],
+ );
+ ok $status, "replied to a ticket";
+
+ @mails = RT::Test->fetch_caught_mails;
+ ok !@mails, "no mail - squelched";
+
+ ($status, $msg) = $ticket->Correspond(
+ Content => 'test mail',
+ );
+ ok $status, "replied to a ticket";
+
+ @mails = RT::Test->fetch_caught_mails;
+ ok @mails, "got some outgoing emails";
+ foreach my $mail ( @mails ) {
+ my $entity = parse_mail( $mail );
+ my $to = $entity->head->get('To');
+ $to =~ s/^\s+|\s+$//;
+ is $to, 'test@localhost', 'got mail'
+ }
+
+ ($status, $msg) = $ticket->Correspond(
+ Content => 'test mail',
+ CcMessageTo => 'test@localhost',
+ SquelchMailTo => ['test@localhost'],
+ );
+ ok $status, "replied to a ticket";
+
+ @mails = RT::Test->fetch_caught_mails;
+ ok @mails, "got some outgoing emails";
+ foreach my $mail ( @mails ) {
+ my $entity = parse_mail( $mail );
+ my $to = $entity->head->get('Cc');
+ $to =~ s/^\s+|\s+$//;
+ is $to, 'test@localhost', 'got mail'
+ }
+}
diff --git a/rt/t/mail/outlook.t b/rt/t/mail/outlook.t
index 15bfa21bc..00bbc9445 100644
--- a/rt/t/mail/outlook.t
+++ b/rt/t/mail/outlook.t
@@ -56,11 +56,11 @@ rt-mailgate - Mail interface to RT3.
use strict;
use warnings;
-use RT::Test tests => 43;
-my ($baseurl, $m) = RT::Test->started_ok;
+use RT::Test tests => 42;
+
# 12.0 is outlook 2007, 14.0 is 2010
for my $mailer ( 'Microsoft Office Outlook 12.0', 'Microsoft Outlook 14.0' ) {
- diag "Test mail with multipart/alternative" if $ENV{'TEST_VERBOSE'};
+ diag "Test mail with multipart/alternative";
{
my $text = <<EOF;
From: root\@localhost
@@ -106,8 +106,7 @@ EOF
$mailer . ' with multipart/alternative, \n\n are replaced' );
}
- diag "Test mail with multipart/mixed, with multipart/alternative in it"
- if $ENV{'TEST_VERBOSE'};
+ diag "Test mail with multipart/mixed, with multipart/alternative in it";
{
my $text = <<EOF;
From: root\@localhost
@@ -167,8 +166,7 @@ EOF
$mailer . ' with multipart/multipart, \n\n are replaced' );
}
- diag "Test mail with with outlook, but the content type is text/plain"
- if $ENV{'TEST_VERBOSE'};
+ diag "Test mail with with outlook, but the content type is text/plain";
{
my $text = <<EOF;
From: root\@localhost
@@ -203,8 +201,7 @@ EOF
}
}
-diag "Test mail with with multipart/alternative but x-mailer is not outlook "
- if $ENV{'TEST_VERBOSE'};
+diag "Test mail with with multipart/alternative but x-mailer is not outlook ";
{
my $text = <<EOF;
From: root\@localhost
diff --git a/rt/t/mail/rfc822-attachment.t b/rt/t/mail/rfc822-attachment.t
new file mode 100644
index 000000000..f498ec55a
--- /dev/null
+++ b/rt/t/mail/rfc822-attachment.t
@@ -0,0 +1,137 @@
+use strict;
+use warnings;
+
+use RT::Test tests => undef;
+
+use MIME::Entity;
+
+diag "simple rfc822 attachment";
+{
+
+ my $top = MIME::Entity->build(
+ From => 'root@localhost',
+ To => 'rt@localhost',
+ Subject => 'this is top',
+ Data => ['top mail'],
+ );
+
+ my $rfc822 = MIME::Entity->build(
+ From => 'foo@localhost',
+ To => 'bar@localhost',
+ Subject => 'rfc822',
+ Data => ['rfc822 attachment'],
+ 'X-Brokenness' => 'high',
+ );
+
+ $top->attach(
+ Data => $rfc822->stringify,
+ Type => 'message/rfc822',
+ );
+
+ my $parsed = content_as_mime($top);
+
+ for my $mime ($top, $parsed) {
+ diag "testing mail";
+ is $mime->parts, 2, 'two mime parts';
+
+ like $mime->head->get('Subject'), qr/this is top/, 'top subject';
+ like $mime->head->get('From'), qr/root\@localhost/, 'top From';
+ like $mime->parts(0)->bodyhandle->as_string, qr/top mail/, 'content of top';
+
+ my $attach = $mime->parts(1);
+ my $body = $attach->bodyhandle->as_string;
+
+ like $attach->head->mime_type, qr/message\/rfc822/, 'attach of type message/rfc822';
+ like $body, qr/rfc822 attachment/, 'attach content';
+
+ headers_like(
+ $attach,
+ Subject => 'rfc822',
+ From => 'foo@localhost',
+ 'X-Brokenness' => 'high',
+ );
+ }
+}
+
+diag "multipart rfc822 attachment";
+{
+
+ my $top = MIME::Entity->build(
+ From => 'root@localhost',
+ To => 'rt@localhost',
+ Subject => 'this is top',
+ Data => ['top mail'],
+ );
+
+ my $rfc822 = MIME::Entity->build(
+ From => 'foo@localhost',
+ To => 'bar@localhost',
+ Subject => 'rfc822',
+ Data => ['rfc822 attachment'],
+ 'X-Brokenness' => 'high',
+ );
+
+ $rfc822->attach(
+ Data => '<b>attachment of rfc822 attachment</b>',
+ Type => 'text/html',
+ );
+
+ $top->attach(
+ Data => $rfc822->stringify,
+ Type => 'message/rfc822',
+ );
+
+ my $parsed = content_as_mime($top);
+
+ for my $mime ($top, $parsed) {
+ diag "testing mail";
+ is $mime->parts, 2, 'two mime parts';
+
+ like $mime->head->get('Subject'), qr/this is top/, 'top subject';
+ like $mime->head->get('From'), qr/root\@localhost/, 'top From';
+ like $mime->parts(0)->bodyhandle->as_string, qr/top mail/, 'content of top';
+
+ my $attach = $mime->parts(1);
+ my $body = $attach->bodyhandle->as_string;
+
+ like $attach->head->mime_type, qr/message\/rfc822/, 'attach of type message/rfc822';
+ like $body, qr/rfc822 attachment/, 'attach content';
+ like $body, qr/attachment of rfc822 attachment/, 'attach content';
+
+ headers_like(
+ $attach,
+ Subject => 'rfc822',
+ From => 'foo@localhost',
+ 'X-Brokenness' => 'high',
+ 'Content-Type' => 'text/plain',
+ 'Content-type' => 'text/html',
+ );
+ }
+}
+
+sub content_as_mime {
+ my $entity = shift;
+ my ( $status, $id ) = RT::Test->send_via_mailgate($entity);
+ is( $status >> 8, 0, "The mail gateway exited normally" );
+ ok( $id, "created ticket" );
+ # We can't simply use Txn->ContentAsMIME since that is wrapped in a
+ # message/rfc822 entity
+ return RT::Test->last_ticket->Transactions->First->Attachments->First->ContentAsMIME(Children => 1);
+}
+
+sub headers_like {
+ my $attach = shift;
+ my %header = (@_);
+ my $body = $attach->bodyhandle->as_string;
+ for my $name (keys %header) {
+ if (lc $name eq 'content-type') {
+ like $attach->head->get($name), qr/message\/rfc822/, "attach $name message/rfc822, not from a subpart";
+ } else {
+ is $attach->head->get($name), undef, "attach $name not in part header";
+ }
+ like $body, qr/$name: $header{$name}/i, "attach $name in part body";
+ }
+}
+
+done_testing;
+
diff --git a/rt/t/mail/sendmail.t b/rt/t/mail/sendmail.t
index 1f97bbb9f..bb5d2db80 100644
--- a/rt/t/mail/sendmail.t
+++ b/rt/t/mail/sendmail.t
@@ -3,7 +3,7 @@
use strict;
use File::Spec ();
-use RT::Test tests => 137;
+use RT::Test tests => 141;
use RT::EmailParser;
use RT::Tickets;
@@ -13,7 +13,7 @@ my @_outgoing_messages;
my @scrips_fired;
#We're not testing acls here.
-my $everyone = RT::Group->new($RT::SystemUser);
+my $everyone = RT::Group->new(RT->SystemUser);
$everyone->LoadSystemInternalGroup('Everyone');
$everyone->PrincipalObj->GrantRight( Right =>'SuperUser' );
@@ -22,13 +22,13 @@ is (__PACKAGE__, 'main', "We're operating in the main package");
{
no warnings qw/redefine/;
- sub RT::Action::SendEmail::SendMessage {
+ *RT::Action::SendEmail::SendMessage = sub {
my $self = shift;
my $MIME = shift;
main::_fired_scrip($self->ScripObj);
main::is(ref($MIME) , 'MIME::Entity', "hey, look. it's a mime entity");
- }
+ };
}
# some utils
@@ -52,7 +52,7 @@ use RT::Interface::Email;
my %args = (message => $content, queue => 1, action => 'correspond');
my ($status, $msg) = RT::Interface::Email::Gateway(\%args);
ok($status, "successfuly used Email::Gateway interface") or diag("error: $msg");
-my $tickets = RT::Tickets->new($RT::SystemUser);
+my $tickets = RT::Tickets->new(RT->SystemUser);
$tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
$tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
my $tick= $tickets->First();
@@ -79,10 +79,10 @@ Foob!');
use Data::Dumper;
-my $ticket = RT::Ticket->new($RT::SystemUser);
+my $ticket = RT::Ticket->new(RT->SystemUser);
my ($id, undef, $create_msg ) = $ticket->Create(Requestor => ['root@localhost'], Queue => 'general', Subject => 'I18NTest', MIMEObj => $parser->Entity);
ok ($id,$create_msg);
-$tickets = RT::Tickets->new($RT::SystemUser);
+$tickets = RT::Tickets->new(RT->SystemUser);
$tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
$tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick = $tickets->First();
@@ -115,7 +115,7 @@ use RT::Interface::Email;
%args = (message => $content, queue => 1, action => 'correspond');
RT::Interface::Email::Gateway(\%args);
- $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets = RT::Tickets->new(RT->SystemUser);
$tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
$tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick = $tickets->First();
@@ -157,7 +157,7 @@ use RT::Interface::Email;
%args = (message => $content, queue => 1, action => 'correspond');
RT::Interface::Email::Gateway(\%args);
-$tickets = RT::Tickets->new($RT::SystemUser);
+$tickets = RT::Tickets->new(RT->SystemUser);
$tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
$tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick = $tickets->First();
@@ -192,8 +192,7 @@ sub _fired_scrip {
sub utf8_redef_sendmessage {
no warnings qw/redefine/;
- eval '
- sub RT::Action::SendEmail::SendMessage {
+ *RT::Action::SendEmail::SendMessage = sub {
my $self = shift;
my $MIME = shift;
@@ -201,26 +200,25 @@ sub utf8_redef_sendmessage {
ok(1, $self->ScripObj->ConditionObj->Name . " ".$self->ScripObj->ActionObj->Name);
main::_fired_scrip($self->ScripObj);
$MIME->make_singlepart;
- main::is( ref($MIME) , \'MIME::Entity\',
- "hey, look. it\'s a mime entity" );
- main::is( ref( $MIME->head ) , \'MIME::Head\',
+ main::is( ref($MIME) , 'MIME::Entity',
+ "hey, look. it's a mime entity" );
+ main::is( ref( $MIME->head ) , 'MIME::Head',
"its mime header is a mime header. yay" );
- main::like( $MIME->head->get(\'Content-Type\') , qr/utf-8/,
+ main::like( $MIME->head->get('Content-Type') , qr/utf-8/,
"Its content type is utf-8" );
my $message_as_string = $MIME->bodyhandle->as_string();
use Encode;
$message_as_string = Encode::decode_utf8($message_as_string);
main::like(
$message_as_string , qr/H\x{e5}vard/,
-"The message\'s content contains havard\'s name. this will fail if it\'s not utf8 out");
+"The message's content contains havard's name. this will fail if it's not utf8 out");
- }';
+ };
}
sub iso8859_redef_sendmessage {
no warnings qw/redefine/;
- eval '
- sub RT::Action::SendEmail::SendMessage {
+ *RT::Action::SendEmail::SendMessage = sub {
my $self = shift;
my $MIME = shift;
@@ -228,22 +226,20 @@ sub iso8859_redef_sendmessage {
ok(1, $self->ScripObj->ConditionObj->Name . " ".$self->ScripObj->ActionObj->Name);
main::_fired_scrip($self->ScripObj);
$MIME->make_singlepart;
- main::is( ref($MIME) , \'MIME::Entity\',
- "hey, look. it\'s a mime entity" );
- main::is( ref( $MIME->head ) , \'MIME::Head\',
+ main::is( ref($MIME) , 'MIME::Entity',
+ "hey, look. it's a mime entity" );
+ main::is( ref( $MIME->head ) , 'MIME::Head',
"its mime header is a mime header. yay" );
- main::like( $MIME->head->get(\'Content-Type\') , qr/iso-8859-1/,
+ main::like( $MIME->head->get('Content-Type') , qr/iso-8859-1/,
"Its content type is iso-8859-1 - " . $MIME->head->get("Content-Type") );
my $message_as_string = $MIME->bodyhandle->as_string();
use Encode;
$message_as_string = Encode::decode("iso-8859-1",$message_as_string);
main::like(
- $message_as_string , qr/H\x{e5}vard/, "The message\'s content contains havard\'s name. this will fail if it\'s not utf8 out");
-
- }';
+ $message_as_string , qr/H\x{e5}vard/, "The message's content contains havard's name. this will fail if it's not utf8 out");
+ };
}
-# {{{ test a multipart alternative containing a text-html part with an umlaut
my $alt_umlaut_email = RT::Test::get_relocatable_file(
'multipart-alternative-with-umlaut', (File::Spec->updir(), 'data', 'emails'));
@@ -260,7 +256,7 @@ $parser->ParseMIMEEntityFromScalar($content);
%args = (message => $content, queue => 1, action => 'correspond');
RT::Interface::Email::Gateway(\%args);
# TODO: following 5 lines should replaced by get_latest_ticket_ok()
- $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets = RT::Tickets->new(RT->SystemUser);
$tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
$tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick = $tickets->First();
@@ -272,9 +268,7 @@ $parser->ParseMIMEEntityFromScalar($content);
}
-# }}}
-# {{{ test a text-html message with an umlaut
my $text_html_email = RT::Test::get_relocatable_file('text-html-with-umlaut',
(File::Spec->updir(), 'data', 'emails'));
$content = RT::Test->file_content($text_html_email);
@@ -287,7 +281,7 @@ $parser->ParseMIMEEntityFromScalar($content);
%args = (message => $content, queue => 1, action => 'correspond');
RT::Interface::Email::Gateway(\%args);
- $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets = RT::Tickets->new(RT->SystemUser);
$tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
$tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick = $tickets->First();
@@ -299,32 +293,54 @@ is (count_attachs($tick), 1 , "Has one attachment, presumably a text-html and a
sub text_html_redef_sendmessage {
no warnings qw/redefine/;
- eval 'sub RT::Action::SendEmail::SendMessage {
- my $self = shift;
- my $MIME = shift;
- return (1) unless ($self->ScripObj->ScripActionObj->Name eq "Notify AdminCcs" );
- is ($MIME->parts, 0, "generated correspondence mime entity
- does not have parts");
- is ($MIME->head->mime_type , "text/plain", "The mime type is a plain");
- }';
+ *RT::Action::SendEmail::SendMessage = sub {
+ my $self = shift;
+ my $MIME = shift;
+ return (1) unless ($self->ScripObj->ScripActionObj->Name eq "Notify AdminCcs" );
+ is ($MIME->parts, 0, "generated correspondence mime entity
+ does not have parts");
+ is ($MIME->head->mime_type , "text/plain", "The mime type is a plain");
+ };
}
-# }}}
-# {{{ test a text-html message with russian characters
my $russian_email = RT::Test::get_relocatable_file('text-html-in-russian',
(File::Spec->updir(), 'data', 'emails'));
$content = RT::Test->file_content($russian_email);
$parser->ParseMIMEEntityFromScalar($content);
-
# be as much like the mail gateway as possible.
&text_html_redef_sendmessage;
%args = (message => $content, queue => 1, action => 'correspond');
- RT::Interface::Email::Gateway(\%args);
- $tickets = RT::Tickets->new($RT::SystemUser);
+
+{
+
+my @warnings;
+local $SIG{__WARN__} = sub {
+ push @warnings, "@_";
+};
+
+RT::Interface::Email::Gateway(\%args);
+
+TODO: {
+ local $TODO =
+'need a better approach of encoding converter, should be fixed in 4.2';
+ok( @warnings == 1 || @warnings == 2, "1 or 2 warnings are ok" );
+ok( @warnings == 1 || ( @warnings == 2 && $warnings[1] eq $warnings[0] ),
+ 'if there are 2 warnings, they should be same' );
+
+like(
+ $warnings[0],
+ qr/\QEncoding error: "\x{041f}" does not map to iso-8859-1/,
+"The badly formed Russian spam we have isn't actually well-formed UTF8, which makes Encode (correctly) warn",
+);
+
+}
+}
+
+ $tickets = RT::Tickets->new(RT->SystemUser);
$tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
$tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick = $tickets->First();
@@ -334,9 +350,7 @@ like (first_attach($tick)->ContentType , qr/text\/html/, "We recorded the conten
is (count_attachs($tick) ,1 , "Has one attachment, presumably a text-html and a multipart alternative");
-# }}}
-# {{{ test a message containing a russian subject and NO content type
RT->Config->Set( EmailInputEncodings => 'koi8-r', RT->Config->Get('EmailInputEncodings') );
RT->Config->Set( EmailOutputEncoding => 'koi8-r' );
@@ -351,7 +365,7 @@ $parser->ParseMIMEEntityFromScalar($content);
&text_plain_russian_redef_sendmessage;
%args = (message => $content, queue => 1, action => 'correspond');
RT::Interface::Email::Gateway(\%args);
- $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets = RT::Tickets->new(RT->SystemUser);
$tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
$tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick= $tickets->First();
@@ -362,26 +376,23 @@ is (count_attachs($tick) ,1 , "Has one attachment, presumably a text-plain");
is ($tick->Subject, "\x{442}\x{435}\x{441}\x{442} \x{442}\x{435}\x{441}\x{442}", "Recorded the subject right");
sub text_plain_russian_redef_sendmessage {
no warnings qw/redefine/;
- eval 'sub RT::Action::SendEmail::SendMessage {
- my $self = shift;
- my $MIME = shift;
- return (1) unless ($self->ScripObj->ScripActionObj->Name eq "Notify AdminCcs" );
- is ($MIME->head->mime_type , "text/plain", "The only part is text/plain ");
- my $subject = $MIME->head->get("subject");
- chomp($subject);
- #is( $subject , /^=\?KOI8-R\?B\?W2V4YW1wbGUuY39tICM3XSDUxdPUINTF09Q=\?=/ , "The $subject is encoded correctly");
- };
- ';
+ *RT::Action::SendEmail::SendMessage = sub {
+ my $self = shift;
+ my $MIME = shift;
+ return (1) unless ($self->ScripObj->ScripActionObj->Name eq "Notify AdminCcs" );
+ is ($MIME->head->mime_type , "text/plain", "The only part is text/plain ");
+ my $subject = $MIME->head->get("subject");
+ chomp($subject);
+ #is( $subject , /^=\?KOI8-R\?B\?W2V4YW1wbGUuY39tICM3XSDUxdPUINTF09Q=\?=/ , "The $subject is encoded correctly");
+ };
}
my @input_encodings = RT->Config->Get( 'EmailInputEncodings' );
shift @input_encodings;
RT->Config->Set(EmailInputEncodings => @input_encodings );
RT->Config->Set(EmailOutputEncoding => 'utf-8');
-# }}}
-# {{{ test a message containing a nested RFC 822 message
my $nested_rfc822_email = RT::Test::get_relocatable_file('nested-rfc-822',
(File::Spec->updir(), 'data', 'emails'));
@@ -395,7 +406,7 @@ $parser->ParseMIMEEntityFromScalar($content);
&text_plain_nested_redef_sendmessage;
%args = (message => $content, queue => 1, action => 'correspond');
RT::Interface::Email::Gateway(\%args);
- $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets = RT::Tickets->new(RT->SystemUser);
$tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
$tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick= $tickets->First();
@@ -405,24 +416,28 @@ like (first_attach($tick)->ContentType , qr/multipart\/mixed/, "We recorded the
is (count_attachs($tick) , 5 , "Has one attachment, presumably a text-plain and a message RFC 822 and another plain");
sub text_plain_nested_redef_sendmessage {
no warnings qw/redefine/;
- eval 'sub RT::Action::SendEmail::SendMessage {
- my $self = shift;
- my $MIME = shift;
- return (1) unless ($self->ScripObj->ScripActionObj->Name eq "Notify AdminCcs" );
- is ($MIME->head->mime_type , "multipart/mixed", "It is a mixed multipart");
- my $subject = $MIME->head->get("subject");
- $subject = MIME::Base64::decode_base64( $subject);
- chomp($subject);
- # TODO, why does this test fail
- #ok($subject =~ qr{Niv\x{e5}er}, "The subject matches the word - $subject");
- 1;
- }';
+ *RT::Action::SendEmail::SendMessage = sub {
+ my $self = shift;
+ my $MIME = shift;
+
+ return (1) unless ($self->ScripObj->ScripActionObj->Name eq "Notify AdminCcs" );
+
+ is ($MIME->head->mime_type , "multipart/mixed", "It is a mixed multipart");
+
+ use MIME::Words qw(:all);
+ my $encoded_subject = $MIME->head->get("subject");
+ my $subject = decode_mimewords($encoded_subject);
+
+ # MIME::Words isn't actually UTF8-safe. There go 4 hours I'll never get back.
+ utf8::decode($subject);
+ like($subject, qr/Niv\x{e5}er/, "The subject matches the word - $subject");
+
+ 1;
+ };
}
-# }}}
-# {{{ test a multipart alternative containing a uuencoded mesage generated by lotus notes
my $uuencoded_email = RT::Test::get_relocatable_file('notes-uuencoded',
(File::Spec->updir(), 'data', 'emails'));
@@ -437,7 +452,7 @@ $parser->ParseMIMEEntityFromScalar($content);
local *RT::Action::SendEmail::SendMessage = sub { return 1};
%args = (message => $content, queue => 1, action => 'correspond');
RT::Interface::Email::Gateway(\%args);
- $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets = RT::Tickets->new(RT->SystemUser);
$tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
$tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick= $tickets->First();
@@ -447,9 +462,7 @@ $parser->ParseMIMEEntityFromScalar($content);
is (count_attachs($tick) , 3 , "Has three attachments");
}
-# }}}
-# {{{ test a multipart that crashes the file-based mime-parser works
my $crashes_file_based_parser_email = RT::Test::get_relocatable_file(
'crashes-file-based-parser', (File::Spec->updir(), 'data', 'emails'));
@@ -464,7 +477,7 @@ no warnings qw/redefine/;
local *RT::Action::SendEmail::SendMessage = sub { return 1};
%args = (message => $content, queue => 1, action => 'correspond');
RT::Interface::Email::Gateway(\%args);
- $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets = RT::Tickets->new(RT->SystemUser);
$tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
$tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick= $tickets->First();
@@ -476,9 +489,7 @@ is (count_attachs($tick) , 5 , "Has three attachments");
-# }}}
-# {{{ test a multi-line RT-Send-CC header
my $rt_send_cc_email = RT::Test::get_relocatable_file('rt-send-cc',
(File::Spec->updir(), 'data', 'emails'));
@@ -490,7 +501,7 @@ $parser->ParseMIMEEntityFromScalar($content);
%args = (message => $content, queue => 1, action => 'correspond');
RT::Interface::Email::Gateway(\%args);
- $tickets = RT::Tickets->new($RT::SystemUser);
+ $tickets = RT::Tickets->new(RT->SystemUser);
$tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
$tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick= $tickets->First();
@@ -503,9 +514,8 @@ like ($cc , qr/test3/, "Found test 3");
like ($cc , qr/test4/, "Found test 4");
like ($cc , qr/test5/, "Found test 5");
-# }}}
-diag q{regression test for #5248 from rt3.fsck.com} if $ENV{TEST_VERBOSE};
+diag q{regression test for #5248 from rt3.fsck.com};
{
my $subject_folding_email = RT::Test::get_relocatable_file(
'subject-with-folding-ws', (File::Spec->updir(), 'data', 'emails'));
@@ -518,7 +528,7 @@ diag q{regression test for #5248 from rt3.fsck.com} if $ENV{TEST_VERBOSE};
is ($ticket->Subject, 'test', 'correct subject');
}
-diag q{regression test for #5248 from rt3.fsck.com} if $ENV{TEST_VERBOSE};
+diag q{regression test for #5248 from rt3.fsck.com};
{
my $long_subject_email = RT::Test::get_relocatable_file('very-long-subject',
(File::Spec->updir(), 'data', 'emails'));
@@ -535,4 +545,3 @@ diag q{regression test for #5248 from rt3.fsck.com} if $ENV{TEST_VERBOSE};
# Don't taint the environment
$everyone->PrincipalObj->RevokeRight(Right =>'SuperUser');
-1;
diff --git a/rt/t/mail/threading.t b/rt/t/mail/threading.t
new file mode 100644
index 000000000..7112ecf07
--- /dev/null
+++ b/rt/t/mail/threading.t
@@ -0,0 +1,90 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use utf8;
+
+use RT::Test tests => 22;
+RT->Config->Set( NotifyActor => 1 );
+
+my $queue = RT::Test->load_or_create_queue(
+ Name => 'General',
+ CorrespondAddress => 'rt-recipient@example.com',
+ CommentAddress => 'rt-recipient@example.com',
+);
+ok $queue && $queue->id, 'loaded or created queue';
+
+my $user = RT::Test->load_or_create_user(
+ Name => 'root',
+ EmailAddress => 'root@localhost',
+);
+ok $user && $user->id, 'loaded or created user';
+
+{
+ my $mail = <<EOF;
+From: root\@localhost
+Subject: a ticket
+Message-ID: <some-message-id>
+
+Foob!
+EOF
+ my ($status, $id) = RT::Test->send_via_mailgate($mail);
+ ok $id, "created a ticket";
+
+ my @mail = RT::Test->fetch_caught_mails;
+ is scalar @mail, 1, "autoreply";
+ like $mail[0], qr{^In-Reply-To:\s*<some-message-id>$}mi;
+ like $mail[0], qr{^References:\s*<RT-Ticket-\Q$id\E\@example\.com>}mi;
+
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ $ticket->Load( $id );
+ ok $ticket->id, "loaded ticket";
+
+ ($status, my ($msg)) = $ticket->Correspond( Content => 'boo' );
+ ok $status, "replied to the ticket";
+
+ @mail = RT::Test->fetch_caught_mails;
+ is scalar @mail, 1, "reply";
+ like $mail[0], qr{^References:\s*<RT-Ticket-\Q$id\E\@example\.com>$}mi,
+ "no context, so only pseudo header is referenced";
+}
+
+{
+ my ($ticket) = RT::Test->create_ticket(
+ Queue => $queue->id,
+ Requestor => $user->EmailAddress
+ );
+ my $id = $ticket->id;
+ ok $id, "created a ticket";
+
+ my @mail = RT::Test->fetch_caught_mails;
+ is scalar @mail, 1, "autoreply";
+ like $mail[0], qr{^References:\s*<RT-Ticket-\Q$id\E\@example\.com>}mi;
+}
+
+{
+ my $scrip = RT::Scrip->new(RT->SystemUser);
+ my ($status, $msg) = $scrip->Create(
+ Description => "Notify requestor on status change",
+ ScripCondition => 'On Status Change',
+ ScripAction => 'Notify Requestors',
+ Template => 'Transaction',
+ Stage => 'TransactionCreate',
+ Queue => 0,
+ );
+ ok($status, "Scrip created");
+
+ my ($ticket) = RT::Test->create_ticket(
+ Queue => $queue->id,
+ Requestor => $user->EmailAddress,
+ );
+ my $id = $ticket->id;
+ ok $id, "created a ticket";
+
+ RT::Test->fetch_caught_mails;
+ ($status, $msg) = $ticket->SetStatus('open');
+ ok $status, "changed status";
+
+ my @mail = RT::Test->fetch_caught_mails;
+ is scalar @mail, 1, "status change notification";
+ like $mail[0], qr{^References:\s*<RT-Ticket-\Q$id\E\@example\.com>}mi;
+}
diff --git a/rt/t/mail/verp.t b/rt/t/mail/verp.t
index 79ede90ab..ed3af6a7b 100644
--- a/rt/t/mail/verp.t
+++ b/rt/t/mail/verp.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl -w
use strict;
-use RT::Test tests => 1;
+use RT::Test nodb => 1, tests => 1;
TODO: {
todo_skip "No tests written for VERP yet", 1;
ok(1,"a test to skip");
diff --git a/rt/t/mail/wrong_mime_charset.t b/rt/t/mail/wrong_mime_charset.t
index 71a574f26..511a7e61d 100644
--- a/rt/t/mail/wrong_mime_charset.t
+++ b/rt/t/mail/wrong_mime_charset.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl
use strict;
use warnings;
-use RT::Test nodata => 1, tests => 3;
+use RT::Test nodb => 1, tests => 6;
use_ok('RT::I18N');
use utf8;
@@ -16,12 +16,31 @@ my $mime = MIME::Entity->build(
# set the wrong charset mime in purpose
$mime->head->mime_attr( "Content-Type.charset" => 'utf8' );
+my @warnings;
+local $SIG{__WARN__} = sub {
+ push @warnings, "@_";
+};
+
RT::I18N::SetMIMEEntityToEncoding( $mime, 'iso-8859-1' );
TODO: {
local $TODO =
'need a better approach of encoding converter, should be fixed in 4.2';
+# this is a weird behavior for different perl versions, 5.12 warns twice,
+# which is correct since we do the encoding thing twice, for Subject
+# and Data respectively.
+# but 5.8 and 5.10 warns only once.
+ok( @warnings == 1 || @warnings == 2, "1 or 2 warnings are ok" );
+ok( @warnings == 1 || ( @warnings == 2 && $warnings[1] eq $warnings[0] ),
+ 'if there are 2 warnings, they should be same' );
+
+like(
+ $warnings[0],
+ qr/\QEncoding error: "\x{fffd}" does not map to iso-8859-1/,
+"We can't encode something into the wrong encoding without Encode complaining"
+);
+
my $subject = decode( 'iso-8859-1', $mime->head->get('Subject') );
chomp $subject;
is( $subject, $test_string, 'subject is set to iso-8859-1' );
diff --git a/rt/t/ticket/clicky.t b/rt/t/ticket/clicky.t
new file mode 100644
index 000000000..3a7ec8241
--- /dev/null
+++ b/rt/t/ticket/clicky.t
@@ -0,0 +1,142 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use Test::More;
+use RT::Test tests => 20;
+
+my $plain = MIME::Entity->build(
+ Subject => 'plain mime',
+ Type => 'text/plain',
+ Data => <<END,
+If you have some problems with RT you could find help
+on http://wiki.bestpractical.com or subscribe to
+the rt-users\@lists.bestpractical.com.
+
+to test anchor:
+https://wiki.bestpractical.com/test#anchor
+--
+Best regards. BestPractical Team.
+END
+);
+
+my $html = MIME::Entity->build(
+ Type => 'text/html',
+ Subject => 'html mime',
+ Data => <<END,
+If you have some problems with RT you could find help
+on <a href="http://wiki.bestpractical.com">wiki</a>
+or find known bugs on http://rt3.fsck.com
+
+to test anchor:
+https://wiki.bestpractical.com/test#anchor
+--
+Best regards. BestPractical Team.
+END
+);
+
+
+my $ticket = RT::Ticket->new( RT->SystemUser );
+
+my ($plain_id) = $ticket->Create(
+ Subject => 'test',
+ Queue => 'General',
+ MIMEObj => $plain,
+);
+ok($plain_id, "We created a ticket #$plain_id");
+
+my ($html_id) = $ticket->Create(
+ Subject => 'test',
+ Queue => 'General',
+ MIMEObj => $html,
+);
+ok($html_id, "We created a ticket #$html_id");
+
+diag 'test no clicky';
+{
+ RT->Config->Set( 'Active_MakeClicky' => () );
+ my ( $baseurl, $m ) = RT::Test->started_ok;
+ ok $m->login, 'logged in';
+ $m->goto_ticket($plain_id);
+
+ my @links = $m->find_link(
+ tag => 'a',
+ url => 'http://wiki.bestpractical.com',
+ );
+ ok( @links == 0, 'no clicky link found with plain message' );
+
+ @links = $m->find_link(
+ tag => 'a',
+ url => 'http://rt3.fsck.com',
+ );
+ ok( @links == 0, 'no extra clicky link found with html message' );
+}
+
+diag 'test httpurl';
+{
+ RT::Test->stop_server;
+ RT->Config->Set( 'Active_MakeClicky' => qw/httpurl/ );
+ my ( $baseurl, $m ) = RT::Test->started_ok;
+ ok $m->login, 'logged in';
+ $m->goto_ticket($plain_id);
+
+ my @links = $m->find_link(
+ tag => 'a',
+ url => 'http://wiki.bestpractical.com',
+ text => 'Open URL',
+ );
+ ok( scalar @links, 'found clicky link' );
+
+ @links = $m->find_link(
+ tag => 'a',
+ url => 'https://wiki.bestpractical.com/test#anchor',
+ text => 'Open URL',
+ );
+ ok( scalar @links, 'found clicky link with anchor' );
+
+ $m->goto_ticket($html_id);
+ @links = $m->find_link(
+ tag => 'a',
+ url => 'http://wiki.bestpractical.com',
+ text => 'Open URL',
+ );
+ ok( @links == 0, 'not make clicky links clicky twice' );
+
+ @links = $m->find_link(
+ tag => 'a',
+ url => 'http://rt3.fsck.com',
+ text => 'Open URL',
+ );
+ ok( scalar @links, 'found clicky link' );
+
+ @links = $m->find_link(
+ tag => 'a',
+ url => 'https://wiki.bestpractical.com/test#anchor',
+ text => 'Open URL',
+ );
+ ok( scalar @links, 'found clicky link with anchor' );
+}
+
+diag 'test httpurl_overwrite';
+{
+ RT::Test->stop_server;
+ RT->Config->Set( 'Active_MakeClicky' => 'httpurl_overwrite' );
+ my ( $baseurl, $m ) = RT::Test->started_ok;
+ ok $m->login, 'logged in';
+ ok $m->goto_ticket($plain_id), 'opened diplay page of the ticket';
+
+ my @links = $m->find_link(
+ tag => 'a',
+ url => 'http://wiki.bestpractical.com',
+ text => 'http://wiki.bestpractical.com',
+ );
+ ok( scalar @links, 'found clicky link' );
+
+ @links = $m->find_link(
+ tag => 'a',
+ url => 'https://wiki.bestpractical.com/test#anchor',
+ text => 'https://wiki.bestpractical.com/test#anchor',
+ );
+ ok( scalar @links, 'found clicky link with anchor' );
+}
+
diff --git a/rt/t/ticket/googleish_search.t b/rt/t/ticket/googleish_search.t
new file mode 100644
index 000000000..aa33257f1
--- /dev/null
+++ b/rt/t/ticket/googleish_search.t
@@ -0,0 +1,43 @@
+
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+
+use RT::Test tests => 12;
+use_ok('RT');
+
+
+my $q = RT::Queue->new(RT->SystemUser);
+my $queue = 'SearchTests-'.$$;
+$q->Create(Name => $queue);
+ok ($q->id, "Created the queue");
+
+my $t1 = RT::Ticket->new(RT->SystemUser);
+my ( $id, undef, $msg ) = $t1->Create(
+ Queue => $q->id,
+ Subject => 'SearchTest1',
+ Requestor => ['search2@example.com'],
+);
+ok( $id, $msg );
+
+use_ok("RT::Search::Googleish");
+
+my $active_statuses = join( " OR ", map "Status = '$_'", RT::Queue->ActiveStatusArray());
+
+my $tickets = RT::Tickets->new(RT->SystemUser);
+my $quick = RT::Search::Googleish->new(Argument => "",
+ TicketsObj => $tickets);
+my @tests = (
+ "General new open root" => "( Owner = 'root' ) AND ( Queue = 'General' ) AND ( Status = 'new' OR Status = 'open' )",
+ "General" => "( Queue = 'General' ) AND ( $active_statuses )",
+ "General any" => "( Queue = 'General' )",
+ "fulltext:jesse" => "( Content LIKE 'jesse' ) AND ( $active_statuses )",
+ $queue => "( Queue = '$queue' ) AND ( $active_statuses )",
+ "root $queue" => "( Owner = 'root' ) AND ( Queue = '$queue' ) AND ( $active_statuses )",
+ "notauser $queue" => "( Queue = '$queue' ) AND ( $active_statuses ) AND ( Subject LIKE 'notauser' )",
+ "notauser $queue root" => "( Owner = 'root' ) AND ( Queue = '$queue' ) AND ( $active_statuses ) AND ( Subject LIKE 'notauser' )");
+
+while (my ($from, $to) = splice @tests, 0, 2) {
+ is($quick->QueryToSQL($from), $to, "<$from> -> <$to>");
+}
diff --git a/rt/t/web/admin_groups.t b/rt/t/web/admin_groups.t
new file mode 100644
index 000000000..783b5ad44
--- /dev/null
+++ b/rt/t/web/admin_groups.t
@@ -0,0 +1,59 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use RT::Test tests => 26;
+
+my ( $url, $m ) = RT::Test->started_ok;
+ok( $m->login(), 'logged in' );
+
+{
+ diag "test creating a group" if $ENV{TEST_VERBOSE};
+ $m->get_ok( $url . '/Admin/Groups/Modify.html?Create=1' );
+ $m->content_contains('Create a new group', 'found title');
+ $m->submit_form_ok({
+ form_number => 3,
+ fields => { Name => 'test group' },
+ });
+ $m->content_contains('Group created', 'found results');
+ $m->content_contains('Modify the group test group', 'found title');
+}
+
+{
+ diag "test creating another group" if $ENV{TEST_VERBOSE};
+ $m->get_ok( $url . '/Admin/Groups/Modify.html?Create=1' );
+ $m->content_contains('Create a new group', 'found title');
+ $m->submit_form_ok({
+ form_number => 3,
+ fields => { Name => 'test group2' },
+ });
+ $m->content_contains('Group created', 'found results');
+ $m->content_contains('Modify the group test group2', 'found title');
+}
+
+{
+ diag "test creating an overlapping group" if $ENV{TEST_VERBOSE};
+ $m->get_ok( $url . '/Admin/Groups/Modify.html?Create=1' );
+ $m->content_contains('Create a new group', 'found title');
+ $m->submit_form_ok({
+ form_number => 3,
+ fields => { Name => 'test group' },
+ });
+ $m->content_contains('Group could not be created', 'found results');
+ $m->content_like(qr/Group name .+? is already in use/, 'found message');
+}
+
+{
+ diag "test updating a group name to overlap" if $ENV{TEST_VERBOSE};
+ $m->get_ok( $url . '/Admin/Groups/' );
+ $m->follow_link_ok({text => 'test group2'}, 'found title');
+ $m->content_contains('Modify the group test group2');
+ $m->submit_form_ok({
+ form_number => 3,
+ fields => { Name => 'test group' },
+ });
+ $m->content_lacks('Name changed', "name not changed");
+ $m->content_contains('Illegal value for Name', 'found error message');
+ $m->content_contains('test group', 'did not find new name');
+}
+
diff --git a/rt/t/web/admin_user.t b/rt/t/web/admin_user.t
new file mode 100644
index 000000000..fde075f4d
--- /dev/null
+++ b/rt/t/web/admin_user.t
@@ -0,0 +1,21 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 7;
+
+my ( $url, $m ) = RT::Test->started_ok;
+ok( $m->login(), 'logged in' );
+
+my $root = RT::User->new( $RT::SystemUser );
+$root->Load('root');
+ok( $root->id, 'loaded root' );
+
+
+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');
+
+# TODO more /Admin/Users tests
+
diff --git a/rt/t/web/articles-links.t b/rt/t/web/articles-links.t
new file mode 100644
index 000000000..713dc05e4
--- /dev/null
+++ b/rt/t/web/articles-links.t
@@ -0,0 +1,52 @@
+use strict;
+use warnings;
+
+use RT::Test tests => 18;
+
+RT->Config->Set( MasonLocalComponentRoot => RT::Test::get_abs_relocatable_dir('html') );
+
+my ($baseurl, $m) = RT::Test->started_ok;
+
+my $queue = RT::Queue->new(RT->SystemUser);
+$queue->Load('General');
+
+my $class = RT::Class->new(RT->SystemUser);
+my ($ok, $msg) = $class->Create(Name => "issues");
+ok($ok, "created class: $msg");
+
+($ok, $msg) = $class->AddToObject($queue);
+ok($ok, "applied class to General: $msg");
+
+my $article = RT::Article->new(RT->SystemUser);
+($ok, $msg) = $article->Create(Name => "instance of ticket #17421", Class => $class->id);
+ok($ok, "created article: $msg");
+
+ok($m->login, "logged in");
+
+my $ticket = RT::Test->create_ticket(Queue => $queue->Id, Subject => 'oh wow! an AUTOLOAD bug');
+
+$m->goto_ticket($ticket->id);
+$m->follow_link_ok({text => 'Reply'});
+
+$m->form_name('TicketUpdate');
+$m->field('Articles-Include-Article-Named' => $article->Name);
+$m->submit;
+
+$m->content_contains('instance of ticket #17421', 'got the name of the article in the ticket');
+
+# delete RT::Article's Name method on the server so we'll need to AUTOLOAD it
+my $clone = $m->clone;
+$clone->get_ok('/delete-article-name-method.html');
+like($clone->content, qr/{deleted}/);
+
+$m->form_name('TicketUpdate');
+$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');
+
+my $refers_to = $ticket->RefersTo;
+is($refers_to->Count, 1, 'the ticket has a refers-to link');
+is($refers_to->First->TargetURI->URI, 'fsck.com-article://example.com/article/' . $article->Id, 'when we included the article it created a refers-to');
+
diff --git a/rt/t/web/attachment-with-name-0.t b/rt/t/web/attachment-with-name-0.t
new file mode 100644
index 000000000..12a8dd548
--- /dev/null
+++ b/rt/t/web/attachment-with-name-0.t
@@ -0,0 +1,23 @@
+use strict;
+use warnings;
+
+use RT::Test tests => 8;
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in as root';
+
+use File::Spec;
+
+my $file = File::Spec->catfile( RT::Test->temp_directory, 0 );
+open my $fh, '>', $file or die $!;
+print $fh 'foobar';
+close $fh;
+
+$m->get_ok( '/Ticket/Create.html?Queue=1' );
+
+$m->submit_form(
+ form_number => 3,
+ fields => { Subject => 'test att 0', Content => 'test', Attach => $file },
+);
+$m->content_like( qr/Ticket \d+ created/i, 'created the ticket' );
+$m->follow_link_ok( { text => 'Download 0' } );
+$m->content_contains( 'foobar', 'file content' );
diff --git a/rt/t/web/attachment_encoding.t b/rt/t/web/attachment_encoding.t
index 9ba567746..bfbf24590 100644
--- a/rt/t/web/attachment_encoding.t
+++ b/rt/t/web/attachment_encoding.t
@@ -3,13 +3,11 @@
use strict;
use warnings;
-use RT::Test tests => 28;
+use RT::Test tests => 32;
use Encode;
my ( $baseurl, $m ) = RT::Test->started_ok;
ok $m->login, 'logged in as root';
-$RT::Test::SKIP_REQUEST_WORK_AROUND = 1;
-
use utf8;
use File::Spec;
@@ -19,7 +17,7 @@ diag 'test without attachments' if $ENV{TEST_VERBOSE};
{
$m->get_ok( $baseurl . '/Ticket/Create.html?Queue=1' );
- $m->form_number(3);
+ $m->form_name('TicketModify');
$m->submit_form(
form_number => 3,
fields => { Subject => '标题', Content => '测试' },
@@ -47,7 +45,7 @@ diag 'test with attachemnts' if $ENV{TEST_VERBOSE};
{
my $file =
- File::Spec->catfile( File::Spec->tmpdir, 'rt_attachemnt_abcde.txt' );
+ File::Spec->catfile( RT::Test->temp_directory, encode_utf8 '附件.txt' );
open( my $fh, '>', $file ) or die $!;
binmode $fh, ':utf8';
print $fh '附件';
@@ -55,12 +53,14 @@ diag 'test with attachemnts' if $ENV{TEST_VERBOSE};
$m->get_ok( $baseurl . '/Ticket/Create.html?Queue=1' );
- $m->form_number(3);
+ $m->form_name('TicketModify');
$m->submit_form(
form_number => 3,
fields => { Subject => '标题', Content => '测试', Attach => $file },
);
$m->content_like( qr/Ticket \d+ created/i, 'created the ticket' );
+ $m->content_contains( '附件.txt', 'attached filename' );
+ $m->content_lacks( encode_utf8 '附件.txt', 'no double encoded attached filename' );
$m->follow_link_ok( { text => 'with headers' },
'-> /Ticket/Attachment/WithHeaders/...' );
@@ -82,7 +82,7 @@ diag 'test with attachemnts' if $ENV{TEST_VERBOSE};
$m->back;
$m->back;
- $m->follow_link_ok( { text_regex => qr/by Enoch Root/ },
+ $m->follow_link_ok( { text => 'Download 附件.txt' },
'-> /Ticket/Attachment/...' );
$m->content_contains( '附件', 'has content 附件' );
@@ -100,4 +100,3 @@ diag 'test with attachemnts' if $ENV{TEST_VERBOSE};
unlink $file;
}
-
diff --git a/rt/t/web/attachments.t b/rt/t/web/attachments.t
index e827b2f02..8c75f6caf 100644
--- a/rt/t/web/attachments.t
+++ b/rt/t/web/attachments.t
@@ -1,15 +1,15 @@
#!/usr/bin/perl -w
use strict;
-use RT::Test tests => 14;
+use RT::Test tests => 25;
-use constant LogoFile => $RT::MasonComponentRoot .'/NoAuth/images/bplogo.gif';
+use constant LogoFile => $RT::MasonComponentRoot .'/NoAuth/images/bpslogo.png';
use constant FaviconFile => $RT::MasonComponentRoot .'/NoAuth/images/favicon.png';
my ($baseurl, $m) = RT::Test->started_ok;
ok $m->login, 'logged in';
-my $queue = RT::Queue->new($RT::Nobody);
+my $queue = RT::Queue->new(RT->Nobody);
my $qid = $queue->Load('General');
ok( $qid, "Loaded General queue" );
@@ -17,7 +17,7 @@ $m->form_name('CreateTicketInQueue');
$m->field('Queue', $qid);
$m->submit;
is($m->status, 200, "request successful");
-$m->content_like(qr/Create a new ticket/, 'ticket create page');
+$m->content_contains("Create a new ticket", 'ticket create page');
$m->form_name('TicketCreate');
$m->field('Subject', 'Attachments test');
@@ -26,9 +26,9 @@ $m->field('Content', 'Some content');
$m->submit;
is($m->status, 200, "request successful");
-$m->content_like(qr/Attachments test/, 'we have subject on the page');
-$m->content_like(qr/Some content/, 'and content');
-$m->content_like(qr/Download bplogo\.gif/, 'page has file name');
+$m->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->follow_link_ok({text => 'Reply'}, "reply to the ticket");
$m->form_name('TicketUpdate');
@@ -42,6 +42,34 @@ $m->field('UpdateContent', 'Message');
$m->click('SubmitTicket');
is($m->status, 200, "request successful");
-$m->content_like(qr/Download bplogo\.gif/, 'page has file name');
-$m->content_like(qr/Download favicon\.png/, 'page has file name');
+$m->content_contains('Download bpslogo.png', 'page has file name');
+$m->content_contains('Download favicon.png', 'page has file name');
+
+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');
diff --git a/rt/t/web/basic.t b/rt/t/web/basic.t
index 3f94e732f..31e28c406 100644
--- a/rt/t/web/basic.t
+++ b/rt/t/web/basic.t
@@ -4,37 +4,35 @@ use strict;
use warnings;
use Encode;
-use RT::Test tests => 21;
-$RT::Test::SKIP_REQUEST_WORK_AROUND = 1;
+use RT::Test tests => 23;
my ($baseurl, $agent) = RT::Test->started_ok;
my $url = $agent->rt_base_url;
-diag $url if $ENV{TEST_VERBOSE};
# get the top page
{
$agent->get($url);
- is ($agent->{'status'}, 200, "Loaded a page");
+ is ($agent->status, 200, "Loaded a page");
}
# test a login
{
$agent->login('root' => 'password');
# the field isn't named, so we have to click link 0
- is( $agent->{'status'}, 200, "Fetched the page ok");
- ok( $agent->{'content'} =~ /Logout/i, "Found a logout link");
+ is( $agent->status, 200, "Fetched the page ok");
+ $agent->content_contains("Logout", "Found a logout link");
}
{
- $agent->get($url."Ticket/Create.html?Queue=1");
- is ($agent->{'status'}, 200, "Loaded Create.html");
- $agent->form_number(3);
+ $agent->goto_create_ticket(1);
+ is ($agent->status, 200, "Loaded Create.html");
+ $agent->form_name('TicketCreate');
my $string = Encode::decode_utf8("I18N Web Testing æøå");
$agent->field('Subject' => "Ticket with utf8 body");
$agent->field('Content' => $string);
ok($agent->submit, "Created new ticket with $string as Content");
- $agent->content_like( qr{$string} , "Found the content");
+ $agent->content_contains($string, "Found the content");
ok($agent->{redirected_uri}, "Did redirection");
{
@@ -48,15 +46,15 @@ diag $url if $ENV{TEST_VERBOSE};
}
{
- $agent->get($url."Ticket/Create.html?Queue=1");
- is ($agent->{'status'}, 200, "Loaded Create.html");
- $agent->form_number(3);
+ $agent->goto_create_ticket(1);
+ is ($agent->status, 200, "Loaded Create.html");
+ $agent->form_name('TicketCreate');
my $string = Encode::decode_utf8("I18N Web Testing æøå");
$agent->field('Subject' => $string);
$agent->field('Content' => "Ticket with utf8 subject");
ok($agent->submit, "Created new ticket with $string as Content");
- $agent->content_like( qr{$string} , "Found the content");
+ $agent->content_contains($string, "Found the content");
ok($agent->{redirected_uri}, "Did redirection");
{
@@ -71,14 +69,13 @@ diag $url if $ENV{TEST_VERBOSE};
# Update time worked in hours
{
$agent->follow_link( text_regex => qr/Basics/ );
- $agent->submit_form( form_number => 3,
+ $agent->submit_form( form_name => 'TicketModify',
fields => { TimeWorked => 5, 'TimeWorked-TimeUnits' => "hours" }
);
- like ($agent->{'content'}, qr/to &#39;300&#39;/, "5 hours is 300 minutes");
+ $agent->content_contains("to &#39;300&#39;", "5 hours is 300 minutes");
}
-# {{{ test an image
TODO: {
todo_skip("Need to handle mason trying to compile images",1);
@@ -94,9 +91,7 @@ is(
"got a file of the correct size ($file)",
);
}
-# }}}
-# {{{ Query Builder tests
#
# XXX: hey-ho, we have these tests in t/web/query-builder
# TODO: move everything about QB there
@@ -135,5 +130,3 @@ $query =~ s/\s+/ /g;
is ($query, "Subject LIKE 'aaa' AND Subject LIKE 'bbb'");
-
-1;
diff --git a/rt/t/web/case-sensitivity.t b/rt/t/web/case-sensitivity.t
new file mode 100644
index 000000000..276b7615a
--- /dev/null
+++ b/rt/t/web/case-sensitivity.t
@@ -0,0 +1,85 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 18;
+
+my $q = RT::Test->load_or_create_queue( Name => 'General' );
+ok $q && $q->id, 'loaded or created queue';
+
+my ($root, $root_id);
+{
+ $root = RT::User->new( RT->SystemUser );
+ $root->Load('root');
+ ok $root_id = $root->id, 'found root';
+}
+
+my ($baseurl, $m) = RT::Test->started_ok;
+$m->login;
+
+# test users auto completer
+{
+ $m->get_ok('/Helpers/Autocomplete/Users?term=eNo');
+ require JSON;
+ is_deeply(
+ JSON::from_json( $m->content ),
+ [{"value" => "root\@localhost","label" => "Enoch Root"}]
+ );
+}
+
+# test ticket's People page
+{
+ my $ticket = RT::Test->create_ticket( Queue => $q->id );
+ ok $ticket && $ticket->id, "created ticket";
+
+ $m->goto_ticket( $ticket->id );
+ $m->follow_link_ok( {text => 'People'} );
+ $m->form_number(3);
+ $m->select( UserField => 'RealName' );
+ $m->field( UserString => 'eNo' );
+ $m->click('OnlySearchForPeople');
+
+ my $form = $m->form_number(3);
+ my $input = $form->find_input('Ticket-AddWatcher-Principal-'. $root->id );
+ ok $input, 'input is there';
+}
+
+# test users' admin UI
+{
+ $m->get_ok('/Admin/Users/');
+
+ $m->form_number(4);
+ $m->select( UserField => 'RealName' );
+ $m->field( UserString => 'eNo' );
+ $m->submit;
+
+ like $m->uri, qr{\QAdmin/Users/Modify.html?id=$root_id\E};
+}
+
+# create a cf for testing
+my $cf;
+{
+ $cf = RT::CustomField->new(RT->SystemUser);
+ my ($id,$msg) = $cf->Create(
+ Name => 'Test',
+ Type => 'Select',
+ MaxValues => '1',
+ Queue => $q->id,
+ );
+ ok($id,$msg);
+
+ ($id,$msg) = $cf->AddValue(Name => 'Enoch', Description => 'Root');
+ ok($id,$msg);
+}
+
+# test custom field values auto completer
+{
+ $m->get_ok('/Helpers/Autocomplete/CustomFieldValues?term=eNo&Object---CustomField-'. $cf->id .'-Value');
+ require JSON;
+ is_deeply(
+ JSON::from_json( $m->content ),
+ [{"value" => "Enoch","label" => "Enoch (Root)"}]
+ );
+}
+
diff --git a/rt/t/web/cf_access.t b/rt/t/web/cf_access.t
index 183597b4a..73b7765c1 100644
--- a/rt/t/web/cf_access.t
+++ b/rt/t/web/cf_access.t
@@ -1,23 +1,54 @@
#!/usr/bin/perl -w
use strict;
-use RT::Test tests => 26;
-$RT::Test::SKIP_REQUEST_WORK_AROUND = 1;
+use RT::Test tests => 32;
my ($baseurl, $m) = RT::Test->started_ok;
-use constant ImageFile => $RT::MasonComponentRoot .'/NoAuth/images/bplogo.gif';
+use constant ImageFile => $RT::MasonComponentRoot .'/NoAuth/images/bpslogo.png';
use constant ImageFileContent => RT::Test->file_content(ImageFile);
ok $m->login, 'logged in';
-diag "Create a CF" if $ENV{'TEST_VERBOSE'};
+diag "Create a CF";
{
- $m->follow_link( text => 'Configuration' );
- $m->title_is(q/RT Administration/, 'admin screen');
- $m->follow_link( text => 'Custom Fields' );
- $m->title_is(q/Select a Custom Field/, 'admin-cf screen');
- $m->follow_link( text => 'Create' );
+ $m->follow_link( id => 'tools-config-custom-fields-create');
+
+ # Test form validation
+ $m->submit_form(
+ form_name => "ModifyCustomField",
+ fields => {
+ TypeComposite => 'Image-0',
+ LookupType => 'RT::Queue-RT::Ticket',
+ Name => '',
+ Description => 'img',
+ },
+ );
+ $m->text_contains('Invalid value for Name');
+
+ $m->submit_form(
+ form_name => "ModifyCustomField",
+ fields => {
+ TypeComposite => 'Image-0',
+ LookupType => 'RT::Queue-RT::Ticket',
+ Name => '0',
+ Description => 'img',
+ },
+ );
+ $m->text_contains('Invalid value for Name');
+
+ $m->submit_form(
+ form_name => "ModifyCustomField",
+ fields => {
+ TypeComposite => 'Image-0',
+ LookupType => 'RT::Queue-RT::Ticket',
+ Name => '1',
+ Description => 'img',
+ },
+ );
+ $m->text_contains('Invalid value for Name');
+
+ # The real submission
$m->submit_form(
form_name => "ModifyCustomField",
fields => {
@@ -27,19 +58,47 @@ diag "Create a CF" if $ENV{'TEST_VERBOSE'};
Description => 'img',
},
);
+ $m->text_contains('Object created');
+
+ # Validation on update
+ $m->form_name("ModifyCustomField");
+ $m->set_fields(
+ TypeComposite => 'Image-0',
+ LookupType => 'RT::Queue-RT::Ticket',
+ Name => '',
+ Description => 'img',
+ );
+ $m->click('Update');
+ $m->text_contains('Illegal value for Name');
+ $m->form_name("ModifyCustomField");
+ $m->set_fields(
+ TypeComposite => 'Image-0',
+ LookupType => 'RT::Queue-RT::Ticket',
+ Name => '0',
+ Description => 'img',
+ );
+ $m->click('Update');
+ $m->text_contains('Illegal value for Name');
+ $m->form_name("ModifyCustomField");
+ $m->set_fields(
+ TypeComposite => 'Image-0',
+ LookupType => 'RT::Queue-RT::Ticket',
+ Name => '1',
+ Description => 'img',
+ );
+ $m->click('Update');
+ $m->text_contains('Illegal value for Name');
}
-diag "apply the CF to General queue" if $ENV{'TEST_VERBOSE'};
+diag "apply the CF to General queue";
my ( $cf, $cfid, $tid );
{
- $m->title_is(q/Created CustomField img/, 'admin-cf created');
- $m->follow_link( text => 'Queues' );
- $m->title_is(q/Admin queues/, 'admin-queues screen');
+ $m->title_is(q/Editing CustomField img/, 'admin-cf created');
+ $m->follow_link( id => 'tools-config-queues');
$m->follow_link( text => 'General' );
- $m->title_is(q/Editing Configuration for queue General/, 'admin-queue: general');
- $m->follow_link( text => 'Ticket Custom Fields' );
-
- $m->title_is(q/Edit Custom Fields for General/, 'admin-queue: general cfid');
+ $m->title_is(q/Configuration for queue General/, 'admin-queue: general');
+ $m->follow_link( id => 'page-ticket-custom-fields');
+ $m->title_is(q/Custom Fields for queue General/, 'admin-queue: general cfid');
$m->form_name('EditCustomFields');
# Sort by numeric IDs in names
@@ -52,7 +111,7 @@ my ( $cf, $cfid, $tid );
$m->tick( AddCustomField => $_ => 0 ) for @names; # ...and not any other. ;-)
$m->click('UpdateCFs');
- $m->content_like( qr/Object created/, 'TCF added to the queue' );
+ $m->content_contains('Object created', 'TCF added to the queue' );
}
my $tester = RT::Test->load_or_create_user( Name => 'tester', Password => '123456' );
@@ -61,17 +120,16 @@ RT::Test->set_rights(
Right => [qw(SeeQueue ShowTicket CreateTicket)],
},
);
-ok $m->login( $tester->Name, 123456), 'logged in';
+ok $m->login( $tester->Name, 123456, logout => 1), 'logged in';
diag "check that we have no the CF on the create"
- ." ticket page when user has no SeeCustomField right"
- if $ENV{'TEST_VERBOSE'};
+ ." ticket page when user has no SeeCustomField right";
{
$m->submit_form(
form_name => "CreateTicketInQueue",
fields => { Queue => 'General' },
);
- $m->content_unlike(qr/Upload multiple images/, 'has no upload image field');
+ $m->content_lacks('Upload multiple images', 'has no upload image field');
my $form = $m->form_name("TicketCreate");
my $upload_field = "Object-RT::Ticket--CustomField-$cfid-Upload";
@@ -83,9 +141,9 @@ diag "check that we have no the CF on the create"
);
$m->content_like(qr/Ticket \d+ created/, "a ticket is created succesfully");
- $m->content_unlike(qr/img:/, 'has no img field on the page');
+ $m->content_lacks('img:', 'has no img field on the page');
$m->follow_link( text => 'Custom Fields');
- $m->content_unlike(qr/Upload multiple images/, 'has no upload image field');
+ $m->content_lacks('Upload multiple images', 'has no upload image field');
}
RT::Test->set_rights(
@@ -95,14 +153,13 @@ RT::Test->set_rights(
);
diag "check that we have no the CF on the create"
- ." ticket page when user has no ModifyCustomField right"
- if $ENV{'TEST_VERBOSE'};
+ ." ticket page when user has no ModifyCustomField right";
{
$m->submit_form(
form_name => "CreateTicketInQueue",
fields => { Queue => 'General' },
);
- $m->content_unlike(qr/Upload multiple images/, 'has no upload image field');
+ $m->content_lacks('Upload multiple images', 'has no upload image field');
my $form = $m->form_name("TicketCreate");
my $upload_field = "Object-RT::Ticket--CustomField-$cfid-Upload";
@@ -115,9 +172,9 @@ diag "check that we have no the CF on the create"
$tid = $1 if $m->content =~ /Ticket (\d+) created/i;
ok $tid, "a ticket is created succesfully";
- $m->follow_link( text => 'Custom Fields' );
- $m->content_unlike(qr/Upload multiple images/, 'has no upload image field');
- $form = $m->form_number(3);
+ $m->follow_link( id => 'page-basics');
+ $m->content_lacks('Upload multiple images', 'has no upload image field');
+ $form = $m->form_name('TicketModify');
$upload_field = "Object-RT::Ticket-$tid-CustomField-$cfid-Upload";
ok !$form->find_input( $upload_field ), 'no form field on the page';
}
@@ -128,13 +185,13 @@ RT::Test->set_rights(
},
);
-diag "create a ticket with an image" if $ENV{'TEST_VERBOSE'};
+diag "create a ticket with an image";
{
$m->submit_form(
form_name => "CreateTicketInQueue",
fields => { Queue => 'General' },
);
- $m->content_like(qr/Upload multiple images/, 'has a upload image field');
+ $m->content_contains('Upload multiple images', 'has a upload image field');
$cf =~ /(\d+)$/ or die "Hey this is impossible dude";
my $upload_field = "Object-RT::Ticket--CustomField-$1-Upload";
@@ -153,14 +210,12 @@ diag "create a ticket with an image" if $ENV{'TEST_VERBOSE'};
$m->title_like(qr/testing img cf creation/, "its title is the Subject");
- $m->follow_link( text => 'bplogo.gif' );
+ $m->follow_link( text => 'bpslogo.png' );
$m->content_is(ImageFileContent, "it links to the uploaded image");
}
$m->get( $m->rt_base_url );
-$m->follow_link( text => 'Tickets' );
-$m->follow_link( text => 'New Query' );
-
+$m->follow_link( id => 'search-new');
$m->title_is(q/Query Builder/, 'Query building');
$m->submit_form(
form_name => "BuildQuery",
@@ -182,7 +237,7 @@ $m->click('AddCol');
$m->form_name('BuildQuery');
$m->click('DoSearch');
-$m->follow_link( text_regex => qr/bplogo\.gif/ );
+$m->follow_link( text_regex => qr/bpslogo\.png/ );
$m->content_is(ImageFileContent, "it links to the uploaded image");
__END__
diff --git a/rt/t/web/cf_date.t b/rt/t/web/cf_date.t
new file mode 100644
index 000000000..887aa4220
--- /dev/null
+++ b/rt/t/web/cf_date.t
@@ -0,0 +1,187 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 35;
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in as root';
+my $root = RT::User->new(RT->SystemUser);
+ok( $root->Load('root'), 'load root user' );
+
+my $cf_name = 'test cf date';
+
+my $cfid;
+diag "Create a CF";
+{
+ $m->follow_link( id => 'tools-config-custom-fields-create');
+ $m->submit_form(
+ form_name => "ModifyCustomField",
+ fields => {
+ Name => $cf_name,
+ TypeComposite => 'Date-1',
+ LookupType => 'RT::Queue-RT::Ticket',
+ },
+ );
+ $m->content_contains('Object created', 'created CF sucessfully' );
+ $cfid = $m->form_name('ModifyCustomField')->value('id');
+ ok $cfid, "found id of the CF in the form, it's #$cfid";
+}
+
+diag "apply the CF to General queue";
+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->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->title_is( q/Custom Fields for queue General/,
+ 'admin-queue: general cfid' );
+
+ $m->form_name('EditCustomFields');
+ $m->tick( "AddCustomField" => $cfid );
+ $m->click('UpdateCFs');
+
+ $m->content_contains('Object created', 'TCF added to the queue' );
+}
+
+diag 'check valid inputs with various timezones in ticket create page';
+{
+ my ( $ticket, $id );
+
+ $m->submit_form(
+ form_name => "CreateTicketInQueue",
+ fields => { Queue => 'General' },
+ );
+ $m->content_contains('Select date', 'has cf field' );
+
+ $m->submit_form(
+ form_name => "TicketCreate",
+ fields => {
+ Subject => 'test 2010-05-04',
+ Content => 'test',
+ "Object-RT::Ticket--CustomField-$cfid-Values" => '2010-05-04',
+ },
+ );
+ ok( ($id) = $m->content =~ /Ticket (\d+) created/, "created ticket $id" );
+
+ $ticket = RT::Ticket->new(RT->SystemUser);
+ $ticket->Load($id);
+ is( $ticket->CustomFieldValues($cfid)->First->Content,
+ '2010-05-04', 'date in db' );
+
+ $m->content_contains('test cf date:', 'has no cf date field on the page' );
+ $m->content_contains('Tue May 04 2010',
+ 'has cf date value on the page' );
+}
+
+diag 'check search build page';
+{
+ $m->get_ok( $baseurl . '/Search/Build.html?Query=Queue=1' );
+
+ $m->form_name('BuildQuery');
+ my ($cf_op) =
+ $m->find_all_inputs( type => 'option', name_regex => qr/test cf date/ );
+ is_deeply(
+ [ $cf_op->possible_values ],
+ [ '<', '=', '>' ],
+ 'right oprators'
+ );
+
+ my ($cf_field) =
+ $m->find_all_inputs( type => 'text', name_regex => qr/test cf date/ );
+ $m->submit_form(
+ fields => {
+ $cf_op->name => '=',
+ $cf_field->name => '2010-05-04'
+ },
+ button => 'DoSearch',
+ );
+
+ $m->content_contains( 'Found 1 ticket', 'Found 1 ticket' );
+ $m->content_contains( '2010-05-04', 'got the right ticket' );
+ $m->content_lacks( '2010-05-06', 'did not get the wrong ticket' );
+
+ $m->get_ok( $baseurl . '/Search/Build.html?Query=Queue=1' );
+ $m->form_name('BuildQuery');
+ $m->submit_form(
+ fields => {
+ $cf_op->name => '<',
+ $cf_field->name => '2010-05-05'
+ },
+ button => 'DoSearch',
+ );
+ $m->content_contains( 'Found 1 ticket', 'Found 1 ticket' );
+
+ $m->get_ok( $baseurl . '/Search/Build.html?Query=Queue=1' );
+ $m->form_name('BuildQuery');
+ $m->submit_form(
+ fields => {
+ $cf_op->name => '>',
+ $cf_field->name => '2010-05-03',
+ },
+ button => 'DoSearch',
+ );
+ $m->content_contains( 'Found 1 ticket', 'Found 1 ticket' );
+
+ $m->get_ok( $baseurl . '/Search/Build.html?Query=Queue=1' );
+ $m->form_name('BuildQuery');
+ $m->submit_form(
+ fields => {
+ $cf_op->name => '=',
+ $cf_field->name => '2010-05-05',
+ },
+ button => 'DoSearch',
+ );
+ $m->content_contains( 'Found 0 tickets', 'Found 0 tickets' );
+
+ $m->get_ok( $baseurl . '/Search/Build.html?Query=Queue=1' );
+ $m->form_name('BuildQuery');
+ $m->submit_form(
+ fields => {
+ $cf_op->name => '<',
+ $cf_field->name => '2010-05-03',
+ },
+ button => 'DoSearch',
+ );
+ $m->content_contains( 'Found 0 tickets', 'Found 0 tickets' );
+
+ $m->get_ok( $baseurl . '/Search/Build.html?Query=Queue=1' );
+ $m->form_name('BuildQuery');
+ $m->submit_form(
+ fields => {
+ $cf_op->name => '>',
+ $cf_field->name => '2010-05-05',
+ },
+ button => 'DoSearch',
+ );
+ $m->content_contains( 'Found 0 tickets', 'Found 0 tickets' );
+}
+
+diag 'check invalid inputs';
+{
+ $m->submit_form(
+ form_name => "CreateTicketInQueue",
+ fields => { Queue => 'General' },
+ );
+ my $form = $m->form_name("TicketCreate");
+
+ $m->submit_form(
+ form_name => "TicketCreate",
+ fields => {
+ Subject => 'test',
+ Content => 'test',
+ "Object-RT::Ticket--CustomField-$cfid-Values" => 'foodate',
+ },
+ );
+ $m->content_like( qr/Ticket \d+ created/,
+ "a ticket is created succesfully" );
+
+ $m->content_contains('test cf date:', 'has no cf date field on the page' );
+ $m->content_lacks('foodate', 'invalid dates not set' );
+}
diff --git a/rt/t/web/cf_datetime.t b/rt/t/web/cf_datetime.t
new file mode 100644
index 000000000..9781c5e2e
--- /dev/null
+++ b/rt/t/web/cf_datetime.t
@@ -0,0 +1,235 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 51;
+
+RT->Config->Set( 'Timezone' => 'EST5EDT' ); # -04:00
+my ($baseurl, $m) = RT::Test->started_ok;
+ok $m->login, 'logged in as root';
+my $root = RT::User->new( RT->SystemUser );
+ok( $root->Load('root'), 'load root user' );
+
+my $cf_name = 'test cf datetime';
+
+my $why;
+
+if ( ( $ENV{RT_TEST_WEB_HANDLER} || '' ) =~ /^apache(\+mod_perl)?$/
+ && RT::Test::Apache->apache_mpm_type =~ /^(?:worker|event)$/ )
+{
+ $why =
+'localizing $ENV{TZ} does *not* work with mod_perl+mpm_event or mod_perl+mpm_worker';
+}
+
+my $cfid;
+diag "Create a CF";
+{
+ $m->follow_link( id => 'tools-config-custom-fields-create');
+ $m->submit_form(
+ form_name => "ModifyCustomField",
+ fields => {
+ Name => $cf_name,
+ TypeComposite => 'DateTime-1',
+ LookupType => 'RT::Queue-RT::Ticket',
+ },
+ );
+ $m->content_contains('Object created', 'created CF sucessfully' );
+ $cfid = $m->form_name('ModifyCustomField')->value('id');
+ ok $cfid, "found id of the CF in the form, it's #$cfid";
+}
+
+diag "apply the CF to General queue";
+my $queue = RT::Test->load_or_create_queue( Name => 'General' );
+ok $queue && $queue->id, 'loaded or created queue';
+
+{
+ $m->follow_link( text => 'Queues' );
+ $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->title_is(q/Custom Fields for queue General/, 'admin-queue: general cfid');
+
+ $m->form_name('EditCustomFields');
+ $m->tick( "AddCustomField" => $cfid );
+ $m->click('UpdateCFs');
+
+ $m->content_contains('Object created', 'TCF added to the queue' );
+}
+
+diag 'check valid inputs with various timezones in ticket create page';
+{
+ my ( $ticket, $id );
+
+ $m->submit_form(
+ form_name => "CreateTicketInQueue",
+ fields => { Queue => 'General' },
+ );
+ $m->content_contains('Select datetime', 'has cf field');
+
+ $m->submit_form(
+ form_name => "TicketCreate",
+ fields => {
+ Subject => 'test 2010-05-04 13:00:01',
+ Content => 'test',
+ "Object-RT::Ticket--CustomField-$cfid-Values" => '2010-05-04 13:00:01',
+ },
+ );
+ ok( ($id) = $m->content =~ /Ticket (\d+) created/,
+ "created ticket $id" );
+
+ $ticket = RT::Ticket->new( RT->SystemUser );
+ $ticket->Load($id);
+ TODO: {
+ local $TODO = $why;
+ is(
+ $ticket->CustomFieldValues($cfid)->First->Content,
+ '2010-05-04 17:00:01',
+ 'date in db is in UTC'
+ );
+ }
+
+ $m->content_contains('test cf datetime:', 'has cf datetime field on the page');
+ $m->content_contains('Tue May 04 13:00:01 2010', 'has cf datetime value on the page');
+
+ $root->SetTimezone( 'Asia/Shanghai' );
+ # interesting that $m->reload doesn't work
+ $m->get_ok( $m->uri );
+
+ TODO: {
+ local $TODO = $why;
+ $m->content_contains( 'Wed May 05 01:00:01 2010',
+ 'cf datetime value respects user timezone' );
+ }
+
+ $m->submit_form(
+ form_name => "CreateTicketInQueue",
+ fields => { Queue => 'General' },
+ );
+ $m->submit_form(
+ form_name => "TicketCreate",
+ fields => {
+ Subject => 'test 2010-05-06 07:00:01',
+ Content => 'test',
+ "Object-RT::Ticket--CustomField-$cfid-Values" => '2010-05-06 07:00:01',
+ },
+ );
+ ok( ($id) = $m->content =~ /Ticket (\d+) created/,
+ "created ticket $id" );
+ $ticket = RT::Ticket->new( RT->SystemUser );
+ $ticket->Load($id);
+ TODO: {
+ local $TODO = $why;
+ is(
+ $ticket->CustomFieldValues($cfid)->First->Content,
+ '2010-05-05 23:00:01',
+ 'date in db is in UTC'
+ );
+ }
+
+ $m->content_contains('test cf datetime:', 'has cf datetime field on the page');
+ $m->content_contains( 'Thu May 06 07:00:01 2010',
+ 'cf datetime input respects user timezone' );
+ $root->SetTimezone( 'EST5EDT' ); # back to -04:00
+ $m->get_ok( $m->uri );
+
+ TODO: {
+ local $TODO = $why;
+ $m->content_contains( 'Wed May 05 19:00:01 2010',
+ 'cf datetime value respects user timezone' );
+ }
+}
+
+
+diag 'check search build page';
+{
+ $m->get_ok( $baseurl . '/Search/Build.html?Query=Queue=1' );
+
+ $m->form_name('BuildQuery');
+ my ($cf_op) =
+ $m->find_all_inputs( type => 'option', name_regex => qr/test cf datetime/ );
+ is_deeply(
+ [ $cf_op->possible_values ],
+ [ '<', '=', '>' ],
+ 'right oprators'
+ );
+
+ my ($cf_field) =
+ $m->find_all_inputs( type => 'text', name_regex => qr/test cf datetime/ );
+
+ is_results_number( { $cf_op->name => '=', $cf_field->name => '2010-05-04', }, 1 );
+ $m->content_contains( '2010-05-04', 'got the right ticket' );
+ $m->content_lacks( '2010-05-06', 'did not get the wrong ticket' );
+
+ my $shanghai = RT::Test->load_or_create_user(
+ Name => 'shanghai',
+ Password => 'password',
+ Timezone => 'Asia/Shanghai',
+ );
+ ok( $shanghai->PrincipalObj->GrantRight(
+ Right => 'SuperUser',
+ Object => $RT::System,
+ ));
+ $m->login( 'shanghai', 'password', logout => 1 );
+
+ is_results_number( { $cf_op->name => '<', $cf_field->name => '2010-05-07', }, 2 );
+ is_results_number( { $cf_op->name => '>', $cf_field->name => '2010-05-04', }, 2 );
+
+ TODO: {
+ local $TODO = $why;
+ is_results_number( { $cf_op->name => '=', $cf_field->name => '2010-05-05', }, 1 );
+ is_results_number( { $cf_op->name => '=', $cf_field->name => '2010-05-05 01:00:01', }, 1 );
+ }
+
+ is_results_number(
+ { $cf_op->name => '=', $cf_field->name => '2010-05-05 02:00:01', }, 0 );
+
+ is_results_number( { $cf_op->name => '=', $cf_field->name => '2010-05-06', }, 1 );
+ is_results_number( { $cf_op->name => '=', $cf_field->name => '2010-05-06 07:00:01', }, 1 );
+ is_results_number( { $cf_op->name => '=', $cf_field->name => '2010-05-06 08:00:01', }, 0 );
+}
+
+diag 'check invalid inputs';
+{
+ $m->submit_form(
+ form_name => "CreateTicketInQueue",
+ fields => { Queue => 'General' },
+ );
+ my $form = $m->form_name("TicketCreate");
+
+ $m->submit_form(
+ form_name => "TicketCreate",
+ fields => {
+ Subject => 'test',
+ Content => 'test',
+ "Object-RT::Ticket--CustomField-$cfid-Values" => 'foodate',
+ },
+ );
+ $m->content_like(qr/Ticket \d+ created/, "a ticket is created succesfully");
+
+ $m->content_contains('test cf datetime:', 'has cf datetime field on the page');
+ $m->content_lacks('foodate', 'invalid dates not set');
+}
+
+sub is_results_number {
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+ my $fields = shift;
+ my $number = shift;
+ my $operator = shift;
+ my $value = shift;
+ {
+ local $TODO;
+ $m->get_ok( $baseurl . '/Search/Build.html?Query=Queue=1' );
+ }
+ $m->form_name('BuildQuery');
+ $m->submit_form(
+ fields => $fields,
+ button => 'DoSearch',
+ );
+ $m->content_contains( "Found $number ticket", "Found $number ticket" );
+}
+
+# to make $m->DESTROY happy
+undef $m;
+
diff --git a/rt/t/web/cf_onqueue.t b/rt/t/web/cf_onqueue.t
index bed4dd188..422eeff60 100644
--- a/rt/t/web/cf_onqueue.t
+++ b/rt/t/web/cf_onqueue.t
@@ -6,13 +6,9 @@ my ($baseurl, $m) = RT::Test->started_ok;
ok $m->login, 'logged in';
-diag "Create a queue CF" if $ENV{'TEST_VERBOSE'};
+diag "Create a queue CF";
{
- $m->follow_link( text => 'Configuration' );
- $m->title_is(q/RT Administration/, 'admin screen');
- $m->follow_link( text => 'Custom Fields' );
- $m->title_is(q/Select a Custom Field/, 'admin-cf screen');
- $m->follow_link( text => 'Create' );
+ $m->follow_link( id => 'tools-config-custom-fields-create');
$m->submit_form(
form_name => "ModifyCustomField",
fields => {
@@ -22,10 +18,10 @@ diag "Create a queue CF" if $ENV{'TEST_VERBOSE'};
Description => 'QueueCFTest',
},
);
- $m->content_like( qr/Object created/, 'CF QueueCFTest created' );
+ $m->content_contains('Object created', 'CF QueueCFTest created' );
}
-diag "Apply the new CF globally" if $ENV{'TEST_VERBOSE'};
+diag "Apply the new CF globally";
{
$m->follow_link( text => 'Global' );
$m->title_is(q!Admin/Global configuration!, 'global configuration screen');
@@ -33,22 +29,22 @@ diag "Apply the new CF globally" if $ENV{'TEST_VERBOSE'};
$m->title_is(q/Global custom field configuration/, 'global custom field configuration screen');
$m->follow_link( url => 'Queues.html' );
$m->title_is(q/Edit Custom Fields for all queues/, 'global custom field for all queues configuration screen');
- $m->content_like( qr/QueueCFTest/, 'CF QueueCFTest displayed on page' );
+ $m->content_contains('QueueCFTest', 'CF QueueCFTest displayed on page' );
$m->form_name('EditCustomFields');
$m->tick( AddCustomField => 1 );
$m->click('UpdateCFs');
- $m->content_like( qr/Object created/, 'CF QueueCFTest enabled globally' );
+ $m->content_contains('Object created', 'CF QueueCFTest enabled globally' );
}
-diag "Edit the CF value for default queue" if $ENV{'TEST_VERBOSE'};
+diag "Edit the CF value for default queue";
{
$m->follow_link( url => '/Admin/Queues/' );
$m->title_is(q/Admin queues/, 'queues configuration screen');
$m->follow_link( text => "1" );
- $m->title_is(q/Editing Configuration for queue General/, 'default queue configuration screen');
- $m->content_like( qr/QueueCFTest/, 'CF QueueCFTest displayed on default queue' );
+ $m->title_is(q/Configuration for queue General/, 'default queue configuration screen');
+ $m->content_contains('QueueCFTest', 'CF QueueCFTest displayed on default queue' );
$m->submit_form(
form_number => 3,
# The following doesn't want to works :(
@@ -57,7 +53,7 @@ diag "Edit the CF value for default queue" if $ENV{'TEST_VERBOSE'};
'Object-RT::Queue-1-CustomField-1-Value' => 'QueueCFTest content',
},
);
- $m->content_like( qr/QueueCFTest QueueCFTest content added/, 'Content filed in CF QueueCFTest for default queue' );
+ $m->content_contains('QueueCFTest QueueCFTest content added', 'Content filed in CF QueueCFTest for default queue' );
}
diff --git a/rt/t/web/cf_render_type.t b/rt/t/web/cf_render_type.t
new file mode 100644
index 000000000..8d8efa897
--- /dev/null
+++ b/rt/t/web/cf_render_type.t
@@ -0,0 +1,50 @@
+use strict;
+use warnings;
+
+use RT::Test tests => 8;
+
+my ($baseurl, $m) = RT::Test->started_ok;
+ok $m->login, 'logged in as root';
+
+my $cf_name = 'test render type';
+
+my $cfid;
+diag "Create a CF";
+{
+ $m->follow_link( id => 'tools-config-custom-fields-create');
+ $m->submit_form(
+ form_name => "ModifyCustomField",
+ fields => {
+ Name => $cf_name,
+ TypeComposite => 'Freeform-1',
+ LookupType => 'RT::Queue-RT::Ticket',
+ },
+ );
+ $m->content_contains('Object created', 'created Freeform-1' );
+ $cfid = $m->form_name('ModifyCustomField')->value('id');
+ ok $cfid, "found id of the CF in the form, it's #$cfid";
+}
+
+diag "change to Select type";
+{
+ $m->submit_form(
+ form_name => "ModifyCustomField",
+ fields => { TypeComposite => 'Select-1', },
+ button => 'Update',
+ );
+ $m->content_contains(
+ "Type changed from &#39;Enter one value&#39; to &#39;Select one value&#39;",
+ 'changed to Select-1' );
+}
+
+diag "let's save it again";
+{
+ $m->submit_form(
+ form_name => "ModifyCustomField",
+ button => 'Update',
+ );
+ $m->content_lacks( "Render Type changed from &#39;1&#39; to &#39;Select box&#39;",
+ 'no buggy RenderType change msg' );
+}
+
+
diff --git a/rt/t/web/cf_select_one.t b/rt/t/web/cf_select_one.t
index 26c1fcf65..15fe416b4 100644
--- a/rt/t/web/cf_select_one.t
+++ b/rt/t/web/cf_select_one.t
@@ -3,7 +3,7 @@
use strict;
use warnings;
-use RT::Test tests => 46;
+use RT::Test tests => 45;
my ($baseurl, $m) = RT::Test->started_ok;
ok $m->login, 'logged in as root';
@@ -11,13 +11,9 @@ ok $m->login, 'logged in as root';
my $cf_name = 'test select one value';
my $cfid;
-diag "Create a CF" if $ENV{'TEST_VERBOSE'};
+diag "Create a CF";
{
- $m->follow_link( text => 'Configuration' );
- $m->title_is(q/RT Administration/, 'admin screen');
- $m->follow_link( text => 'Custom Fields' );
- $m->title_is(q/Select a Custom Field/, 'admin-cf screen');
- $m->follow_link( text => 'Create' );
+ $m->follow_link( id => 'tools-config-custom-fields-create');
$m->submit_form(
form_name => "ModifyCustomField",
fields => {
@@ -26,12 +22,12 @@ diag "Create a CF" if $ENV{'TEST_VERBOSE'};
LookupType => 'RT::Queue-RT::Ticket',
},
);
- $m->content_like( qr/Object created/, 'created CF sucessfully' );
+ $m->content_contains('Object created', 'created CF sucessfully' );
$cfid = $m->form_name('ModifyCustomField')->value('id');
ok $cfid, "found id of the CF in the form, it's #$cfid";
}
-diag "add 'qwe', 'ASD', '0' and ' foo ' as values to the CF" if $ENV{'TEST_VERBOSE'};
+diag "add 'qwe', 'ASD', '0' and ' foo ' as values to the CF";
{
foreach my $value(qw(qwe ASD 0), 'foo ') {
$m->submit_form(
@@ -41,38 +37,36 @@ diag "add 'qwe', 'ASD', '0' and ' foo ' as values to the CF" if $ENV{'TEST_VERBO
},
button => 'Update',
);
- $m->content_like( qr/Object created/, 'added a value to the CF' ); # or diag $m->content;
+ $m->content_contains('Object created', 'added a value to the CF' ); # or diag $m->content;
my $v = $value;
$v =~ s/^\s+$//;
$v =~ s/\s+$//;
- $m->content_like( qr/value="$v"/, 'the added value is right' );
+ $m->content_contains("value=\"$v\"", 'the added value is right' );
}
}
my $queue = RT::Test->load_or_create_queue( Name => 'General' );
ok $queue && $queue->id, 'loaded or created queue';
-diag "apply the CF to General queue" if $ENV{'TEST_VERBOSE'};
+diag "apply the CF to General queue";
{
- $m->follow_link( text => 'Queues' );
- $m->title_is(q/Admin queues/, 'admin-queues screen');
+ $m->follow_link( id => 'tools-config-queues');
$m->follow_link( text => 'General' );
- $m->title_is(q/Editing Configuration for queue General/, 'admin-queue: general');
- $m->follow_link( text => 'Ticket Custom Fields' );
- $m->title_is(q/Edit Custom Fields for General/, 'admin-queue: general cfid');
+ $m->title_is(q/Configuration for queue General/, 'admin-queue: general');
+ $m->follow_link( id => 'page-ticket-custom-fields');
+ $m->title_is(q/Custom Fields for queue General/, 'admin-queue: general cfid');
$m->form_name('EditCustomFields');
$m->tick( "AddCustomField" => $cfid );
$m->click('UpdateCFs');
- $m->content_like( qr/Object created/, 'TCF added to the queue' );
+ $m->content_contains('Object created', 'TCF added to the queue' );
}
my $tid;
-diag "create a ticket using API with 'asd'(not 'ASD') as value of the CF"
- if $ENV{'TEST_VERBOSE'};
+diag "create a ticket using API with 'asd'(not 'ASD') as value of the CF";
{
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ my $ticket = RT::Ticket->new( RT->SystemUser );
my ($txnid, $msg);
($tid, $txnid, $msg) = $ticket->Create(
Subject => 'test',
@@ -80,7 +74,7 @@ diag "create a ticket using API with 'asd'(not 'ASD') as value of the CF"
"CustomField-$cfid" => 'asd',
);
ok $tid, "created ticket";
- diag $msg if $msg && $ENV{'TEST_VERBOSE'};
+ diag $msg if $msg;
# we use lc as we really don't care about case
# so if later we'll add canonicalization of value
@@ -89,72 +83,69 @@ diag "create a ticket using API with 'asd'(not 'ASD') as value of the CF"
'asd', 'assigned value of the CF';
}
-diag "check that values of the CF are case insensetive(asd vs. ASD)"
- if $ENV{'TEST_VERBOSE'};
+diag "check that values of the CF are case insensetive(asd vs. ASD)";
{
ok $m->goto_ticket( $tid ), "opened ticket's page";
- $m->follow_link( text => 'Custom Fields' );
+ $m->follow_link( id => 'page-basics');
$m->title_like(qr/Modify ticket/i, 'modify ticket');
- $m->content_like(qr/\Q$cf_name/, 'CF on the page');
+ $m->content_contains($cf_name, 'CF on the page');
- my $value = $m->form_number(3)->value("Object-RT::Ticket-$tid-CustomField-$cfid-Values");
+ my $value = $m->form_name('TicketModify')->value("Object-RT::Ticket-$tid-CustomField-$cfid-Values");
is lc $value, 'asd', 'correct value is selected';
$m->submit;
$m->content_unlike(qr/\Q$cf_name\E.*?changed/mi, 'field is not changed');
- $value = $m->form_number(3)->value("Object-RT::Ticket-$tid-CustomField-$cfid-Values");
+ $value = $m->form_name('TicketModify')->value("Object-RT::Ticket-$tid-CustomField-$cfid-Values");
is lc $value, 'asd', 'the same value is still selected';
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ my $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Load( $tid );
ok $ticket->id, 'loaded the ticket';
is lc $ticket->FirstCustomFieldValue( $cf_name ),
'asd', 'value is still the same';
}
-diag "check that 0 is ok value of the CF"
- if $ENV{'TEST_VERBOSE'};
+diag "check that 0 is ok value of the CF";
{
ok $m->goto_ticket( $tid ), "opened ticket's page";
- $m->follow_link( text => 'Custom Fields' );
+ $m->follow_link( id => 'page-basics');
$m->title_like(qr/Modify ticket/i, 'modify ticket');
- $m->content_like(qr/\Q$cf_name/, 'CF on the page');
+ $m->content_contains($cf_name, 'CF on the page');
- my $value = $m->form_number(3)->value("Object-RT::Ticket-$tid-CustomField-$cfid-Values");
+ my $value = $m->form_name('TicketModify')->value("Object-RT::Ticket-$tid-CustomField-$cfid-Values");
is lc $value, 'asd', 'correct value is selected';
$m->select("Object-RT::Ticket-$tid-CustomField-$cfid-Values" => 0 );
$m->submit;
$m->content_like(qr/\Q$cf_name\E.*?changed/mi, 'field is changed');
- $m->content_unlike(qr/0 is no longer a value for custom field/mi, 'no bad message in results');
+ $m->content_lacks('0 is no longer a value for custom field', 'no bad message in results');
- $value = $m->form_number(3)->value("Object-RT::Ticket-$tid-CustomField-$cfid-Values");
+ $value = $m->form_name('TicketModify')->value("Object-RT::Ticket-$tid-CustomField-$cfid-Values");
is lc $value, '0', 'new value is selected';
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ my $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Load( $tid );
ok $ticket->id, 'loaded the ticket';
is lc $ticket->FirstCustomFieldValue( $cf_name ),
'0', 'API returns correct value';
}
-diag "check that we can set empty value when the current is 0"
- if $ENV{'TEST_VERBOSE'};
+diag "check that we can set empty value when the current is 0";
{
ok $m->goto_ticket( $tid ), "opened ticket's page";
- $m->follow_link( text => 'Custom Fields' );
+ $m->follow_link( id => 'page-basics');
$m->title_like(qr/Modify ticket/i, 'modify ticket');
- $m->content_like(qr/\Q$cf_name/, 'CF on the page');
+ $m->content_contains($cf_name, 'CF on the page');
- my $value = $m->form_number(3)->value("Object-RT::Ticket-$tid-CustomField-$cfid-Values");
+ my $value = $m->form_name('TicketModify')->value("Object-RT::Ticket-$tid-CustomField-$cfid-Values");
is lc $value, '0', 'correct value is selected';
$m->select("Object-RT::Ticket-$tid-CustomField-$cfid-Values" => '' );
$m->submit;
- $m->content_like(qr/0 is no longer a value for custom field/mi, '0 is no longer a value');
+ $m->content_contains('0 is no longer a value for custom field', '0 is no longer a value');
- $value = $m->form_number(3)->value("Object-RT::Ticket-$tid-CustomField-$cfid-Values");
+ $value = $m->form_name('TicketModify')->value("Object-RT::Ticket-$tid-CustomField-$cfid-Values");
is $value, '', '(no value) is selected';
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ my $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Load( $tid );
ok $ticket->id, 'loaded the ticket';
is $ticket->FirstCustomFieldValue( $cf_name ),
diff --git a/rt/t/web/charting.t b/rt/t/web/charting.t
index 7c11f9c92..32d95d99b 100644
--- a/rt/t/web/charting.t
+++ b/rt/t/web/charting.t
@@ -1,7 +1,16 @@
use strict;
use warnings;
-use RT::Test no_plan => 1;
+BEGIN {
+ require RT::Test;
+
+ if (eval { require GD; 1 }) {
+ RT::Test->import(plan => 'no_plan');
+ }
+ else {
+ RT::Test->import(skip_all => 'GD required.');
+ }
+}
for my $n (1..7) {
my $ticket = RT::Ticket->new( RT->SystemUser );
@@ -26,8 +35,8 @@ ok( $m->login, "Logged in" );
# Test that defaults work
$m->get_ok( "/Search/Chart.html?Query=id>0" );
-$m->content_like(qr{<th[^>]*>\s*Queue\s*</th>\s*<th[^>]*>\s*Tickets\s*</th>}, "Grouped by queue");
-$m->content_like(qr{General</a>\s*</td>\s*<td[^>]*>\s*7}, "Found results in table");
+$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{<img src="/Search/Chart\?}, "Found image");
$m->get_ok( "/Search/Chart?Query=id>0" );
@@ -37,8 +46,8 @@ 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[^>]*>\s*Queue\s*</th>\s*<th[^>]*>\s*Tickets\s*</th>}, "Grouped by queue");
-$m->content_like(qr{General</a>\s*</td>\s*<td[^>]*>\s*7}, "Found results in table");
+$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{<img src="/Search/Chart\?}, "Found image");
$m->get_ok( "/Search/Chart?Query=id>0&PrimaryGroupBy=Queue" );
@@ -48,9 +57,9 @@ 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[^>]*>\s*Requestor\.EmailAddress\s*</th>\s*<th[^>]*>\s*Tickets\s*</th>},
+$m->content_like(qr{<th[^>]*>Requestor\.EmailAddress\s*</th>\s*<th[^>]*>Tickets\s*</th>},
"Grouped by requestor");
-$m->content_like(qr{root0\@localhost</a>\s*</td>\s*<td[^>]*>\s*3}, "Found results in table");
+$m->content_like(qr{root0\@localhost</a>\s*</td>\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" );
@@ -60,7 +69,7 @@ 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*7},
+$m->content_like(qr{General</a>\s*</td>\s*<td[^>]*>\s*<a[^>]*>7</a>},
"Found queue results in table, as a default");
$m->content_like(qr{<img src="/Search/Chart\?}, "Found image");
diff --git a/rt/t/web/class_create.t b/rt/t/web/class_create.t
new file mode 100644
index 000000000..cec41a8aa
--- /dev/null
+++ b/rt/t/web/class_create.t
@@ -0,0 +1,75 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 13;
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in as root';
+my $root = RT::User->new(RT->SystemUser);
+ok( $root->Load('root'), 'load root user' );
+
+my $class_name = 'test class';
+
+my $class_id;
+diag "Create a class";
+{
+ $m->follow_link( id => 'tools-config-articles-classes-create');
+
+ # Test class form validation
+ $m->submit_form(
+ form_name => 'ModifyClass',
+ fields => {
+ Name => '',
+ },
+ );
+ $m->text_contains('Invalid value for Name');
+ $m->submit_form(
+ form_name => 'ModifyClass',
+ fields => {
+ Name => '0',
+ },
+ );
+ $m->text_contains('Invalid value for Name');
+ $m->submit_form(
+ form_name => 'ModifyClass',
+ fields => {
+ Name => '1',
+ },
+ );
+ $m->text_contains('Invalid value for Name');
+ $m->submit_form(
+ form_name => 'ModifyClass',
+ fields => {
+ Name => $class_name,
+ },
+ );
+ $m->content_contains('Object created', 'created class sucessfully' );
+
+ # Test validation on updae
+ $m->form_name('ModifyClass');
+ $m->set_fields(
+ Name => '',
+ );
+ $m->click_button(value => 'Save Changes');
+ $m->text_contains('Illegal value for Name');
+
+ $m->form_name('ModifyClass');
+ $m->set_fields(
+ Name => '0',
+ );
+ $m->click_button(value => 'Save Changes');
+ $m->text_contains('Illegal value for Name');
+
+ $m->form_name('ModifyClass');
+ $m->set_fields(
+ Name => '1',
+ );
+ $m->click_button(value => 'Save Changes');
+ $m->text_contains('Illegal value for Name');
+
+ $class_id = $m->form_name('ModifyClass')->value('id');
+ ok $class_id, "found id of the class in the form, it's #$class_id";
+}
+
diff --git a/rt/t/web/clickjacking-preventions.t b/rt/t/web/clickjacking-preventions.t
new file mode 100644
index 000000000..dde82952b
--- /dev/null
+++ b/rt/t/web/clickjacking-preventions.t
@@ -0,0 +1,30 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+
+use RT::Test tests => 11;
+
+my ($url, $m);
+
+# Enabled by default
+{
+ ok(RT->Config->Get('Framebusting'), "Framebusting enabled by default");
+
+ ($url, $m) = RT::Test->started_ok;
+ $m->get_ok($url);
+ $m->content_contains('if (window.top !== window.self) {', "Found the framekiller javascript");
+ is $m->response->header('X-Frame-Options'), 'DENY', "X-Frame-Options is set to DENY";
+
+ RT::Test->stop_server;
+}
+
+# Disabled
+{
+ RT->Config->Set('Framebusting', 0);
+
+ ($url, $m) = RT::Test->started_ok;
+ $m->get_ok($url);
+ $m->content_lacks('if (window.top !== window.self) {', "Didn't find the framekiller javascript");
+ is $m->response->header('X-Frame-Options'), undef, "X-Frame-Options is not present";
+}
+
diff --git a/rt/t/web/command_line.t b/rt/t/web/command_line.t
index 884b064e6..1fed8e69e 100644
--- a/rt/t/web/command_line.t
+++ b/rt/t/web/command_line.t
@@ -3,7 +3,7 @@
use strict;
use File::Spec ();
use Test::Expect;
-use RT::Test tests => 295;
+use RT::Test tests => 303, actual_server => 1;
my ($baseurl, $m) = RT::Test->started_ok;
use RT::User;
@@ -11,7 +11,6 @@ use RT::Queue;
my $rt_tool_path = "$RT::BinPath/rt";
-# {{{ test configuration options
# config directives:
# (in $CWD/.rtrc)
@@ -38,14 +37,13 @@ $ENV{'RTSERVER'} =RT->Config->Get('WebBaseURL') ;
$ENV{'RTDEBUG'} = '1';
# - RTCONFIG Specifies a name other than ".rtrc" for the
# configuration file.
+$ENV{'RTCONFIG'} = '/dev/null';
#
# - RTQUERY Default RT Query for rt list
# - RTORDERBY Default order for rt list
-# }}}
-# {{{ test ticket manipulation
# create a ticket
expect_run(
@@ -54,6 +52,7 @@ expect_run(
quit => 'quit',
);
expect_send(q{create -t ticket set subject='new ticket' add cc=foo@example.com}, "Creating a ticket...");
+
expect_like(qr/Ticket \d+ created/, "Created the ticket");
expect_handle->before() =~ /Ticket (\d+) created/;
my $ticket_id = $1;
@@ -65,7 +64,6 @@ expect_like(qr/Ticket \d+ created/, "Created the ticket");
expect_send(q{rt create -t ticket set subject='rt ticket'}, "Creating a ticket with 'rt create'...");
expect_like(qr/Ticket \d+ created/, "Created the ticket");
-# {{{ test queue manipulation
# creating queues
expect_send("create -t queue set Name='NewQueue$$'", 'Creating a queue...');
@@ -85,19 +83,18 @@ TODO: {
expect_like(qr/$queue_id: EditedQueue$$/, 'Found the queue');
}
-# }}}
# Set up a custom field for editing tests
-my $cf = RT::CustomField->new($RT::SystemUser);
+my $cf = RT::CustomField->new(RT->SystemUser);
my ($val,$msg) = $cf->Create(Name => 'MyCF'.$$, Type => 'FreeformSingle', Queue => $queue_id);
ok($val,$msg);
-my $othercf = RT::CustomField->new($RT::SystemUser);
+my $othercf = RT::CustomField->new(RT->SystemUser);
($val,$msg) = $othercf->Create(Name => 'My CF'.$$, Type => 'FreeformSingle', Queue => $queue_id);
ok($val,$msg);
-my $multiple_cf = RT::CustomField->new($RT::SystemUser);
+my $multiple_cf = RT::CustomField->new(RT->SystemUser);
($val,$msg) = $multiple_cf->Create(Name => 'MultipleCF'.$$, Type =>
'FreeformMultiple', Queue => $queue_id);
ok($val,$msg);
@@ -118,7 +115,7 @@ ok($val,$msg);
# text attachment
check_attachment($test_email);
# binary attachment
- check_attachment($RT::MasonComponentRoot.'/NoAuth/images/bplogo.gif');
+ check_attachment($RT::MasonComponentRoot.'/NoAuth/images/bpslogo.png');
# change a ticket's Owner
expect_send("edit ticket/$ticket_id set owner=root", 'Changing owner...');
@@ -130,6 +127,11 @@ expect_send("edit ticket/$ticket_id set requestors=foo\@example.com", 'Changing
expect_like(qr/Ticket $ticket_id updated/, 'Changed Requestor');
expect_send("show ticket/$ticket_id -f requestors", 'Verifying change...');
expect_like(qr/Requestors: foo\@example.com/, 'Verified change');
+# set multiple Requestors
+expect_send("edit ticket/$ticket_id set requestors=foo\@example.com,bar\@example.com", 'Changing Requestor...');
+expect_like(qr/Ticket $ticket_id updated/, 'Changed Requestor');
+expect_send("show ticket/$ticket_id -f requestors", 'Verifying change...');
+expect_like(qr/Requestors: bar\@example.com, foo\@example.com/, 'Verified change');
# change a ticket's Cc
expect_send("edit ticket/$ticket_id set cc=bar\@example.com", 'Changing Cc...');
expect_like(qr/Ticket $ticket_id updated/, 'Changed Cc');
@@ -269,17 +271,19 @@ expect_send("show ticket/$ticket_id -f status", 'Verifying change...');
expect_like(qr/Status: resolved/, 'Verified change');
# try to set status to an illegal value
expect_send("edit ticket/$ticket_id set status=quux", 'Changing status to an illegal value...');
-expect_like(qr/illegal value/i, 'Errored out');
+expect_like(qr/isn't a valid status/i, 'Errored out');
expect_send("show ticket/$ticket_id -f status", 'Verifying lack of change...');
expect_like(qr/Status: resolved/, 'Verified change');
-# }}}
-# {{{ display
# show ticket list
expect_send("ls -s -t ticket -o +id \"Status='resolved'\"", 'Listing resolved tickets...');
expect_like(qr/$ticket_id: new ticket/, 'Found our ticket');
+
+expect_send("ls -s -t ticket -f Requestors $ticket_id", 'getting Requestors');
+expect_like(qr/$ticket_id\s+bar\@example.com,\s+foo\@example.com/, 'got Requestors');
+
# show ticket list verbosely
expect_send("ls -l -t ticket -o +id \"Status='resolved'\"", 'Listing resolved tickets verbosely...');
expect_like(qr/id: ticket\/$ticket_id/, 'Found our ticket');
@@ -307,9 +311,7 @@ ok($attachment_id, "Got attachment id=$attachment_id $attachment_type");
expect_send("show -s ticket/$ticket_id/attachments/$attachment_id", "Showing attachment $attachment_id...");
expect_like(qr/ContentType: $attachment_type/, 'Got the attachment');
-# }}}
-# {{{ test user manipulation
# creating users
expect_send("create -t user set Name='NewUser$$' EmailAddress='fbar$$\@example.com'", 'Creating a user...');
@@ -329,9 +331,7 @@ TODO: {
expect_like(qr/$user_id: EditedUser$$/, 'Found the user');
}
-# }}}
-# {{{ test group manipulation
TODO: {
todo_skip "Group manipulation doesn't work right now", 8;
@@ -354,11 +354,9 @@ TODO: {
}
}
-# }}}
TODO: {
todo_skip "Custom field manipulation not yet implemented", 8;
-# {{{ test custom field manipulation
# creating custom fields
expect_send("create -t custom_field set Name='NewCF$$'", 'Creating a custom field...');
@@ -379,9 +377,7 @@ TODO: {
}
}
-# }}}
-# {{{ test merging tickets
expect_send("create -t ticket set subject='CLIMergeTest1-$$'", 'Creating first ticket to merge...');
expect_like(qr/Ticket \d+ created/, 'Created first ticket');
expect_handle->before() =~ /Ticket (\d+) created/;
@@ -395,30 +391,23 @@ ok($merge_ticket_B, "Got second ticket to merge id=$merge_ticket_B");
expect_send("merge $merge_ticket_B $merge_ticket_A", 'Merging the tickets...');
expect_like(qr/Merge completed/, 'Merged the tickets');
-TODO: {
- local $TODO = "we generate a spurious warning here";
- $m->no_warnings_ok;
-}
-
expect_send("show ticket/$merge_ticket_A/history", 'Checking merge on first ticket');
expect_like(qr/Merged into ticket #$merge_ticket_A by root/, 'Merge recorded in first ticket');
expect_send("show ticket/$merge_ticket_B/history", 'Checking merge on second ticket');
expect_like(qr/Merged into ticket #$merge_ticket_A by root/, 'Merge recorded in second ticket');
-# }}}
-# {{{ test taking/stealing tickets
{
# create a user; give them privileges to take and steal
### TODO: implement 'grant' in the CLI tool; use that here instead.
### this breaks the abstraction barrier, like, a lot.
- my $steal_user = RT::User->new($RT::SystemUser);
+ my $steal_user = RT::User->new(RT->SystemUser);
my ($steal_user_id, $msg) = $steal_user->Create( Name => "fooser$$",
EmailAddress => "fooser$$\@localhost",
Privileged => 1,
Password => 'foobar',
);
ok($steal_user_id, "Created the user? $msg");
- my $steal_queue = RT::Queue->new($RT::SystemUser);
+ my $steal_queue = RT::Queue->new(RT->SystemUser);
my $steal_queue_id;
($steal_queue_id, $msg) = $steal_queue->Create( Name => "Steal$$" );
ok($steal_queue_id, "Got the queue? $msg");
@@ -476,9 +465,7 @@ expect_like(qr/Merged into ticket #$merge_ticket_A by root/, 'Merge recorded in
expect_send("steal $steal_ticket_id", 'root steals the ticket back...');
expect_like(qr/Owner changed from fooser$$ to root/, '...and succeeds.');
}
-# }}}
-# {{{ test ticket linking
my @link_relns = ( 'DependsOn', 'DependedOnBy', 'RefersTo', 'ReferredToBy',
'MemberOf', 'HasMember', );
my %display_relns = map { $_ => $_ } @link_relns;
@@ -502,7 +489,6 @@ expect_like(qr/Merged into ticket #$merge_ticket_A by root/, 'Merge recorded in
#expect_unlike(qr/\Q$reln: \E[\w\d\.]+\Q://\E[w\d\.]+\/ticket\/$link2_id/, "Removed link $reln");
}
-# }}}
expect_quit(); # We need to do this ourselves, so that we quit
# *before* we tear down the webserver.
@@ -536,9 +522,16 @@ sub check_attachment {
my $attachment_content = do { local($/); <$fh> };
close $fh;
chomp $attachment_content;
- expect_is($attachment_content,"Attachment contains original text");
+ 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");
+ }
}
+# you may encounter warning like Use of uninitialized value $ampm
+# ... in Time::ParseDate
+my @warnings = grep { $_ !~ /\$ampm/ } $m->get_warnings;
+is( scalar @warnings, 0, 'no extra warnings' );
-
-1;
+1; # needed to avoid a weird exit value from expect_quit
diff --git a/rt/t/web/command_line_with_unknown_field.t b/rt/t/web/command_line_with_unknown_field.t
index 9a7ec7acd..736be4d1c 100644
--- a/rt/t/web/command_line_with_unknown_field.t
+++ b/rt/t/web/command_line_with_unknown_field.t
@@ -3,7 +3,7 @@
use strict;
use File::Spec ();
use Test::Expect;
-use RT::Test tests => 10;
+use RT::Test tests => 14, actual_server => 1;
my ($baseurl, $m) = RT::Test->started_ok;
my $rt_tool_path = "$RT::BinPath/rt";
@@ -12,6 +12,7 @@ $ENV{'RTPASSWD'} = 'password';
$RT::Logger->debug("Connecting to server at ".RT->Config->Get('WebBaseURL'));
$ENV{'RTSERVER'} =RT->Config->Get('WebBaseURL') ;
$ENV{'RTDEBUG'} = '1';
+$ENV{'RTCONFIG'} = '/dev/null';
expect_run(
command => "$rt_tool_path shell",
@@ -19,6 +20,7 @@ expect_run(
quit => 'quit',
);
expect_send(q{create -t ticket set subject='new ticket' add cc=foo@example.com}, "Creating a ticket...");
+
expect_like(qr/Ticket \d+ created/, "Created the ticket");
expect_handle->before() =~ /Ticket (\d+) created/;
my $ticket_id = $1;
@@ -32,3 +34,10 @@ expect_like(qr/homer: Unknown field/, 'homer is unknown field');
expect_like(qr/homer: simpson/, 'the value we set for homer is shown too');
expect_quit();
+
+# you may encounter warning like Use of uninitialized value $ampm
+# ... in Time::ParseDate
+my @warnings = grep { $_ !~ /\$ampm/ } $m->get_warnings;
+is( scalar @warnings, 0, 'no extra warnings' );
+
+1; # needed to avoid a weird exit value from expect_quit
diff --git a/rt/t/web/compilation_errors.t b/rt/t/web/compilation_errors.t
index 36a006890..1f82ab91f 100644
--- a/rt/t/web/compilation_errors.t
+++ b/rt/t/web/compilation_errors.t
@@ -7,7 +7,7 @@ BEGIN {
sub wanted {
-f && /\.html$/ && $_ !~ /Logout.html$/ && $File::Find::dir !~ /RichText/;
}
- my $tests = 4;
+ my $tests = 8;
find( sub { wanted() and $tests += 4 }, 'share/html/' );
plan tests => $tests;
}
@@ -28,33 +28,37 @@ $agent->cookie_jar($cookie_jar);
# get the top page
my $url = $agent->rt_base_url;
-diag "Base URL is '$url'" if $ENV{TEST_VERBOSE};
$agent->get($url);
-is ($agent->{'status'}, 200, "Loaded a page");
-
-# {{{ test a login
+is($agent->status, 200, "Loaded a page");
# follow the link marked "Login"
$agent->login(root => 'password');
-is($agent->{'status'}, 200, "Fetched the page ok");
-like( $agent->{'content'} , qr/Logout/i, "Found a logout link");
+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 ( sub { wanted() and test_get($File::Find::name) } , 'share/html/');
+TODO: {
+ local $TODO = "we spew *lots* of undef warnings";
+ $agent->no_warnings_ok;
+};
sub test_get {
+ my $agent = shift;
my $file = shift;
$file =~ s#^share/html/##;
- diag( "testing $url/$file" ) if $ENV{TEST_VERBOSE};
- ok ($agent->get("$url/$file", "GET $url/$file"), "Can Get $url/$file");
- is ($agent->{'status'}, 200, "Loaded $file");
-# ok( $agent->{'content'} =~ /Logout/i, "Found a logout link on $file ");
- ok( $agent->{'content'} !~ /Not logged in/i, "Still logged in for $file");
- ok( $agent->{'content'} !~ /raw error/i, "Didn't get a Mason compilation error on $file");
+ diag( "testing $url/$file" );
+
+ $agent->get_ok("$url/$file");
+ is($agent->status, 200, "Loaded $file");
+ $agent->content_lacks('Not logged in', "Still logged in for $file");
+ $agent->content_lacks('raw error', "Didn't get a Mason compilation error on $file") or do {
+ if (my ($error) = $agent->content =~ /<pre>(.*?line.*?)$/s) {
+ diag "$file: $error";
+ }
+ };
}
-# }}}
-
-1;
diff --git a/rt/t/web/config_tab_right.t b/rt/t/web/config_tab_right.t
index 4dc9ec082..361506c10 100644
--- a/rt/t/web/config_tab_right.t
+++ b/rt/t/web/config_tab_right.t
@@ -2,11 +2,11 @@
use strict;
use warnings;
-use RT::Test tests => 8;
+use RT::Test nodata => 1, tests => 10;
my ($uname, $upass, $user) = ('tester', 'tester');
{
- $user = RT::User->new($RT::SystemUser);
+ $user = RT::User->new(RT->SystemUser);
my ($status, $msg) = $user->Create(
Name => $uname,
Password => $upass,
@@ -20,7 +20,7 @@ my ($baseurl, $m) = RT::Test->started_ok;
ok $m->login($uname, $upass), "logged in";
{
- $m->content_unlike(qr/Configuration/, 'no configuration');
+ $m->content_lacks('Configuration', 'no configuration tab');
$m->get('/Admin/');
is $m->status, 403, 'no access to /Admin/';
}
@@ -33,7 +33,7 @@ RT::Test->set_rights(
{
$m->get('/');
- $m->content_like(qr/Configuration/, 'configuration is there');
+ $m->content_contains('Configuration', 'configuration tab is there');
$m->follow_link_ok({text => 'Configuration'});
is $m->status, 200, 'user has access to /Admin/';
diff --git a/rt/t/web/crypt-gnupg.t b/rt/t/web/crypt-gnupg.t
index fb28c887c..6bdefdac7 100644
--- a/rt/t/web/crypt-gnupg.t
+++ b/rt/t/web/crypt-gnupg.t
@@ -1,20 +1,16 @@
#!/usr/bin/perl -w
use strict;
-use RT::Test tests => 94;
-
-plan skip_all => 'GnuPG required.'
- unless eval 'use GnuPG::Interface; 1';
-plan skip_all => 'gpg executable is required.'
- unless RT::Test->find_executable('gpg');
-
+use RT::Test::GnuPG
+ tests => 102,
+ gnupg_options => {
+ passphrase => 'recipient',
+ 'trust-model' => 'always',
+};
+use Test::Warn;
use RT::Action::SendEmail;
-eval 'use GnuPG::Interface; 1' or plan skip_all => 'GnuPG required.';
-
-RT::Test->set_mail_catcher;
-
RT->Config->Set( CommentAddress => 'general@example.com');
RT->Config->Set( CorrespondAddress => 'general@example.com');
RT->Config->Set( DefaultSearchResultFormat => qq{
@@ -26,23 +22,6 @@ RT->Config->Set( DefaultSearchResultFormat => qq{
'KR-__KeyRequestors__-K',
Status});
-use File::Spec ();
-use Cwd;
-use File::Temp qw(tempdir);
-my $homedir = tempdir( CLEANUP => 1 );
-
-use_ok('RT::Crypt::GnuPG');
-
-RT->Config->Set( 'GnuPG',
- Enable => 1,
- OutgoingMessagesFormat => 'RFC' );
-
-RT->Config->Set( 'GnuPGOptions',
- homedir => $homedir,
- passphrase => 'recipient',
- 'no-permission-warning' => undef,
- 'trust-model' => 'always');
-RT->Config->Set( 'MailPlugins' => 'Auth::MailFrom', 'Auth::GnuPG' );
RT::Test->import_gnupg_key('recipient@example.com', 'public');
RT::Test->import_gnupg_key('recipient@example.com', 'secret');
@@ -51,7 +30,7 @@ RT::Test->import_gnupg_key('general@example.com', 'secret');
RT::Test->import_gnupg_key('general@example.com.2', 'public');
RT::Test->import_gnupg_key('general@example.com.2', 'secret');
-ok(my $user = RT::User->new($RT::SystemUser));
+ok(my $user = RT::User->new(RT->SystemUser));
ok($user->Load('root'), "Loaded user 'root'");
$user->SetEmailAddress('recipient@example.com');
@@ -62,11 +41,6 @@ my $queue = RT::Test->load_or_create_queue(
ok $queue && $queue->id, 'loaded or created queue';
my $qid = $queue->id;
-RT::Test->set_rights(
- Principal => 'Everyone',
- Right => ['CreateTicket', 'ShowTicket', 'SeeQueue', 'ModifyTicket'],
-);
-
my ($baseurl, $m) = RT::Test->started_ok;
ok $m->login, 'logged in';
@@ -113,7 +87,7 @@ 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 );
+ my $tick = RT::Ticket->new( RT->SystemUser );
$tick->Load( $id );
ok ($tick->id, "loaded ticket #$id");
@@ -181,7 +155,7 @@ 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 );
+ my $tick = RT::Ticket->new( RT->SystemUser );
$tick->Load( $id );
ok ($tick->id, "loaded ticket #$id");
@@ -253,7 +227,7 @@ 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 );
+ my $tick = RT::Ticket->new( RT->SystemUser );
$tick->Load( $id );
ok ($tick->id, "loaded ticket #$id");
@@ -319,7 +293,7 @@ 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 );
+ my $tick = RT::Ticket->new( RT->SystemUser );
$tick->Load( $id );
ok ($tick->id, "loaded ticket #$id");
@@ -361,12 +335,12 @@ my $nokey = RT::Test->load_or_create_user(Name => 'nokey', EmailAddress => 'noke
$nokey->PrincipalObj->GrantRight(Right => 'CreateTicket');
$nokey->PrincipalObj->GrantRight(Right => 'OwnTicket');
-my $tick = RT::Ticket->new( $RT::SystemUser );
+my $tick = RT::Ticket->new( RT->SystemUser );
$tick->Create(Subject => 'owner lacks pubkey', Queue => 'general',
Owner => $nokey);
ok(my $id = $tick->id, 'created ticket for owner-without-pubkey');
-$tick = RT::Ticket->new( $RT::SystemUser );
+$tick = RT::Ticket->new( RT->SystemUser );
$tick->Create(Subject => 'owner has pubkey', Queue => 'general',
Owner => 'root');
ok($id = $tick->id, 'created ticket for owner-with-pubkey');
@@ -379,11 +353,18 @@ To: general\@example.com
hello
MAIL
-((my $status), $id) = RT::Test->send_via_mailgate($mail);
+my $status;
+warning_like {
+ ($status, $id) = RT::Test->send_via_mailgate($mail);
+} [
+ qr/nokey\@example.com: skipped: public key not found/,
+ qr/Recipient 'nokey\@example.com' is unusable/,
+];
+
is ($status >> 8, 0, "The mail gateway exited normally");
ok ($id, "got id of a newly created ticket - $id");
-$tick = RT::Ticket->new( $RT::SystemUser );
+$tick = RT::Ticket->new( RT->SystemUser );
$tick->Load( $id );
ok ($tick->id, "loaded ticket #$id");
@@ -396,7 +377,7 @@ is ($tick->Subject,
my $key1 = "EC1E81E7DC3DB42788FB0E4E9FA662C06DE22FC2";
my $key2 = "75E156271DCCF02DDD4A7A8CDF651FA0632C4F50";
-ok($user = RT::User->new($RT::SystemUser));
+ok($user = RT::User->new(RT->SystemUser));
ok($user->Load('root'), "Loaded user 'root'");
is($user->PreferredKey, $key1, "preferred key is set correctly");
$m->get("$baseurl/Prefs/Other.html");
@@ -407,11 +388,11 @@ like($m->content, qr/$key1/, "first key shows up in preferences");
like($m->content, qr/$key2/, "second key shows up in preferences");
like($m->content, qr/$key1.*?$key2/s, "first key shows up before the second");
-$m->form_number(3);
+$m->form_name('ModifyPreferences');
$m->select("PreferredKey" => $key2);
$m->submit;
-ok($user = RT::User->new($RT::SystemUser));
+ok($user = RT::User->new(RT->SystemUser));
ok($user->Load('root'), "Loaded user 'root'");
is($user->PreferredKey, $key2, "preferred key is set correctly to the new value");
@@ -423,6 +404,8 @@ like($m->content, qr/$key2/, "second key shows up in preferences");
like($m->content, qr/$key1/, "first key shows up in preferences");
like($m->content, qr/$key2.*?$key1/s, "second key (now preferred) shows up before the first");
+$m->no_warnings_ok;
+
# test that the new fields work
$m->get("$baseurl/Search/Simple.html?q=General");
my $content = $m->content;
@@ -441,6 +424,10 @@ like($content, qr/KO-nokey \(no pubkey!\)-K/, "KeyOwnerName issues no-pubkey war
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");
+$m->next_warning_like(qr/public key not found/);
+$m->next_warning_like(qr/public key not found/);
+$m->no_leftover_warnings_ok;
diff --git a/rt/t/web/custom_frontpage.t b/rt/t/web/custom_frontpage.t
index 79ea56629..43c5f6e33 100644
--- a/rt/t/web/custom_frontpage.t
+++ b/rt/t/web/custom_frontpage.t
@@ -1,12 +1,12 @@
#!/usr/bin/perl -w
use strict;
-use RT::Test tests => 7;
+use RT::Test tests => 12;
my ($baseurl, $m) = RT::Test->started_ok;
my $url = $m->rt_base_url;
-my $user_obj = RT::User->new($RT::SystemUser);
+my $user_obj = RT::User->new(RT->SystemUser);
my ($ret, $msg) = $user_obj->LoadOrCreateByEmail('customer@example.com');
ok($ret, 'ACL test user creation');
$user_obj->SetName('customer');
@@ -29,9 +29,9 @@ $m->field ( "SavedSearchDescription" => 'stupid tickets');
$m->click_button (name => 'SavedSearchSave');
$m->get ( $url.'Prefs/MyRT.html' );
-$m->content_like (qr/stupid tickets/, 'saved search listed in rt at a glance items');
+$m->content_contains('stupid tickets', 'saved search listed in rt at a glance items');
-ok $m->login, 'we did log in as root';
+ok $m->login('root', 'password', logout => 1), 'we did log in as root';
$m->get ( $url.'Prefs/MyRT.html' );
$m->form_name ('SelectionBox-body');
@@ -58,4 +58,33 @@ $m->click_button (name => 'movedown');
$m->form_name ('SelectionBox-body');
#$m->click_button (name => 'body-Save');
$m->get ( $url );
-$m->content_like (qr'highest priority tickets', 'adds them back');
+$m->content_contains('highest priority tickets', 'adds them back');
+
+
+#create a saved search with special chars
+$m->get( $url . "Search/Build.html" );
+$m->form_name('BuildQuery');
+$m->field( "ValueOfAttachment" => 'stupid' );
+$m->field( "SavedSearchDescription" => 'special chars [test] [_1] ~[_1~]' );
+$m->click_button( name => 'SavedSearchSave' );
+my ($name) = $m->content =~ /value="(RT::User-\d+-SavedSearch-\d+)"/;
+ok( $name, 'saved search name' );
+$m->get( $url . 'Prefs/MyRT.html' );
+$m->content_contains( 'special chars [test] [_1] ~[_1~]',
+ 'saved search listed in rt at a glance items' );
+
+$m->get( $url . 'Prefs/MyRT.html' );
+$m->form_name('SelectionBox-body');
+$m->field(
+ 'body-Available' => [
+ 'component-QuickCreate',
+ 'system-Unowned Tickets',
+ 'system-My Tickets',
+ 'saved-' . $name,
+ ]
+);
+$m->click_button( name => 'add' );
+
+$m->get($url);
+$m->content_like( qr/special chars \[test\] \d+ \[_1\]/,
+ 'special chars in titlebox' );
diff --git a/rt/t/web/custom_search.t b/rt/t/web/custom_search.t
index 05cfdab60..f8fde2500 100644
--- a/rt/t/web/custom_search.t
+++ b/rt/t/web/custom_search.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl -w
use strict;
-use RT::Test tests => 11;
+use RT::Test tests => 13;
my ($baseurl, $m) = RT::Test->started_ok;
my $url = $m->rt_base_url;
@@ -9,7 +9,7 @@ my $url = $m->rt_base_url;
-my $t = RT::Ticket->new($RT::SystemUser);
+my $t = RT::Ticket->new(RT->SystemUser);
$t->Create(Subject => 'for custom search'.$$, Queue => 'general',
Owner => 'root', Requestor => 'customsearch@localhost');
ok(my $id = $t->id, 'created ticket for custom search');
@@ -24,7 +24,7 @@ $m->get ( $url.'Prefs/MyRT.html' );
my $cus_hp = $m->find_link( text => "My Tickets" );
my $cus_qs = $m->find_link( text => "Quick search" );
$m->get ($cus_hp);
-$m->content_like (qr'highest priority tickets');
+$m->content_contains('highest priority tickets');
# add Requestor to the fields
$m->form_name ('BuildQuery');
diff --git a/rt/t/web/dashboards-basics.t b/rt/t/web/dashboards-basics.t
new file mode 100644
index 000000000..1d56da5be
--- /dev/null
+++ b/rt/t/web/dashboards-basics.t
@@ -0,0 +1,268 @@
+#!/usr/bin/perl -w
+use strict;
+
+use RT::Test tests => 122;
+my ($baseurl, $m) = RT::Test->started_ok;
+
+my $url = $m->rt_base_url;
+
+my $user_obj = RT::User->new(RT->SystemUser);
+my ($ret, $msg) = $user_obj->LoadOrCreateByEmail('customer@example.com');
+ok($ret, 'ACL test user creation');
+$user_obj->SetName('customer');
+$user_obj->SetPrivileged(1);
+($ret, $msg) = $user_obj->SetPassword('customer');
+$user_obj->PrincipalObj->GrantRight(Right => 'ModifySelf');
+my $currentuser = RT::CurrentUser->new($user_obj);
+
+my $onlooker = RT::User->new(RT->SystemUser);
+($ret, $msg) = $onlooker->LoadOrCreateByEmail('onlooker@example.com');
+ok($ret, 'ACL test user creation');
+$onlooker->SetName('onlooker');
+$onlooker->SetPrivileged(1);
+($ret, $msg) = $onlooker->SetPassword('onlooker');
+
+my $queue = RT::Queue->new(RT->SystemUser);
+$queue->Create(Name => 'SearchQueue'.$$);
+
+for my $user ($user_obj, $onlooker) {
+ $user->PrincipalObj->GrantRight(Right => 'ModifySelf');
+ for my $right (qw/SeeQueue ShowTicket OwnTicket/) {
+ $user->PrincipalObj->GrantRight(Right => $right, Object => $queue);
+ }
+}
+
+ok $m->login(customer => 'customer'), "logged in";
+
+$m->get_ok($url."Dashboards/index.html");
+$m->content_lacks('<a href="/Dashboards/Modify.html?Create=1">New</a>',
+ "No 'new dashboard' link because we have no CreateOwnDashboard");
+
+$m->no_warnings_ok;
+
+$m->get_ok($url."Dashboards/Modify.html?Create=1");
+$m->content_contains("Permission denied");
+$m->content_lacks("Save Changes");
+
+$m->warning_like(qr/Permission denied/, "got a permission denied warning");
+
+$user_obj->PrincipalObj->GrantRight(Right => 'ModifyOwnDashboard', Object => $RT::System);
+
+# Modify itself is no longer good enough, you need Create
+$m->get_ok($url."Dashboards/Modify.html?Create=1");
+$m->content_contains("Permission denied");
+$m->content_lacks("Save Changes");
+
+$m->warning_like(qr/Permission denied/, "got a permission denied warning");
+
+$user_obj->PrincipalObj->GrantRight(Right => 'CreateOwnDashboard', Object => $RT::System);
+
+$m->get_ok($url."Dashboards/Modify.html?Create=1");
+$m->content_lacks("Permission denied");
+$m->content_contains("Create");
+
+$m->get_ok($url."Dashboards/index.html");
+$m->content_contains("New", "'New' link because we now have ModifyOwnDashboard");
+$m->follow_link_ok({ id => 'home-dashboard_create'});
+$m->form_name('ModifyDashboard');
+$m->field("Name" => 'different dashboard');
+$m->content_lacks('Delete', "Delete button hidden because we are creating");
+$m->click_button(value => 'Create');
+$m->content_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('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->follow_link_ok({text => "different dashboard"});
+$m->content_contains("Basics");
+$m->content_contains("Content");
+$m->content_lacks("Subscription", "we don't have the SubscribeDashboard right");
+
+$m->follow_link_ok({text => "Basics"});
+$m->content_contains("Modify the dashboard different dashboard");
+
+$m->follow_link_ok({text => "Content"});
+$m->content_contains("Modify the content of dashboard different dashboard");
+my $form = $m->form_name('Dashboard-Searches-body');
+my @input = $form->find_input('Searches-body-Available');
+my ($unowned) =
+ map { ( $_->possible_values )[1] }
+ grep { ( $_->value_names )[1] =~ /Saved Search: Unowned Tickets/ } @input;
+$form->value('Searches-body-Available' => $unowned );
+$m->click_button(name => 'add');
+$m->content_contains("Dashboard updated");
+
+my $dashboard = RT::Dashboard->new($currentuser);
+my ($id) = $m->content =~ /name="id" value="(\d+)"/;
+ok($id, "got an ID, $id");
+$dashboard->LoadById($id);
+is($dashboard->Name, "different dashboard");
+
+is($dashboard->Privacy, 'RT::User-' . $user_obj->Id, "correct privacy");
+is($dashboard->PossibleHiddenSearches, 0, "all searches are visible");
+
+my @searches = $dashboard->Searches;
+is(@searches, 1, "one saved search in the dashboard");
+like($searches[0]->Name, qr/newest unowned tickets/, "correct search name");
+
+$form = $m->form_name('Dashboard-Searches-body');
+@input = $form->find_input('Searches-body-Available');
+my ($my_tickets) =
+ map { ( $_->possible_values )[1] }
+ grep { ( $_->value_names )[1] =~ /Saved Search: My Tickets/ } @input;
+$form->value('Searches-body-Available' => $my_tickets );
+$m->click_button(name => 'add');
+$m->content_contains("Dashboard updated");
+
+RT::Record->FlushCache if RT::Record->can('FlushCache');
+$dashboard = RT::Dashboard->new($currentuser);
+$dashboard->LoadById($id);
+
+@searches = $dashboard->Searches;
+is(@searches, 2, "two saved searches in the dashboard");
+like($searches[0]->Name, qr/newest unowned tickets/, "correct existing search name");
+like($searches[1]->Name, qr/highest priority tickets I own/, "correct new search name");
+
+my $ticket = RT::Ticket->new(RT->SystemUser);
+$ticket->Create(
+ Queue => $queue->Id,
+ Requestor => [ $user_obj->Name ],
+ Owner => $user_obj,
+ Subject => 'dashboard test',
+);
+
+$m->follow_link_ok({id => 'page-show'});
+$m->content_contains("50 highest priority tickets I own");
+$m->content_contains("50 newest unowned tickets");
+$m->content_unlike( qr/Bookmarked Tickets.*Bookmarked Tickets/s,
+ 'only dashboard queries show up' );
+$m->content_contains("dashboard test", "ticket subject");
+
+$m->get_ok("/Dashboards/$id/This fragment left intentionally blank");
+$m->content_contains("50 highest priority tickets I own");
+$m->content_contains("50 newest unowned tickets");
+$m->content_unlike( qr/Bookmarked Tickets.*Bookmarked Tickets/s,
+ 'only dashboard queries show up' );
+$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");
+
+$user_obj->Attributes->RedoSearch;
+is($user_obj->Attributes->Named('Subscription'), 0, "no subscriptions");
+
+$user_obj->PrincipalObj->GrantRight(Right => 'SubscribeDashboard', Object => $RT::System);
+
+$m->get_ok("/Dashboards/Modify.html?id=$id");
+$m->follow_link_ok({text => "Subscription"});
+$m->content_contains("Subscribe to dashboard different dashboard");
+$m->content_contains("Unowned Tickets");
+$m->content_contains("My Tickets");
+$m->content_unlike( qr/Bookmarked Tickets.*Bookmarked Tickets/s,
+ 'only dashboard queries show up' );
+
+$m->form_name('SubscribeDashboard');
+$m->click_button(name => 'Save');
+$m->content_lacks("Permission denied");
+$m->content_contains("Subscribed to dashboard different dashboard");
+
+$user_obj->Attributes->RedoSearch;
+is($user_obj->Attributes->Named('Subscription'), 1, "we have a subscription");
+
+$m->get_ok("/Dashboards/Modify.html?id=$id");
+$m->follow_link_ok({text => "Subscription"});
+$m->content_contains("Modify the subscription to dashboard different dashboard");
+
+$m->get_ok("/Dashboards/Modify.html?id=$id&Delete=1");
+$m->content_contains("Permission denied", "unable to delete dashboard because we lack DeleteOwnDashboard");
+
+$m->warning_like(qr/Couldn't delete dashboard.*Permission denied/, "got a permission denied warning when trying to delete the dashboard");
+
+$user_obj->PrincipalObj->GrantRight(Right => 'DeleteOwnDashboard', Object => $RT::System);
+
+$m->get_ok("/Dashboards/Modify.html?id=$id");
+$m->content_contains('Delete', "Delete button shows because we have DeleteOwnDashboard");
+
+$m->form_name('ModifyDashboard');
+$m->click_button(name => 'Delete');
+$m->content_contains("Deleted dashboard");
+
+$m->get("/Dashboards/Modify.html?id=$id");
+$m->content_lacks("different dashboard", "dashboard was deleted");
+$m->content_contains("Failed to load dashboard $id");
+
+$m->warning_like(qr/Failed to load dashboard.*Couldn't find row/, "the dashboard was deleted");
+
+$user_obj->PrincipalObj->GrantRight(Right => "SuperUser", Object => $RT::System);
+
+# now test that we warn about searches others can't see
+# first create a personal saved search...
+$m->get_ok($url."Search/Build.html");
+$m->follow_link_ok({text => 'Advanced'});
+$m->form_with_fields('Query');
+$m->field(Query => "id > 0");
+$m->submit;
+
+$m->form_with_fields('SavedSearchDescription');
+$m->field(SavedSearchDescription => "personal search");
+$m->click_button(name => "SavedSearchSave");
+
+# then the system-wide dashboard
+$m->get_ok($url."Dashboards/Modify.html?Create=1");
+
+$m->form_name('ModifyDashboard');
+$m->field("Name" => 'system dashboard');
+$m->field("Privacy" => 'RT::System-1');
+$m->content_lacks('Delete', "Delete button hidden because we are creating");
+$m->click_button(value => 'Create');
+$m->content_lacks("No permission to create dashboards");
+$m->content_contains("Saved dashboard system dashboard");
+
+$m->follow_link_ok({id => 'page-content'});
+
+$form = $m->form_name('Dashboard-Searches-body');
+@input = $form->find_input('Searches-body-Available');
+my ($personal) =
+ map { ( $_->possible_values )[1] }
+ grep { ( $_->value_names )[1] =~ /Saved Search: personal search/ } @input;
+$form->value('Searches-body-Available' => $personal );
+$m->click_button(name => 'add');
+$m->content_contains("Dashboard updated");
+
+$m->content_contains("The following queries may not be visible to all users who can see this dashboard.");
+
+$m->follow_link_ok({id => 'page-show'});
+$m->content_contains("personal search", "saved search shows up");
+$m->content_contains("dashboard test", "matched ticket shows up");
+
+# make sure the onlooker can't see the search...
+$onlooker->PrincipalObj->GrantRight(Right => 'SeeDashboard', Object => $RT::System);
+
+my $omech = RT::Test::Web->new;
+ok $omech->login(onlooker => 'onlooker'), "logged in";
+$omech->get_ok("/Dashboards");
+
+$omech->follow_link_ok({text => 'system dashboard'});
+$omech->content_lacks("personal search", "saved search doesn't show up");
+$omech->content_lacks("dashboard test", "matched ticket doesn't show up");
+
+$omech->warning_like(qr/User .* tried to load container user /, "can't see other users' personal searches");
+
+# make sure that navigating to dashboard pages with bad IDs throws an error
+my ($bad_id) = $personal =~ /^search-(\d+)/;
+
+for my $page (qw/Modify Queries Render Subscription/) {
+ $m->get("/Dashboards/$page.html?id=$bad_id");
+ $m->content_like(qr/Couldn.+t load dashboard $bad_id: Invalid object type/);
+ $m->warning_like(qr/Couldn't load dashboard $bad_id: Invalid object type/);
+}
+
diff --git a/rt/t/web/dashboards-deleted-saved-search.t b/rt/t/web/dashboards-deleted-saved-search.t
new file mode 100644
index 000000000..4cd7fea1f
--- /dev/null
+++ b/rt/t/web/dashboards-deleted-saved-search.t
@@ -0,0 +1,89 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+
+use RT::Test tests => 20;
+my ( $url, $m ) = RT::Test->started_ok;
+ok( $m->login, 'logged in' );
+
+# create a saved search
+$m->get_ok( $url . "/Search/Build.html?Query=" . 'id=1' );
+
+$m->submit_form(
+ form_name => 'BuildQuery',
+ fields => { SavedSearchDescription => 'foo', },
+ button => 'SavedSearchSave',
+);
+
+my ( $search_uri, $user_id, $search_id ) =
+ $m->content =~ /value="(RT::User-(\d+)-SavedSearch-(\d+))"/;
+$m->submit_form(
+ form_name => 'BuildQuery',
+ fields => { SavedSearchLoad => $search_uri },
+ button => 'SavedSearchSave',
+);
+
+$m->content_like( qr/name="SavedSearchDelete"\s+value="Delete"/,
+ 'found Delete button' );
+$m->content_like(
+ qr/name="SavedSearchDescription"\s+value="foo"/,
+ 'found Description input with the value filled'
+);
+
+# create a dashboard with the created search
+
+$m->get_ok( $url . "/Dashboards/Modify.html?Create=1" );
+$m->submit_form(
+ form_name => 'ModifyDashboard',
+ fields => { Name => 'bar' },
+);
+
+$m->content_contains('Saved dashboard bar', 'dashboard saved' );
+my $dashboard_queries_link = $m->find_link( text_regex => qr/Content/ );
+my ( $dashboard_id ) = $dashboard_queries_link->url =~ /id=(\d+)/;
+
+$m->get_ok( $url . "/Dashboards/Queries.html?id=$dashboard_id" );
+
+$m->content_lacks( 'value="Update"', 'no update button' );
+
+$m->submit_form(
+ form_name => 'Dashboard-Searches-body',
+ fields =>
+ { 'Searches-body-Available' => "search-$search_id-RT::User-$user_id" },
+ button => 'add',
+);
+
+$m->content_contains('Dashboard updated', 'added search foo to dashboard bar' );
+
+# delete the created search
+
+$m->get_ok( $url . "/Search/Build.html?Query=" . 'id=1' );
+$m->submit_form(
+ form_name => 'BuildQuery',
+ fields => { SavedSearchLoad => $search_uri },
+);
+$m->submit_form(
+ form_name => 'BuildQuery',
+ button => 'SavedSearchDelete',
+);
+
+$m->content_lacks( $search_uri, 'deleted search foo' );
+
+# here is what we really want to test
+
+$m->get_ok( $url . "/Dashboards/Queries.html?id=$dashboard_id" );
+$m->content_contains('Deleted queries', 'found deleted message' );
+
+# Update button shows so we can update the deleted search easily
+$m->content_contains( 'value="Update"', 'found update button' );
+
+$m->submit_form(
+ form_name => 'Dashboard-Searches-body',
+ button => 'update',
+);
+
+$m->content_lacks('Deleted queries', 'deleted message is gone' );
+$m->content_lacks( 'value="Update"', 'update button is gone too' );
+
+$m->get_warnings; # we'll get a lot of warnings because the deleted search
+
diff --git a/rt/t/web/dashboards-groups.t b/rt/t/web/dashboards-groups.t
index cbf1d6a9f..ac2a5aca0 100644
--- a/rt/t/web/dashboards-groups.t
+++ b/rt/t/web/dashboards-groups.t
@@ -1,13 +1,13 @@
#!/usr/bin/perl -w
use strict;
-use RT::Test tests => 40;
+use RT::Test nodata => 1, tests => 64;
my ($baseurl, $m) = RT::Test->started_ok;
my $url = $m->rt_base_url;
-# create user and queue {{{
-my $user_obj = RT::User->new($RT::SystemUser);
+# create user and queue
+my $user_obj = RT::User->new(RT->SystemUser);
my ($ok, $msg) = $user_obj->LoadOrCreateByEmail('customer@example.com');
ok($ok, 'ACL test user creation');
$user_obj->SetName('customer');
@@ -16,7 +16,7 @@ $user_obj->SetPrivileged(1);
$user_obj->PrincipalObj->GrantRight(Right => 'ModifySelf');
my $currentuser = RT::CurrentUser->new($user_obj);
-my $queue = RT::Queue->new($RT::SystemUser);
+my $queue = RT::Queue->new(RT->SystemUser);
$queue->Create(Name => 'SearchQueue'.$$);
$user_obj->PrincipalObj->GrantRight(Right => $_, Object => $queue)
@@ -26,13 +26,12 @@ $user_obj->PrincipalObj->GrantRight(Right => $_, Object => $queue)
# are checked and not these as well
$user_obj->PrincipalObj->GrantRight(Right => $_, Object => $RT::System)
for qw/SubscribeDashboard CreateOwnDashboard SeeOwnDashboard ModifyOwnDashboard DeleteOwnDashboard/;
-# }}}
-# create and test groups (outer < inner < user) {{{
-my $inner_group = RT::Group->new($RT::SystemUser);
+# create and test groups (outer < inner < user)
+my $inner_group = RT::Group->new(RT->SystemUser);
($ok, $msg) = $inner_group->CreateUserDefinedGroup(Name => "inner", Description => "inner group");
ok($ok, "created inner group: $msg");
-my $outer_group = RT::Group->new($RT::SystemUser);
+my $outer_group = RT::Group->new(RT->SystemUser);
($ok, $msg) = $outer_group->CreateUserDefinedGroup(Name => "outer", Description => "outer group");
ok($ok, "created outer group: $msg");
@@ -51,28 +50,36 @@ ok(!$inner_group->HasMember($outer_group->PrincipalId), "inner doesn't have oute
ok($inner_group->HasMember($user_obj->PrincipalId), "inner has user");
ok(!$inner_group->HasMemberRecursively($outer_group->PrincipalId), "inner doesn't have outer, even recursively");
ok($inner_group->HasMemberRecursively($user_obj->PrincipalId), "inner has user recursively");
-# }}}
ok $m->login(customer => 'customer'), "logged in";
-$m->get_ok("$url/Dashboards");
-$m->follow_link_ok({text => "New"});
+$m->follow_link_ok({ id => 'home-dashboard_create'});
$m->form_name('ModifyDashboard');
is_deeply([$m->current_form->find_input('Privacy')->possible_values], ["RT::User-" . $user_obj->Id], "the only selectable privacy is user");
$m->content_lacks('Delete', "Delete button hidden because we are creating");
$user_obj->PrincipalObj->GrantRight(Right => 'CreateGroupDashboard', Object => $inner_group);
-$m->follow_link_ok({text => "New"});
+$m->follow_link_ok({ id => 'home-dashboard_create'});
$m->form_name('ModifyDashboard');
is_deeply([$m->current_form->find_input('Privacy')->possible_values], ["RT::User-" . $user_obj->Id, "RT::Group-" . $inner_group->Id], "the only selectable privacies are user and inner group (not outer group)");
-$m->field("Name" => 'inner dashboard');
+$m->field("Name" => 'broken dashboard');
$m->field("Privacy" => "RT::Group-" . $inner_group->Id);
$m->content_lacks('Delete', "Delete button hidden because we are creating");
+$m->click_button(value => 'Create');
+$m->content_contains("saved", "we lack SeeGroupDashboard, so we end up back at the index.");
+$user_obj->PrincipalObj->GrantRight(
+ Right => 'SeeGroupDashboard',
+ Object => $inner_group,
+);
+$m->follow_link_ok({ id => 'home-dashboard_create'});
+$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("No permission to create dashboards");
+$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");
@@ -85,18 +92,104 @@ is($dashboard->Name, "inner dashboard");
is($dashboard->Privacy, 'RT::Group-' . $inner_group->Id, "correct privacy");
is($dashboard->PossibleHiddenSearches, 0, "all searches are visible");
-$m->no_warnings_ok;
-
-$m->get_ok("/Dashboards/Modify.html?id=$id");
-$m->content_lacks("inner dashboard", "no SeeGroupDashboard right");
-$m->content_contains("Permission denied");
-
-$m->warning_like(qr/Permission denied/, "got a permission denied warning");
-$user_obj->PrincipalObj->GrantRight(Right => 'SeeGroupDashboard', Object => $inner_group);
$m->get_ok("/Dashboards/Modify.html?id=$id");
$m->content_contains("inner dashboard", "we now have SeeGroupDashboard right");
$m->content_lacks("Permission denied");
-
$m->content_contains('Subscription', "Subscription link not hidden because we have SubscribeDashboard");
+
+$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");
+
+my ($group) = grep {$_->isa("RT::Group") and $_->Id == $inner_group->Id}
+ RT::Dashboard->new($currentuser)->_PrivacyObjects;
+ok($group, "Found the group in the privacy objects list");
+
+my @loading = map {ref($_)."-".$_->Id} RT::Dashboard->new($currentuser)->ObjectsForLoading;
+is_deeply(
+ \@loading,
+ ["RT::User-".$user_obj->Id, "RT::Group-".$inner_group->Id],
+ "We can load from ourselves (SeeOwnDashboard) and a group we are with SeeGroupDashboard"
+);
+
+# If you are granted SeeGroupDashboard globally, you can only see
+# dashboards in groups you are in.
+$user_obj->PrincipalObj->RevokeRight(
+ Right => 'SeeGroupDashboard',
+ Object => $inner_group,
+);
+$user_obj->PrincipalObj->GrantRight(
+ Right => 'SeeGroupDashboard',
+ Object => RT->System,
+);
+$m->get_ok("/Dashboards/index.html");
+$m->content_contains("inner dashboard", "Having SeeGroupDashboard gobally is fine for groups you are in");
+@loading = map {ref($_)."-".$_->Id} RT::Dashboard->new($currentuser)->ObjectsForLoading;
+is_deeply(
+ \@loading,
+ ["RT::User-".$user_obj->Id, "RT::Group-".$inner_group->Id],
+ "SeeGroupDashboard globally still works for groups you are in"
+);
+
+$inner_group->DeleteMember($user_obj->PrincipalObj->Id);
+ok(!$outer_group->HasMemberRecursively($user_obj->PrincipalId), "outer no longer has user recursively");
+ok(!$inner_group->HasMemberRecursively($user_obj->PrincipalId), "inner no longer has user recursively");
+$m->get_ok("/Dashboards/index.html");
+$m->content_lacks("inner dashboard", "But global SeeGroupDashboard isn't enough for other groups");
+$m->no_warnings_ok;
+@loading = map {ref($_)."-".$_->Id} RT::Dashboard->new($currentuser)->ObjectsForLoading;
+is_deeply(
+ \@loading,
+ ["RT::User-".$user_obj->Id],
+ "We only have our SeeOwnDashboard right, as we are no longer in inner"
+);
+
+# Similarly, if you're a SuperUser, you still only see dashboards for
+# groups you belong to
+$user_obj->PrincipalObj->RevokeRight(
+ Right => 'SeeGroupDashboard',
+ Object => RT->System,
+);
+$user_obj->PrincipalObj->GrantRight(
+ Right => 'SuperUser',
+ Object => RT->System,
+);
+$m->get_ok("/Dashboards/index.html");
+$m->content_lacks("inner dashboard", "Superuser can't see dashboards in groups they're not in");
+@loading = map {ref($_)."-".$_->Id} RT::Dashboard->new($currentuser)->ObjectsForLoading;
+is_deeply(
+ \@loading,
+ ["RT::User-".$user_obj->Id, "RT::System-1"],
+ "We pick up the system-level SeeDashboard right from superuser"
+);
+@loading = map {ref($_)."-".$_->Id} RT::Dashboard->new($currentuser)->ObjectsForLoading(IncludeSuperuserGroups => 0);
+is_deeply(
+ \@loading,
+ ["RT::User-".$user_obj->Id, "RT::System-1"],
+ "IncludeSuperusers only cuts out _group_ dashboard objects for loading, not user and system ones"
+);
+
+$inner_group->AddMember($user_obj->PrincipalId);
+$m->get_ok("/Dashboards/index.html");
+$m->content_contains("inner dashboard", "Superuser can see dashboards in groups they are in");
+@loading = map {ref($_)."-".$_->Id} RT::Dashboard->new($currentuser)->ObjectsForLoading;
+is_deeply(
+ \@loading,
+ ["RT::User-".$user_obj->Id, "RT::Group-".$inner_group->Id, "RT::System-1"],
+ "Becoming a member of the group makes it a possibility"
+);
+@loading = map {ref($_)."-".$_->Id} RT::Dashboard->new($currentuser)->ObjectsForLoading(IncludeSuperuserGroups => 0);
+is_deeply(
+ \@loading,
+ ["RT::User-".$user_obj->Id, "RT::System-1"],
+ "But only via superuser"
+);
+
+$m->get_ok("/Dashboards/index.html");
+$m->content_contains("inner dashboard", "The dashboards list includes superuser rights");
+$m->get_ok("/index.html");
+$m->content_lacks("inner dashboard", "But the menu skips them");
diff --git a/rt/t/web/dashboards-permissions.t b/rt/t/web/dashboards-permissions.t
index 172404289..f2e59e5cc 100644
--- a/rt/t/web/dashboards-permissions.t
+++ b/rt/t/web/dashboards-permissions.t
@@ -2,13 +2,13 @@
use strict;
use warnings;
-use RT::Test tests => 7;
+use RT::Test nodata => 1, tests => 8;
my ($baseurl, $m) = RT::Test->started_ok;
my $url = $m->rt_base_url;
# create user and queue {{{
-my $user_obj = RT::User->new($RT::SystemUser);
+my $user_obj = RT::User->new(RT->SystemUser);
my ($ok, $msg) = $user_obj->LoadOrCreateByEmail('customer@example.com');
ok($ok, 'ACL test user creation');
$user_obj->SetName('customer');
@@ -17,7 +17,7 @@ $user_obj->SetPrivileged(1);
$user_obj->PrincipalObj->GrantRight(Right => 'ModifySelf');
my $currentuser = RT::CurrentUser->new($user_obj);
-my $queue = RT::Queue->new($RT::SystemUser);
+my $queue = RT::Queue->new(RT->SystemUser);
$queue->Create(Name => 'SearchQueue'.$$);
$user_obj->PrincipalObj->GrantRight(Right => $_, Object => $queue)
@@ -25,13 +25,11 @@ $user_obj->PrincipalObj->GrantRight(Right => $_, Object => $queue)
$user_obj->PrincipalObj->GrantRight(Right => $_, Object => $RT::System)
for qw/SubscribeDashboard CreateOwnDashboard SeeOwnDashboard ModifyOwnDashboard DeleteOwnDashboard/;
-# }}}
ok $m->login(customer => 'customer'), "logged in";
-$m->get_ok("$url/Dashboards");
-$m->follow_link_ok({text => "New"});
+$m->follow_link_ok( {id => 'home-dashboard_create'});
$m->form_name('ModifyDashboard');
is_deeply([$m->current_form->find_input('Privacy')->possible_values], ["RT::User-" . $user_obj->Id], "the only selectable privacy is user");
$m->content_lacks('Delete', "Delete button hidden because we are creating");
diff --git a/rt/t/web/dashboards-search-cache.t b/rt/t/web/dashboards-search-cache.t
new file mode 100644
index 000000000..ad2a96969
--- /dev/null
+++ b/rt/t/web/dashboards-search-cache.t
@@ -0,0 +1,73 @@
+#!/usr/bin/perl -w
+use strict;
+
+use RT::Test tests => 20;
+my ($baseurl, $m) = RT::Test->started_ok;
+
+my $url = $m->rt_base_url;
+
+ok($m->login, 'logged in');
+
+# create a search
+$m->follow_link_ok({text => 'Tickets'}, 'to query builder');
+$m->form_name('BuildQuery');
+
+$m->field(ValueOfid => 10 );
+$m->click('AddClause');
+$m->text_contains( 'id < 10', 'added new clause');
+
+$m->form_name('BuildQuery');
+$m->field(SavedSearchDescription => 'Original Name');
+$m->click('SavedSearchSave');
+
+# create a dashboard
+$m->get_ok("$url/Dashboards/Modify.html?Create=1");
+$m->form_name('ModifyDashboard');
+$m->field('Name' => 'cachey dashboard');
+$m->click_button(value => 'Create');
+$m->text_contains('Saved dashboard cachey dashboard');
+
+my ($dashboard_id) = $m->content =~ /name="id" value="(\d+)"/;
+ok($dashboard_id, "got an ID, $dashboard_id");
+
+# add the search to the dashboard
+$m->follow_link_ok({text => 'Content'});
+my $form = $m->form_name('Dashboard-Searches-body');
+my @input = $form->find_input('Searches-body-Available');
+my ($search) =
+ map { ( $_->possible_values )[1] }
+ grep { ( $_->value_names )[1] =~ /Saved Search: Original Name/ } @input;
+$form->value('Searches-body-Available' => $search );
+$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->form_name('SubscribeDashboard');
+$m->click_button(name => 'Save');
+$m->text_contains('Subscribed to dashboard cachey dashboard');
+
+# rename the search
+$m->follow_link_ok({text => 'Tickets'}, 'to query builder');
+$form = $m->form_name('BuildQuery');
+@input = $form->find_input('SavedSearchLoad');
+($search) =
+ map { ( $_->possible_values )[1] }
+ grep { ( $_->value_names )[1] =~ /Original Name/ } @input;
+$form->value('SavedSearchLoad' => $search );
+$m->click_button(value => 'Load');
+$m->text_contains('Loaded saved search "Original Name"');
+
+$m->form_name('BuildQuery');
+$m->field('SavedSearchDescription' => 'New Name');
+$m->click_button(value => 'Update');
+$m->text_contains('Updated saved search "New Name"');
+
+# 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
+}
diff --git a/rt/t/web/gnupg-headers.t b/rt/t/web/gnupg-headers.t
new file mode 100644
index 000000000..88b3ab9c2
--- /dev/null
+++ b/rt/t/web/gnupg-headers.t
@@ -0,0 +1,53 @@
+#!/usr/bin/perl -w
+use strict;
+
+use RT::Test::GnuPG
+ tests => 15,
+ gnupg_options => {
+ passphrase => 'recipient',
+ 'trust-model' => 'always',
+ };
+
+RT::Test->import_gnupg_key( 'recipient@example.com', 'public' );
+RT::Test->import_gnupg_key( 'general@example.com', 'secret' );
+
+ok( my $user = RT::User->new( RT->SystemUser ) );
+ok( $user->Load('root'), "Loaded user 'root'" );
+$user->SetEmailAddress('recipient@example.com');
+
+my $queue = RT::Test->load_or_create_queue(
+ Name => 'General',
+ CorrespondAddress => 'general@example.com',
+);
+ok $queue && $queue->id, 'loaded or created queue';
+my $qid = $queue->id;
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in';
+
+diag "test with Encrypt and Sign disabled";
+
+$m->goto_create_ticket($queue);
+$m->form_name('TicketCreate');
+$m->field( 'Subject', 'Signing test' );
+$m->field( 'Content', 'Some other content' );
+$m->submit;
+$m->content_like( qr/Ticket \d+ created/i, 'created the ticket' );
+$m->follow_link_ok( { text => 'with headers' } );
+$m->content_contains('X-RT-Encrypt: 0');
+$m->content_contains('X-RT-Sign: 0');
+
+diag "test with Encrypt and Sign enabled";
+
+$m->goto_create_ticket($queue);
+$m->form_name('TicketCreate');
+$m->field( 'Subject', 'Signing test' );
+$m->field( 'Content', 'Some other content' );
+$m->tick( 'Encrypt', 1 );
+$m->tick( 'Sign', 1 );
+$m->submit;
+$m->content_like( qr/Ticket \d+ created/i, 'created the ticket' );
+$m->follow_link_ok( { text => 'with headers' } );
+$m->content_contains('X-RT-Encrypt: 1');
+$m->content_contains('X-RT-Sign: 1');
+
diff --git a/rt/t/web/gnupg-select-keys-on-create.t b/rt/t/web/gnupg-select-keys-on-create.t
index deee6b291..cf27e48a7 100644
--- a/rt/t/web/gnupg-select-keys-on-create.t
+++ b/rt/t/web/gnupg-select-keys-on-create.t
@@ -2,34 +2,8 @@
use strict;
use warnings;
-use RT::Test tests => 60;
-
-plan skip_all => 'GnuPG required.'
- unless eval 'use GnuPG::Interface; 1';
-plan skip_all => 'gpg executable is required.'
- unless RT::Test->find_executable('gpg');
-
-
+use RT::Test::GnuPG tests => 79, gnupg_options => { passphrase => 'rt-test' };
use RT::Action::SendEmail;
-use File::Temp qw(tempdir);
-
-RT::Test->set_mail_catcher;
-
-use_ok('RT::Crypt::GnuPG');
-
-RT->Config->Set( GnuPG =>
- Enable => 1,
- OutgoingMessagesFormat => 'RFC',
-);
-
-RT->Config->Set( GnuPGOptions =>
- homedir => scalar tempdir( CLEANUP => 0 ),
- passphrase => 'rt-test',
- 'no-permission-warning' => undef,
-);
-diag "GnuPG --homedir ". RT->Config->Get('GnuPGOptions')->{'homedir'} if $ENV{TEST_VERBOSE};
-
-RT->Config->Set( 'MailPlugins' => 'Auth::MailFrom', 'Auth::GnuPG' );
my $queue = RT::Test->load_or_create_queue(
Name => 'Regression',
@@ -38,28 +12,24 @@ my $queue = RT::Test->load_or_create_queue(
);
ok $queue && $queue->id, 'loaded or created queue';
-RT::Test->set_rights(
- Principal => 'Everyone',
- Right => ['CreateTicket', 'ShowTicket', 'SeeQueue', 'ReplyToTicket', 'ModifyTicket'],
-);
-
my ($baseurl, $m) = RT::Test->started_ok;
ok $m->login, 'logged in';
-diag "check that signing doesn't work if there is no key" if $ENV{TEST_VERBOSE};
+diag "check that signing doesn't work if there is no key";
{
RT::Test->clean_caught_mails;
ok $m->goto_create_ticket( $queue ), "UI -> create ticket";
- $m->form_number(3);
+ $m->form_name('TicketCreate');
$m->tick( Sign => 1 );
$m->field( Requestors => 'rt-test@example.com' );
$m->field( Content => 'Some content' );
$m->submit;
- $m->content_like(
- qr/unable to sign outgoing email messages/i,
+ $m->content_contains(
+ 'unable to sign outgoing email messages',
'problems with passphrase'
);
+ $m->warning_like(qr/signing failed: secret key not available/);
my @mail = RT::Test->fetch_caught_mails;
ok !@mail, 'there are no outgoing emails';
@@ -72,33 +42,36 @@ diag "check that signing doesn't work if there is no key" if $ENV{TEST_VERBOSE};
is $res{'info'}[0]{'TrustTerse'}, 'ultimate', 'ultimately trusted key';
}
-diag "check that things don't work if there is no key" if $ENV{TEST_VERBOSE};
+diag "check that things don't work if there is no key";
{
RT::Test->clean_caught_mails;
ok $m->goto_create_ticket( $queue ), "UI -> create ticket";
- $m->form_number(3);
+ $m->form_name('TicketCreate');
$m->tick( Encrypt => 1 );
$m->field( Requestors => 'rt-test@example.com' );
$m->field( Content => 'Some content' );
$m->submit;
- $m->content_like(
- qr/You are going to encrypt outgoing email messages/i,
+ $m->content_contains(
+ 'You are going to encrypt outgoing email messages',
'problems with keys'
);
- $m->content_like(
- qr/There is no key suitable for encryption/i,
+ $m->content_contains(
+ 'There is no key suitable for encryption',
'problems with keys'
);
- my $form = $m->form_number(3);
+ my $form = $m->form_name('TicketCreate');
ok !$form->find_input( 'UseKey-rt-test@example.com' ), 'no key selector';
my @mail = RT::Test->fetch_caught_mails;
ok !@mail, 'there are no outgoing emails';
+
+ $m->next_warning_like(qr/public key not found/) for 1 .. 4;
+ $m->no_leftover_warnings_ok;
}
-diag "import first key of rt-test\@example.com" if $ENV{TEST_VERBOSE};
+diag "import first key of rt-test\@example.com";
my $fpr1 = '';
{
RT::Test->import_gnupg_key('rt-test@example.com', 'public');
@@ -107,45 +80,47 @@ my $fpr1 = '';
$fpr1 = $res{'info'}[0]{'Fingerprint'};
}
-diag "check that things still doesn't work if key is not trusted" if $ENV{TEST_VERBOSE};
+diag "check that things still doesn't work if key is not trusted";
{
RT::Test->clean_caught_mails;
ok $m->goto_create_ticket( $queue ), "UI -> create ticket";
- $m->form_number(3);
+ $m->form_name('TicketCreate');
$m->tick( Encrypt => 1 );
$m->field( Requestors => 'rt-test@example.com' );
$m->field( Content => 'Some content' );
$m->submit;
- $m->content_like(
- qr/You are going to encrypt outgoing email messages/i,
+ $m->content_contains(
+ 'You are going to encrypt outgoing email messages',
'problems with keys'
);
- $m->content_like(
- qr/There is one suitable key, but trust level is not set/i,
+ $m->content_contains(
+ 'There is one suitable key, but trust level is not set',
'problems with keys'
);
- my $form = $m->form_number(3);
+ my $form = $m->form_name('TicketCreate');
ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector';
is scalar $input->possible_values, 1, 'one option';
$m->select( 'UseKey-rt-test@example.com' => $fpr1 );
$m->submit;
- $m->content_like(
- qr/You are going to encrypt outgoing email messages/i,
+ $m->content_contains(
+ 'You are going to encrypt outgoing email messages',
'problems with keys'
);
- $m->content_like(
- qr/Selected key either is not trusted/i,
+ $m->content_contains(
+ 'Selected key either is not trusted',
'problems with keys'
);
my @mail = RT::Test->fetch_caught_mails;
ok !@mail, 'there are no outgoing emails';
+
+ $m->no_warnings_ok;
}
-diag "import a second key of rt-test\@example.com" if $ENV{TEST_VERBOSE};
+diag "import a second key of rt-test\@example.com";
my $fpr2 = '';
{
RT::Test->import_gnupg_key('rt-test@example.com.2', 'public');
@@ -154,42 +129,44 @@ my $fpr2 = '';
$fpr2 = $res{'info'}[2]{'Fingerprint'};
}
-diag "check that things still doesn't work if two keys are not trusted" if $ENV{TEST_VERBOSE};
+diag "check that things still doesn't work if two keys are not trusted";
{
RT::Test->clean_caught_mails;
ok $m->goto_create_ticket( $queue ), "UI -> create ticket";
- $m->form_number(3);
+ $m->form_name('TicketCreate');
$m->tick( Encrypt => 1 );
$m->field( Requestors => 'rt-test@example.com' );
$m->field( Content => 'Some content' );
$m->submit;
- $m->content_like(
- qr/You are going to encrypt outgoing email messages/i,
+ $m->content_contains(
+ 'You are going to encrypt outgoing email messages',
'problems with keys'
);
- $m->content_like(
- qr/There are several keys suitable for encryption/i,
+ $m->content_contains(
+ 'There are several keys suitable for encryption',
'problems with keys'
);
- my $form = $m->form_number(3);
+ my $form = $m->form_name('TicketCreate');
ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector';
is scalar $input->possible_values, 2, 'two options';
$m->select( 'UseKey-rt-test@example.com' => $fpr1 );
$m->submit;
- $m->content_like(
- qr/You are going to encrypt outgoing email messages/i,
+ $m->content_contains(
+ 'You are going to encrypt outgoing email messages',
'problems with keys'
);
- $m->content_like(
- qr/Selected key either is not trusted/i,
+ $m->content_contains(
+ 'Selected key either is not trusted',
'problems with keys'
);
my @mail = RT::Test->fetch_caught_mails;
ok !@mail, 'there are no outgoing emails';
+
+ $m->no_warnings_ok;
}
{
@@ -204,26 +181,28 @@ diag "check that we see key selector even if only one key is trusted but there a
RT::Test->clean_caught_mails;
ok $m->goto_create_ticket( $queue ), "UI -> create ticket";
- $m->form_number(3);
+ $m->form_name('TicketCreate');
$m->tick( Encrypt => 1 );
$m->field( Requestors => 'rt-test@example.com' );
$m->field( Content => 'Some content' );
$m->submit;
- $m->content_like(
- qr/You are going to encrypt outgoing email messages/i,
+ $m->content_contains(
+ 'You are going to encrypt outgoing email messages',
'problems with keys'
);
- $m->content_like(
- qr/There are several keys suitable for encryption/i,
+ $m->content_contains(
+ 'There are several keys suitable for encryption',
'problems with keys'
);
- my $form = $m->form_number(3);
+ my $form = $m->form_name('TicketCreate');
ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector';
is scalar $input->possible_values, 2, 'two options';
my @mail = RT::Test->fetch_caught_mails;
ok !@mail, 'there are no outgoing emails';
+
+ $m->no_warnings_ok;
}
diag "check that key selector works and we can select trusted key";
@@ -231,21 +210,21 @@ diag "check that key selector works and we can select trusted key";
RT::Test->clean_caught_mails;
ok $m->goto_create_ticket( $queue ), "UI -> create ticket";
- $m->form_number(3);
+ $m->form_name('TicketCreate');
$m->tick( Encrypt => 1 );
$m->field( Requestors => 'rt-test@example.com' );
$m->field( Content => 'Some content' );
$m->submit;
- $m->content_like(
- qr/You are going to encrypt outgoing email messages/i,
+ $m->content_contains(
+ 'You are going to encrypt outgoing email messages',
'problems with keys'
);
- $m->content_like(
- qr/There are several keys suitable for encryption/i,
+ $m->content_contains(
+ 'There are several keys suitable for encryption',
'problems with keys'
);
- my $form = $m->form_number(3);
+ my $form = $m->form_name('TicketCreate');
ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector';
is scalar $input->possible_values, 2, 'two options';
@@ -256,6 +235,8 @@ diag "check that key selector works and we can select trusted key";
my @mail = RT::Test->fetch_caught_mails;
ok @mail, 'there are some emails';
check_text_emails( { Encrypt => 1 }, @mail );
+
+ $m->no_warnings_ok;
}
diag "check encrypting of attachments";
@@ -263,22 +244,22 @@ diag "check encrypting of attachments";
RT::Test->clean_caught_mails;
ok $m->goto_create_ticket( $queue ), "UI -> create ticket";
- $m->form_number(3);
+ $m->form_name('TicketCreate');
$m->tick( Encrypt => 1 );
$m->field( Requestors => 'rt-test@example.com' );
$m->field( Content => 'Some content' );
$m->field( Attach => $0 );
$m->submit;
- $m->content_like(
- qr/You are going to encrypt outgoing email messages/i,
+ $m->content_contains(
+ 'You are going to encrypt outgoing email messages',
'problems with keys'
);
- $m->content_like(
- qr/There are several keys suitable for encryption/i,
+ $m->content_contains(
+ 'There are several keys suitable for encryption',
'problems with keys'
);
- my $form = $m->form_number(3);
+ my $form = $m->form_name('TicketCreate');
ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector';
is scalar $input->possible_values, 2, 'two options';
@@ -289,37 +270,7 @@ diag "check encrypting of attachments";
my @mail = RT::Test->fetch_caught_mails;
ok @mail, 'there are some emails';
check_text_emails( { Encrypt => 1, Attachment => 1 }, @mail );
-}
-sub check_text_emails {
- my %args = %{ shift @_ };
- my @mail = @_;
-
- ok scalar @mail, "got some mail";
- for my $mail (@mail) {
- for my $type ('email', 'attachment') {
- next if $type eq 'attachment' && !$args{'Attachment'};
-
- my $content = $type eq 'email'
- ? "Some content"
- : "Attachment content";
-
- if ( $args{'Encrypt'} ) {
- unlike $mail, qr/$content/, "outgoing $type was encrypted";
- } else {
- like $mail, qr/$content/, "outgoing $type was not encrypted";
- }
-
- next unless $type eq 'email';
-
- if ( $args{'Sign'} && $args{'Encrypt'} ) {
- like $mail, qr/BEGIN PGP MESSAGE/, 'outgoing email was signed';
- } elsif ( $args{'Sign'} ) {
- like $mail, qr/SIGNATURE/, 'outgoing email was signed';
- } else {
- unlike $mail, qr/SIGNATURE/, 'outgoing email was not signed';
- }
- }
- }
+ $m->no_warnings_ok;
}
diff --git a/rt/t/web/gnupg-select-keys-on-update.t b/rt/t/web/gnupg-select-keys-on-update.t
index 76817ddf2..4842dcd54 100644
--- a/rt/t/web/gnupg-select-keys-on-update.t
+++ b/rt/t/web/gnupg-select-keys-on-update.t
@@ -2,34 +2,9 @@
use strict;
use warnings;
-use RT::Test tests => 68;
-
-plan skip_all => 'GnuPG required.'
- unless eval 'use GnuPG::Interface; 1';
-plan skip_all => 'gpg executable is required.'
- unless RT::Test->find_executable('gpg');
-
+use RT::Test::GnuPG tests => 86, gnupg_options => { passphrase => 'rt-test' };
use RT::Action::SendEmail;
-use File::Temp qw(tempdir);
-
-RT::Test->set_mail_catcher;
-
-use_ok('RT::Crypt::GnuPG');
-
-RT->Config->Set( GnuPG =>
- Enable => 1,
- OutgoingMessagesFormat => 'RFC',
-);
-
-RT->Config->Set( GnuPGOptions =>
- homedir => scalar tempdir( CLEANUP => 0 ),
- passphrase => 'rt-test',
- 'no-permission-warning' => undef,
-);
-diag "GnuPG --homedir ". RT->Config->Get('GnuPGOptions')->{'homedir'} if $ENV{TEST_VERBOSE};
-
-RT->Config->Set( 'MailPlugins' => 'Auth::MailFrom', 'Auth::GnuPG' );
my $queue = RT::Test->load_or_create_queue(
Name => 'Regression',
@@ -38,18 +13,13 @@ my $queue = RT::Test->load_or_create_queue(
);
ok $queue && $queue->id, 'loaded or created queue';
-RT::Test->set_rights(
- Principal => 'Everyone',
- Right => ['CreateTicket', 'ShowTicket', 'SeeQueue', 'ReplyToTicket', 'ModifyTicket'],
-);
-
my ($baseurl, $m) = RT::Test->started_ok;
ok $m->login, 'logged in';
my $tid;
{
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ my $ticket = RT::Ticket->new( RT->SystemUser );
($tid) = $ticket->Create(
Subject => 'test',
Queue => $queue->id,
@@ -57,24 +27,27 @@ my $tid;
ok $tid, 'ticket created';
}
-diag "check that signing doesn't work if there is no key" if $ENV{TEST_VERBOSE};
+diag "check that signing doesn't work if there is no key";
{
RT::Test->clean_caught_mails;
ok $m->goto_ticket( $tid ), "UI -> ticket #$tid";
$m->follow_link_ok( { text => 'Reply' }, 'ticket -> reply' );
- $m->form_number(3);
+ $m->form_name('TicketUpdate');
$m->tick( Sign => 1 );
$m->field( UpdateCc => 'rt-test@example.com' );
$m->field( UpdateContent => 'Some content' );
$m->click('SubmitTicket');
- $m->content_like(
- qr/unable to sign outgoing email messages/i,
+ $m->content_contains(
+ 'unable to sign outgoing email messages',
'problems with passphrase'
);
my @mail = RT::Test->fetch_caught_mails;
ok !@mail, 'there are no outgoing emails';
+
+ $m->next_warning_like(qr/secret key not available/);
+ $m->no_leftover_warnings_ok;
}
{
@@ -84,35 +57,38 @@ diag "check that signing doesn't work if there is no key" if $ENV{TEST_VERBOSE};
is $res{'info'}[0]{'TrustTerse'}, 'ultimate', 'ultimately trusted key';
}
-diag "check that things don't work if there is no key" if $ENV{TEST_VERBOSE};
+diag "check that things don't work if there is no key";
{
RT::Test->clean_caught_mails;
ok $m->goto_ticket( $tid ), "UI -> ticket #$tid";
$m->follow_link_ok( { text => 'Reply' }, 'ticket -> reply' );
- $m->form_number(3);
+ $m->form_name('TicketUpdate');
$m->tick( Encrypt => 1 );
$m->field( UpdateCc => 'rt-test@example.com' );
$m->field( UpdateContent => 'Some content' );
$m->click('SubmitTicket');
- $m->content_like(
- qr/You are going to encrypt outgoing email messages/i,
+ $m->content_contains(
+ 'You are going to encrypt outgoing email messages',
'problems with keys'
);
- $m->content_like(
- qr/There is no key suitable for encryption/i,
+ $m->content_contains(
+ 'There is no key suitable for encryption',
'problems with keys'
);
- my $form = $m->form_number(3);
+ my $form = $m->form_name('TicketUpdate');
ok !$form->find_input( 'UseKey-rt-test@example.com' ), 'no key selector';
my @mail = RT::Test->fetch_caught_mails;
ok !@mail, 'there are no outgoing emails';
+
+ $m->next_warning_like(qr/public key not found/) for 1 .. 2;
+ $m->no_leftover_warnings_ok;
}
-diag "import first key of rt-test\@example.com" if $ENV{TEST_VERBOSE};
+diag "import first key of rt-test\@example.com";
my $fpr1 = '';
{
RT::Test->import_gnupg_key('rt-test@example.com', 'public');
@@ -121,46 +97,48 @@ my $fpr1 = '';
$fpr1 = $res{'info'}[0]{'Fingerprint'};
}
-diag "check that things still doesn't work if key is not trusted" if $ENV{TEST_VERBOSE};
+diag "check that things still doesn't work if key is not trusted";
{
RT::Test->clean_caught_mails;
ok $m->goto_ticket( $tid ), "UI -> ticket #$tid";
$m->follow_link_ok( { text => 'Reply' }, 'ticket -> reply' );
- $m->form_number(3);
+ $m->form_name('TicketUpdate');
$m->tick( Encrypt => 1 );
$m->field( UpdateCc => 'rt-test@example.com' );
$m->field( UpdateContent => 'Some content' );
$m->click('SubmitTicket');
- $m->content_like(
- qr/You are going to encrypt outgoing email messages/i,
+ $m->content_contains(
+ 'You are going to encrypt outgoing email messages',
'problems with keys'
);
- $m->content_like(
- qr/There is one suitable key, but trust level is not set/i,
+ $m->content_contains(
+ 'There is one suitable key, but trust level is not set',
'problems with keys'
);
- my $form = $m->form_number(3);
+ my $form = $m->form_name('TicketUpdate');
ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector';
is scalar $input->possible_values, 1, 'one option';
$m->select( 'UseKey-rt-test@example.com' => $fpr1 );
$m->click('SubmitTicket');
- $m->content_like(
- qr/You are going to encrypt outgoing email messages/i,
+ $m->content_contains(
+ 'You are going to encrypt outgoing email messages',
'problems with keys'
);
- $m->content_like(
- qr/Selected key either is not trusted/i,
+ $m->content_contains(
+ 'Selected key either is not trusted',
'problems with keys'
);
my @mail = RT::Test->fetch_caught_mails;
ok !@mail, 'there are no outgoing emails';
+
+ $m->no_warnings_ok;
}
-diag "import a second key of rt-test\@example.com" if $ENV{TEST_VERBOSE};
+diag "import a second key of rt-test\@example.com";
my $fpr2 = '';
{
RT::Test->import_gnupg_key('rt-test@example.com.2', 'public');
@@ -169,43 +147,45 @@ my $fpr2 = '';
$fpr2 = $res{'info'}[2]{'Fingerprint'};
}
-diag "check that things still doesn't work if two keys are not trusted" if $ENV{TEST_VERBOSE};
+diag "check that things still doesn't work if two keys are not trusted";
{
RT::Test->clean_caught_mails;
ok $m->goto_ticket( $tid ), "UI -> ticket #$tid";
$m->follow_link_ok( { text => 'Reply' }, 'ticket -> reply' );
- $m->form_number(3);
+ $m->form_name('TicketUpdate');
$m->tick( Encrypt => 1 );
$m->field( UpdateCc => 'rt-test@example.com' );
$m->field( UpdateContent => 'Some content' );
$m->click('SubmitTicket');
- $m->content_like(
- qr/You are going to encrypt outgoing email messages/i,
+ $m->content_contains(
+ 'You are going to encrypt outgoing email messages',
'problems with keys'
);
- $m->content_like(
- qr/There are several keys suitable for encryption/i,
+ $m->content_contains(
+ 'There are several keys suitable for encryption',
'problems with keys'
);
- my $form = $m->form_number(3);
+ my $form = $m->form_name('TicketUpdate');
ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector';
is scalar $input->possible_values, 2, 'two options';
$m->select( 'UseKey-rt-test@example.com' => $fpr1 );
$m->click('SubmitTicket');
- $m->content_like(
- qr/You are going to encrypt outgoing email messages/i,
+ $m->content_contains(
+ 'You are going to encrypt outgoing email messages',
'problems with keys'
);
- $m->content_like(
- qr/Selected key either is not trusted/i,
+ $m->content_contains(
+ 'Selected key either is not trusted',
'problems with keys'
);
my @mail = RT::Test->fetch_caught_mails;
ok !@mail, 'there are no outgoing emails';
+
+ $m->no_warnings_ok;
}
{
@@ -215,130 +195,103 @@ diag "check that things still doesn't work if two keys are not trusted" if $ENV{
is $res{'info'}[1]{'TrustLevel'}, 0, 'is not trusted key';
}
-diag "check that we see key selector even if only one key is trusted but there are more keys" if $ENV{TEST_VERBOSE};
+diag "check that we see key selector even if only one key is trusted but there are more keys";
{
RT::Test->clean_caught_mails;
ok $m->goto_ticket( $tid ), "UI -> ticket #$tid";
$m->follow_link_ok( { text => 'Reply' }, 'ticket -> reply' );
- $m->form_number(3);
+ $m->form_name('TicketUpdate');
$m->tick( Encrypt => 1 );
$m->field( UpdateCc => 'rt-test@example.com' );
$m->field( UpdateContent => 'Some content' );
$m->click('SubmitTicket');
- $m->content_like(
- qr/You are going to encrypt outgoing email messages/i,
+ $m->content_contains(
+ 'You are going to encrypt outgoing email messages',
'problems with keys'
);
- $m->content_like(
- qr/There are several keys suitable for encryption/i,
+ $m->content_contains(
+ 'There are several keys suitable for encryption',
'problems with keys'
);
- my $form = $m->form_number(3);
+ my $form = $m->form_name('TicketUpdate');
ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector';
is scalar $input->possible_values, 2, 'two options';
my @mail = RT::Test->fetch_caught_mails;
ok !@mail, 'there are no outgoing emails';
+
+ $m->no_warnings_ok;
}
-diag "check that key selector works and we can select trusted key" if $ENV{TEST_VERBOSE};
+diag "check that key selector works and we can select trusted key";
{
RT::Test->clean_caught_mails;
ok $m->goto_ticket( $tid ), "UI -> ticket #$tid";
$m->follow_link_ok( { text => 'Reply' }, 'ticket -> reply' );
- $m->form_number(3);
+ $m->form_name('TicketUpdate');
$m->tick( Encrypt => 1 );
$m->field( UpdateCc => 'rt-test@example.com' );
$m->field( UpdateContent => 'Some content' );
$m->click('SubmitTicket');
- $m->content_like(
- qr/You are going to encrypt outgoing email messages/i,
+ $m->content_contains(
+ 'You are going to encrypt outgoing email messages',
'problems with keys'
);
- $m->content_like(
- qr/There are several keys suitable for encryption/i,
+ $m->content_contains(
+ 'There are several keys suitable for encryption',
'problems with keys'
);
- my $form = $m->form_number(3);
+ my $form = $m->form_name('TicketUpdate');
ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector';
is scalar $input->possible_values, 2, 'two options';
$m->select( 'UseKey-rt-test@example.com' => $fpr1 );
$m->click('SubmitTicket');
- $m->content_like( qr/Message recorded/i, 'Message recorded' );
+ $m->content_contains('Message recorded', 'Message recorded' );
my @mail = RT::Test->fetch_caught_mails;
ok @mail, 'there are some emails';
check_text_emails( { Encrypt => 1 }, @mail );
+
+ $m->no_warnings_ok;
}
-diag "check encrypting of attachments" if $ENV{TEST_VERBOSE};
+diag "check encrypting of attachments";
{
RT::Test->clean_caught_mails;
ok $m->goto_ticket( $tid ), "UI -> ticket #$tid";
$m->follow_link_ok( { text => 'Reply' }, 'ticket -> reply' );
- $m->form_number(3);
+ $m->form_name('TicketUpdate');
$m->tick( Encrypt => 1 );
$m->field( UpdateCc => 'rt-test@example.com' );
$m->field( UpdateContent => 'Some content' );
$m->field( Attach => $0 );
$m->click('SubmitTicket');
- $m->content_like(
- qr/You are going to encrypt outgoing email messages/i,
+ $m->content_contains(
+ 'You are going to encrypt outgoing email messages',
'problems with keys'
);
- $m->content_like(
- qr/There are several keys suitable for encryption/i,
+ $m->content_contains(
+ 'There are several keys suitable for encryption',
'problems with keys'
);
- my $form = $m->form_number(3);
+ my $form = $m->form_name('TicketUpdate');
ok my $input = $form->find_input( 'UseKey-rt-test@example.com' ), 'found key selector';
is scalar $input->possible_values, 2, 'two options';
$m->select( 'UseKey-rt-test@example.com' => $fpr1 );
$m->click('SubmitTicket');
- $m->content_like( qr/Message recorded/i, 'Message recorded' );
+ $m->content_contains('Message recorded', 'Message recorded' );
my @mail = RT::Test->fetch_caught_mails;
ok @mail, 'there are some emails';
check_text_emails( { Encrypt => 1, Attachment => 1 }, @mail );
-}
-sub check_text_emails {
- my %args = %{ shift @_ };
- my @mail = @_;
-
- ok scalar @mail, "got some mail";
- for my $mail (@mail) {
- for my $type ('email', 'attachment') {
- next if $type eq 'attachment' && !$args{'Attachment'};
-
- my $content = $type eq 'email'
- ? "Some content"
- : "Attachment content";
-
- if ( $args{'Encrypt'} ) {
- unlike $mail, qr/$content/, "outgoing $type was encrypted";
- } else {
- like $mail, qr/$content/, "outgoing $type was not encrypted";
- }
-
- next unless $type eq 'email';
-
- if ( $args{'Sign'} && $args{'Encrypt'} ) {
- like $mail, qr/BEGIN PGP MESSAGE/, 'outgoing email was signed';
- } elsif ( $args{'Sign'} ) {
- like $mail, qr/SIGNATURE/, 'outgoing email was signed';
- } else {
- unlike $mail, qr/SIGNATURE/, 'outgoing email was not signed';
- }
- }
- }
+ $m->no_warnings_ok;
}
-
diff --git a/rt/t/web/gnupg-tickyboxes.t b/rt/t/web/gnupg-tickyboxes.t
new file mode 100644
index 000000000..944539758
--- /dev/null
+++ b/rt/t/web/gnupg-tickyboxes.t
@@ -0,0 +1,84 @@
+#!/usr/bin/perl -w
+use strict;
+use warnings;
+
+use RT::Test::GnuPG tests => 22, gnupg_options => { passphrase => 'rt-test' };
+
+use RT::Action::SendEmail;
+
+RT::Test->import_gnupg_key('rt-recipient@example.com');
+RT::Test->import_gnupg_key('rt-test@example.com', 'public');
+
+my $queue = RT::Test->load_or_create_queue(
+ Name => 'Regression',
+ CorrespondAddress => 'rt-recipient@example.com',
+ CommentAddress => 'rt-recipient@example.com',
+);
+ok $queue && $queue->id, 'loaded or created queue';
+
+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";
+{
+ foreach my $variant ( @variants ) {
+ set_queue_crypt_options( $queue => %$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($queue);
+
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ my ($id) = $ticket->Create(
+ Subject => 'test',
+ Queue => $queue->id,
+ Requestor => 'rt-test@example.com',
+ );
+ ok $id, 'ticket created';
+
+ foreach my $variant ( @variants ) {
+ set_queue_crypt_options( $queue => %$variant );
+ $m->get( $m->rt_base_url . "/Ticket/Update.html?Action=Respond&id=$id" );
+ $m->form_name('TicketUpdate');
+ 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";
+ }
+ }
+}
+
+
+
diff --git a/rt/t/web/googleish_search.t b/rt/t/web/googleish_search.t
new file mode 100644
index 000000000..e2a4e9116
--- /dev/null
+++ b/rt/t/web/googleish_search.t
@@ -0,0 +1,219 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+
+use RT::Test tests => 96, config => 'Set( %FullTextSearch, Enable => 1, Indexed => 0 );';
+my ($baseurl, $m) = RT::Test->started_ok;
+my $url = $m->rt_base_url;
+
+my $queue = RT::Queue->new($RT::SystemUser);
+$queue->Create( Name => 'other' );
+ok( $queue->id, 'created queue other');
+
+my $two_words_queue = RT::Test->load_or_create_queue(
+ Name => 'Two Words',
+);
+ok $two_words_queue && $two_words_queue->id, 'loaded or created a queue';
+
+
+{
+ my $tickets = RT::Tickets->new( RT->SystemUser );
+ 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(
+ TicketsObj => $tickets,
+ Argument => '',
+ );
+ is $parser->QueryToSQL("foo"), "$active AND ( Subject LIKE 'foo' )", "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("foo bar"),
+ "$active AND ( Subject LIKE 'foo' AND Subject LIKE 'bar' )",
+ "correct parsing";
+ is $parser->QueryToSQL("'foo bar'"),
+ "$active AND ( Subject LIKE 'foo bar' )",
+ "correct parsing";
+
+ is $parser->QueryToSQL("'foo \\' bar'"),
+ "$active AND ( Subject LIKE 'foo \\' bar' )",
+ "correct parsing";
+ is $parser->QueryToSQL('"foo \' bar"'),
+ "$active AND ( Subject LIKE 'foo \\' bar' )",
+ "correct parsing";
+ is $parser->QueryToSQL('"\f\o\o"'),
+ "$active AND ( Subject LIKE '\\\\f\\\\o\\\\o' )",
+ "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("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("owner:me"), "( Owner.id = '__CurrentUser__' ) AND $active", "correct parsing";
+ is $parser->QueryToSQL("owner:'me'"), "( Owner = 'me' ) AND $active", "correct parsing";
+
+ is $parser->QueryToSQL("resolved me"), "( Owner.id = '__CurrentUser__' ) AND ( Status = 'resolved' )", "correct parsing";
+ is $parser->QueryToSQL("resolved active me"), "( Owner.id = '__CurrentUser__' ) AND ( Status = 'resolved' OR Status = 'new' OR Status = 'open' OR Status = 'stalled' )", "correct parsing";
+ is $parser->QueryToSQL("status:active"), $active, "Explicit active search";
+ is $parser->QueryToSQL("status:'active'"), "( Status = 'active' )", "Quoting active makes it the actual word";
+ is $parser->QueryToSQL("inactive me"), "( Owner.id = '__CurrentUser__' ) AND $inactive", "correct parsing";
+
+ is $parser->QueryToSQL("cf.Foo:bar"), "( 'CF.{Foo}' LIKE 'bar' ) AND $active", "correct parsing of CFs";
+ is $parser->QueryToSQL(q{cf."don't foo?":'bar n\\' baz'}), qq/( 'CF.{don\\'t foo?}' LIKE 'bar n\\' baz' ) AND $active/, "correct parsing of CFs with quotes";
+}
+
+my $ticket_found_1 = RT::Ticket->new($RT::SystemUser);
+my $ticket_found_2 = RT::Ticket->new($RT::SystemUser);
+my $ticket_not_found = RT::Ticket->new($RT::SystemUser);
+
+$ticket_found_1->Create(
+ Subject => 'base ticket 1'.$$,
+ Queue => 'general',
+ Owner => 'root',
+ Requestor => 'customsearch@localhost',
+ Content => 'this is base ticket 1',
+);
+ok( $ticket_found_1->id, 'created ticket for custom search');
+
+
+$ticket_found_2->Create(
+ Subject => 'base ticket 2'.$$,
+ Queue => 'general',
+ Owner => 'root',
+ Requestor => 'customsearch@localhost',
+ Content => 'this is base ticket 2',
+);
+ok( $ticket_found_2->id, 'created ticket for custom search');
+
+$ticket_not_found = RT::Ticket->new($RT::SystemUser);
+$ticket_not_found->Create(
+ Subject => 'not found subject' . $$,
+ Queue => 'other',
+ Owner => 'nobody',
+ Requestor => 'notfound@localhost',
+ Content => 'this is not found content',
+);
+ok( $ticket_not_found->id, 'created ticket for custom search');
+
+ok($m->login, 'logged in');
+
+my @queries = (
+ 'base ticket', 'root',
+ 'customsearch@localhost', 'requestor:customsearch',
+ 'subject:base', 'subject:"base ticket"',
+ 'queue:general', 'owner:root',
+);
+
+for my $q (@queries) {
+ $m->form_with_fields('q');
+ $m->field( q => $q );
+ $m->submit;
+ $m->content_contains( 'base ticket 1', 'base ticket 1 is found' );
+ $m->content_contains( 'base ticket 2', 'base ticket 2 is found' );
+ $m->content_lacks( 'not found subject', 'not found ticket is not found' );
+}
+
+$ticket_not_found->SetStatus('open');
+is( $ticket_not_found->Status, 'open', 'status of not found ticket is open' );
+@queries = qw/new status:new/;
+for my $q (@queries) {
+ $m->form_with_fields('q');
+ $m->field( q => $q );
+ $m->submit;
+ $m->content_contains( 'base ticket 1', 'base ticket 1 is found' );
+ $m->content_contains( 'base ticket 2', 'base ticket 2 is found' );
+ $m->content_lacks( 'not found subject', 'not found ticket is not found' );
+}
+
+@queries = ( 'fulltext:"base ticket 1"', "'base ticket 1'" );
+for my $q (@queries) {
+ $m->form_with_fields('q');
+ $m->field( q => $q );
+ $m->submit;
+ $m->content_contains( 'base ticket 1', 'base ticket 1 is found' );
+ $m->content_lacks( 'base ticket 2', 'base ticket 2 is not found' );
+ $m->content_lacks( 'not found subject', 'not found ticket is not found' );
+}
+
+# now let's test with ' or "
+for my $quote ( q{'}, q{"} ) {
+ my $user = RT::User->new($RT::SystemUser);
+ is( ref($user), 'RT::User' );
+ my ( $id, $msg ) = $user->Create(
+ Name => qq!foo${quote}bar!,
+ EmailAddress => qq!foo${quote}bar$$\@example.com !,
+ Privileged => 1,
+ );
+ ok ($id, "Creating user - " . $msg );
+
+ my ( $grantid, $grantmsg ) =
+ $user->PrincipalObj->GrantRight( Right => 'OwnTicket' );
+ ok( $grantid, $grantmsg );
+
+
+
+ my $ticket_quote = RT::Ticket->new($RT::SystemUser);
+ $ticket_quote->Create(
+ Subject => qq!base${quote}ticket $$!,
+ Queue => 'general',
+ Owner => $user->Name,
+ 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' );
+
+ @queries = (
+ qq!fulltext:base${quote}ticket!,
+ "base${quote}ticket",
+ "owner:foo${quote}bar",
+ "foo${quote}bar",
+
+ # email doesn't allow " character
+ $quote eq q{'}
+ ? (
+ "requestor:custom${quote}search\@localhost",
+ "custom${quote}search\@localhost",
+ )
+ : (),
+ );
+ for my $q (@queries) {
+ $m->form_with_fields('q');
+ $m->field( q => $q );
+ $m->submit;
+ my $escape_quote = $quote;
+ RT::Interface::Web::EscapeUTF8(\$escape_quote);
+ $m->content_contains( "base${escape_quote}ticket",
+ "base${quote}ticket is found" );
+ }
+}
+
+# Create a CF
+{
+ my $cf = RT::CustomField->new(RT->SystemUser);
+ ok( $cf->Create(Name => 'Foo', Type => 'Freeform', MaxValues => '1', Queue => 0) );
+ ok $cf->Id;
+
+ $ticket_found_1->AddCustomFieldValue( Field => 'Foo', Value => 'bar' );
+ $ticket_found_2->AddCustomFieldValue( Field => 'Foo', Value => 'bar' );
+ $ticket_not_found->AddCustomFieldValue( Field => 'Foo', Value => 'baz' );
+ is( $ticket_found_1->FirstCustomFieldValue('Foo'), 'bar', 'cf value is ok' );
+ is( $ticket_found_2->FirstCustomFieldValue('Foo'), 'bar', 'cf value is ok' );
+ is( $ticket_not_found->FirstCustomFieldValue('Foo'), 'baz', 'cf value is ok' );
+
+ @queries = qw/cf.Foo:bar/;
+ for my $q (@queries) {
+ $m->form_with_fields('q');
+ $m->field( q => $q );
+ $m->submit;
+ $m->content_contains( 'base ticket 1', 'base ticket 1 is found' );
+ $m->content_contains( 'base ticket 2', 'base ticket 2 is found' );
+ $m->content_lacks( 'not found subject', 'not found ticket is not found' );
+ }
+}
+
diff --git a/rt/t/web/group_create.t b/rt/t/web/group_create.t
new file mode 100644
index 000000000..26da59268
--- /dev/null
+++ b/rt/t/web/group_create.t
@@ -0,0 +1,75 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 13;
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in as root';
+my $root = RT::User->new(RT->SystemUser);
+ok( $root->Load('root'), 'load root user' );
+
+my $group_name = 'test group';
+
+my $group_id;
+diag "Create a group";
+{
+ $m->follow_link( id => 'tools-config-groups-create');
+
+ # Test group form validation
+ $m->submit_form(
+ form_name => 'ModifyGroup',
+ fields => {
+ Name => '',
+ },
+ );
+ $m->text_contains('Name is required');
+ $m->submit_form(
+ form_name => 'ModifyGroup',
+ fields => {
+ Name => '0',
+ },
+ );
+ $m->text_contains('Could not create group');
+ $m->submit_form(
+ form_name => 'ModifyGroup',
+ fields => {
+ Name => '1',
+ },
+ );
+ $m->text_contains('Could not create group');
+ $m->submit_form(
+ form_name => 'ModifyGroup',
+ fields => {
+ Name => $group_name,
+ },
+ );
+ $m->content_contains('Group created', 'created group sucessfully' );
+
+ # Test validation on updae
+ $m->form_name('ModifyGroup');
+ $m->set_fields(
+ Name => '',
+ );
+ $m->click_button(value => 'Save Changes');
+ $m->text_contains('Illegal value for Name');
+
+ $m->form_name('ModifyGroup');
+ $m->set_fields(
+ Name => '0',
+ );
+ $m->click_button(value => 'Save Changes');
+ $m->text_contains('Illegal value for Name');
+
+ $m->form_name('ModifyGroup');
+ $m->set_fields(
+ Name => '1',
+ );
+ $m->click_button(value => 'Save Changes');
+ $m->text_contains('Illegal value for Name');
+
+ $group_id = $m->form_name('ModifyGroup')->value('id');
+ ok $group_id, "found id of the group in the form, it's #$group_id";
+}
+
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/Default
new file mode 100644
index 000000000..90278ae49
--- /dev/null
+++ b/rt/t/web/html/Callbacks/logout.t/NoAuth/Logout.html/Default
@@ -0,0 +1,6 @@
+<%args>
+$URL
+</%args>
+<%init>
+$$URL = 'http://bestpractical.com/rt';
+</%init>
diff --git a/rt/t/web/html/NoAuth/js/not-by-default.js b/rt/t/web/html/NoAuth/js/not-by-default.js
new file mode 100644
index 000000000..568f670ee
--- /dev/null
+++ b/rt/t/web/html/NoAuth/js/not-by-default.js
@@ -0,0 +1,3 @@
+function just_testing() {
+ alert("hi");
+}
diff --git a/rt/t/web/html/delete-article-name-method.html b/rt/t/web/html/delete-article-name-method.html
new file mode 100644
index 000000000..27592c1d0
--- /dev/null
+++ b/rt/t/web/html/delete-article-name-method.html
@@ -0,0 +1,15 @@
+<%INIT>
+# This is used by t/web/articles-links.t. Since we fork off a server
+# under most test configurations, and we need a way to run code in the
+# middle of the test script, we have to play at shenanigans to delete
+# RT::Article's Name method. Other options were a Plack::Middleware that
+# eval'd code given by paths like /__perl/(.+) (is scary), a signal
+# handler (fails under apache), and only running articles-links.t for
+# inline tests (fails under apache and standalone)
+
+delete $RT::Article::{Name};
+
+</%INIT>
+
+<% RT::Article->can('Name') ? '{exists}' : '{deleted}' %>
+
diff --git a/rt/t/web/html_template.t b/rt/t/web/html_template.t
index a2461dc97..662a26bbd 100644
--- a/rt/t/web/html_template.t
+++ b/rt/t/web/html_template.t
@@ -8,22 +8,17 @@ use Encode;
my ( $baseurl, $m ) = RT::Test->started_ok;
ok $m->login, 'logged in as root';
-$RT::Test::SKIP_REQUEST_WORK_AROUND = 1;
-RT::Test->set_mail_catcher;
-
use utf8;
diag('make Autoreply template a html one and add utf8 chars')
if $ENV{TEST_VERBOSE};
{
- $m->follow_link_ok( { text => 'Configuration' }, '-> Configuration' );
- $m->follow_link_ok( { text => 'Global' }, '-> Global' );
- $m->follow_link_ok( { text => 'Templates' }, '-> Templates' );
+ $m->follow_link_ok( { id => 'tools-config-global-templates' }, '-> Templates' );
$m->follow_link_ok( { text => 'Autoreply' }, '-> Autoreply' );
- $m->form_number(3);
$m->submit_form(
+ form_name => 'ModifyTemplate',
fields => {
Content => <<'EOF',
Subject: AutoReply: {$Ticket->Subject}
@@ -46,9 +41,8 @@ diag('create a ticket to see the autoreply mail') if $ENV{TEST_VERBOSE};
{
$m->get_ok( $baseurl . '/Ticket/Create.html?Queue=1' );
- $m->form_number(3);
$m->submit_form(
- form_number => 3,
+ form_name => 'TicketCreate',
fields => { Subject => '标题', Content => '<h1>测试</h1>',
ContentType => 'text/html' },
);
diff --git a/rt/t/web/logout.t b/rt/t/web/logout.t
new file mode 100644
index 000000000..889e5fc18
--- /dev/null
+++ b/rt/t/web/logout.t
@@ -0,0 +1,39 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use RT::Test tests => 12;
+
+my ($baseurl, $agent) = RT::Test->started_ok;
+
+my $url = $agent->rt_base_url;
+diag $url if $ENV{TEST_VERBOSE};
+
+# test that logout would actually redirects to the correct URL
+{
+ ok $agent->login, "logged in";
+ $agent->follow_link_ok({ text => 'Logout' });
+ like $agent->uri, qr'/Logout\.html$', "right url";
+ $agent->content_contains('<meta http-equiv="refresh" content="1;URL=/"', "found the expected meta-refresh");
+}
+
+# Stop server and set MasonLocalComponentRoot
+RT::Test->stop_server;
+
+RT->Config->Set(MasonLocalComponentRoot => RT::Test::get_abs_relocatable_dir('html'));
+
+($baseurl, $agent) = RT::Test->started_ok;
+
+$url = $agent->rt_base_url;
+diag $url if $ENV{TEST_VERBOSE};
+
+# test that logout would actually redirects to URL from the callback
+{
+ ok $agent->login, "logged in";
+ $agent->follow_link_ok({ text => 'Logout' });
+ like $agent->uri, qr'/Logout\.html$', "right url";
+ $agent->content_contains('<meta http-equiv="refresh" content="1;URL=http://bestpractical.com/rt"', "found the expected meta-refresh");
+}
+
+
+1;
diff --git a/rt/t/web/offline.t b/rt/t/web/offline.t
new file mode 100644
index 000000000..b3762fc20
--- /dev/null
+++ b/rt/t/web/offline.t
@@ -0,0 +1,78 @@
+#!/usr/bin/env perl
+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
index 9901b4555..bf9cf39fa 100644
--- a/rt/t/web/offline_messages_utf8.t
+++ b/rt/t/web/offline_messages_utf8.t
@@ -2,8 +2,7 @@
use strict;
use warnings;
-use RT::Test tests => 6;
-use File::Temp qw/tempfile/;
+use RT::Test tests => 8;
use Encode;
use RT::Ticket;
diff --git a/rt/t/web/offline_utf8.t b/rt/t/web/offline_utf8.t
index 2a3e64d3c..24795c0d3 100644
--- a/rt/t/web/offline_utf8.t
+++ b/rt/t/web/offline_utf8.t
@@ -2,11 +2,14 @@
use strict;
use warnings;
-use RT::Test tests => 8;
-use File::Temp qw/tempfile/;
+use RT::Test tests => 9;
+use utf8;
+
use Encode;
+
use RT::Ticket;
-my ( $fh, $file ) = tempfile;
+my $file = File::Spec->catfile( RT::Test->temp_directory, 'template' );
+open my $fh, '>', $file or die $!;
my $template = <<EOF;
===Create-Ticket: ticket1
Queue: General
@@ -38,17 +41,17 @@ $m->submit_form(
button => 'UpdateTickets',
# mimic what browsers do: they seems decoded $template
- fields => { string => decode( 'utf8', $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 );
+my $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Load( $ticket_id );
is( $ticket->Subject, '标题', 'subject in $ticket is right' );
-$m->get_ok( $url . "/Ticket/Display.html?id=$ticket_id" );
+$m->goto_ticket($ticket_id);
$m->content_contains( '这是正文',
'content is right in ticket display page' );
diff --git a/rt/t/web/passthrough-jsmin b/rt/t/web/passthrough-jsmin
new file mode 100644
index 000000000..3d9bf0129
--- /dev/null
+++ b/rt/t/web/passthrough-jsmin
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+echo "// passthrough-jsmin added this";
+
+exec cat;
diff --git a/rt/t/web/path-traversal.t b/rt/t/web/path-traversal.t
index 8d2f5cc88..5d5c954a1 100644
--- a/rt/t/web/path-traversal.t
+++ b/rt/t/web/path-traversal.t
@@ -1,7 +1,7 @@
use strict;
use warnings;
-use RT::Test tests => 20;
+use RT::Test tests => 22;
my ($baseurl, $agent) = RT::Test->started_ok;
@@ -19,11 +19,17 @@ $agent->warning_like(qr/Invalid request.*aborting/,);
$agent->get("$baseurl/NoAuth/../../../etc/RT_Config.pm");
is($agent->status, 400);
-$agent->warning_like(qr/Invalid request.*aborting/,);
+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/NoAuth/css/web2/images/../../../../../../etc/RT_Config.pm");
is($agent->status, 400);
-$agent->warning_like(qr/Invalid request.*aborting/,);
+SKIP: {
+ skip "Apache rejects busting up above / for us", 2 if $ENV{RT_TEST_WEB_HANDLER} =~ /^apache/;
+ $agent->warning_like(qr/Invalid request.*aborting/,);
+};
# 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/private-components.t b/rt/t/web/private-components.t
index 30e145f34..ceb2b34af 100644
--- a/rt/t/web/private-components.t
+++ b/rt/t/web/private-components.t
@@ -1,6 +1,6 @@
use strict;
-use RT::Test tests => 20;
+use RT::Test tests => 24;
my ($baseurl, $agent) = RT::Test->started_ok;
ok $agent->login, 'logged in';
@@ -18,6 +18,10 @@ $agent->get("/Widgets/TitleBox?title=private");
is($agent->status, 403);
$agent->content_lacks("private");
+$agent->get("/m/_elements/header?title=private");
+is($agent->status, 403);
+$agent->content_lacks("private");
+
$agent->get("/autohandler");
is($agent->status, 403);
$agent->content_lacks("comp called without component");
diff --git a/rt/t/web/query_builder.t b/rt/t/web/query_builder.t
index 25d6ec5a3..0abbfaca8 100644
--- a/rt/t/web/query_builder.t
+++ b/rt/t/web/query_builder.t
@@ -5,7 +5,7 @@ use HTTP::Request::Common;
use HTTP::Cookies;
use LWP;
use Encode;
-use RT::Test tests => 50;
+use RT::Test tests => 56;
my $cookie_jar = HTTP::Cookies->new;
my ($baseurl, $agent) = RT::Test->started_ok;
@@ -22,12 +22,12 @@ ok $queue && $queue->id, 'loaded or created queue';
my $url = $agent->rt_base_url;
ok $agent->login, "logged in";
-# {{{ Query Builder tests
my $response = $agent->get($url."Search/Build.html");
ok $response->is_success, "Fetched ". $url ."Search/Build.html";
sub getQueryFromForm {
+ my $agent = shift;
$agent->form_name('BuildQuery');
# This pulls out the "hidden input" query from the page
my $q = $agent->current_form->find_input("Query")->value;
@@ -38,117 +38,117 @@ sub getQueryFromForm {
}
sub selectedClauses {
+ my $agent = shift;
my @clauses = grep { defined } map { $_->value } $agent->current_form->find_input("clauses");
return [ @clauses ];
}
-diag "add the first condition" if $ENV{'TEST_VERBOSE'};
+diag "add the first condition";
{
ok $agent->form_name('BuildQuery'), "found the form once";
$agent->field("ActorField", "Owner");
$agent->field("ActorOp", "=");
$agent->field("ValueOfActor", "Nobody");
$agent->submit;
- is getQueryFromForm, "Owner = 'Nobody'", 'correct query';
+ is getQueryFromForm($agent), "Owner = 'Nobody'", 'correct query';
}
-diag "set the next condition" if $ENV{'TEST_VERBOSE'};
+diag "set the next condition";
{
ok($agent->form_name('BuildQuery'), "found the form again");
$agent->field("QueueOp", "!=");
$agent->field("ValueOfQueue", "Regression");
$agent->submit;
- is getQueryFromForm, "Owner = 'Nobody' AND Queue != 'Regression'",
+ is getQueryFromForm($agent), "Owner = 'Nobody' AND Queue != 'Regression'",
'correct query';
}
-diag "We're going to delete the owner" if $ENV{'TEST_VERBOSE'};
+diag "We're going to delete the owner";
{
$agent->select("clauses", ["0"] );
$agent->click("DeleteClause");
ok $agent->form_name('BuildQuery'), "found the form";
- is getQueryFromForm, "Queue != 'Regression'", 'correct query';
+ is getQueryFromForm($agent), "Queue != 'Regression'", 'correct query';
}
-diag "add a cond with OR and se number by the way" if $ENV{'TEST_VERBOSE'};
+diag "add a cond with OR and se number by the way";
{
$agent->field("AndOr", "OR");
$agent->select("idOp", ">");
$agent->field("ValueOfid" => "1234");
$agent->click("AddClause");
ok $agent->form_name('BuildQuery'), "found the form again";
- is getQueryFromForm, "Queue != 'Regression' OR id > 1234",
+ is getQueryFromForm($agent), "Queue != 'Regression' OR id > 1234",
"added something as OR, and number not quoted";
- is_deeply selectedClauses, ["1"], 'the id that we just entered is still selected';
+ is_deeply selectedClauses($agent), ["1"], 'the id that we just entered is still selected';
}
-diag "Move the second one up a level" if $ENV{'TEST_VERBOSE'};
+diag "Move the second one up a level";
{
$agent->click("Up");
ok $agent->form_name('BuildQuery'), "found the form again";
- is getQueryFromForm, "id > 1234 OR Queue != 'Regression'", "moved up one";
- is_deeply selectedClauses, ["0"], 'the one we moved up is selected';
+ is getQueryFromForm($agent), "id > 1234 OR Queue != 'Regression'", "moved up one";
+ is_deeply selectedClauses($agent), ["0"], 'the one we moved up is selected';
}
-diag "Move the second one right" if $ENV{'TEST_VERBOSE'};
+diag "Move the second one right";
{
$agent->click("Right");
ok $agent->form_name('BuildQuery'), "found the form again";
- is getQueryFromForm, "Queue != 'Regression' OR ( id > 1234 )",
+ is getQueryFromForm($agent), "Queue != 'Regression' OR ( id > 1234 )",
"moved over to the right (and down)";
- is_deeply selectedClauses, ["2"], 'the one we moved right is selected';
+ is_deeply selectedClauses($agent), ["2"], 'the one we moved right is selected';
}
-diag "Move the block up" if $ENV{'TEST_VERBOSE'};
+diag "Move the block up";
{
$agent->select("clauses", ["1"]);
$agent->click("Up");
ok $agent->form_name('BuildQuery'), "found the form again";
- is getQueryFromForm, "( id > 1234 ) OR Queue != 'Regression'", "moved up";
- is_deeply selectedClauses, ["0"], 'the one we moved up is selected';
+ is getQueryFromForm($agent), "( id > 1234 ) OR Queue != 'Regression'", "moved up";
+ is_deeply selectedClauses($agent), ["0"], 'the one we moved up is selected';
}
-diag "Can not move up the top most clause" if $ENV{'TEST_VERBOSE'};
+diag "Can not move up the top most clause";
{
$agent->select("clauses", ["0"]);
$agent->click("Up");
ok $agent->form_name('BuildQuery'), "found the form again";
- $agent->content_like(qr/error: can\S+t move up/, "i shouldn't have been able to hit up");
- is_deeply selectedClauses, ["0"], 'the one we tried to move is selected';
+ $agent->content_contains("error: can&#39;t move up", "i shouldn't have been able to hit up");
+ is_deeply selectedClauses($agent), ["0"], 'the one we tried to move is selected';
}
-diag "Can not move left the left most clause" if $ENV{'TEST_VERBOSE'};
+diag "Can not move left the left most clause";
{
$agent->click("Left");
ok($agent->form_name('BuildQuery'), "found the form again");
- $agent->content_like(qr/error: can\S+t move left/, "i shouldn't have been able to hit left");
- is_deeply selectedClauses, ["0"], 'the one we tried to move is selected';
+ $agent->content_contains("error: can&#39;t move left", "i shouldn't have been able to hit left");
+ is_deeply selectedClauses($agent), ["0"], 'the one we tried to move is selected';
}
-diag "Add a condition into a nested block" if $ENV{'TEST_VERBOSE'};
+diag "Add a condition into a nested block";
{
$agent->select("clauses", ["1"]);
$agent->select("ValueOfStatus" => "stalled");
$agent->submit;
ok $agent->form_name('BuildQuery'), "found the form again";
- is_deeply selectedClauses, ["2"], 'the one we added is only selected';
- is getQueryFromForm,
+ is_deeply selectedClauses($agent), ["2"], 'the one we added is only selected';
+ is getQueryFromForm($agent),
"( id > 1234 AND Status = 'stalled' ) OR Queue != 'Regression'",
"added new one";
}
-diag "click advanced, enter 'C1 OR ( C2 AND C3 )', apply, aggregators should stay the same."
- if $ENV{'TEST_VERBOSE'};
+diag "click advanced, enter 'C1 OR ( C2 AND C3 )', apply, aggregators should stay the same.";
{
my $response = $agent->get($url."Search/Edit.html");
ok( $response->is_success, "Fetched /Search/Edit.html" );
- ok($agent->form_number(3), "found the form");
+ ok($agent->form_name('BuildQueryAdvanced'), "found the form");
$agent->field("Query", "Status = 'new' OR ( Status = 'open' AND Subject LIKE 'office' )");
$agent->submit;
- is( getQueryFromForm,
+ is( getQueryFromForm($agent),
"Status = 'new' OR ( Status = 'open' AND Subject LIKE 'office' )",
"no aggregators change"
);
@@ -194,11 +194,10 @@ diag "click advanced, enter 'C1 OR ( C2 AND C3 )', apply, aggregators should sta
# - clears entire query
# - clears it from the session, too
-# }}}
# create a custom field with nonascii name and try to add a condition
{
- my $cf = RT::CustomField->new( $RT::SystemUser );
+ my $cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName( Name => "\x{442}", Queue => 0 );
if ( $cf->id ) {
is($cf->Type, 'Freeform', 'loaded and type is correct');
@@ -217,22 +216,21 @@ diag "click advanced, enter 'C1 OR ( C2 AND C3 )', apply, aggregators should sta
ok($agent->form_name('BuildQuery'), "found the form once");
$agent->field("ValueOf'CF.{\x{442}}'", "\x{441}");
$agent->submit();
- is( getQueryFromForm,
+ is( getQueryFromForm($agent),
"'CF.{\x{442}}' LIKE '\x{441}'",
"no changes, no duplicate condition with badly encoded text"
);
}
-diag "input a condition, select (several conditions), click delete"
- if $ENV{'TEST_VERBOSE'};
+diag "input a condition, select (several conditions), click delete";
{
my $response = $agent->get( $url."Search/Edit.html" );
ok $response->is_success, "Fetched /Search/Edit.html";
- ok $agent->form_number(3), "found the form";
+ ok $agent->form_name('BuildQueryAdvanced'), "found the form";
$agent->field("Query", "( Status = 'new' OR Status = 'open' )");
$agent->submit;
- is( getQueryFromForm,
+ is( getQueryFromForm($agent),
"( Status = 'new' OR Status = 'open' )",
"query is the same"
);
@@ -240,7 +238,7 @@ diag "input a condition, select (several conditions), click delete"
$agent->field( ValueOfid => 10 );
$agent->click("DeleteClause");
- is( getQueryFromForm,
+ is( getQueryFromForm($agent),
"id < 10",
"replaced query successfuly"
);
@@ -251,7 +249,7 @@ diag "send query with not quoted negative number";
my $response = $agent->get($url."Search/Build.html?Query=Priority%20>%20-2");
ok( $response->is_success, "Fetched " . $url."Search/Build.html" );
- is( getQueryFromForm,
+ is( getQueryFromForm($agent),
"Priority > -2",
"query is the same"
);
@@ -261,7 +259,7 @@ diag "click advanced, enter an invalid SQL IS restriction, apply and check that
{
my $response = $agent->get($url."Search/Edit.html");
ok( $response->is_success, "Fetched /Search/Edit.html" );
- ok($agent->form_number(3), "found the form");
+ ok($agent->form_name('BuildQueryAdvanced'), "found the form");
$agent->field("Query", "Requestor.EmailAddress IS 'FOOBAR'");
$agent->submit;
is( getQueryFromForm($agent),
@@ -274,7 +272,7 @@ diag "click advanced, enter an invalid SQL IS NOT restriction, apply and check t
{
my $response = $agent->get($url."Search/Edit.html");
ok( $response->is_success, "Fetched /Search/Edit.html" );
- ok($agent->form_number(3), "found the form");
+ ok($agent->form_name('BuildQueryAdvanced'), "found the form");
$agent->field("Query", "Requestor.EmailAddress IS NOT 'FOOBAR'");
$agent->submit;
is( getQueryFromForm($agent),
@@ -283,3 +281,17 @@ diag "click advanced, enter an invalid SQL IS NOT restriction, apply and check t
);
}
+diag "click advanced, enter a valid SQL, but the field is lower cased";
+{
+ my $response = $agent->get($url."Search/Edit.html");
+ ok( $response->is_success, "Fetched /Search/Edit.html" );
+ ok($agent->form_name('BuildQueryAdvanced'), "found the form");
+ $agent->field("Query", "status = 'new'");
+ $agent->submit;
+ $agent->content_lacks( 'Unknown field:', 'no "unknown field" warning' );
+ is( getQueryFromForm($agent),
+ "Status = 'new'",
+ "field's case is corrected"
+ );
+}
+
diff --git a/rt/t/web/query_log.t b/rt/t/web/query_log.t
new file mode 100644
index 000000000..e19f44dc6
--- /dev/null
+++ b/rt/t/web/query_log.t
@@ -0,0 +1,20 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use RT::Test tests => 9;
+
+RT->Config->Set(StatementLog => 1);
+
+my ($baseurl, $m) = RT::Test->started_ok;
+ok $m->login, 'logged in';
+
+my $root = RT::User->new($RT::SystemUser);
+$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_contains("SELECT * FROM Principals WHERE id = '".$root->id."'", "we interpolate bind params");
+
diff --git a/rt/t/web/queue_caching.t b/rt/t/web/queue_caching.t
new file mode 100644
index 000000000..d90aacbdf
--- /dev/null
+++ b/rt/t/web/queue_caching.t
@@ -0,0 +1,90 @@
+use strict;
+use warnings;
+use RT::Test tests => 36;
+
+# make an initial queue, so we have more than 1
+my $original_test_queue = new_queue("Test$$");
+
+my ($baseurl, $m) = RT::Test->started_ok;
+ok $m->login, 'logged in';
+
+diag("Check for 2 existing queues being visible");
+{
+ check_queues($m);
+}
+
+diag("Add a new queue, which won't show up until we fix the cache");
+{
+ new_queue("New Test $$");
+ check_queues($m);
+}
+
+diag("Disable an existing queue, it should stop appearing in the list");
+{
+ ok($original_test_queue->SetDisabled(1));
+ check_queues($m);
+}
+
+diag("Bring back a disabled queue");
+{
+ ok($original_test_queue->SetDisabled(0));
+ check_queues($m);
+}
+
+diag("Test a user who has more limited rights Queues");
+{
+
+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( RT::Test->set_rights(
+ { Principal => $user_a, Right => [qw(SeeQueue CreateTicket)], Object => $original_test_queue },
+), 'Allow user a to see the testing queue');
+
+my $a_m = RT::Test::Web->new;
+ok $a_m->login('user_a', 'password'), 'logged in as user A';
+
+# check that they see a single queue
+check_queues($a_m,[$original_test_queue->Id]);
+
+ok( RT::Test->add_rights(
+ { Principal => $user_a, Right => [qw(SeeQueue CreateTicket)] },
+), 'add global queue viewing rights');
+
+check_queues($a_m);
+
+}
+
+sub new_queue {
+ my $name = shift;
+ my $new_queue = RT::Queue->new(RT->SystemUser);
+ ok($new_queue->Create( Name => $name, Description => "Testing for $name queue" ), "Created queue ".$new_queue->Name);
+ return $new_queue;
+}
+
+sub internal_queues {
+ my $internal_queues = RT::Queues->new(RT->SystemUser);
+ $internal_queues->Limit(FIELD => 'Disabled', VALUE => 0);
+ my $queuelist;
+ while ( my $q = $internal_queues->Next ) {
+ $queuelist->{$q->Id} = $q->Name;
+ }
+ return $queuelist;
+}
+
+
+# takes a WWW::Mech object and an optional arrayref of queue ids
+# compares the list of ids to the dropdown of Queues for the New Ticket In form
+sub check_queues {
+ my $browser = shift;
+ my $queue_list = shift;
+ $browser->get_ok($baseurl,"Navigated to homepage");
+ ok(my $form = $browser->form_name('CreateTicketInQueue'), "Found New Ticket In form");
+ ok(my $queuelist = $form->find_input('Queue','option'), "Found queue select");
+ my @queues = $queuelist->possible_values;
+
+ $queue_list = [keys %{internal_queues()}] unless $queue_list;
+ is_deeply([sort @queues],[sort @$queue_list], "Queue list contains the expected queues");
+}
diff --git a/rt/t/web/queue_create.t b/rt/t/web/queue_create.t
new file mode 100644
index 000000000..3d2cd04d0
--- /dev/null
+++ b/rt/t/web/queue_create.t
@@ -0,0 +1,75 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 13;
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in as root';
+my $root = RT::User->new(RT->SystemUser);
+ok( $root->Load('root'), 'load root user' );
+
+my $queue_name = 'test queue';
+
+my $queue_id;
+diag "Create a queue";
+{
+ $m->follow_link( id => 'tools-config-queues-create');
+
+ # Test queue form validation
+ $m->submit_form(
+ form_name => 'ModifyQueue',
+ fields => {
+ Name => '',
+ },
+ );
+ $m->text_contains('Queue name is required');
+ $m->submit_form(
+ form_name => 'ModifyQueue',
+ fields => {
+ Name => '0',
+ },
+ );
+ $m->text_contains("'0' is not a valid name");
+ $m->submit_form(
+ form_name => 'ModifyQueue',
+ fields => {
+ Name => '1',
+ },
+ );
+ $m->text_contains("'1' is not a valid name");
+ $m->submit_form(
+ form_name => 'ModifyQueue',
+ fields => {
+ Name => $queue_name,
+ },
+ );
+ $m->content_contains('Queue created', 'created queue sucessfully' );
+
+ # Test validation on update
+ $m->form_name('ModifyQueue');
+ $m->set_fields(
+ Name => '',
+ );
+ $m->click_button(value => 'Save Changes');
+ $m->content_contains('Illegal value for Name');
+
+ $m->form_name('ModifyQueue');
+ $m->set_fields(
+ Name => '0',
+ );
+ $m->click_button(value => 'Save Changes');
+ $m->content_contains('Illegal value for Name');
+
+ $m->form_name('ModifyQueue');
+ $m->set_fields(
+ Name => '1',
+ );
+ $m->click_button(value => 'Save Changes');
+ $m->content_contains('Illegal value for Name');
+
+ $queue_id = $m->form_name('ModifyQueue')->value('id');
+ ok $queue_id, "found id of the queue in the form, it's #$queue_id";
+}
+
diff --git a/rt/t/web/quickcreate.t b/rt/t/web/quickcreate.t
new file mode 100644
index 000000000..b257f9ddd
--- /dev/null
+++ b/rt/t/web/quickcreate.t
@@ -0,0 +1,37 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+
+use RT::Test tests => 11;
+
+RT->Config->Set('DisplayTicketAfterQuickCreate' => 0);
+
+my ($baseurl, $m) = RT::Test->started_ok;
+
+ok($m->login, 'logged in');
+
+$m->form_with_fields('Subject', 'Content');
+$m->field(Subject => 'from quick create');
+$m->submit;
+
+$m->content_like(qr/Ticket \d+ created in queue/, 'created ticket');
+like( $m->uri, qr{^\Q$baseurl\E/(?:index\.html)?\?results=}, 'still in homepage' );
+unlike( $m->uri, qr{Ticket/Display.html}, 'not on ticket display page' );
+
+$m->get_ok($baseurl . '/Prefs/Other.html');
+$m->submit_form(
+ form_name => 'ModifyPreferences',
+ fields => { 'DisplayTicketAfterQuickCreate' => 1, },
+ button => 'Update',
+);
+
+$m->content_contains( 'Preferences saved',
+ 'enabled DisplayTicketAfterQuickCreate' );
+$m->get($baseurl);
+
+$m->form_with_fields('Subject', 'Content');
+$m->field(Subject => 'from quick create');
+$m->submit;
+
+$m->content_like(qr/Ticket \d+ created in queue/, 'created ticket');
+like( $m->uri, qr!/Ticket/Display.html!, 'still in homepage' );
diff --git a/rt/t/web/quicksearch.t b/rt/t/web/quicksearch.t
index cd9a8e76c..8cc084ce5 100644
--- a/rt/t/web/quicksearch.t
+++ b/rt/t/web/quicksearch.t
@@ -2,12 +2,12 @@
use strict;
use warnings;
-use RT::Test tests => 7;
+use RT::Test tests => 9;
my ($baseurl, $m) = RT::Test->started_ok;
my $url = $m->rt_base_url;
# merged tickets still show up in search
-my $t1 = RT::Ticket->new($RT::SystemUser);
+my $t1 = RT::Ticket->new(RT->SystemUser);
$t1->Create(
Subject => 'base ticket'.$$,
Queue => 'general',
@@ -22,7 +22,7 @@ $t1->Create(
);
ok(my $id1 = $t1->id, 'created ticket for custom search');
-my $t2 = RT::Ticket->new($RT::SystemUser);
+my $t2 = RT::Ticket->new(RT->SystemUser);
$t2->Create(
Subject => 'merged away'.$$,
Queue => 'general',
diff --git a/rt/t/web/redirect-after-login.t b/rt/t/web/redirect-after-login.t
index d39bb58c8..d429d30d1 100644
--- a/rt/t/web/redirect-after-login.t
+++ b/rt/t/web/redirect-after-login.t
@@ -3,7 +3,9 @@
use strict;
use warnings;
-use RT::Test tests => 120;
+use RT::Test tests => 122;
+
+RT->Config->Set( GnuPG => Enable => 0 );
my ($baseurl, $agent) = RT::Test->started_ok;
@@ -51,11 +53,9 @@ diag $url if $ENV{TEST_VERBOSE};
ok( $agent->content =~ /Your username or password is incorrect/i, "Found the error message");
like( $agent->uri, qr{/NoAuth/Login\.html$}, "now on /NoAuth/Login.html" );
- $agent->logout();
-
- # Handle the warning after we're done with the page, since this leaves us
- # with a completely different $mech
$agent->warning_like(qr/FAILED LOGIN for root/, "got failed login warning");
+
+ $agent->logout();
}
# test a login from a non-front page, both with a double leading slash and without
@@ -116,6 +116,7 @@ for my $path (qw(Prefs/Other.html /Prefs/Other.html)) {
ok( $agent->content =~ /Your username or password is incorrect/i, "Found the error message");
like( $agent->uri, qr{/NoAuth/Login\.html$}, "still on /NoAuth/Login.html" );
+ $agent->warning_like(qr/FAILED LOGIN for root/, "got failed login warning");
# try to login again
ok($agent->current_form->find_input('user'));
@@ -136,10 +137,6 @@ for my $path (qw(Prefs/Other.html /Prefs/Other.html)) {
is( $agent->uri, $requested, "right URL" );
like( $agent->{redirected_uri}, qr{/NoAuth/Login\.html}, "We redirected from login");
$agent->logout();
-
- # Handle the warning after we're done with the page, since this leaves us
- # with a completely different $mech
- $agent->warning_like(qr/FAILED LOGIN for root/, "got failed login warning");
}
# test a login from the main page with query params
@@ -163,9 +160,6 @@ for my $path (qw(Prefs/Other.html /Prefs/Other.html)) {
ok($agent->current_form->find_input('user'));
ok($agent->current_form->find_input('pass'));
like($agent->current_form->action, qr{/NoAuth/Login\.html$}, "login form action is correct");
-
- # Handle the warning after we're done with the page, since this leaves us
- # with a completely different $mech
$agent->warning_like(qr/FAILED LOGIN for root/, "got failed login warning");
}
@@ -183,6 +177,7 @@ for my $path (qw(Prefs/Other.html /Prefs/Other.html)) {
ok($agent->current_form->find_input('next'));
like($agent->value('next'), qr/^[a-z0-9]{32}$/i, "next page argument is a hash");
like($agent->current_form->action, qr{/NoAuth/Login\.html$}, "login form action is correct");
+ $agent->warning_like(qr/FAILED LOGIN for root/, "got failed login warning");
# Try to login again
ok($agent->content =~ /username:/i);
@@ -197,10 +192,6 @@ for my $path (qw(Prefs/Other.html /Prefs/Other.html)) {
is( $agent->uri, $requested, "right URL" );
like( $agent->{redirected_uri}, qr{/NoAuth/Login\.html}, "We redirected from login");
$agent->logout();
-
- # Handle the warning after we're done with the page, since this leaves us
- # with a completely different $mech
- $agent->warning_like(qr/FAILED LOGIN for root/, "got failed login warning");
}
# test REST login response
@@ -221,9 +212,6 @@ for my $path (qw(Prefs/Other.html /Prefs/Other.html)) {
is($agent->uri, $requested, "didn't redirect to /NoAuth/Login.html for REST");
like($agent->content, qr/401 Credentials required/i, "got error status");
like($agent->content, qr/Your username or password is incorrect/, "got error message");
-
- # Handle the warning after we're done with the page, since this leaves us
- # with a completely different $mech
$agent->warning_like(qr/FAILED LOGIN for root/, "got failed login warning");
}
diff --git a/rt/t/web/redirect.t b/rt/t/web/redirect.t
new file mode 100644
index 000000000..d92386bb8
--- /dev/null
+++ b/rt/t/web/redirect.t
@@ -0,0 +1,106 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 13;
+
+my $r = $HTML::Mason::Commands::r = bless {}, 'R';
+my $m = $HTML::Mason::Commands::m = bless {}, 'M';
+
+set_config(
+ CanonicalizeRedirectURLs => 0,
+ WebDomain => 'localhost',
+ WebPort => 80,
+ WebPath => '',
+);
+is( RT->Config->Get('WebBaseURL'), 'http://localhost' );
+is( RT->Config->Get('WebURL'), 'http://localhost/' );
+
+redirect_ok(
+ 'http://localhost/Ticket/', 'http://localhost/Ticket/',
+ { SERVER_NAME => 'localhost', SERVER_PORT => 80 },
+);
+redirect_ok(
+ '/Ticket/', 'http://localhost/Ticket/',
+ { SERVER_NAME => 'localhost', SERVER_PORT => 80 },
+);
+redirect_ok(
+ 'http://localhost/Ticket/', 'http://example.com/Ticket/',
+ { SERVER_NAME => 'example.com', SERVER_PORT => 80 },
+);
+
+set_config(
+ CanonicalizeRedirectURLs => 0,
+ WebDomain => 'localhost',
+ WebPort => 443,
+ WebPath => '',
+);
+is( RT->Config->Get('WebBaseURL'), 'https://localhost' );
+is( RT->Config->Get('WebURL'), 'https://localhost/' );
+
+redirect_ok(
+ 'https://localhost/Ticket/', 'https://localhost/Ticket/',
+ { SERVER_NAME => 'localhost', SERVER_PORT => 443, HTTPS => 'on' },
+);
+redirect_ok(
+ '/Ticket/', 'https://localhost/Ticket/',
+ { SERVER_NAME => 'localhost', SERVER_PORT => 443, HTTPS => 'on' },
+);
+redirect_ok(
+ 'https://localhost/Ticket/', 'http://localhost/Ticket/',
+ { SERVER_NAME => 'localhost', SERVER_PORT => 80 },
+);
+redirect_ok(
+ '/Ticket/', 'http://localhost/Ticket/',
+ { SERVER_NAME => 'localhost', SERVER_PORT => 80 },
+);
+redirect_ok(
+ 'https://localhost/Ticket/', 'http://example.com/Ticket/',
+ { SERVER_NAME => 'example.com', SERVER_PORT => 80 },
+);
+redirect_ok(
+ 'https://localhost/Ticket/', 'https://example.com/Ticket/',
+ { SERVER_NAME => 'example.com', SERVER_PORT => 443, HTTPS => 'on' },
+);
+
+sub set_config {
+ my %values = @_;
+ while ( my ($k, $v) = each %values ) {
+ RT->Config->Set( $k => $v );
+ }
+
+ unless ( $values{'WebBaseURL'} ) {
+ my $port = RT->Config->Get('WebPort');
+ RT->Config->Set(
+ WebBaseURL =>
+ ($port == 443? 'https': 'http') .'://'
+ . RT->Config->Get('WebDomain')
+ . ($port != 80 && $port != 443? ":$port" : '')
+ );
+ }
+ unless ( $values{'WebURL'} ) {
+ RT->Config->Set(
+ WebURL => RT->Config->Get('WebBaseURL') . RT->Config->Get('WebPath') . "/"
+ );
+ }
+}
+
+sub redirect_ok {
+ my ($to, $expected, $env, $details) = @_;
+
+ local %ENV = %ENV;
+ while ( my ($k, $v) = each %{ $env || {} } ) {
+ $ENV{ $k } = $v;
+ }
+ RT::Interface::Web::Redirect( $to );
+ is($m->redirect, $expected, $details || "correct for '$to'");
+}
+
+package R;
+sub status {};
+
+package M;
+sub redirect { $_[0]{'last'} = $_[1] if @_ > 1; return $_[0]{'last'} }
+sub abort {}
+
diff --git a/rt/t/web/reminders.t b/rt/t/web/reminders.t
new file mode 100644
index 000000000..32e130c47
--- /dev/null
+++ b/rt/t/web/reminders.t
@@ -0,0 +1,88 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use RT::Test tests => 35;
+
+my ($baseurl, $m) = RT::Test->started_ok;
+
+ok($m->login, 'logged in');
+my $user = RT::CurrentUser->new('root');
+
+my $ticket = RT::Ticket->new($user);
+$ticket->Create(Subject => 'testing reminders!', Queue => 'General');
+ok($ticket->id, 'created a ticket');
+
+$m->goto_ticket($ticket->id);
+$m->text_contains('New reminder:', 'can create a new reminder');
+$m->content_unlike(qr{Check box to complete}, "we don't display this text when there are no reminders");
+$m->content_unlike(qr{<th[^>]*>Reminders?</th>}, "no reminder titlebar");
+
+$m->follow_link_ok({id => 'page-reminders'});
+$m->title_is("Reminders for ticket #" . $ticket->id);
+$m->text_contains('New reminder:', 'can create a new reminder');
+$m->content_unlike(qr{Check box to complete}, "we don't display this text when there are no reminders");
+$m->content_unlike(qr{<th[^>]*>Reminders?</th>}, "no reminder titlebar");
+
+$m->goto_ticket($ticket->id);
+$m->form_name('UpdateReminders');
+$m->field( 'NewReminder-Subject' => "baby's first reminder" );
+$m->submit;
+
+my $reminders = RT::Reminders->new($user);
+$reminders->Ticket($ticket->id);
+my $col = $reminders->Collection;
+is($col->Count, 1, 'got a reminder');
+my $reminder = $col->First;
+is($reminder->Subject, "baby's first reminder");
+my $reminder_id = $reminder->id;
+is($reminder->Status, 'new');
+
+$m->text_contains('New reminder:', 'can create a new reminder');
+$m->text_contains('Check box to complete', "we DO display this text when there are reminders");
+$m->content_like(qr{<th[^>]*>Reminders?</th>}, "now we have a reminder titlebar");
+$m->text_contains("baby's first reminder", "display the reminder's subject");
+
+$m->follow_link_ok({id => 'page-reminders'});
+$m->title_is("Reminders for ticket #" . $ticket->id);
+$m->form_name('UpdateReminders');
+$m->field("Reminder-Subject-$reminder_id" => "changed the subject");
+$m->submit;
+
+DBIx::SearchBuilder::Record::Cachable->FlushCache;
+$reminder = RT::Ticket->new($user);
+$reminder->Load($reminder_id);
+is($reminder->Subject, 'changed the subject');
+is($reminder->Status, 'new');
+
+$m->goto_ticket($ticket->id);
+$m->form_name('UpdateReminders');
+$m->tick("Complete-Reminder-$reminder_id" => 1);
+$m->submit;
+
+DBIx::SearchBuilder::Record::Cachable->FlushCache;
+$reminder = RT::Ticket->new($user);
+$reminder->Load($reminder_id);
+is($reminder->Status, 'resolved');
+
+$m->text_contains('New reminder:', 'can create a new reminder');
+$m->content_unlike(qr{Check box to complete}, "we don't display this text when there are open reminders");
+$m->content_unlike(qr{<th[^>]*>Reminders?</th>}, "no reminder titlebar");
+$m->content_unlike(qr{baby's first reminder}, "we don't display resolved reminders");
+
+$m->follow_link_ok({id => 'page-reminders'});
+$m->title_is("Reminders for ticket #" . $ticket->id);
+$m->text_contains('New reminder:', 'can create a new reminder');
+$m->text_contains('Check box to complete', "we DO display this text when there are reminders");
+$m->content_contains("changed the subject", "display the resolved reminder's subject");
+
+# make sure that when we submit the form, it doesn't accidentally reopen
+# resolved reminders
+$m->goto_ticket($ticket->id);
+$m->form_name('UpdateReminders');
+$m->submit;
+
+DBIx::SearchBuilder::Record::Cachable->FlushCache;
+$reminder = RT::Ticket->new($user);
+$reminder->Load($reminder_id);
+is($reminder->Status, 'resolved');
+
diff --git a/rt/t/web/remote_user.t b/rt/t/web/remote_user.t
new file mode 100644
index 000000000..edad6ef95
--- /dev/null
+++ b/rt/t/web/remote_user.t
@@ -0,0 +1,36 @@
+use strict;
+use warnings;
+use RT;
+use RT::Test tests => 9;
+use MIME::Base64 qw//;
+
+RT->Config->Set( DevelMode => 0 );
+RT->Config->Set( WebExternalAuth => 1 );
+
+sub auth {
+ return Authorization => "Basic " .
+ MIME::Base64::encode( join(":", @_) );
+}
+
+my ( $url, $m ) = RT::Test->started_ok( basic_auth => 1 );
+$m->get($url);
+is($m->status, 401, "Initial request with no creds gets 401");
+
+$m->get($url, auth( root => "wrong" ));
+is($m->status, 401, "Request with wrong creds gets 401");
+
+$m->get($url, auth( 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 WebFallbackToInternalAuth");
+
+$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->default_header( auth( root => "password" ));
diff --git a/rt/t/web/requestor_groups_edit_link.t b/rt/t/web/requestor_groups_edit_link.t
new file mode 100644
index 000000000..9d1fefd5c
--- /dev/null
+++ b/rt/t/web/requestor_groups_edit_link.t
@@ -0,0 +1,56 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 11;
+
+RT->Config->Set( ShowMoreAboutPrivilegedUsers => 1 );
+
+my ( $url, $m ) = RT::Test->started_ok;
+my $user_a = RT::Test->load_or_create_user(
+ Name => 'user_a',
+ Password => 'password',
+);
+ok( $user_a, 'created user user_a' );
+ok(
+ RT::Test->set_rights(
+ {
+ Principal => $user_a,
+ Right => [ qw/SeeQueue ShowTicket CreateTicket/ ]
+ },
+ ),
+ 'set rights for user_a'
+);
+
+my $ticket = RT::Ticket->new(RT->SystemUser);
+my ($id) = $ticket->Create(
+ Subject => 'groups limit',
+ Queue => 'General',
+ Requestor => $user_a->id,
+);
+ok( $id, 'created ticket' );
+
+
+ok( $m->login( user_a => 'password' ), 'logged in as user_a' );
+
+$m->goto_ticket($id);
+
+ok(
+ !$m->find_link( text => 'Edit' ), 'no Edit link without AdminUsers permission'
+);
+
+ok(
+ RT::Test->add_rights(
+ {
+ Principal => $user_a,
+ Right => [ qw/AdminUsers ShowConfigTab/ ]
+ },
+ ),
+ 'add AdminUsers and ShowConfigTab rights for user_a'
+);
+
+$m->goto_ticket($id);
+$m->follow_link_ok( { text => 'Edit' }, 'follow the Edit link' );
+is( $m->uri, $url . "/Admin/Users/Memberships.html?id=" . $user_a->id, 'url is right' );
+
diff --git a/rt/t/web/requestor_groups_limit.t b/rt/t/web/requestor_groups_limit.t
new file mode 100644
index 000000000..7987a136c
--- /dev/null
+++ b/rt/t/web/requestor_groups_limit.t
@@ -0,0 +1,36 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 11;
+
+diag "set groups limit to 1";
+RT->Config->Set( ShowMoreAboutPrivilegedUsers => 1 );
+RT->Config->Set( MoreAboutRequestorGroupsLimit => 1 );
+
+my $ticket = RT::Ticket->new(RT->SystemUser);
+my ($id) = $ticket->Create(
+ Subject => 'groups limit',
+ Queue => 'General',
+ Requestor => 'root@localhost',
+);
+ok( $id, 'created ticket' );
+
+my ( $url, $m ) = RT::Test->started_ok;
+ok( $m->login(), 'logged in as root' );
+$m->goto_ticket($id);
+$m->content_like( qr/Everyone|Privileged/, 'got one group' );
+$m->content_unlike( qr/Everyone.*?Privileged/, 'not 2 groups' );
+
+RT::Test->stop_server;
+
+diag "set groups limit to 2";
+
+RT->Config->Set( MoreAboutRequestorGroupsLimit => 2 );
+( $url, $m ) = RT::Test->started_ok;
+ok( $m->login(), 'logged in as root' );
+$m->goto_ticket($id);
+$m->content_contains( 'Everyone', 'got the first group' );
+$m->content_contains( 'Privileged', 'got the second group' );
+
diff --git a/rt/t/web/rest-non-ascii-subject.t b/rt/t/web/rest-non-ascii-subject.t
index 371b2ffc0..d7a89af5e 100644
--- a/rt/t/web/rest-non-ascii-subject.t
+++ b/rt/t/web/rest-non-ascii-subject.t
@@ -2,9 +2,7 @@
# Test ticket creation with REST using non ascii subject
use strict;
use warnings;
-use RT::Test tests => 7;
-
-local $RT::Test::SKIP_REQUEST_WORK_AROUND = 1;
+use RT::Test tests => 9;
use Encode;
# \x{XX} where XX is less than 255 is not treated as unicode code point
@@ -42,7 +40,7 @@ $m->post("$baseurl/REST/1.0/ticket/new", [
my ($id) = $m->content =~ /Ticket (\d+) created/;
ok($id, "got ticket #$id");
-my $ticket = RT::Ticket->new($RT::SystemUser);
+my $ticket = RT::Ticket->new(RT->SystemUser);
$ticket->Load($id);
is($ticket->Id, $id, "loaded the REST-created ticket");
is($ticket->Subject, $subject, "ticket subject successfully set");
diff --git a/rt/t/web/rest-sort.t b/rt/t/web/rest-sort.t
new file mode 100644
index 000000000..6b4d35169
--- /dev/null
+++ b/rt/t/web/rest-sort.t
@@ -0,0 +1,46 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use RT::Test tests => 25;
+
+my ($baseurl, $m) = RT::Test->started_ok;
+
+RT::Test->create_tickets(
+ { },
+ { Subject => 'uno' },
+ { Subject => 'dos' },
+ { Subject => 'tres' },
+);
+
+ok($m->login, 'logged in');
+
+sorted_tickets_ok('Subject', ['2: dos', '3: tres', '1: uno']);
+sorted_tickets_ok('+Subject', ['2: dos', '3: tres', '1: uno']);
+sorted_tickets_ok('-Subject', ['1: uno', '3: tres', '2: dos']);
+
+sorted_tickets_ok('id', ['1: uno', '2: dos', '3: tres']);
+sorted_tickets_ok('+id', ['1: uno', '2: dos', '3: tres']);
+sorted_tickets_ok('-id', ['3: tres', '2: dos', '1: uno']);
+
+undef $m;
+
+sub sorted_tickets_ok {
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+ my $order = shift;
+ my $expected = shift;
+
+ my $query = 'id > 0';
+
+ my $uri = URI->new("$baseurl/REST/1.0/search/ticket");
+ $uri->query_form(
+ query => $query,
+ orderby => $order,
+ );
+ $m->get_ok($uri);
+
+ my @lines = split /\n/, $m->content;
+ shift @lines; # header
+ shift @lines; # empty line
+
+ is_deeply(\@lines, $expected, "sorted results by '$order'");
+}
diff --git a/rt/t/web/rest.t b/rt/t/web/rest.t
index b3a7c558b..5e7194c95 100644
--- a/rt/t/web/rest.t
+++ b/rt/t/web/rest.t
@@ -1,7 +1,7 @@
#!/usr/bin/env perl
use strict;
use warnings;
-use RT::Test tests => 16;
+use RT::Test tests => 18;
my ($baseurl, $m) = RT::Test->started_ok;
@@ -46,7 +46,7 @@ $m->post("$baseurl/REST/1.0/ticket/edit", [
my ($id) = $m->content =~ /Ticket (\d+) created/;
ok($id, "got ticket #$id");
-my $ticket = RT::Ticket->new($RT::SystemUser);
+my $ticket = RT::Ticket->new(RT->SystemUser);
$ticket->Load($id);
is($ticket->Id, $id, "loaded the REST-created ticket");
is($ticket->Subject, "REST interface", "subject successfully set");
diff --git a/rt/t/web/richtext-autohandler.t b/rt/t/web/richtext-autohandler.t
index 56617b2fb..734426fc3 100644
--- a/rt/t/web/richtext-autohandler.t
+++ b/rt/t/web/richtext-autohandler.t
@@ -1,13 +1,13 @@
use strict;
-use RT::Test tests => 7;
+use RT::Test tests => 9;
my ($baseurl, $agent) = RT::Test->started_ok;
-$agent->get("$baseurl/NoAuth/RichText/FCKeditor/license.txt");
+$agent->get("$baseurl/NoAuth/RichText/ckeditor/config.js");
is($agent->status, 403);
-$agent->content_lacks("It is not the purpose of this section to induce");
+$agent->content_lacks("config.disableNativeSpellChecker");
-$agent->get_ok("/NoAuth/RichText/license.txt");
-$agent->content_contains("It is not the purpose of this section to induce");
+$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 b47ba99af..9a5f358e2 100644
--- a/rt/t/web/rights.t
+++ b/rt/t/web/rights.t
@@ -7,34 +7,32 @@ use RT::Test tests => 14;
my ($baseurl, $m) = RT::Test->started_ok;
ok $m->login, "logged in";
-$m->follow_link_ok({ text => 'Configuration' });
-$m->follow_link_ok({ text => 'Global' });
-$m->follow_link_ok({ text => 'Group Rights' });
+$m->follow_link_ok({ id => 'tools-config-global-group-rights'});
sub get_rights {
my $agent = shift;
my $principal_id = shift;
my $object = shift;
- $agent->form_number(3);
- my @inputs = $agent->current_form->find_input("RevokeRight-$principal_id-$object");
- my @rights = sort grep $_, map $_->possible_values, grep $_, @inputs;
+ $agent->form_name('ModifyGroupRights');
+ my @inputs = $agent->current_form->find_input("SetRights-$principal_id-$object");
+ my @rights = sort grep $_, map $_->possible_values, grep $_ && $_->value, @inputs;
return @rights;
};
-diag "load Everyone group" if $ENV{'TEST_VERBOSE'};
+diag "load Everyone group";
my ($everyone, $everyone_gid);
{
- $everyone = RT::Group->new( $RT::SystemUser );
+ $everyone = RT::Group->new( RT->SystemUser );
$everyone->LoadSystemInternalGroup('Everyone');
ok($everyone_gid = $everyone->id, "loaded 'everyone' group");
}
-diag "revoke all global rights from Everyone group" if $ENV{'TEST_VERBOSE'};
+diag "revoke all global rights from Everyone group";
my @has = get_rights( $m, $everyone_gid, 'RT::System-1' );
if ( @has ) {
- $m->form_number(3);
- $m->tick("RevokeRight-$everyone_gid-RT::System-1", $_) foreach @has;
+ $m->form_name('ModifyGroupRights');
+ $m->untick("SetRights-$everyone_gid-RT::System-1", $_) foreach @has;
$m->submit;
is_deeply([get_rights( $m, $everyone_gid, 'RT::System-1' )], [], 'deleted all rights' );
@@ -42,10 +40,10 @@ if ( @has ) {
ok(1, 'the group has no global rights');
}
-diag "grant SuperUser right to everyone" if $ENV{'TEST_VERBOSE'};
+diag "grant SuperUser right to everyone";
{
- $m->form_number(3);
- $m->select("GrantRight-$everyone_gid-RT::System-1", ['SuperUser']);
+ $m->form_name('ModifyGroupRights');
+ $m->tick("SetRights-$everyone_gid-RT::System-1", 'SuperUser');
$m->submit;
$m->content_contains('Right Granted', 'got message');
@@ -54,10 +52,10 @@ diag "grant SuperUser right to everyone" if $ENV{'TEST_VERBOSE'};
is_deeply( [get_rights( $m, $everyone_gid, 'RT::System-1' )], ['SuperUser'], 'granted SuperUser right' );
}
-diag "revoke the right" if $ENV{'TEST_VERBOSE'};
+diag "revoke the right";
{
- $m->form_number(3);
- $m->tick("RevokeRight-$everyone_gid-RT::System-1", 'SuperUser');
+ $m->form_name('ModifyGroupRights');
+ $m->untick("SetRights-$everyone_gid-RT::System-1", 'SuperUser');
$m->submit;
$m->content_contains('Right revoked', 'got message');
@@ -67,10 +65,10 @@ diag "revoke the right" if $ENV{'TEST_VERBOSE'};
}
-diag "return rights the group had in the beginning" if $ENV{'TEST_VERBOSE'};
+diag "return rights the group had in the beginning";
if ( @has ) {
- $m->form_number(3);
- $m->select("GrantRight-$everyone_gid-RT::System-1", \@has);
+ $m->form_name('ModifyGroupRights');
+ $m->tick("SetRights-$everyone_gid-RT::System-1", $_) for @has;
$m->submit;
$m->content_contains('Right Granted', 'got message');
diff --git a/rt/t/web/rights1.t b/rt/t/web/rights1.t
index c8892f2fe..24e5c3448 100644
--- a/rt/t/web/rights1.t
+++ b/rt/t/web/rights1.t
@@ -2,11 +2,11 @@
use strict;
use HTTP::Cookies;
-use RT::Test tests => 29;
+use RT::Test nodata => 1, tests => 31;
my ($baseurl, $agent) = RT::Test->started_ok;
# Create a user with basically no rights, to start.
-my $user_obj = RT::User->new($RT::SystemUser);
+my $user_obj = RT::User->new(RT->SystemUser);
my ($ret, $msg) = $user_obj->LoadOrCreateByEmail('customer-'.$$.'@example.com');
ok($ret, 'ACL test user creation');
$user_obj->SetName('customer-'.$$);
@@ -24,7 +24,6 @@ my $cookie_jar = HTTP::Cookies->new;
$agent->cookie_jar($cookie_jar);
-no warnings 'once';
# get the top page
$agent->login( $user_obj->Name, 'customer');
@@ -36,13 +35,13 @@ ok(!$agent->find_link( url => "$RT::WebPath/User/Prefs.html",
# Now test for their presence, one at a time. Sleep for a bit after
# ACL changes, thanks to the 10s ACL cache.
-my ($grantid,$grantmsg) =$user_obj->PrincipalObj->GrantRight(Right => 'ShowConfigTab', Object => $RT::System);
+my ($grantid,$grantmsg) =$user_obj->PrincipalObj->GrantRight(Right => 'ShowConfigTab', Object => RT->System);
ok($grantid,$grantmsg);
$agent->reload;
-like($agent->{'content'} , qr/Logout/i, "Reloaded page successfully");
+$agent->content_contains('Logout', "Reloaded page successfully");
ok($agent->find_link( url => "$RT::WebPath/Admin/",
text => 'Configuration'), "Found config tab" );
my ($revokeid,$revokemsg) =$user_obj->PrincipalObj->RevokeRight(Right => 'ShowConfigTab');
@@ -50,41 +49,40 @@ ok ($revokeid,$revokemsg);
($grantid,$grantmsg) =$user_obj->PrincipalObj->GrantRight(Right => 'ModifySelf');
ok ($grantid,$grantmsg);
$agent->reload();
-like($agent->{'content'} , qr/Logout/i, "Reloaded page successfully");
+$agent->content_contains('Logout', "Reloaded page successfully");
ok($agent->find_link(
- text => 'Preferences'), "Found prefs pane" );
+ 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');
-is($agent->{'status'}, 200, "Fetched search builder page");
-ok($agent->{'content'} !~ /Load saved search/i, "No search loading box");
-ok($agent->{'content'} !~ /Saved searches/i, "No saved searches box");
+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");
($grantid,$grantmsg) = $user_obj->PrincipalObj->GrantRight(Right => 'LoadSavedSearch');
ok($grantid,$grantmsg);
$agent->reload();
-like($agent->{'content'} , qr/Load saved search/i, "Search loading box exists");
-ok($agent->{'content'} !~ /input\s+type=['"]submit['"][^>]+name=['"]SavedSearchSave['"]/i,
+$agent->content_contains("Load saved search", "Search loading box exists");
+$agent->content_unlike(qr/input\s+type=['"]submit['"][^>]+name=['"]SavedSearchSave['"]/i,
"Still no saved searches box");
($grantid,$grantmsg) =$user_obj->PrincipalObj->GrantRight(Right => 'CreateSavedSearch');
ok ($grantid,$grantmsg);
$agent->reload();
-like($agent->{'content'} , qr/Load saved search/i,
- "Search loading box still exists");
-like($agent->{'content'} , qr/input\s+type=['"]submit['"][^>]+name=['"]SavedSearchSave['"]/i,
+$agent->content_contains("Load saved search", "Search loading box still exists");
+$agent->content_like(qr/input\s+type=['"]submit['"][^>]+name=['"]SavedSearchSave['"]/i,
"Saved searches box exists");
# Create a group, and a queue, so we can test limited user visibility
# via SelectOwner.
-my $queue_obj = RT::Queue->new($RT::SystemUser);
+my $queue_obj = RT::Queue->new(RT->SystemUser);
($ret, $msg) = $queue_obj->Create(Name => 'CustomerQueue-'.$$,
Description => 'queue for SelectOwner testing');
ok($ret, "SelectOwner test queue creation. $msg");
-my $group_obj = RT::Group->new($RT::SystemUser);
+my $group_obj = RT::Group->new(RT->SystemUser);
($ret, $msg) = $group_obj->CreateUserDefinedGroup(Name => 'CustomerGroup-'.$$,
Description => 'group for SelectOwner testing');
ok($ret, "SelectOwner test group creation. $msg");
@@ -107,4 +105,3 @@ ok($agent->form_name('BuildQuery'), "Yep, form is still there");
my $input = $agent->current_form->find_input('ValueOfActor');
ok(grep(/customer-$$/, $input->value_names()), "Found self in the actor listing");
-1;
diff --git a/rt/t/web/saved_search_chart.t b/rt/t/web/saved_search_chart.t
index 105166233..f84307162 100644
--- a/rt/t/web/saved_search_chart.t
+++ b/rt/t/web/saved_search_chart.t
@@ -2,11 +2,12 @@
use strict;
use warnings;
-use RT::Test tests => 19;
+use RT::Test no_plan => 1;
my ( $url, $m ) = RT::Test->started_ok;
use RT::Attribute;
-my $search = RT::Attribute->new($RT::SystemUser);
-my $ticket = RT::Ticket->new($RT::SystemUser);
+
+my $search = RT::Attribute->new(RT->SystemUser);
+my $ticket = RT::Ticket->new(RT->SystemUser);
my ( $ret, $msg ) = $ticket->Create(
Subject => 'base ticket' . $$,
Queue => 'general',
@@ -35,7 +36,7 @@ $m->submit_form(
button => 'SavedSearchSave',
);
-$m->content_like( qr/Chart first chart saved/, 'saved first chart' );
+$m->content_contains("Chart first chart saved", 'saved first chart' );
my ( $search_uri, $id ) = $m->content =~ /value="(RT::User-\d+-SavedSearch-(\d+))"/;
$m->submit_form(
@@ -64,8 +65,8 @@ $m->submit_form(
button => 'SavedSearchSave',
);
-$m->content_like( qr/Chart first chart updated/, 'found updated message' );
-$m->content_like( qr/id=2/, 'Query is updated' );
+$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' );
$m->content_like( qr/value="pie"\s+selected="selected"/,
@@ -81,6 +82,73 @@ $m->submit_form(
form_name => 'SaveSearch',
button => 'SavedSearchDelete',
);
-$m->content_like( qr/Chart first chart deleted/, 'found deleted message' );
+$m->content_contains("Chart first chart deleted", 'found deleted message' );
$m->content_unlike( qr/value="RT::User-\d+-SavedSearch-\d+"/,
'no saved search' );
+
+for ('A' .. 'F') {
+ $ticket->Create(
+ Subject => $$ . $_,
+ );
+}
+
+for ([A => 'subject="'.$$.'A"'], [BorC => 'subject="'.$$.'B" OR subject="'.$$.'C"']) {
+ $m->get_ok('/Search/Edit.html');
+ $m->form_name('BuildQueryAdvanced');
+ $m->field('Query', $_->[1]);
+ $m->submit;
+
+ # Save the search
+ $m->follow_link_ok({id => 'page-chart'});
+ $m->form_name('SaveSearch');
+ $m->field(SavedSearchDescription => $_->[0]);
+ $m->click_ok('SavedSearchSave');
+ $m->text_contains('Chart ' . $_->[0] . ' saved.');
+
+}
+
+$m->form_name('SaveSearch');
+my @saved_search_ids =
+ $m->current_form->find_input('SavedSearchLoad')->possible_values;
+shift @saved_search_ids; # first value is blank
+
+cmp_ok(@saved_search_ids, '==', 2, 'Two saved charts were made');
+
+# TODO get find_link('page-chart')->URI->params to work...
+sub page_chart_link_has {
+ my ($m, $id, $msg) = @_;
+
+ $Test::Builder::Level = $Test::Builder::Level + 1;
+
+ (my $dec_id = $id) =~ s/:/%3A/g;
+
+ my $chart_url = $m->find_link(id => 'page-chart')->url;
+ like(
+ $chart_url, qr{SavedChartSearchId=\Q$dec_id\E},
+ $msg || 'Page chart link matches the pattern we expected'
+ );
+}
+
+# load the first chart
+$m->field('SavedSearchLoad' => $saved_search_ids[0]);
+$m->click('SavedSearchLoadSubmit');
+
+page_chart_link_has($m, $saved_search_ids[0]);
+
+$m->form_name('SaveSearch');
+is($m->form_number(3)->value('SavedChartSearchId'), $saved_search_ids[0]);
+
+$m->form_name('SaveSearch');
+
+# now load the second chart
+$m->field('SavedSearchLoad' => $saved_search_ids[1]);
+$m->click('SavedSearchLoadSubmit');
+
+page_chart_link_has($m, $saved_search_ids[1]);
+
+is(
+ $m->form_number(3)->value('SavedChartSearchId'), $saved_search_ids[1],
+ 'Second form is seen as a hidden field'
+);
+
+page_chart_link_has($m, $saved_search_ids[1]);
diff --git a/rt/t/web/saved_search_context.t b/rt/t/web/saved_search_context.t
new file mode 100644
index 000000000..fe9c51ead
--- /dev/null
+++ b/rt/t/web/saved_search_context.t
@@ -0,0 +1,69 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+
+use RT::Test no_plan => 1;
+my ( $url, $m ) = RT::Test->started_ok;
+
+my $ticket = RT::Ticket->new(RT->SystemUser);
+for (['x', 50], ['y', 40], ['z', 30]) {
+ $ticket->Create(
+ Subject => $_->[0],
+ Queue => 'general',
+ Owner => 'root',
+ Priority => $_->[1],
+ Requestor => 'root@localhost',
+ );
+}
+
+ok( $m->login, 'logged in' );
+
+$m->get($url . '/Search/Build.html?NewQuery=1');
+$m->form_name('BuildQuery');
+$m->field(ValueOfPriority => 45);
+$m->click('DoSearch');
+#RT->Logger->error($m->uri); sleep 100;
+#{ open my $fh, '>', 'm.html'; print $fh $m->content; close $fh; }; die;
+$m->text_contains('Found 2 tickets');
+
+$m->follow_link(id => 'page-edit_search');
+$m->form_name('BuildQuery');
+$m->field(ValueOfAttachment => 'z');
+$m->click('DoSearch');
+
+$m->text_contains('Found 1 ticket');
+
+$m->follow_link(id => 'page-bulk');
+
+$m->form_name('BulkUpdate');
+ok(!$m->value('UpdateTicket2'), "There is no Ticket #2 in the search's bulk update");
+
+sub edit_search_link_has {
+ my ($m, $id, $msg) = @_;
+
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+
+ (my $dec_id = $id) =~ s/:/%3A/g;
+
+ my $chart_url = $m->find_link(id => 'page-edit_search')->url;
+ like(
+ $chart_url, qr{SavedSearchId=\Q$dec_id\E},
+ $msg || 'Search link matches the pattern we expected'
+ );
+}
+
+diag("Test search context");
+{
+ $m->get_ok($url . '/Search/Build.html');
+ $m->form_name('BuildQuery');
+ $m->field(ValueOfPriority => 45);
+ $m->click('AddClause');
+ $m->form_name('BuildQuery');
+ $m->set_fields(
+ SavedSearchDescription => 'my saved search',
+ );
+ $m->click('SavedSearchSave');
+
+ my $saved_search_id = $m->form_name('BuildQuery')->value('SavedSearchId');
+ edit_search_link_has($m, $saved_search_id);
+}
diff --git a/rt/t/web/saved_search_permissions.t b/rt/t/web/saved_search_permissions.t
index f91ca13c6..5cae30b28 100644
--- a/rt/t/web/saved_search_permissions.t
+++ b/rt/t/web/saved_search_permissions.t
@@ -2,8 +2,8 @@
use strict;
use warnings;
-use RT::Test tests => 10;
-my $user = RT::User->new($RT::SystemUser);
+use RT::Test tests => 12;
+my $user = RT::User->new(RT->SystemUser);
ok(
$user->Create(
Name => 'foo',
@@ -23,7 +23,7 @@ $m->submit_form(
$m->content_contains( q{name="SavedSearchDescription" value="test"},
'saved test search' );
my ($id) = $m->content =~ /value="(RT::User-\d+-SavedSearch-\d+)"/;
-ok( $m->login( 'foo', 'foobar' ), 'logged in' );
+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"};
diff --git a/rt/t/web/saved_search_update.t b/rt/t/web/saved_search_update.t
index 9b2724e82..dfb18d49c 100644
--- a/rt/t/web/saved_search_update.t
+++ b/rt/t/web/saved_search_update.t
@@ -3,7 +3,7 @@
use strict;
use warnings;
-use RT::Test tests => 16;
+use RT::Test tests => 18;
my $root = RT::User->new( $RT::SystemUser );
$root->Load('root');
diff --git a/rt/t/web/scrips.t b/rt/t/web/scrips.t
new file mode 100644
index 000000000..def20eca7
--- /dev/null
+++ b/rt/t/web/scrips.t
@@ -0,0 +1,105 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 14;
+
+# TODO:
+# Test the rest of the conditions.
+# Test actions.
+# Test templates?
+# Test cleanup scripts.
+
+my ($baseurl, $m) = RT::Test->started_ok;
+ok $m->login, "logged in";
+
+$m->follow_link_ok({id => 'tools-config-global-scrips-create'});
+
+sub prepare_code_with_value {
+ my $value = shift;
+
+ # changing the ticket is an easy scrip check for a test
+ return
+ '$self->TicketObj->SetSubject(' .
+ '$self->TicketObj->Subject . ' .
+ '"|" . ' . $value .
+ ')';
+}
+
+{
+ # preserve order for checking the subject string later
+ my @values_for_actions;
+
+ my $conds = RT::ScripConditions->new(RT->SystemUser);
+ foreach my $cond_value ('On Forward', 'On Forward Ticket', 'On Forward Transaction') {
+ $conds->Limit(
+ FIELD => 'name',
+ VALUE => $cond_value,
+ ENTRYAGGREGATOR => 'OR',
+ );
+ }
+
+ while (my $rec = $conds->Next) {
+ push @values_for_actions, [$rec->Id, '"' . $rec->Name . '"'];
+ }
+
+ @values_for_actions = sort { $a->[0] cmp $b->[0] } @values_for_actions;
+
+ 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'});
+ my $prepare_code = prepare_code_with_value($prepare_code_value);
+ $m->form_name('ModifyScrip');
+ $m->set_fields(
+ 'Scrip-new-ScripCondition' => $condition,
+ 'Scrip-new-ScripAction' => 15, # User Defined
+ 'Scrip-new-Template' => 1, # Blank
+ 'Scrip-new-CustomPrepareCode' => $prepare_code,
+ );
+ $m->submit;
+ }
+
+ my $ticket_obj = RT::Test->create_ticket(
+ Subject => 'subject',
+ Content => 'stuff',
+ Queue => 1,
+ );
+ my $ticket = $ticket_obj->id;
+ $m->goto_ticket($ticket);
+
+ $m->follow_link_ok(
+ { id => 'page-actions-forward' },
+ 'follow 1st Forward to forward ticket'
+ );
+
+ diag "Forward Ticket" if $ENV{TEST_VERBOSE};
+ $m->submit_form(
+ form_name => 'ForwardMessage',
+ fields => {
+ To => 'rt-test, rt-to@example.com',
+ },
+ button => 'ForwardAndReturn'
+ );
+
+ $m->text_contains("#${ticket}: subject|On Forward|On Forward Ticket");
+
+ diag "Forward Transaction" if $ENV{TEST_VERBOSE};
+ # get the first transaction on the ticket
+ my ($transaction) = $ticket_obj->Transactions->First->id;
+ $m->get(
+ "$baseurl/Ticket/Forward.html?id=1&QuoteTransaction=$transaction"
+ );
+ $m->submit_form(
+ form_name => 'ForwardMessage',
+ fields => {
+ To => 'rt-test, rt-to@example.com',
+ },
+ button => 'ForwardAndReturn'
+ );
+
+ $m->text_contains("#${ticket}: subject|On Forward|On Forward Ticket|On Forward|On Forward Transaction");
+
+ RT::Test->clean_caught_mails;
+}
diff --git a/rt/t/web/scrub.t b/rt/t/web/scrub.t
new file mode 100644
index 000000000..6483a7500
--- /dev/null
+++ b/rt/t/web/scrub.t
@@ -0,0 +1,46 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use RT::Test nodb => 1, tests => 6;
+use RT::Interface::Web; # This gets us HTML::Mason::Commands
+use Test::LongString;
+
+{
+ my $html = 'This is a test of <span style="color: rgb(255, 0, 0); ">color</span> and <span style="font-size: 18px; "><span style="font-family: Georgia, serif; ">font</span></span> and <em><u><strike><strong>boldness</strong></strike></u></em>.';
+ is_string(scrub_html($html), $html, "CKEditor produced HTML sails through");
+}
+
+{
+ my $html = '<p style="text-align: right; ">
+ And <span style="color: rgb(255, 0, 0); "><span style="font-size: 16px; "><span style="font-family: Georgia, serif; ">alignment with color</span></span></span>?</p>';
+ is_string(scrub_html($html), $html, "CKEditor produced HTML sails through");
+}
+
+{
+ my $html = 'This is a test of <span style="color: rgb(255, 0, 0); content: url(/Nasty/URL);">color</span> and <span style="font-size: 18px; "><span style="font-family: Georgia, serif; ">font</span></span> and <em><u><strike><strong>boldness</strong></strike></u></em>.';
+ my $expected = 'This is a test of <span>color</span> and <span style="font-size: 18px; "><span style="font-family: Georgia, serif; ">font</span></span> and <em><u><strike><strong>boldness</strong></strike></u></em>.';
+ is_string(scrub_html($html), $expected, "nasty CSS not allowed through");
+}
+
+{
+ my $html = 'Let\'s add some <span style="color: blue; font-family: Georgia">color</span> up in <span style="color: #DEADBE">here</span>.';
+ is_string(scrub_html($html), $html, "multiple props and color specs allowed");
+}
+
+{
+ my $html = q[<span lang=EN-US style='font-family:"Century Gothic","sans-serif";'>oh hai I'm some text</span>];
+ my $expected = q[<span style="font-family:&quot;Century Gothic&quot;,&quot;sans-serif&quot;;">oh hai I'm some text</span>];
+ is_string(scrub_html($html), $expected, "font lists");
+}
+
+{
+ my $html = q[<span lang=EN-US style='font-size:7.5pt;font-family:"Century Gothic","sans-serif";color:#666666;mso-fareast-language:IT'>oh hai I'm some text</span>];
+ my $expected = q[<span style="font-size:7.5pt;font-family:&quot;Century Gothic&quot;,&quot;sans-serif&quot;;color:#666666;mso-fareast-language:IT">oh hai I'm some text</span>];
+ is_string(scrub_html($html), $expected, "outlook html");
+}
+
+sub scrub_html {
+ return HTML::Mason::Commands::ScrubHTML(shift);
+}
+
diff --git a/rt/t/web/search_bulk_update_links.t b/rt/t/web/search_bulk_update_links.t
index d6bfdfd3c..7d150a699 100644
--- a/rt/t/web/search_bulk_update_links.t
+++ b/rt/t/web/search_bulk_update_links.t
@@ -2,7 +2,7 @@
use strict;
use warnings;
-use RT::Test tests => 28;
+use RT::Test tests => 47;
my ( $url, $m ) = RT::Test->started_ok;
ok( $m->login, 'logged in' );
@@ -13,7 +13,7 @@ use RT::Ticket;
my ( @link_tickets, @search_tickets );
for ( 1 .. 3 ) {
- my $link_ticket = RT::Ticket->new($RT::SystemUser);
+ my $link_ticket = RT::Ticket->new(RT->SystemUser);
my ( $ret, $msg ) = $link_ticket->Create(
Subject => "link ticket $_",
Queue => 'general',
@@ -25,7 +25,7 @@ for ( 1 .. 3 ) {
}
for ( 1 .. 3 ) {
- my $ticket = RT::Ticket->new($RT::SystemUser);
+ my $ticket = RT::Ticket->new(RT->SystemUser);
my ( $ret, $msg ) = $ticket->Create(
Subject => "search ticket $_",
Queue => 'general',
@@ -41,7 +41,7 @@ $m->get_ok( $url . "/Search/Bulk.html?Query=id=$search_tickets[0]&Rows=10" );
$m->content_contains( 'Current Links', 'has current links part' );
$m->content_lacks( 'DeleteLink--', 'no delete link stuff' );
$m->submit_form(
- form_number => 3,
+ form_name => 'BulkUpdate',
fields => {
'Ticket-DependsOn' => $link_tickets[0],
'Ticket-MemberOf' => $link_tickets[1],
@@ -77,9 +77,17 @@ $m->get_ok( $url . "/Search/Bulk.html?Query=$query&Rows=10" );
$m->content_contains( 'Current Links', 'has current links part' );
$m->content_lacks( 'DeleteLink--', 'no delete link stuff' );
+$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/;
+for my $field ( @fields ) {
+ is( $m->value($field), '', "default $field is empty" );
+}
+
# test DependsOn, MemberOf and RefersTo
$m->submit_form(
- form_number => 3,
+ form_name => 'BulkUpdate',
fields => {
'Ticket-DependsOn' => $link_tickets[0],
'Ticket-MemberOf' => $link_tickets[1],
@@ -98,7 +106,7 @@ $m->content_contains(
'found refers to link' );
$m->submit_form(
- form_number => 3,
+ form_name => 'BulkUpdate',
fields => {
"DeleteLink--DependsOn-fsck.com-rt://$rtname/ticket/$link_tickets[0]" =>
1,
@@ -114,7 +122,7 @@ $m->content_lacks( 'DeleteLink--', 'links are all deleted' );
# test DependedOnBy, Members and ReferredToBy
$m->submit_form(
- form_number => 3,
+ form_name => 'BulkUpdate',
fields => {
'DependsOn-Ticket' => $link_tickets[0],
'MemberOf-Ticket' => $link_tickets[1],
@@ -133,7 +141,7 @@ $m->content_contains(
'found referrd to link' );
$m->submit_form(
- form_number => 3,
+ form_name => 'BulkUpdate',
fields => {
"DeleteLink-fsck.com-rt://$rtname/ticket/$link_tickets[0]-DependsOn-" =>
1,
diff --git a/rt/t/web/search_cf_quotes.t b/rt/t/web/search_cf_quotes.t
new file mode 100644
index 000000000..360fe0dc9
--- /dev/null
+++ b/rt/t/web/search_cf_quotes.t
@@ -0,0 +1,53 @@
+use strict;
+use warnings;
+
+use RT::Test tests => 24;
+my ( $baseurl, $m ) = RT::Test->started_ok;
+
+my $cf = RT::CustomField->new($RT::SystemUser);
+ok(
+ $cf->Create(
+ Name => "I'm a cf",
+ Type => 'Date',
+ LookupType => 'RT::Queue-RT::Ticket',
+ )
+);
+ok( $cf->AddToObject( RT::Queue->new($RT::SystemUser) ) );
+
+RT::Test->create_tickets(
+ { Queue => 'General' },
+ { Subject => 'ticket foo', 'CustomField-' . $cf->id => '2011-09-15' },
+ { Subject => 'ticket bar', 'CustomField-' . $cf->id => '2011-10-15' },
+ { Subject => 'ticket baz' },
+);
+
+ok( $m->login, 'logged in' );
+
+$m->get_ok('/Search/Build.html');
+$m->form_name( 'BuildQuery' );
+
+my ($cf_op) =
+ $m->find_all_inputs( type => 'option', name_regex => qr/I'm a cf/ );
+my ($cf_field) =
+ $m->find_all_inputs( type => 'text', name_regex => qr/I'm a cf/ );
+
+diag "search directly";
+$m->submit_form(
+ fields => { $cf_op->name => '<', $cf_field->name => '2011-09-30', },
+ button => 'DoSearch',
+);
+
+$m->title_is( 'Found 1 ticket', 'found only 1 ticket' );
+$m->content_contains( 'ticket foo', 'has ticket foo' );
+
+diag "first add clause, then search";
+$m->get_ok('/Search/Build.html?NewQuery=1');
+$m->form_name( 'BuildQuery' );
+$m->submit_form(
+ fields => { $cf_op->name => '<', $cf_field->name => '2011-09-30', },
+ button => 'AddClause',
+);
+$m->follow_link_ok( { text => 'Show Results' } );
+$m->title_is( 'Found 1 ticket', 'found only 1 ticket' );
+$m->content_contains( 'ticket foo', 'has ticket foo' );
+
diff --git a/rt/t/web/search_rss.t b/rt/t/web/search_rss.t
index 454dc0369..95de931c3 100644
--- a/rt/t/web/search_rss.t
+++ b/rt/t/web/search_rss.t
@@ -2,10 +2,10 @@
use strict;
-use RT::Test tests => 36;
-RT::Test->started_ok;
+use RT::Test tests => 38;
+my ($baseurl, $agent) = RT::Test->started_ok;
-my $ticket = RT::Ticket->new($RT::SystemUser);
+my $ticket = RT::Ticket->new(RT->SystemUser);
for ( 1 .. 5 ) {
$ticket->Create(
Subject => 'Ticket ' . $_,
@@ -15,7 +15,6 @@ for ( 1 .. 5 ) {
);
}
-my $agent = RT::Test::Web->new;
ok $agent->login('root', 'password'), 'logged in as root';
$agent->get_ok('/Search/Build.html');
@@ -23,7 +22,7 @@ $agent->form_name('BuildQuery');
$agent->field('idOp', '>');
$agent->field('ValueOfid', '0');
$agent->submit('DoSearch');
-$agent->follow_link_ok({text=>'Show Results'});
+$agent->follow_link_ok({id => 'page-results'});
for ( 1 .. 5 ) {
$agent->content_contains('Ticket ' . $_);
@@ -64,7 +63,7 @@ my $user_b = RT::Test->load_or_create_user(
Name => 'user_b', Password => 'password',
);
ok $user_b && $user_b->id, 'loaded or created user';
-$agent_b->login('user_b', 'password'), 'logged in as user B';
+$agent_b->login('user_b', 'password');
$agent_b->get_ok($noauth_uri);
is( $agent_b->content_type, 'application/rss+xml', 'content type' );
is( $agent_b->content, $rss_content, 'content' );
diff --git a/rt/t/web/search_simple.t b/rt/t/web/search_simple.t
new file mode 100644
index 000000000..1efc9a566
--- /dev/null
+++ b/rt/t/web/search_simple.t
@@ -0,0 +1,22 @@
+use strict;
+use warnings;
+
+use RT::Test tests => 16;
+my ( $baseurl, $m ) = RT::Test->started_ok;
+
+RT::Test->create_tickets(
+ { Queue => 'General' },
+ { Subject => 'ticket foo' },
+ { Subject => 'ticket bar' },
+);
+
+ok( $m->login, 'logged in' );
+
+$m->get_ok('/Search/Simple.html');
+$m->content_lacks( 'Show Results', 'no page menu' );
+$m->get_ok('/Search/Simple.html?q=ticket foo');
+$m->content_contains( 'Show Results', "has page menu" );
+$m->title_is( 'Found 1 ticket', 'title' );
+$m->content_contains( 'ticket foo', 'has ticket foo' );
+
+# TODO more simple search tests
diff --git a/rt/t/web/search_tabs.t b/rt/t/web/search_tabs.t
new file mode 100644
index 000000000..b3ed2cbdf
--- /dev/null
+++ b/rt/t/web/search_tabs.t
@@ -0,0 +1,86 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+
+use RT::Test tests => 21;
+my ($baseurl, $agent) = RT::Test->started_ok;
+
+my $ticket = RT::Ticket->new(RT->SystemUser);
+for ( 1 .. 3 ) {
+ $ticket->Create(
+ Subject => 'Ticket ' . $_,
+ Queue => 'General',
+ Owner => 'root',
+ Requestor => 'clownman@localhost',
+ );
+}
+
+ok $agent->login('root', 'password'), 'logged in as root';
+
+# [issues.bestpractical.com #16841] {
+$agent->get_ok('/Search/Build.html');
+
+$agent->form_name('BuildQuery');
+$agent->field('idOp', '=');
+$agent->field('ValueOfid', '1');
+$agent->submit('AddClause');
+
+$agent->form_name('BuildQuery');
+$agent->field('idOp', '=');
+$agent->field('ValueOfid', '2');
+$agent->field('AndOr', 'OR');
+$agent->submit('AddClause');
+
+$agent->follow_link_ok({id => 'page-results'});
+$agent->title_is('Found 2 tickets');
+# }
+
+# [issues.bestpractical.com #17237] {
+$agent->follow_link_ok({text => 'New Search'});
+$agent->title_is('Query Builder');
+
+$agent->form_name('BuildQuery');
+$agent->field('idOp', '=');
+$agent->field('ValueOfid', '1');
+$agent->submit('AddClause');
+
+$agent->form_name('BuildQuery');
+$agent->field('idOp', '=');
+$agent->field('ValueOfid', '2');
+$agent->field('AndOr', 'OR');
+$agent->click_button(name => 'DoSearch');
+
+$agent->title_is('Found 2 tickets');
+
+$agent->follow_link_ok({id => 'page-results'});
+$agent->title_is('Found 2 tickets');
+# }
+
+$agent->follow_link_ok({text => 'Chart'});
+$agent->text_contains('id = 1 OR id = 2');
+$agent->form_name('SaveSearch');
+$agent->field('SavedSearchDescription' => 'this is my saved chart');
+$agent->click_button(name => 'SavedSearchSave');
+
+# Confirm that we saved the chart and that it's the "current chart"
+$agent->text_contains('Chart this is my saved chart saved.');
+$agent->form_name('SaveSearch');
+is($agent->value('SavedSearchDescription'), 'this is my saved chart');
+
+$agent->follow_link_ok({text => 'Edit Search'});
+$agent->form_name('BuildQuery');
+$agent->field('idOp', '=');
+$agent->field('ValueOfid', '3');
+$agent->field('AndOr', 'OR');
+$agent->click_button(name => 'DoSearch');
+
+$agent->title_is('Found 3 tickets');
+
+$agent->follow_link_ok({text => 'Chart'});
+$agent->text_contains('id = 1 OR id = 2 OR id = 3');
+
+# The interesting bit: confirm that the chart we saved is still the
+# "current chart" after roundtripping through search builder
+$agent->form_name('SaveSearch');
+is($agent->value('SavedSearchDescription'), 'this is my saved chart');
+
diff --git a/rt/t/web/self_service.t b/rt/t/web/self_service.t
new file mode 100644
index 000000000..49d9e37ee
--- /dev/null
+++ b/rt/t/web/self_service.t
@@ -0,0 +1,19 @@
+use strict;
+use warnings;
+use RT::Test tests => 9;
+
+my ($url, $m) = RT::Test->started_ok;
+
+my ($ticket) =
+ RT::Test->create_ticket( Queue => 'General', Subject => 'test subject' );
+
+$m->login();
+
+$m->get_ok( '/SelfService/Display.html?id=' . $ticket->id,
+ 'got selfservice display page' );
+
+my $title = '#' . $ticket->id . ': test subject';
+$m->title_is( $title );
+$m->content_contains( "<h1>$title</h1>", "contains <h1>$title</h1>" );
+
+# TODO need more SelfService tests
diff --git a/rt/t/web/squish.t b/rt/t/web/squish.t
new file mode 100644
index 000000000..ff43e74fb
--- /dev/null
+++ b/rt/t/web/squish.t
@@ -0,0 +1,78 @@
+use strict;
+use warnings;
+use RT;
+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') );
+
+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! },
+ '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->back;
+my ($js_link) =
+ $m->content =~ m!src="([^"]+?squished-([a-f0-9]{32})\.js)"!;
+$m->get_ok( $url . $js_link, 'follow squished js' );
+$m->content_lacks('function just_testing', "no not-by-default.js");
+$m->content_contains('jQuery.noConflict', "found default js content");
+
+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' );
+
+( $url, $m ) = RT::Test->started_ok;
+
+$m->login;
+$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->back;
+($js_link) =
+ $m->content =~ m!src="([^"]+?squished-([a-f0-9]{32})\.js)"!;
+$m->get_ok( $url . $js_link, 'follow squished js' );
+$m->content_contains( 'function just_testing', "has not-by-default.js" );
+$m->content_contains('jQuery.noConflict', "found default js content");
+RT::Test->stop_server;
+
+
+diag "Test with a trivial jsmin which is a pass-through";
+RT->Config->Set( 'JSMinPath' => RT::Test::get_abs_relocatable_dir("passthrough-jsmin"));
+( $url, $m ) = RT::Test->started_ok;
+$m->login;
+($js_link) =
+ $m->content =~ m!src="([^"]+?squished-([a-f0-9]{32})\.js)"!;
+$m->get_ok( $url . $js_link, 'follow squished js' );
+$m->content_contains( 'passthrough-jsmin added this', "has passthrough-added content" );
+$m->content_contains( 'function just_testing', "has not-by-default.js" );
+$m->content_contains('jQuery.noConflict', "found default js content");
+RT::Test->stop_server;
+
+
+diag "test squished files with devel mode enabled";
+RT->Config->Set( 'DevelMode' => 1 );
+RT->AddJavaScript( 'not-by-default.js' );
+RT->AddStyleSheets( 'nottherebutwedontcare.css' );
+
+( $url, $m ) = RT::Test->started_ok;
+$m->login;
+$m->content_unlike( qr!squished-.*?\.(js|css)!,
+ 'no squished link with develmode' );
+
+$m->content_contains('not-by-default.js', "found extra javascript resource");
+$m->content_contains('nottherebutwedontcare.css', "found extra css resource");
+$m->content_contains('jquery_noconflict.js', "found a default js resource");
+
diff --git a/rt/t/web/template.t b/rt/t/web/template.t
new file mode 100644
index 000000000..40a5366dc
--- /dev/null
+++ b/rt/t/web/template.t
@@ -0,0 +1,62 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use RT::Test tests => 19;
+
+my $user_a = RT::Test->load_or_create_user(
+ Name => 'user_a', Password => 'password',
+);
+ok $user_a && $user_a->id, 'loaded or created user';
+
+my ($baseurl, $m) = RT::Test->started_ok;
+
+ok( RT::Test->set_rights(
+ { Principal => $user_a, Right => [qw(ShowConfigTab ShowTemplate ModifyTemplate)] },
+), 'set rights');
+
+ok $m->login('user_a', 'password'), 'logged in as user A';
+
+# get to the templates screen
+$m->follow_link( text => 'Configuration' );
+$m->title_is(q{RT Administration}, 'admin screen');
+
+$m->follow_link( text => 'Global' );
+$m->title_is(q{Admin/Global configuration}, 'global admin');
+
+$m->follow_link( text => 'Templates' );
+$m->title_is(q{Modify templates which apply to all queues}, 'global templates');
+
+$m->follow_link( text => 'Resolved' ); # template name
+$m->title_is(q{Modify template Resolved}, 'modifying the Resolved template');
+
+# now try changing Type back and forth
+$m->form_name('ModifyTemplate');
+is($m->value('Type'), 'Perl');
+
+$m->field(Type => 'Simple');
+$m->submit;
+
+$m->title_is(q{Modify template Resolved}, 'modifying the Resolved template');
+$m->form_name('ModifyTemplate');
+is($m->value('Type'), 'Simple', 'updated type to simple');
+
+$m->field(Type => 'Perl');
+$m->submit;
+
+$m->title_is(q{Modify template Resolved}, 'modifying the Resolved template');
+$m->form_name('ModifyTemplate');
+is($m->value('Type'), 'Simple', 'need the ExecuteCode right to update Type to Perl');
+$m->content_contains('Permission Denied');
+
+ok( RT::Test->add_rights(
+ { Principal => $user_a, Right => [qw(ExecuteCode)] },
+), 'add ExecuteCode rights');
+
+$m->field(Type => 'Perl');
+$m->submit;
+
+$m->title_is(q{Modify template Resolved}, 'modifying the Resolved template');
+$m->form_name('ModifyTemplate');
+is($m->value('Type'), 'Perl', 'now that we have ExecuteCode we can update Type to Perl');
+
diff --git a/rt/t/web/ticket-create-utf8.t b/rt/t/web/ticket-create-utf8.t
index f37eeec06..8d36bd19e 100644
--- a/rt/t/web/ticket-create-utf8.t
+++ b/rt/t/web/ticket-create-utf8.t
@@ -3,9 +3,7 @@
use strict;
use warnings;
-use RT::Test tests => 41;
-
-$RT::Test::SKIP_REQUEST_WORK_AROUND = 1;
+use RT::Test tests => 43;
use Encode;
@@ -32,7 +30,7 @@ ok $m->login, 'logged in';
# create a ticket with a subject only
foreach my $test_str ( $ru_test, $l1_test ) {
ok $m->goto_create_ticket( $q ), "go to create ticket";
- $m->form_number(3);
+ $m->form_name('TicketCreate');
$m->field( Subject => $test_str );
$m->submit;
@@ -49,7 +47,7 @@ foreach my $test_str ( $ru_test, $l1_test ) {
foreach my $test_str ( $ru_test, $l1_test ) {
foreach my $support_str ( $ru_support, $l1_support ) {
ok $m->goto_create_ticket( $q ), "go to create ticket";
- $m->form_number(3);
+ $m->form_name('TicketCreate');
$m->field( Subject => $test_str );
$m->field( Content => $support_str );
$m->submit;
@@ -58,8 +56,8 @@ foreach my $test_str ( $ru_test, $l1_test ) {
qr{<td\s+class="message-header-value"[^>]*>\s*\Q$test_str\E\s*</td>}i,
'header on the page'
);
- $m->content_like(
- qr{\Q$support_str\E}i,
+ $m->content_contains(
+ $support_str,
'content on the page'
);
@@ -72,7 +70,7 @@ foreach my $test_str ( $ru_test, $l1_test ) {
foreach my $test_str ( $ru_test, $l1_test ) {
foreach my $support_str ( $ru_support, $l1_support ) {
ok $m->goto_create_ticket( $q ), "go to create ticket";
- $m->form_number(3);
+ $m->form_name('TicketCreate');
$m->field( Subject => $test_str );
$m->field( Content => $support_str );
$m->submit;
@@ -81,8 +79,8 @@ foreach my $test_str ( $ru_test, $l1_test ) {
qr{<td\s+class="message-header-value"[^>]*>\s*\Q$test_str\E\s*</td>}i,
'header on the page'
);
- $m->content_like(
- qr{\Q$support_str\E}i,
+ $m->content_contains(
+ $support_str,
'content on the page'
);
diff --git a/rt/t/web/ticket_display.t b/rt/t/web/ticket_display.t
new file mode 100644
index 000000000..a9cab0cbf
--- /dev/null
+++ b/rt/t/web/ticket_display.t
@@ -0,0 +1,63 @@
+use strict;
+use warnings;
+
+use RT::Test tests => 18;
+
+my $queue = RT::Test->load_or_create_queue( Name => 'General' );
+
+my $user = RT::Test->load_or_create_user(
+ Name => 'user',
+ Password => 'password',
+);
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok(
+ RT::Test->set_rights(
+ { Principal => $user, Right => [qw(SeeQueue CreateTicket)] },
+ ),
+ 'set rights'
+);
+
+ok $m->login( 'user', 'password' ), 'logged in as user';
+
+diag "test ShowTicket right";
+{
+
+ $m->get_ok( '/Ticket/Create.html?Queue=' . $queue->id,
+ 'go to ticket create page' );
+ my $form = $m->form_name('TicketCreate');
+ $m->submit_form( fields => { Subject => 'ticket foo' } );
+
+ my $ticket = RT::Test->last_ticket;
+ ok( $ticket->id, 'ticket is created' );
+ my $id = $ticket->id;
+
+ $m->content_lacks( "Ticket $id created", 'created ticket' );
+ $m->content_contains( "No permission to view newly created ticket #$id",
+ 'got no permission msg' );
+ $m->warning_like( qr/No permission to view newly created ticket #$id/,
+ 'got no permission warning' );
+
+
+ $m->goto_ticket($id);
+ $m->content_contains( "No permission to view ticket",
+ 'got no permission msg' );
+ $m->warning_like( qr/No permission to view ticket/, 'got warning' );
+ $m->title_is('RT Error');
+
+ ok(
+ RT::Test->add_rights(
+ { Principal => $user, Right => [qw(ShowTicket)] },
+ ),
+ 'add ShowTicket right'
+ );
+
+ $m->reload;
+
+ $m->content_lacks( "No permission to view ticket", 'no error msg' );
+ $m->title_is( "#$id: ticket foo", 'we can it' );
+}
+
+
+# TODO more /Ticket/Display.html tests here
+
diff --git a/rt/t/web/ticket_forward.t b/rt/t/web/ticket_forward.t
new file mode 100644
index 000000000..be06ad976
--- /dev/null
+++ b/rt/t/web/ticket_forward.t
@@ -0,0 +1,232 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use RT::Test tests => undef;
+use File::Spec;
+my $att_file = File::Spec->catfile( RT::Test->temp_directory, 'attachment' );
+open my $att_fh, '>', $att_file or die $!;
+print $att_fh "this is an attachment";
+close $att_fh;
+my $att_name = ( File::Spec->splitpath($att_file) )[-1];
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in as root';
+
+# Create a ticket with content and an attachment
+$m->get_ok( $baseurl . '/Ticket/Create.html?Queue=1' );
+
+$m->submit_form(
+ form_name => 'TicketCreate',
+ fields => {
+ Subject => 'test forward',
+ Content => 'this is content',
+ Attach => $att_file,
+ },
+);
+$m->content_like( qr/Ticket \d+ created/i, 'created the ticket' );
+RT::Test->clean_caught_mails;
+
+diag "Forward Ticket" if $ENV{TEST_VERBOSE};
+{
+ $m->follow_link_ok(
+ { id => 'page-actions-forward' },
+ 'follow 1st Forward to forward ticket'
+ );
+
+ $m->submit_form(
+ form_name => 'ForwardMessage',
+ fields => {
+ To => 'rt-test, rt-to@example.com',
+ Cc => 'rt-cc@example.com',
+ },
+ 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',
+ '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!Cc: rt-cc\@example.com!, 'Cc 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' );
+}
+
+diag "Forward Transaction" if $ENV{TEST_VERBOSE};
+{
+ $m->follow_link_ok( { text => 'Forward', n => 2 }, 'follow 2nd Forward' );
+ $m->submit_form(
+ form_name => 'ForwardMessage',
+ fields => {
+ To => 'rt-test, rt-to@example.com',
+ Cc => 'rt-cc@example.com',
+ Bcc => 'rt-bcc@example.com'
+ },
+ 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/,
+ '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!Cc: rt-cc\@example.com!, 'Cc field' );
+ like( $mail, qr!Bcc: rt-bcc\@example.com!, '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' );
+}
+
+diag "Forward Ticket without content" if $ENV{TEST_VERBOSE};
+{
+ my $ticket = RT::Test->create_ticket(
+ Subject => 'test forward without content',
+ Queue => 1,
+ );
+ $m->get_ok( $baseurl . '/Ticket/Forward.html?id=' . $ticket->id );
+ $m->submit_form(
+ form_name => 'ForwardMessage',
+ 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/To: rt-test\@example\.com/, 'To field' );
+ like( $mail, qr/This is a forward of ticket #\d/, 'content' );
+}
+
+diag "Forward Transaction with attachments but empty content" if $ENV{TEST_VERBOSE};
+{
+ # Create a ticket without content but with a non-text/plain attachment
+ $m->get_ok( $baseurl . '/Ticket/Create.html?Queue=1' );
+
+ $m->form_name('TicketCreate');
+ my $attach = $m->current_form->find_input('Attach');
+ $attach->filename("awesome.patch");
+ $attach->headers('Content-Type' => 'text/x-diff');
+ $m->set_fields(
+ Subject => 'test forward, empty content but attachments',
+ Attach => $att_file, # from up top
+ );
+ $m->click('AddMoreAttach');
+ $m->form_name('TicketCreate');
+ $attach = $m->current_form->find_input('Attach');
+ $attach->filename("bpslogo.png");
+ $attach->headers('Content-Type' => 'image/png');
+ $m->set_fields(
+ 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/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' );
+ RT::Test->clean_caught_mails;
+
+ $m->follow_link_ok( { text => 'Forward', n => 2 }, 'follow 2nd Forward' );
+ $m->submit_form(
+ form_name => 'ForwardMessage',
+ fields => {
+ To => 'rt-test@example.com',
+ },
+ 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' );
+ 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/this is an attachment/, 'att content' );
+ like( $mail, qr/text\/x-diff/, 'att content type' );
+ like( $mail, qr/bpslogo\.png/, 'att image file name' );
+ like( $mail, qr/image\/png/, 'att image content type' );
+}
+
+diag "Forward Transaction with attachments but no 'content' part" if $ENV{TEST_VERBOSE};
+{
+ my $mime = MIME::Entity->build(
+ From => 'test@example.com',
+ Subject => 'attachments for everyone',
+ Type => 'multipart/mixed',
+ );
+
+ $mime->attach(
+ Path => $att_file,
+ Type => 'text/x-diff',
+ Filename => 'awesome.patch',
+ Disposition => 'attachment',
+ );
+
+ $mime->attach(
+ Path => RT::Test::get_relocatable_file('bpslogo.png', '..', 'data'),
+ Type => 'image/png',
+ Filename => 'bpslogo.png',
+ Encoding => 'base64',
+ Disposition => 'attachment',
+ );
+
+ my $ticket = RT::Test->create_ticket(
+ Queue => 1,
+ Subject => 'test forward, attachments but no "content"',
+ MIMEObj => $mime,
+ );
+
+ $m->get_ok( $baseurl . '/Ticket/Display.html?id=' . $ticket->Id );
+ $m->content_like( qr/awesome\.patch/, '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' );
+ RT::Test->clean_caught_mails;
+
+ # Forward txn
+ $m->follow_link_ok( { text => 'Forward', n => 2 }, 'follow 2nd Forward' );
+ $m->submit_form(
+ form_name => 'ForwardMessage',
+ fields => {
+ To => 'rt-test@example.com',
+ },
+ 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' );
+
+ # Forward ticket
+ $m->follow_link_ok( { text => 'Forward', n => 1 }, 'follow 1st Forward' );
+ $m->submit_form(
+ form_name => 'ForwardMessage',
+ fields => {
+ To => 'rt-test@example.com',
+ },
+ button => 'ForwardAndReturn'
+ );
+ $m->content_contains( 'Sent email successfully', 'sent mail msg' );
+ $m->content_like( qr/Forwarded Ticket to rt-test\@example\.com/, 'txn msg' );
+
+ my ($forward_txn, $forward_ticket) = RT::Test->fetch_caught_mails;
+ my $tag = qr/Fwd: \[example\.com #\d+\]/;
+ 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' );
+
+ for my $mail ($forward_txn, $forward_ticket) {
+ like( $mail, qr/To: rt-test\@example.com/, 'To field' );
+ like( $mail, qr/awesome\.patch/, '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' );
+ like( $mail, qr/image\/png/, 'att image content type' );
+ }
+}
+
+undef $m;
+done_testing;
diff --git a/rt/t/web/ticket_links.t b/rt/t/web/ticket_links.t
new file mode 100644
index 000000000..cb30e92f9
--- /dev/null
+++ b/rt/t/web/ticket_links.t
@@ -0,0 +1,110 @@
+use strict;
+use warnings;
+use RT::Test tests => 106;
+
+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 the General queue" );
+
+my ( $deleted, $active, $inactive ) = RT::Test->create_tickets(
+ { Queue => 'General' },
+ { Subject => 'deleted ticket', },
+ { Subject => 'active ticket', },
+ { Subject => 'inactive ticket', }
+);
+
+my ( $deleted_id, $active_id, $inactive_id ) =
+ ( $deleted->id, $active->id, $inactive->id );
+
+$deleted->SetStatus('deleted');
+is( $deleted->Status, 'deleted', "deleted $deleted_id" );
+
+$inactive->SetStatus('resolved');
+is( $inactive->Status, 'resolved', 'resolved $inactive_id' );
+
+for my $type ( "DependsOn", "MemberOf", "RefersTo" ) {
+ for my $c (qw/base target/) {
+ my $id;
+
+ diag "create ticket with links of type $type $c";
+ {
+ ok( $m->goto_create_ticket($queue), "go to create ticket" );
+ $m->form_name('TicketCreate');
+ $m->field( Subject => "test ticket creation with $type $c" );
+ if ( $c eq 'base' ) {
+ $m->field( "new-$type", "$deleted_id $active_id $inactive_id" );
+ }
+ else {
+ $m->field( "$type-new", "$deleted_id $active_id $inactive_id" );
+ }
+
+ $m->submit;
+ $m->content_like(qr/Ticket \d+ created/, 'created ticket');
+ $m->content_contains("Can&#39;t link to a deleted ticket");
+ $id = RT::Test->last_ticket->id;
+ }
+
+ diag "add ticket links of type $type $c";
+ {
+ my $ticket = RT::Test->create_ticket(
+ Queue => 'General',
+ Subject => "test $type $c",
+ );
+ $id = $ticket->id;
+
+ $m->goto_ticket($id);
+ $m->follow_link_ok( { text => 'Links' }, "Followed link to Links" );
+
+ ok( $m->form_with_fields("$id-DependsOn"), "found the form" );
+ if ( $c eq 'base' ) {
+ $m->field( "$id-$type", "$deleted_id $active_id $inactive_id" );
+ }
+ else {
+ $m->field( "$type-$id", "$deleted_id $active_id $inactive_id" );
+ }
+ $m->submit;
+ $m->content_contains("Can&#39;t link to a deleted ticket");
+
+ if ( $c eq 'base' ) {
+ $m->content_like(
+ qr{"DeleteLink--$type-.*?ticket/$active_id"},
+ "$c for $type: has active ticket",
+ );
+ $m->content_like(
+ qr{"DeleteLink--$type-.*?ticket/$inactive_id"},
+ "base for $type: has inactive ticket",
+ );
+ $m->content_unlike(
+ qr{"DeleteLink--$type-.*?ticket/$deleted_id"},
+ "base for $type: no deleted ticket",
+ );
+ }
+ else {
+ $m->content_like(
+ qr{"DeleteLink-.*?ticket/$active_id-$type-"},
+ "$c for $type: has active ticket",
+ );
+ $m->content_like(
+ qr{"DeleteLink-.*?ticket/$inactive_id-$type-"},
+ "base for $type: has inactive ticket",
+ );
+ $m->content_unlike(
+ qr{"DeleteLink-.*?ticket/$deleted_id-$type-"},
+ "base for $type: no deleted ticket",
+ );
+ }
+ }
+
+ $m->goto_ticket($id);
+ $m->content_like( qr{$active_id:.*?\[new\]}, "has active ticket", );
+ $m->content_like(
+ qr{$inactive_id:.*?\[resolved\]},
+ "has inactive ticket",
+ );
+ $m->content_unlike( qr{$deleted_id.*?\[deleted\]}, "no deleted ticket",
+ );
+ }
+}
+
diff --git a/rt/t/web/ticket_modify_all.t b/rt/t/web/ticket_modify_all.t
new file mode 100644
index 000000000..c9dd7e7cd
--- /dev/null
+++ b/rt/t/web/ticket_modify_all.t
@@ -0,0 +1,44 @@
+use strict;
+use warnings;
+
+use RT::Test tests => 15;
+
+my $ticket = RT::Test->create_ticket(
+ Subject => 'test bulk update',
+ Queue => 1,
+);
+
+my ( $url, $m ) = RT::Test->started_ok;
+ok( $m->login, 'logged in' );
+
+$m->get_ok( $url . "/Ticket/ModifyAll.html?id=" . $ticket->id );
+
+$m->submit_form(
+ form_number => 3,
+ fields => { 'UpdateContent' => 'this is update content' },
+ button => 'SubmitTicket',
+);
+
+$m->content_contains("Message recorded", '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');
+$m->field(Owner => 'root');
+$m->click('SubmitTicket');
+
+$m->form_name('TicketModifyAll');
+is($m->value('Owner'), 'root', 'owner was successfully changed to root');
+
+# XXX TODO test other parts, i.e. basic, dates, people and links
+
diff --git a/rt/t/web/ticket_modify_people.t b/rt/t/web/ticket_modify_people.t
new file mode 100644
index 000000000..750be3f2c
--- /dev/null
+++ b/rt/t/web/ticket_modify_people.t
@@ -0,0 +1,113 @@
+use strict;
+use warnings;
+
+use RT::Test tests => 23;
+
+my $root = RT::Test->load_or_create_user( Name => 'root' );
+my $group_foo = RT::Group->new($RT::SystemUser);
+my ( $ret, $msg ) = $group_foo->CreateUserDefinedGroup(
+ Name => 'group_foo',
+ Description => 'group_foo',
+);
+ok( $ret, 'created group_foo' );
+
+my $ticket = RT::Test->create_ticket(
+ Subject => 'test modify people',
+ Queue => 'General',
+ Requestor => $root->id,
+ Cc => $group_foo->id,
+);
+
+my $user = RT::Test->load_or_create_user(
+ Name => 'user',
+ Password => 'password',
+);
+ok $user && $user->id, 'loaded or created user';
+
+ok(
+ RT::Test->set_rights(
+ { Principal => $user, Right => [qw(SeeQueue ShowTicket ModifyTicket)] },
+ ),
+ 'set rights'
+);
+
+my ( $url, $m ) = RT::Test->started_ok;
+ok( $m->login( 'user', 'password' ), 'logged in' );
+$m->get_ok( $url . "/Ticket/ModifyPeople.html?id=" . $ticket->id );
+
+ok(
+ !$m->find_link(
+ text => 'Enoch Root',
+ url_regex => qr!/Admin/Users/Modify\.html!,
+ ),
+ 'no link to modify user'
+);
+$m->content_contains('Enoch Root', 'still has the user name' );
+
+ok(
+ !$m->find_link(
+ text => 'group_foo',
+ url_regex => qr!/Admin/Groups/Modify\.html!,
+ ),
+ 'no link to modify group'
+);
+
+$m->content_contains('group_foo', 'still has the group name' );
+
+ok( RT::Test->add_rights( { Principal => $user, Right => ['AdminUsers'] }, ),
+ 'added AdminUsers right' );
+$m->reload;
+ok(
+ !$m->find_link(
+ text => 'Enoch Root',
+ url_regex => qr!/Admin/Users/Modify\.html!,
+ ),
+ 'still no link to modify user'
+);
+ok(
+ !$m->find_link(
+ text => 'group_foo',
+ url_regex => qr!/Admin/Groups/Modify\.html!,
+ ),
+ 'still no link to modify group'
+);
+
+ok(
+ RT::Test->add_rights( { Principal => $user, Right => ['ShowConfigTab'] }, ),
+ 'added ShowConfigTab right',
+);
+
+$m->reload;
+ok(
+ $m->find_link(
+ text => 'Enoch Root',
+ url_regex => qr!/Admin/Users/Modify\.html!,
+ ),
+ 'got link to modify user'
+);
+
+ok(
+ !$m->find_link(
+ text => 'group_foo',
+ url_regex => qr!/Admin/Groups/Modify\.html!,
+ ),
+ 'still no link to modify group'
+);
+
+ok(
+ RT::Test->add_rights( { Principal => $user, Right => ['AdminGroup'] }, ),
+ 'added AdminGroup right'
+);
+
+$m->reload;
+ok(
+ $m->find_link(
+ text => 'group_foo',
+ url_regex => qr!/Admin/Groups/Modify\.html!,
+ ),
+ 'got link to modify group'
+);
+
+
+# TODO test Add|Delete people
+
diff --git a/rt/t/web/ticket_owner.t b/rt/t/web/ticket_owner.t
index 0bacaf1bc..4db39e61a 100644
--- a/rt/t/web/ticket_owner.t
+++ b/rt/t/web/ticket_owner.t
@@ -3,7 +3,7 @@
use strict;
use warnings;
-use RT::Test tests => 91;
+use RT::Test nodata => 1, tests => 105;
my $queue = RT::Test->load_or_create_queue( Name => 'Regression' );
ok $queue && $queue->id, 'loaded or created queue';
@@ -18,26 +18,25 @@ my $user_b = RT::Test->load_or_create_user(
);
ok $user_b && $user_b->id, 'loaded or created user';
-RT::Test->started_ok;
+my ($baseurl, $agent_a) = RT::Test->started_ok;
ok( RT::Test->set_rights(
{ Principal => $user_a, Right => [qw(SeeQueue ShowTicket CreateTicket ReplyToTicket)] },
{ Principal => $user_b, Right => [qw(SeeQueue ShowTicket OwnTicket)] },
), 'set rights');
-my $agent_a = RT::Test::Web->new;
ok $agent_a->login('user_a', 'password'), 'logged in as user A';
-diag "current user has no right to own, nobody selected as owner on create" if $ENV{TEST_VERBOSE};
+diag "current user has no right to own, nobody selected as owner on create";
{
$agent_a->get_ok('/', 'open home page');
$agent_a->form_name('CreateTicketInQueue');
$agent_a->select( 'Queue', $queue->id );
$agent_a->submit;
- $agent_a->content_like(qr/Create a new ticket/i, 'opened create ticket page');
+ $agent_a->content_contains('Create a new ticket', 'opened create ticket page');
my $form = $agent_a->form_name('TicketCreate');
- is $form->value('Owner'), $RT::Nobody->id, 'correct owner selected';
+ is $form->value('Owner'), RT->Nobody->id, 'correct owner selected';
ok !grep($_ == $user_a->id, $form->find_input('Owner')->possible_values),
'user A can not own tickets';
$agent_a->submit;
@@ -46,22 +45,22 @@ diag "current user has no right to own, nobody selected as owner on create" if $
my ($id) = ($agent_a->content =~ /Ticket (\d+) created in queue/);
ok $id, 'found id of the ticket';
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ my $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Load( $id );
ok $ticket->id, 'loaded the ticket';
- is $ticket->Owner, $RT::Nobody->id, 'correct owner';
+ is $ticket->Owner, RT->Nobody->id, 'correct owner';
}
-diag "user can chose owner of a new ticket" if $ENV{TEST_VERBOSE};
+diag "user can chose owner of a new ticket";
{
$agent_a->get_ok('/', 'open home page');
$agent_a->form_name('CreateTicketInQueue');
$agent_a->select( 'Queue', $queue->id );
$agent_a->submit;
- $agent_a->content_like(qr/Create a new ticket/i, 'opened create ticket page');
+ $agent_a->content_contains('Create a new ticket', 'opened create ticket page');
my $form = $agent_a->form_name('TicketCreate');
- is $form->value('Owner'), $RT::Nobody->id, 'correct owner selected';
+ is $form->value('Owner'), RT->Nobody->id, 'correct owner selected';
ok grep($_ == $user_b->id, $form->find_input('Owner')->possible_values),
'user B is listed as potential owner';
@@ -72,7 +71,7 @@ diag "user can chose owner of a new ticket" if $ENV{TEST_VERBOSE};
my ($id) = ($agent_a->content =~ /Ticket (\d+) created in queue/);
ok $id, 'found id of the ticket';
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ my $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Load( $id );
ok $ticket->id, 'loaded the ticket';
is $ticket->Owner, $user_b->id, 'correct owner';
@@ -81,7 +80,7 @@ diag "user can chose owner of a new ticket" if $ENV{TEST_VERBOSE};
my $agent_b = RT::Test::Web->new;
ok $agent_b->login('user_b', 'password'), 'logged in as user B';
-diag "user A can not change owner after create" if $ENV{TEST_VERBOSE};
+diag "user A can not change owner after create";
{
my $ticket = RT::Ticket->new( $user_a );
my ($id, $txn, $msg) = $ticket->Create(
@@ -95,30 +94,29 @@ diag "user A can not change owner after create" if $ENV{TEST_VERBOSE};
# try the following group of tests twice with different agents(logins)
my $test_cb = sub {
my $agent = shift;
- $agent->goto_ticket( $id );
- $agent->follow_link_ok({text => 'Basics'}, 'Ticket -> Basics');
- my $form = $agent->form_number(3);
+ $agent->get("/Ticket/Modify.html?id=$id");
+ my $form = $agent->form_name('TicketModify');
is $form->value('Owner'), $user_b->id, 'correct owner selected';
- $agent->select('Owner', $RT::Nobody->id);
+ $agent->select('Owner', RT->Nobody->id);
$agent->submit;
- $agent->content_like(
- qr/Permission denied/i,
+ $agent->content_contains(
+ 'Permission Denied',
'no way to change owner after create if you have no rights'
);
- my $ticket = RT::Ticket->new( $RT::SystemUser );
+ my $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Load( $id );
ok $ticket->id, 'loaded the ticket';
is $ticket->Owner, $user_b->id, 'correct owner';
};
$test_cb->($agent_a);
- diag "even owner(user B) can not change owner" if $ENV{TEST_VERBOSE};
+ diag "even owner(user B) can not change owner";
$test_cb->($agent_b);
}
-diag "on reply correct owner is selected" if $ENV{TEST_VERBOSE};
+diag "on reply correct owner is selected";
{
my $ticket = RT::Ticket->new( $user_a );
my ($id, $txn, $msg) = $ticket->Create(
@@ -130,13 +128,13 @@ diag "on reply correct owner is selected" if $ENV{TEST_VERBOSE};
is $ticket->Owner, $user_b->id, 'correct owner';
$agent_a->goto_ticket( $id );
- $agent_a->follow_link_ok({text => 'Reply'}, 'Ticket -> Basics');
+ $agent_a->follow_link_ok({text => 'Reply'}, 'Ticket -> Reply');
- my $form = $agent_a->form_number(3);
+ my $form = $agent_a->form_name('TicketUpdate');
is $form->value('Owner'), '', 'empty value selected';
$agent_a->submit;
- $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Load( $id );
ok $ticket->id, 'loaded the ticket';
is $ticket->Owner, $user_b->id, 'correct owner';
@@ -147,7 +145,7 @@ ok( RT::Test->set_rights(
{ Principal => $user_b, Right => [qw(SeeQueue ShowTicket OwnTicket)] },
), 'set rights');
-diag "Couldn't take without coresponding right" if $ENV{TEST_VERBOSE};
+diag "Couldn't take without coresponding right";
{
my $ticket = RT::Ticket->new( $user_a );
my ($id, $txn, $msg) = $ticket->Create(
@@ -155,7 +153,7 @@ diag "Couldn't take without coresponding right" if $ENV{TEST_VERBOSE};
Subject => 'test',
);
ok $id, 'created a ticket #'. $id or diag "error: $msg";
- is $ticket->Owner, $RT::Nobody->id, 'correct owner';
+ is $ticket->Owner, RT->Nobody->id, 'correct owner';
$agent_a->goto_ticket( $id );
ok !($agent_a->find_all_links( text => 'Take' ))[0],
@@ -164,7 +162,7 @@ diag "Couldn't take without coresponding right" if $ENV{TEST_VERBOSE};
'no Steal link as well';
}
-diag "Couldn't steal without coresponding right" if $ENV{TEST_VERBOSE};
+diag "Couldn't steal without coresponding right";
{
my $ticket = RT::Ticket->new( $user_a );
my ($id, $txn, $msg) = $ticket->Create(
@@ -186,7 +184,7 @@ ok( RT::Test->set_rights(
{ Principal => $user_a, Right => [qw(SeeQueue ShowTicket CreateTicket TakeTicket)] },
), 'set rights');
-diag "TakeTicket require OwnTicket to work" if $ENV{TEST_VERBOSE};
+diag "TakeTicket require OwnTicket to work";
{
my $ticket = RT::Ticket->new( $user_a );
my ($id, $txn, $msg) = $ticket->Create(
@@ -194,7 +192,7 @@ diag "TakeTicket require OwnTicket to work" if $ENV{TEST_VERBOSE};
Subject => 'test',
);
ok $id, 'created a ticket #'. $id or diag "error: $msg";
- is $ticket->Owner, $RT::Nobody->id, 'correct owner';
+ is $ticket->Owner, RT->Nobody->id, 'correct owner';
$agent_a->goto_ticket( $id );
ok !($agent_a->find_all_links( text => 'Take' ))[0],
@@ -208,7 +206,7 @@ ok( RT::Test->set_rights(
{ Principal => $user_b, Right => [qw(SeeQueue ShowTicket OwnTicket)] },
), 'set rights');
-diag "TakeTicket+OwnTicket work" if $ENV{TEST_VERBOSE};
+diag "TakeTicket+OwnTicket work";
{
my $ticket = RT::Ticket->new( $user_a );
my ($id, $txn, $msg) = $ticket->Create(
@@ -216,20 +214,20 @@ diag "TakeTicket+OwnTicket work" if $ENV{TEST_VERBOSE};
Subject => 'test',
);
ok $id, 'created a ticket #'. $id or diag "error: $msg";
- is $ticket->Owner, $RT::Nobody->id, 'correct owner';
+ is $ticket->Owner, RT->Nobody->id, 'correct owner';
$agent_a->goto_ticket( $id );
ok !($agent_a->find_all_links( text => 'Steal' ))[0],
'no Steal link';
$agent_a->follow_link_ok({text => 'Take'}, 'Ticket -> Take');
- $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Load( $id );
ok $ticket->id, 'loaded the ticket';
is $ticket->Owner, $user_a->id, 'correct owner';
}
-diag "TakeTicket+OwnTicket don't work when owner is not nobody" if $ENV{TEST_VERBOSE};
+diag "TakeTicket+OwnTicket don't work when owner is not nobody";
{
my $ticket = RT::Ticket->new( $user_a );
my ($id, $txn, $msg) = $ticket->Create(
@@ -252,7 +250,7 @@ ok( RT::Test->set_rights(
{ Principal => $user_b, Right => [qw(SeeQueue ShowTicket OwnTicket)] },
), 'set rights');
-diag "StealTicket require OwnTicket to work" if $ENV{TEST_VERBOSE};
+diag "StealTicket require OwnTicket to work";
{
my $ticket = RT::Ticket->new( $user_a );
my ($id, $txn, $msg) = $ticket->Create(
@@ -275,7 +273,7 @@ ok( RT::Test->set_rights(
{ Principal => $user_b, Right => [qw(SeeQueue ShowTicket OwnTicket)] },
), 'set rights');
-diag "StealTicket+OwnTicket work" if $ENV{TEST_VERBOSE};
+diag "StealTicket+OwnTicket work";
{
my $ticket = RT::Ticket->new( $user_a );
my ($id, $txn, $msg) = $ticket->Create(
@@ -291,13 +289,13 @@ diag "StealTicket+OwnTicket work" if $ENV{TEST_VERBOSE};
'but no Take link';
$agent_a->follow_link_ok({text => 'Steal'}, 'Ticket -> Steal');
- $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket = RT::Ticket->new( RT->SystemUser );
$ticket->Load( $id );
ok $ticket->id, 'loaded the ticket';
is $ticket->Owner, $user_a->id, 'correct owner';
}
-diag "StealTicket+OwnTicket don't work when owner is nobody" if $ENV{TEST_VERBOSE};
+diag "StealTicket+OwnTicket don't work when owner is nobody";
{
my $ticket = RT::Ticket->new( $user_a );
my ($id, $txn, $msg) = $ticket->Create(
@@ -305,7 +303,7 @@ diag "StealTicket+OwnTicket don't work when owner is nobody" if $ENV{TEST_VERBOS
Subject => 'test',
);
ok $id, 'created a ticket #'. $id or diag "error: $msg";
- is $ticket->Owner, $RT::Nobody->id, 'correct owner';
+ is $ticket->Owner, RT->Nobody->id, 'correct owner';
$agent_a->goto_ticket( $id );
ok !($agent_a->find_all_links( text => 'Steal' ))[0],
@@ -319,7 +317,7 @@ ok( RT::Test->set_rights(
{ Principal => $user_b, Right => [qw(SeeQueue ShowTicket OwnTicket)] },
), 'set rights');
-diag "no Steal link when owner nobody" if $ENV{TEST_VERBOSE};
+diag "no Steal link when owner nobody";
{
my $ticket = RT::Ticket->new( $user_a );
my ($id, $txn, $msg) = $ticket->Create(
@@ -327,7 +325,7 @@ diag "no Steal link when owner nobody" if $ENV{TEST_VERBOSE};
Subject => 'test',
);
ok $id, 'created a ticket #'. $id or diag "error: $msg";
- is $ticket->Owner, $RT::Nobody->id, 'correct owner';
+ is $ticket->Owner, RT->Nobody->id, 'correct owner';
$agent_a->goto_ticket( $id );
ok !($agent_a->find_all_links( text => 'Steal' ))[0],
@@ -336,7 +334,7 @@ diag "no Steal link when owner nobody" if $ENV{TEST_VERBOSE};
'but have Take link');
}
-diag "no Take link when owner is not nobody" if $ENV{TEST_VERBOSE};
+diag "no Take link when owner is not nobody";
{
my $ticket = RT::Ticket->new( $user_a );
my ($id, $txn, $msg) = $ticket->Create(
@@ -354,3 +352,68 @@ diag "no Take link when owner is not nobody" if $ENV{TEST_VERBOSE};
'but have Steal link');
}
+ok(
+ RT::Test->set_rights(
+ {
+ Principal => $user_a,
+ Right => [
+ qw(SeeQueue ShowTicket CreateTicket ReplyToTicket OwnTicket TakeTicket StealTicket)
+ ]
+ },
+ { Principal => $user_b, Right => [qw(SeeQueue ShowTicket OwnTicket)] },
+ ),
+ 'set rights'
+);
+
+diag
+"action is Take if old owner is nobody and new owner is current user in update page";
+{
+ my $ticket = RT::Ticket->new( $user_a );
+ my ( $id, $txn, $msg ) = $ticket->Create(
+ Queue => $queue->id,
+ Subject => 'test',
+ );
+ ok $id, 'created a ticket #'. $id or diag "error: $msg";
+ is $ticket->Owner, RT->Nobody->id, 'correct owner';
+
+ $agent_a->goto_ticket( $id );
+ $agent_a->content_lacks('Taken', 'no Taken');
+ $agent_a->follow_link_ok({text => 'Reply'}, 'Ticket -> Reply');
+ $agent_a->submit_form(
+ form_name => 'TicketUpdate',
+ fields => { Owner => $user_a->id },
+ button => 'SubmitTicket',
+ );
+ $agent_a->content_like( 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 ' );
+}
+
+diag
+"action is Take if old owner is nobody and new owner is current user in basics page";
+{
+ my $ticket = RT::Ticket->new($user_a);
+ my ( $id, $txn, $msg ) = $ticket->Create(
+ Queue => $queue->id,
+ Subject => 'test',
+ );
+ ok $id, 'created a ticket #' . $id or diag "error: $msg";
+ is $ticket->Owner, RT->Nobody->id, 'correct owner';
+
+ $agent_a->goto_ticket($id);
+ $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);
+ $agent_a->content_like( 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 ' );
+}
+
diff --git a/rt/t/web/ticket_owner_autocomplete.t b/rt/t/web/ticket_owner_autocomplete.t
new file mode 100644
index 000000000..3aa3f282f
--- /dev/null
+++ b/rt/t/web/ticket_owner_autocomplete.t
@@ -0,0 +1,185 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test nodata => 1, tests => 43;
+use JSON qw(from_json);
+
+my $queue = RT::Test->load_or_create_queue( Name => 'Regression' );
+ok $queue && $queue->id, 'loaded or created queue';
+
+my $user_a = RT::Test->load_or_create_user(
+ Name => 'user_a', Password => 'password',
+);
+ok $user_a && $user_a->id, 'loaded or created user';
+
+my $user_b = RT::Test->load_or_create_user(
+ Name => 'user_b', Password => 'password',
+);
+ok $user_b && $user_b->id, 'loaded or created user';
+
+RT->Config->Set( AutocompleteOwners => 1 );
+my ($baseurl, $agent_a) = RT::Test->started_ok;
+
+ok( RT::Test->set_rights(
+ { Principal => $user_a, Right => [qw(SeeQueue ShowTicket CreateTicket ReplyToTicket)] },
+ { Principal => $user_b, Right => [qw(SeeQueue ShowTicket OwnTicket)] },
+), 'set rights');
+
+ok $agent_a->login('user_a', 'password'), 'logged in as user A';
+
+diag "current user has no right to own, nobody selected as owner on create";
+{
+ $agent_a->get_ok('/', 'open home page');
+ $agent_a->form_name('CreateTicketInQueue');
+ $agent_a->select( 'Queue', $queue->id );
+ $agent_a->submit;
+
+ $agent_a->content_contains('Create a new ticket', 'opened create ticket page');
+ my $form = $agent_a->form_name('TicketCreate');
+ is $form->value('Owner'), RT->Nobody->Name, 'correct owner selected';
+ autocomplete_lacks( 'RT::Queue-'.$queue->id, 'user_a' );
+ $agent_a->submit;
+
+ $agent_a->content_like(qr/Ticket \d+ created in queue/i, 'created ticket');
+ my ($id) = ($agent_a->content =~ /Ticket (\d+) created in queue/);
+ ok $id, 'found id of the ticket';
+
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ $ticket->Load( $id );
+ ok $ticket->id, 'loaded the ticket';
+ is $ticket->Owner, RT->Nobody->id, 'correct owner';
+}
+
+diag "user can chose owner of a new ticket";
+{
+ $agent_a->get_ok('/', 'open home page');
+ $agent_a->form_name('CreateTicketInQueue');
+ $agent_a->select( 'Queue', $queue->id );
+ $agent_a->submit;
+
+ $agent_a->content_contains('Create a new ticket', 'opened create ticket page');
+ my $form = $agent_a->form_name('TicketCreate');
+ is $form->value('Owner'), RT->Nobody->Name, 'correct owner selected';
+
+ autocomplete_contains( 'RT::Queue-'.$queue->id, 'user_b' );
+ $form->value('Owner', $user_b->Name);
+ $agent_a->submit;
+
+ $agent_a->content_like(qr/Ticket \d+ created in queue/i, 'created ticket');
+ my ($id) = ($agent_a->content =~ /Ticket (\d+) created in queue/);
+ ok $id, 'found id of the ticket';
+
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ $ticket->Load( $id );
+ ok $ticket->id, 'loaded the ticket';
+ is $ticket->Owner, $user_b->id, 'correct owner';
+}
+
+my $agent_b = RT::Test::Web->new;
+ok $agent_b->login('user_b', 'password'), 'logged in as user B';
+
+diag "user A can not change owner after create";
+{
+ my $ticket = RT::Ticket->new( $user_a );
+ my ($id, $txn, $msg) = $ticket->Create(
+ Queue => $queue->id,
+ Owner => $user_b->id,
+ Subject => 'test',
+ );
+ ok $id, 'created a ticket #'. $id or diag "error: $msg";
+ is $ticket->Owner, $user_b->id, 'correct owner';
+
+ # try the following group of tests twice with different agents(logins)
+ my $test_cb = sub {
+ my $agent = shift;
+ $agent->get("/Ticket/Modify.html?id=$id");
+ my $form = $agent->form_name('TicketModify');
+ is $form->value('Owner'), $user_b->Name, 'correct owner selected';
+ $form->value('Owner', RT->Nobody->Name);
+ $agent->submit;
+
+ $agent->content_contains(
+ 'Permission Denied',
+ 'no way to change owner after create if you have no rights'
+ );
+
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ $ticket->Load( $id );
+ ok $ticket->id, 'loaded the ticket';
+ is $ticket->Owner, $user_b->id, 'correct owner';
+ };
+
+ $test_cb->($agent_a);
+ diag "even owner(user B) can not change owner";
+ $test_cb->($agent_b);
+}
+
+diag "on reply correct owner is selected";
+{
+ my $ticket = RT::Ticket->new( $user_a );
+ my ($id, $txn, $msg) = $ticket->Create(
+ Queue => $queue->id,
+ Owner => $user_b->id,
+ Subject => 'test',
+ );
+ ok $id, 'created a ticket #'. $id or diag "error: $msg";
+ is $ticket->Owner, $user_b->id, 'correct owner';
+
+ $agent_a->goto_ticket( $id );
+ $agent_a->follow_link_ok( { id => 'page-actions-reply' }, 'Reply' );
+
+ my $form = $agent_a->form_number(3);
+ is $form->value('Owner'), 'user_b', 'current user selected';
+ $agent_a->submit;
+
+ $ticket = RT::Ticket->new( RT->SystemUser );
+ $ticket->Load( $id );
+ ok $ticket->id, 'loaded the ticket';
+ is $ticket->Owner, $user_b->id, 'correct owner';
+}
+
+sub autocomplete {
+ my $limit = shift;
+ my $agent = shift;
+ $agent->get_ok("/Helpers/Autocomplete/Owners?term=&limit=$limit&return=Name", "fetched autocomplete values");
+ return from_json($agent->content);
+}
+
+sub autocomplete_contains {
+ my $limit = shift;
+ my $expected = shift;
+ my $agent = shift;
+
+ unless ( $agent ) {
+ $agent = RT::Test::Web->new;
+ $agent->login('user_a', 'password');
+ }
+
+ my $results = autocomplete( $limit, $agent );
+
+ my %seen;
+ $seen{$_->{value}}++ for @$results;
+ $expected = [$expected] unless ref $expected eq 'ARRAY';
+ is((scalar grep { not $seen{$_} } @$expected), 0, "got all expected values");
+}
+
+sub autocomplete_lacks {
+ my $limit = shift;
+ my $lacks = shift;
+ my $agent = shift;
+
+ unless ( $agent ) {
+ $agent = RT::Test::Web->new;
+ $agent->login('user_a', 'password');
+ }
+
+ my $results = autocomplete( $limit, $agent );
+
+ my %seen;
+ $seen{$_->{value}}++ for @$results;
+ $lacks = [$lacks] unless ref $lacks eq 'ARRAY';
+ is((scalar grep { $seen{$_} } @$lacks), 0, "didn't get any unexpected values");
+}
+
diff --git a/rt/t/web/ticket_owner_issues_16656.t b/rt/t/web/ticket_owner_issues_16656.t
new file mode 100644
index 000000000..a6306f740
--- /dev/null
+++ b/rt/t/web/ticket_owner_issues_16656.t
@@ -0,0 +1,63 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+
+use RT::Test tests => 19;
+
+my $queue = RT::Test->load_or_create_queue( Name => 'Test' );
+ok $queue && $queue->id, 'loaded or created queue';
+
+my $user_a = RT::Test->load_or_create_user(
+ Name => 'user_a',
+ EmailAddress => 'user_a@example.com',
+ Password => 'password',
+);
+ok $user_a && $user_a->id, 'loaded or created user';
+
+RT->Config->Set( AutocompleteOwners => 0 );
+my ($baseurl, $agent_root) = RT::Test->started_ok;
+
+ok( RT::Test->set_rights({
+ Principal => 'Requestor',
+ Object => $queue,
+ Right => [qw(OwnTicket)]
+}), 'set rights');
+
+ok $agent_root->login('root', 'password'), 'logged in as user root';
+
+diag "user_a doesn't show up in create form";
+{
+ $agent_root->get_ok('/', 'open home page');
+ $agent_root->form_name('CreateTicketInQueue');
+ $agent_root->select( 'Queue', '1' );
+ $agent_root->submit;
+
+ $agent_root->content_contains('Create a new ticket', 'opened create ticket page');
+ my $form = $agent_root->form_name('TicketCreate');
+ my $input = $form->find_input('Owner');
+ is $input->value, RT->Nobody->Id, 'correct owner selected';
+ ok((not scalar grep { $_ == $user_a->Id } $input->possible_values), 'no user_a value in dropdown');
+ $form->value('Requestors', 'user_a@example.com');
+ $agent_root->submit;
+
+ $agent_root->content_like(qr/Ticket \d+ created in queue/i, 'created ticket');
+ my ($id) = ($agent_root->content =~ /Ticket (\d+) created in queue/);
+ ok $id, 'found id of the ticket';
+
+ my $ticket = RT::Ticket->new( RT->SystemUser );
+ $ticket->Load( $id );
+ ok $ticket->id, 'loaded the ticket';
+ is $ticket->Queue, '1', 'correct queue';
+ is $ticket->Owner, RT->Nobody->Id, 'correct owner';
+ is $ticket->RequestorAddresses, 'user_a@example.com', 'correct requestor';
+}
+
+diag "user_a doesn't appear in owner list after being made requestor";
+{
+ $agent_root->get("/Ticket/Modify.html?id=1");
+ my $form = $agent_root->form_name('TicketModify');
+ my $input = $form->find_input('Owner');
+ is $input->value, RT->Nobody->Id, 'correct owner selected';
+ ok((not scalar grep { $_ == $user_a->Id } $input->possible_values), 'no user_a value in dropdown');
+}
+
diff --git a/rt/t/web/ticket_seen.t b/rt/t/web/ticket_seen.t
index 3a77a5899..8dacaf59f 100644
--- a/rt/t/web/ticket_seen.t
+++ b/rt/t/web/ticket_seen.t
@@ -3,7 +3,7 @@
use strict;
use warnings;
-use RT::Test tests => 21;
+use RT::Test nodata => 1, tests => 23, config => 'Set($ShowUnreadMessageNotifications, 1);';
my $queue = RT::Test->load_or_create_queue( Name => 'Regression' );
ok $queue && $queue->id, 'loaded or created queue';
@@ -30,7 +30,7 @@ ok $agent_a->login('user_a', 'password'), 'logged in as user A';
my $agent_b = RT::Test::Web->new;
ok $agent_b->login('user_b', 'password'), 'logged in as user B';
-diag "create a ticket for testing" if $ENV{TEST_VERBOSE};
+diag "create a ticket for testing";
my $tid;
{
my $ticket = RT::Ticket->new( $user_a );
@@ -44,7 +44,7 @@ my $tid;
is $ticket->Owner, $user_a->id, 'correct owner';
}
-diag "user B adds a message, we check that user A see notification and can clear it" if $ENV{TEST_VERBOSE};
+diag "user B adds a message, we check that user A see notification and can clear it";
{
my $ticket = RT::Ticket->new( $user_b );
$ticket->Load( $tid );
@@ -62,10 +62,10 @@ diag "user B adds a message, we check that user A see notification and can clear
ok( $reply_id, 'got correspond txn id' );
$agent_a->goto_ticket($tid);
- $agent_a->content_like(qr/bla-bla/ims, 'the message on the page');
+ $agent_a->content_contains('bla-bla', 'the message on the page');
- $agent_a->content_like(
- qr/unread message/ims,
+ $agent_a->content_contains(
+ 'unread message',
'we have not seen something'
);
@@ -76,20 +76,20 @@ diag "user B adds a message, we check that user A see notification and can clear
like( $agent_a->base, qr/#txn-$reply_id$/, 'contains anchor' );
$agent_a->follow_link_ok({text => 'jump to the first unread message and mark all messages as seen'}, 'try to mark all as seen');
- $agent_a->content_like(
- qr/Marked all messages as seen/ims,
+ $agent_a->content_contains(
+ 'Marked all messages as seen',
'see success message'
);
like( $agent_a->base, qr/#txn-$reply_id$/, 'contains anchor' );
- $agent_a->content_like(
- qr/Marked all messages as seen/ims,
+ $agent_a->content_contains(
+ 'Marked all messages as seen',
'see success message'
);
$agent_a->goto_ticket($tid);
- $agent_a->content_unlike(
- qr/unread message/ims,
+ $agent_a->content_lacks(
+ 'unread message',
'we have seen everything, so no messages'
);
}
diff --git a/rt/t/web/ticket_txn_content.t b/rt/t/web/ticket_txn_content.t
index 1c1056a3e..db4751218 100644
--- a/rt/t/web/ticket_txn_content.t
+++ b/rt/t/web/ticket_txn_content.t
@@ -1,37 +1,48 @@
#!/usr/bin/perl -w
use strict;
-use RT::Test tests => 37;
-use File::Temp 'tempfile';
-use File::Spec;
-my ( $plain_fh, $plain_file ) =
- tempfile( 'rttestXXXXXX', SUFFIX => '.txt', UNLINK => 1, TMPDIR => 1 );
+use RT::Test tests => 63;
+my $plain_file = File::Spec->catfile( RT::Test->temp_directory, 'attachment.txt' );
+open my $plain_fh, '>', $plain_file or die $!;
print $plain_fh "this is plain content";
close $plain_fh;
my $plain_name = (File::Spec->splitpath($plain_file))[-1];
-my ( $html_fh, $html_file ) =
- tempfile( 'rttestXXXXXX', SUFFIX => '.html', UNLINK => 1, TMPDIR => 1 );
-print $html_fh "this is html content";
+my $html_file = File::Spec->catfile( RT::Test->temp_directory, 'attachment.html' );
+open my $html_fh, '>', $html_file or die $!;
+print $html_fh "this is plain content";
close $html_fh;
my $html_name = (File::Spec->splitpath($html_file))[-1];
my ($baseurl, $m) = RT::Test->started_ok;
ok $m->login, 'logged in';
-my $queue = RT::Queue->new($RT::Nobody);
+my $queue = RT::Queue->new(RT->Nobody);
my $qid = $queue->Load('General');
ok( $qid, "Loaded General queue" );
-RT::Test->set_mail_catcher;
RT::Test->clean_caught_mails;
+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);
+}
+
+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);
+}
+
for my $type ( 'text/plain', 'text/html' ) {
$m->form_name('CreateTicketInQueue');
$m->field( 'Queue', $qid );
$m->submit;
is( $m->status, 200, "request successful" );
- $m->content_like( qr/Create a new ticket/, 'ticket create page' );
+ $m->content_contains('Create a new ticket', 'ticket create page' );
$m->form_name('TicketCreate');
$m->field( 'Subject', 'with plain attachment' );
@@ -40,16 +51,26 @@ for my $type ( 'text/plain', 'text/html' ) {
$m->field( 'ContentType', $type ) unless $type eq 'text/plain';
$m->submit;
is( $m->status, 200, "request successful" );
- $m->content_like( qr/with plain attachment/,
+ $m->content_contains('with plain attachment',
'we have subject on the page' );
- $m->content_like( qr/this is main content/, 'main content' );
- $m->content_like( qr/Download $plain_name/, 'download plain file link' );
+ $m->content_contains('this is main content', 'main content' );
+ $m->content_contains("Download $plain_name", 'download plain file link' );
+
+ # Check for Message-IDs
+ follow_parent_with_headers_link($m, text => 'with headers', n => 1);
+ $m->content_like(qr/^Message-ID:/im, 'create content has one Message-ID');
+ $m->content_unlike(qr/^Message-ID:.+?Message-ID:/ism, 'but not two Message-IDs');
+ $m->back;
+
+ follow_with_headers_link($m, text => "Download $plain_name", n => 1);
+ $m->content_unlike(qr/^Message-ID:/im, 'attachment lacks a Message-ID');
+ $m->back;
my ( $mail ) = RT::Test->fetch_caught_mails;
like( $mail, qr/this is main content/, 'email contains main content' );
# check the email link in page too
$m->follow_link_ok( { text => 'Show' }, 'show the email outgoing' );
- $m->content_like( qr/this is main content/, 'email contains main content');
+ $m->content_contains('this is main content', 'email contains main content');
$m->back;
$m->follow_link_ok( { text => 'Reply' }, "reply to the ticket" );
@@ -67,13 +88,27 @@ for my $type ( 'text/plain', 'text/html' ) {
$m->click('SubmitTicket');
is( $m->status, 200, "request successful" );
- $m->content_like( qr/this is main reply content/, 'main reply content' );
- $m->content_like( qr/Download $html_name/, 'download html file link' );
+ $m->content_contains("this is main reply content", 'main reply content' );
+ $m->content_contains("Download $html_name", 'download html file link' );
+
+ # Check for Message-IDs
+ follow_parent_with_headers_link($m, text => 'with headers', n => 2);
+ $m->content_like(qr/^Message-ID:/im, 'correspondence has one Message-ID');
+ $m->content_unlike(qr/^Message-ID:.+?Message-ID:/ism, 'but not two Message-IDs');
+ $m->back;
+
+ follow_with_headers_link($m, text => "Download $plain_name", n => 2);
+ $m->content_unlike(qr/^Message-ID:/im, 'text/plain attach lacks a Message-ID');
+ $m->back;
+
+ follow_with_headers_link($m, text => "Download $html_name", n => 1);
+ $m->content_unlike(qr/^Message-ID:/im, 'text/html attach lacks a Message-ID');
+ $m->back;
( $mail ) = RT::Test->fetch_caught_mails;
like( $mail, qr/this is main reply content/, 'email contains main reply content' );
# check the email link in page too
$m->follow_link_ok( { text => 'Show', n => 2 }, 'show the email outgoing' );
- $m->content_like( qr/this is main reply content/, 'email contains main reply content');
+ $m->content_contains("this is main reply content", 'email contains main reply content');
$m->back;
}
diff --git a/rt/t/web/ticket_update_without_content.t b/rt/t/web/ticket_update_without_content.t
index 595cb74e9..54f0c5a8a 100644
--- a/rt/t/web/ticket_update_without_content.t
+++ b/rt/t/web/ticket_update_without_content.t
@@ -2,11 +2,11 @@
use strict;
use warnings;
-use RT::Test tests => 10;
+use RT::Test tests => 12;
my ( $url, $m ) = RT::Test->started_ok;
# merged tickets still show up in search
-my $ticket = RT::Ticket->new($RT::SystemUser);
+my $ticket = RT::Ticket->new(RT->SystemUser);
my ( $ret, $msg ) = $ticket->Create(
Subject => 'base ticket' . $$,
Queue => 'general',
@@ -30,10 +30,10 @@ $m->submit_form(
fields => { Priority => '1', }
);
-$m->content_like(qr/priority changed/i);
-$m->content_unlike(qr/message recorded/i);
+$m->content_contains("Priority changed");
+$m->content_lacks("message recorded");
-my $root = RT::User->new( $RT::SystemUser );
+my $root = RT::User->new( RT->SystemUser );
$root->Load('root');
( $ret, $msg ) = $root->SetSignature(<<EOF);
best wishes
@@ -48,5 +48,5 @@ $m->submit_form(
form_number => 3,
fields => { Priority => '2', }
);
-$m->content_like(qr/priority changed/i);
-$m->content_unlike(qr/message recorded/i);
+$m->content_contains("Priority changed");
+$m->content_lacks("message recorded");
diff --git a/rt/t/web/transaction_batch.t b/rt/t/web/transaction_batch.t
new file mode 100644
index 000000000..ae04e1fca
--- /dev/null
+++ b/rt/t/web/transaction_batch.t
@@ -0,0 +1,55 @@
+use strict;
+use warnings;
+use RT;
+use RT::Test tests => 12;
+
+
+my $q = RT::Test->load_or_create_queue ( Name => 'General' );
+
+my $s1 = RT::Scrip->new(RT->SystemUser);
+my ($val, $msg) =$s1->Create( Queue => $q->Id,
+ ScripCondition => 'User Defined',
+ ScripAction => 'User Defined',
+ CustomIsApplicableCode => 'return ($self->TransactionObj->Field||"") eq "TimeEstimated"',
+ CustomPrepareCode => 'return 1',
+ CustomCommitCode => '$self->TicketObj->SetPriority($self->TicketObj->Priority + 2); return 1;',
+ Template => 'Blank',
+ Stage => 'TransactionBatch',
+ );
+ok($val,$msg);
+
+my $ticket = RT::Ticket->new(RT->SystemUser);
+my ($tv,$ttv,$tm) = $ticket->Create(Queue => $q->Id,
+ Subject => "hair on fire",
+ );
+ok($tv, $tm);
+
+# Flush the Create transaction off of the ticket
+$ticket->ApplyTransactionBatch;
+
+my $testuser = RT::Test->load_or_create_user( Name => 'bob', EmailAddress => 'bob@example.com', Password => 'password' );
+ok($testuser->Id, "Created test user bob");
+
+ok( RT::Test->add_rights({ Principal => 'Privileged', Right => [qw(ShowTicket ModifyTicket SeeQueue)]}), 'Granted ticket management rights');
+
+my $test_current_user = RT::CurrentUser->new();
+$test_current_user->LoadByName($testuser->Name);
+my $api_test = RT::Ticket->new($test_current_user);
+$api_test->Load($ticket->Id);
+is($api_test->Priority,0,"Ticket priority starts at 0");
+$api_test->SetTimeEstimated(12);
+$api_test->ApplyTransactionBatch;
+is($api_test->CurrentUser->UserObj->Name, $testuser->Name,"User didn't change running Transaction Batch scrips");
+$api_test->Load($api_test->Id);
+is($api_test->Priority,2,"Ticket priority updated");
+
+my ($baseurl, $m) = RT::Test->started_ok;
+$m->login('bob','password');
+$m->get_ok("$baseurl/Ticket/Modify.html?id=".$ticket->Id);
+ $m->submit_form( form_name => 'TicketModify',
+ fields => { TimeEstimated => 5 }
+ );
+
+
+$ticket->Load($ticket->Id);
+is ($ticket->Priority , 4, "Ticket priority is set right");
diff --git a/rt/t/web/unlimited_search.t b/rt/t/web/unlimited_search.t
index d98baaac0..988a2918d 100644
--- a/rt/t/web/unlimited_search.t
+++ b/rt/t/web/unlimited_search.t
@@ -2,12 +2,12 @@
use strict;
-use RT::Test tests => 8;
-RT::Test->started_ok;
+use RT::Test tests => 85;
+my ($baseurl, $agent) = RT::Test->started_ok;
-my $ticket = RT::Ticket->new($RT::SystemUser);
+my $ticket = RT::Ticket->new(RT->SystemUser);
for ( 1 .. 75 ) {
- $ticket->Create(
+ ok $ticket->Create(
Subject => 'Ticket ' . $_,
Queue => 'General',
Owner => 'root',
@@ -15,7 +15,6 @@ for ( 1 .. 75 ) {
);
}
-my $agent = RT::Test::Web->new;
ok $agent->login('root', 'password'), 'logged in as root';
$agent->get_ok('/Search/Build.html');
@@ -27,7 +26,7 @@ $agent->form_name('BuildQuery');
$agent->field('RowsPerPage', '0');
$agent->submit('DoSearch');
$agent->follow_link_ok({text=>'Show Results'});
-$agent->content_like(qr/Ticket 75/);
+$agent->content_contains("Ticket 75");
$agent->follow_link_ok({text=>'New Search'});
$agent->form_name('BuildQuery');
@@ -38,4 +37,4 @@ $agent->form_name('BuildQuery');
$agent->field('RowsPerPage', '50');
$agent->submit('DoSearch');
$agent->follow_link_ok({text=>'Bulk Update'});
-$agent->content_unlike(qr/Ticket 51/);
+$agent->content_lacks("Ticket 51");
diff --git a/rt/t/web/user_update.t b/rt/t/web/user_update.t
new file mode 100644
index 000000000..dc908fc10
--- /dev/null
+++ b/rt/t/web/user_update.t
@@ -0,0 +1,32 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use utf8;
+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 => 'ja');
+$m->submit;
+
+$m->text_contains("Lang changed from (no value) to 'ja'");
+
+# we only changed one field, and it wasn't the default, so this feedback is
+# spurious and annoying
+$m->content_lacks("That is already the current value");
+
+# change back to English
+$m->form_with_fields('Lang');
+$m->field(Lang => 'en_us');
+$m->submit;
+
+# This message shows up in Japanese
+# $m->text_contains("Lang changed from 'ja' to 'en_us'");
+$m->text_contains("Langは「'ja'」から「'en_us'」に変更されました");
+
+# another spurious update
+$m->content_lacks("That is already the current value");
+
diff --git a/rt/t/web/walk.t b/rt/t/web/walk.t
new file mode 100644
index 000000000..34fab1476
--- /dev/null
+++ b/rt/t/web/walk.t
@@ -0,0 +1,92 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test;
+use HTML::TreeBuilder;
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+
+ok( $m->login( 'root' => 'password' ), 'login as root' );
+
+my %viewed = ( '/NoAuth/Logout.html' => 1 ); # in case logout
+
+my $user = RT::User->new($RT::SystemUser);
+$user->Load('root');
+ok( $user->id, 'loaded root' );
+
+my $queue = RT::Queue->new($RT::SystemUser);
+$queue->Load('General');
+ok( $queue->id, 'loaded General queue' );
+
+my $group = RT::Group->new($RT::SystemUser);
+ok( $group->CreateUserDefinedGroup( Name => 'group_foo' ) );
+my $cf = RT::CustomField->new($RT::SystemUser);
+ok(
+ $cf->Create(
+ Name => 'cf_foo',
+ Type => 'Freeform',
+ LookupType => 'RT::Queue-RT::Ticket',
+ )
+);
+ok( $cf->id, 'created cf_foo' );
+
+my $class = RT::Class->new($RT::SystemUser);
+ok( $class->Create( Name => 'class_foo' ) );
+ok( $class->id, 'created class_foo' );
+
+# to make search have results
+my $open_ticket = RT::Test->create_ticket(
+ Subject => 'ticket_foo',
+ Queue => 1,
+);
+
+my $resolved_ticket = RT::Test->create_ticket(
+ Subject => 'ticket_bar',
+ Status => 'resolved',
+ Queue => 1,
+);
+
+my @links = (
+ '/',
+ '/Admin/Users/Modify.html?id=' . $user->id,
+ '/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/Global/Template.html?Template=1',
+ '/Admin/Articles/Classes/Modify.html?id=' . $class->id,
+ '/Search/Build.html?Query=id<10',
+ '/Ticket/Display.html?id=' . $open_ticket->id,
+ '/Ticket/Display.html?id=' . $resolved_ticket->id,
+);
+
+for my $link (@links) {
+ test_page($m, $link);
+}
+
+$m->get_ok('/NoAuth/Logout.html');
+
+sub test_page {
+ my $m = shift;
+ my $link = shift;
+ $m->get_ok( $link, $link );
+ $m->no_warnings_ok($link);
+
+ my $tree = HTML::TreeBuilder->new();
+ $tree->parse( $m->content );
+ $tree->elementify;
+ my ($top_menu) = $tree->look_down( id => 'main-navigation' );
+ my ($page_menu) = $tree->look_down( id => 'page-navigation' );
+
+ my (@links) =
+ grep { !$viewed{$_}++ && /^[^#]/ }
+ map { $_->attr('href') || () } ( $top_menu ? $top_menu->find('a') : () ),
+ ( $page_menu ? $page_menu->find('a') : () );
+
+ for my $link (@links) {
+ test_page($m, $link);
+ }
+}
+