summaryrefslogtreecommitdiff
path: root/rt/lib/t/regression
diff options
context:
space:
mode:
authorivan <ivan>2007-08-02 19:56:20 +0000
committerivan <ivan>2007-08-02 19:56:20 +0000
commitef20b2b6b1feb47ad02b5ff7525f1a0fd11d0fa4 (patch)
treea2ea500cf510739908761a6bfbd14e990131f2cc /rt/lib/t/regression
parenta513c0bef534d05f03c1242831b6f3be19b97dae (diff)
import rt 3.6.4
Diffstat (limited to 'rt/lib/t/regression')
-rw-r--r--rt/lib/t/regression/00-mason-syntax.t42
-rw-r--r--rt/lib/t/regression/01ticket_link_searching.t96
-rw-r--r--rt/lib/t/regression/02basic_web.t27
-rw-r--r--rt/lib/t/regression/03web_compiliation_errors.t14
-rw-r--r--rt/lib/t/regression/04send_email.t130
-rw-r--r--rt/lib/t/regression/06-mime_decoding.t54
-rw-r--r--rt/lib/t/regression/06mailgateway.t219
-rw-r--r--rt/lib/t/regression/07acl.t96
-rw-r--r--rt/lib/t/regression/07rights.t2
-rw-r--r--rt/lib/t/regression/08web_cf_access.t15
-rw-r--r--rt/lib/t/regression/12-search.t59
-rw-r--r--rt/lib/t/regression/13-attribute-tests.t24
-rw-r--r--rt/lib/t/regression/14linking.t112
-rw-r--r--rt/lib/t/regression/15cf_combo_cascade.t49
-rw-r--r--rt/lib/t/regression/15cf_pattern.t54
-rw-r--r--rt/lib/t/regression/17custom_search.t88
-rw-r--r--rt/lib/t/regression/18custom_frontpage.t75
-rw-r--r--rt/lib/t/regression/19quicksearch.t39
-rw-r--r--rt/lib/t/regression/20-sort-by-requestor.t143
-rw-r--r--rt/lib/t/regression/21query-builder.t74
-rw-r--r--rt/lib/t/regression/22search_tix_by_txn.t14
-rw-r--r--rt/lib/t/regression/22search_tix_by_watcher.t192
-rw-r--r--rt/lib/t/regression/23-batch-upload-csv.t47
-rw-r--r--rt/lib/t/regression/23-web_attachments.t60
-rw-r--r--rt/lib/t/regression/23cfsort.t143
-rw-r--r--rt/lib/t/regression/24pawsort.t104
-rw-r--r--rt/lib/t/regression/25scrip_order.t57
-rw-r--r--rt/lib/t/regression/26command_line.t415
-rw-r--r--rt/lib/t/regression/27verp.t9
29 files changed, 2131 insertions, 322 deletions
diff --git a/rt/lib/t/regression/00-mason-syntax.t b/rt/lib/t/regression/00-mason-syntax.t
new file mode 100644
index 0000000..96674ca
--- /dev/null
+++ b/rt/lib/t/regression/00-mason-syntax.t
@@ -0,0 +1,42 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 1;
+
+my $ok = 1;
+
+use File::Find;
+find( {
+ no_chdir => 1,
+ wanted => sub {
+ return if /\.(?:jpe?g|png|gif|rej|\~)$/i;
+ if (m!/\.svn$!) {
+ $File::Find::prune = 1;
+ return;
+ }
+ return unless -f $_;
+ diag "testing $_" if $ENV{'TEST_VERBOSE'};
+ eval { compile_file($_) } and return;
+ $ok = 0;
+ diag "error in ${File::Find::name}:\n$@";
+ },
+}, 'html');
+ok($ok, "mason syntax is ok");
+
+use HTML::Mason::Compiler;
+use HTML::Mason::Compiler::ToObject;
+
+sub compile_file {
+ my $file = shift;
+
+ open my $fh, '<:utf8', $file or die "couldn't open '$file': $!";
+ my $text = do { local $/; <$fh> };
+ close $fh or die "couldn't close '$file': $!";
+
+ my $compiler = new HTML::Mason::Compiler::ToObject;
+ $compiler->compile( comp_source => $text, name => 'my' );
+ return 1;
+}
+
diff --git a/rt/lib/t/regression/01ticket_link_searching.t b/rt/lib/t/regression/01ticket_link_searching.t
index 6d10221..a402c73 100644
--- a/rt/lib/t/regression/01ticket_link_searching.t
+++ b/rt/lib/t/regression/01ticket_link_searching.t
@@ -1,6 +1,6 @@
#!/usr/bin/perl -w
-use Test::More tests => 25;
+use Test::More tests => 30;
use strict;
use RT;
@@ -17,54 +17,46 @@ my $queue = new RT::Queue($CurrentUser);
$queue->Load('General') || Abort(loc("Queue could not be loaded."));
my $child_ticket = new RT::Ticket( $CurrentUser );
-
-my ( $childid ) = $child_ticket->Create
- ( Subject => 'test child',
- Queue => $queue->Id);
-
-ok($childid != 0);
+my ($childid) = $child_ticket->Create(
+ Subject => 'test child',
+ Queue => $queue->Id,
+);
+ok($childid, "We created a child ticket");
my $parent_ticket = new RT::Ticket( $CurrentUser );
+my ($parentid) = $parent_ticket->Create(
+ Subject => 'test parent',
+ Children => [ $childid ],
+ Queue => $queue->Id,
+);
+ok($parentid, "We created a parent ticket");
-my ( $parentid ) = $parent_ticket->Create
- ( Subject => 'test parent',
- Children => [$childid],
- Queue => $queue->Id);
-
-ok($parentid != 0, "We created a parent ticket");
my $Collection = RT::Tickets->new($CurrentUser);
-$Collection->LimitMemberOf ($parentid);
-
-ok ($Collection->First);
-is ($Collection->First->id, $childid, "We found the collection of all children of $parentid with Limit");
+$Collection->LimitMemberOf( $parentid );
is($Collection->Count,1, "We found only one result");
+ok($Collection->First);
+is($Collection->First->id, $childid, "We found the collection of all children of $parentid with Limit");
$Collection = RT::Tickets->new($CurrentUser);
-$Collection->FromSQL( "MemberOf = $parentid");
-is ($Collection->First->id, $childid, "We found the collection of all children of $parentid with TicketSQL");
-is($Collection->Count,1, "We found only one result");
-
-
-
+$Collection->FromSQL("MemberOf = $parentid");
+is($Collection->Count, 1, "We found only one result");
+ok($Collection->First);
+is($Collection->First->id, $childid, "We found the collection of all children of $parentid with TicketSQL");
$Collection = RT::Tickets->new($CurrentUser);
$Collection->LimitHasMember ($childid);
-
-ok ($Collection->First);
-is ($Collection->First->id, $parentid, "We found the collection of all parents of $childid with Limit");
is($Collection->Count,1, "We found only one result");
-
+ok($Collection->First);
+is($Collection->First->id, $parentid, "We found the collection of all parents of $childid with Limit");
$Collection = RT::Tickets->new($CurrentUser);
$Collection->FromSQL("HasMember = $childid");
-
-ok ($Collection->First);
-is ($Collection->First->id, $parentid, "We found the collection of all parents of $childid with TicketSQL");
is($Collection->Count,1, "We found only one result");
-
+ok($Collection->First);
+is($Collection->First->id, $parentid, "We found the collection of all parents of $childid with TicketSQL");
# Now we find a collection of all the tickets which have no members. they should have no children.
@@ -75,12 +67,10 @@ my %has;
while (my $t = $Collection->Next) {
++$has{$t->id};
}
-ok ($has{$childid} , "The collection has our child - $childid");
+ok( $has{$childid}, "The collection has our child - $childid");
ok( !$has{$parentid}, "The collection doesn't have our parent - $parentid");
-
-
# Now we find a collection of all the tickets which are not members of anything. they should have no parents.
$Collection = RT::Tickets->new($CurrentUser);
$Collection->LimitMemberOf('');
@@ -102,28 +92,27 @@ ok( !$has{$childid}, "The collection doesn't have our child - $childid");
$Collection = RT::Tickets->new($CurrentUser);
$Collection->FromSQL ("HasMember IS NULL");
# must contain parent; must not contain child
- %has = ();
+%has = ();
while (my $t = $Collection->Next) {
++$has{$t->id};
}
-ok (!$has{$parentid} , "The collection doesn't have our parent - $parentid");
+ok( !$has{$parentid}, "The collection doesn't have our parent - $parentid");
ok( $has{$childid}, "The collection has our child - $childid");
# Now we find a collection of all the tickets which have no members. they should have no children.
# Alternate syntax
$Collection = RT::Tickets->new($CurrentUser);
-$Collection->FromSQL ("HasMember = ''");
+$Collection->FromSQL("HasMember = ''");
# must contain parent; must not contain child
- %has = ();
+%has = ();
while (my $t = $Collection->Next) {
++$has{$t->id};
}
-ok (!$has{$parentid} , "The collection doesn't have our parent - $parentid");
+ok( !$has{$parentid}, "The collection doesn't have our parent - $parentid");
ok( $has{$childid}, "The collection has our child - $childid");
-
# Now we find a collection of all the tickets which are not members of anything. they should have no parents.
$Collection = RT::Tickets->new($CurrentUser);
$Collection->FromSQL("MemberOf IS NULL");
@@ -132,8 +121,8 @@ $Collection->FromSQL("MemberOf IS NULL");
while (my $t = $Collection->Next) {
++$has{$t->id};
}
-ok ($has{$parentid} , "The collection has our parent - $parentid");
-ok(!$has{$childid}, "The collection doesn't have our child - $childid");
+ok( $has{$parentid}, "The collection has our parent - $parentid");
+ok( !$has{$childid}, "The collection doesn't have our child - $childid");
# Now we find a collection of all the tickets which are not members of anything. they should have no parents.
@@ -144,12 +133,27 @@ $Collection->FromSQL("MemberOf = ''");
while (my $t = $Collection->Next) {
++$has{$t->id};
}
-ok ($has{$parentid} , "The collection has our parent - $parentid");
-ok(!$has{$childid}, "The collection doesn't have our child - $childid");
+ok( $has{$parentid}, "The collection has our parent - $parentid");
+ok( !$has{$childid}, "The collection doesn't have our child - $childid");
+# Now we find a collection of all the tickets which are not members of the parent ticket
+$Collection = RT::Tickets->new($CurrentUser);
+$Collection->FromSQL("MemberOf != $parentid");
+%has = ();
+while (my $t = $Collection->Next) {
+ ++$has{$t->id};
+}
+ok( $has{$parentid}, "The collection has our parent - $parentid");
+ok( !$has{$childid}, "The collection doesn't have our child - $childid");
+$Collection = RT::Tickets->new($CurrentUser);
+$Collection->LimitMemberOf($parentid, OPERATOR => '!=');
+%has = ();
+while (my $t = $Collection->Next) {
+ ++$has{$t->id};
+}
+ok( $has{$parentid}, "The collection has our parent - $parentid");
+ok( !$has{$childid}, "The collection doesn't have our child - $childid");
1;
-
-
diff --git a/rt/lib/t/regression/02basic_web.t b/rt/lib/t/regression/02basic_web.t
index d3376d0..3b8619b 100644
--- a/rt/lib/t/regression/02basic_web.t
+++ b/rt/lib/t/regression/02basic_web.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl
use strict;
-use Test::More tests => 17;
+use Test::More tests => 19;
use WWW::Mechanize;
use HTTP::Request::Common;
use HTTP::Cookies;
@@ -16,10 +16,10 @@ my $agent = WWW::Mechanize->new();
$agent->cookie_jar($cookie_jar);
use RT;
-RT::LoadConfig;
-
+RT::LoadConfig();
# get the top page
my $url = $RT::WebURL;
+diag $url;
$agent->get($url);
is ($agent->{'status'}, 200, "Loaded a page");
@@ -44,17 +44,20 @@ ok( $agent->{'content'} =~ /Logout/i, "Found a logout link");
$agent->get($url."Ticket/Create.html?Queue=1");
is ($agent->{'status'}, 200, "Loaded Create.html");
-$agent->form(3);
+$agent->form_number(3);
# Start with a string containing characters in latin1
my $string = "I18N Web Testing זרו";
Encode::from_to($string, 'iso-8859-1', 'utf8');
$agent->field('Subject' => "Ticket with utf8 body");
$agent->field('Content' => $string);
ok($agent->submit(), "Created new ticket with $string as Content");
-ok( $agent->{'content'} =~ qr{$string} , "Found the content");
+like( $agent->{'content'}, qr{$string} , "Found the content");
+ok($agent->{redirected_uri}, "Did redirection");
+
+
$agent->get($url."Ticket/Create.html?Queue=1");
is ($agent->{'status'}, 200, "Loaded Create.html");
-$agent->form(3);
+$agent->form_number(3);
# Start with a string containing characters in latin1
my $string = "I18N Web Testing זרו";
Encode::from_to($string, 'iso-8859-1', 'utf8');
@@ -62,9 +65,15 @@ $agent->field('Subject' => $string);
$agent->field('Content' => "Ticket with utf8 subject");
ok($agent->submit(), "Created new ticket with $string as Subject");
-ok( $agent->{'content'} =~ qr{$string} , "Found the content");
+like( $agent->{'content'}, qr{$string} , "Found the content");
+# Update time worked in hours
+$agent->follow_link( text_regex => qr/Basics/ );
+$agent->submit_form( form_number => 3,
+ fields => { TimeWorked => 5, 'TimeWorked-TimeUnits' => "hours" }
+);
+like ($agent->{'content'}, qr/to &#39;300&#39;/, "5 hours is 300 minutes");
# }}}
@@ -82,14 +91,14 @@ ok($agent->form_name('BuildQuery'));
$agent->field("AttachmentField", "Subject");
$agent->field("AttachmentOp", "LIKE");
$agent->field("ValueOfAttachment", "aaa");
-$agent->submit();
+$agent->submit("AddClause");
# set the next value
ok($agent->form_name('BuildQuery'));
$agent->field("AttachmentField", "Subject");
$agent->field("AttachmentOp", "LIKE");
$agent->field("ValueOfAttachment", "bbb");
-$agent->submit();
+$agent->submit("AddClause");
ok($agent->form_name('BuildQuery'));
diff --git a/rt/lib/t/regression/03web_compiliation_errors.t b/rt/lib/t/regression/03web_compiliation_errors.t
index f2e62c9..29e56d6 100644
--- a/rt/lib/t/regression/03web_compiliation_errors.t
+++ b/rt/lib/t/regression/03web_compiliation_errors.t
@@ -12,19 +12,18 @@ my $cookie_jar = HTTP::Cookies->new;
my $agent = WWW::Mechanize->new();
# give the agent a place to stash the cookies
-
$agent->cookie_jar($cookie_jar);
use RT;
-RT::LoadConfig;
+RT::LoadConfig();
# get the top page
my $url = $RT::WebURL;
+diag "Base URL is '$url'" if $ENV{TEST_VERBOSE};
$agent->get($url);
is ($agent->{'status'}, 200, "Loaded a page");
-
# {{{ test a login
# follow the link marked "Login"
@@ -45,20 +44,19 @@ use File::Find;
find ( \&wanted , 'html/');
sub wanted {
- -f && /\.html$/ && $_ !~ /Logout.html$/ && test_get($File::Find::name);
+ -f && /\.html$/ && $_ !~ /Logout.html$/ && test_get($File::Find::name);
}
sub test_get {
my $file = shift;
-
- $file =~ s#^html/##;
+ $file =~ s#^html/##;
+ diag( "testing $url/$file" ) if $ENV{TEST_VERBOSE};
ok ($agent->get("$url/$file", "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'} !~ /System error/i, "Didn't get a Mason compilation error on $file");
-
+ ok( $agent->{'content'} !~ /raw error/i, "Didn't get a Mason compilation error on $file");
}
# }}}
diff --git a/rt/lib/t/regression/04send_email.t b/rt/lib/t/regression/04send_email.t
index 09e6e6f..a175ffa 100644
--- a/rt/lib/t/regression/04send_email.t
+++ b/rt/lib/t/regression/04send_email.t
@@ -1,10 +1,12 @@
#!/usr/bin/perl -w
use strict;
-use Test::More tests => 137;
+use Test::More tests => 142;
+
use RT;
RT::LoadConfig();
RT::Init;
+
use RT::EmailParser;
use RT::Tickets;
use RT::Action::SendEmail;
@@ -20,17 +22,29 @@ $everyone->PrincipalObj->GrantRight(Right =>'SuperUser');
is (__PACKAGE__, 'main', "We're operating in the main package");
-
{
-no warnings qw/redefine/;
-sub RT::Action::SendEmail::SendMessage {
+ no warnings qw/redefine/;
+ sub RT::Action::SendEmail::SendMessage {
my $self = shift;
my $MIME = shift;
main::_fired_scrip($self->ScripObj);
main::ok(ref($MIME) eq 'MIME::Entity', "hey, look. it's a mime entity");
+ }
}
+# some utils
+sub first_txn { return $_[0]->Transactions->First }
+sub first_attach { return first_txn($_[0])->Attachments->First }
+
+sub count_txns { return $_[0]->Transactions->Count }
+sub count_attachs { return first_txn($_[0])->Attachments->Count }
+
+sub file_content
+{
+ open my $fh, "<:raw", $_[0] or die "couldn't open file '$_[0]': $!";
+ local $/;
+ return scalar <$fh>;
}
# instrument SendEmail to pass us what it's about to send.
@@ -40,7 +54,7 @@ my $parser = RT::EmailParser->new();
# Let's test to make sure a multipart/report is processed correctly
-my $content = `cat $RT::BasePath/lib/t/data/multipart-report` || die "couldn't find new content";
+my $content = file_content("$RT::BasePath/lib/t/data/multipart-report");
# be as much like the mail gateway as possible.
use RT::Interface::Email;
@@ -53,7 +67,7 @@ my $tick= $tickets->First();
isa_ok($tick, "RT::Ticket", "got a ticket object");
ok ($tick->Id, "found ticket ".$tick->Id);
-ok ($tick->Transactions->First->Content =~ /The original message was received/, "It's the bounce");
+ok (first_txn($tick)->Content =~ /The original message was received/, "It's the bounce");
# make sure it fires scrips.
@@ -96,7 +110,7 @@ is ($#scrips_fired, 1, "Fired 2 scrips on ticket creation");
# create an iso 8859-1 ticket
@scrips_fired = ();
-$content = `cat $RT::BasePath/lib/t/data/new-ticket-from-iso-8859-1` || die "couldn't find new content";
+$content = file_content("$RT::BasePath/lib/t/data/new-ticket-from-iso-8859-1");
@@ -114,7 +128,7 @@ $tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick = $tickets->First();
ok ($tick->Id, "found ticket ".$tick->Id);
-ok ($tick->Transactions->First->Content =~ /H\x{e5}vard/, "It's signed by havard. yay");
+ok (first_txn($tick)->Content =~ /H\x{e5}vard/, "It's signed by havard. yay");
# make sure it fires scrips.
@@ -144,7 +158,7 @@ $RT::EmailOutputEncoding = 'iso-8859-1';
# create an iso 8859-1 ticket
@scrips_fired = ();
- $content = `cat $RT::BasePath/lib/t/data/new-ticket-from-iso-8859-1` || die "couldn't find new content";
+ $content = file_content("$RT::BasePath/lib/t/data/new-ticket-from-iso-8859-1");
# be as much like the mail gateway as possible.
use RT::Interface::Email;
@@ -156,7 +170,7 @@ $tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick = $tickets->First();
ok ($tick->Id, "found ticket ".$tick->Id);
-ok ($tick->Transactions->First->Content =~ /H\x{e5}vard/, "It's signed by havard. yay");
+ok (first_txn($tick)->Content =~ /H\x{e5}vard/, "It's signed by havard. yay");
# make sure it fires scrips.
@@ -238,7 +252,7 @@ sub iso8859_redef_sendmessage {
# {{{ test a multipart alternative containing a text-html part with an umlaut
- $content = `cat $RT::BasePath/lib/t/data/multipart-alternative-with-umlaut` || die "couldn't find new content";
+ $content = file_content("$RT::BasePath/lib/t/data/multipart-alternative-with-umlaut");
$parser->ParseMIMEEntityFromScalar($content);
@@ -246,16 +260,17 @@ $parser->ParseMIMEEntityFromScalar($content);
# be as much like the mail gateway as possible.
&umlauts_redef_sendmessage;
- %args = (message => $content, queue => 1, action => 'correspond');
- RT::Interface::Email::Gateway(\%args);
- $tickets = RT::Tickets->new($RT::SystemUser);
+%args = (message => $content, queue => 1, action => 'correspond');
+RT::Interface::Email::Gateway(\%args);
+$tickets = RT::Tickets->new($RT::SystemUser);
$tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
$tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
- $tick = $tickets->First();
+$tick = $tickets->First();
+
ok ($tick->Id, "found ticket ".$tick->Id);
-ok ($tick->Transactions->First->Content =~ /causes Error/, "We recorded the content right as text-plain");
-is ($tick->Transactions->First->Attachments->Count , 3 , "Has three attachments, presumably a text-plain, a text-html and a multipart alternative");
+ok (first_txn($tick)->Content =~ /causes Error/, "We recorded the content right as text-plain");
+is (count_attachs($tick) , 3 , "Has three attachments, presumably a text-plain, a text-html and a multipart alternative");
sub umlauts_redef_sendmessage {
no warnings qw/redefine/;
@@ -266,7 +281,7 @@ sub umlauts_redef_sendmessage {
# {{{ test a text-html message with an umlaut
- $content = `cat $RT::BasePath/lib/t/data/text-html-with-umlaut` || die "couldn't find new content";
+ $content = file_content("$RT::BasePath/lib/t/data/text-html-with-umlaut");
$parser->ParseMIMEEntityFromScalar($content);
@@ -282,29 +297,28 @@ $tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick = $tickets->First();
ok ($tick->Id, "found ticket ".$tick->Id);
-ok ($tick->Transactions->First->Attachments->First->Content =~ /causes Error/, "We recorded the content as containing 'causes error'");
-ok ($tick->Transactions->First->Attachments->First->ContentType =~ /text\/html/, "We recorded the content as text/html");
-ok ($tick->Transactions->First->Attachments->Count ==1 , "Has one attachment, presumably a text-html and a multipart alternative");
+ok (first_attach($tick)->Content =~ /causes Error/, "We recorded the content as containing 'causes error'") or diag( first_attach($tick)->Content );
+ok (first_attach($tick)->ContentType =~ /text\/html/, "We recorded the content as text/html");
+is (count_attachs($tick), 1 , "Has one attachment, presumably a text-html and a multipart alternative");
sub text_html_umlauts_redef_sendmessage {
no warnings qw/redefine/;
eval 'sub RT::Action::SendEmail::SendMessage {
- my $self = shift;
- my $MIME = shift;
- use Data::Dumper;
+ my $self = shift;
+ my $MIME = shift;
return (1) unless ($self->ScripObj->ScripActionObj->Name eq "Notify AdminCcs" );
- ok (is $MIME->parts, 2, "generated correspondence mime entityis composed of three parts");
+ is ($MIME->parts, 2, "generated correspondence mime entityis composed of three parts");
is ($MIME->head->mime_type , "multipart/mixed", "The first part is a multipart mixed". $MIME->head->mime_type);
is ($MIME->parts(0)->head->mime_type , "text/plain", "The second part is a plain");
is ($MIME->parts(1)->head->mime_type , "text/html", "The third part is an html ");
- }';
+ }';
}
# }}}
# {{{ test a text-html message with russian characters
- $content = `cat $RT::BasePath/lib/t/data/text-html-in-russian` || die "couldn't find new content";
+ $content = file_content("$RT::BasePath/lib/t/data/text-html-in-russian");
$parser->ParseMIMEEntityFromScalar($content);
@@ -320,8 +334,8 @@ $tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick = $tickets->First();
ok ($tick->Id, "found ticket ".$tick->Id);
-ok ($tick->Transactions->First->Attachments->First->ContentType =~ /text\/html/, "We recorded the content right as text-html");
-ok ($tick->Transactions->First->Attachments->Count ==1 , "Has one attachment, presumably a text-html and a multipart alternative");
+ok (first_attach($tick)->ContentType =~ /text\/html/, "We recorded the content right as text-html");
+ok (count_attachs($tick) ==1 , "Has one attachment, presumably a text-html and a multipart alternative");
sub text_html_russian_redef_sendmessage {
no warnings qw/redefine/;
@@ -347,7 +361,7 @@ sub text_html_russian_redef_sendmessage {
unshift (@RT::EmailInputEncodings, 'koi8-r');
$RT::EmailOutputEncoding = 'koi8-r';
-$content = `cat $RT::BasePath/lib/t/data/russian-subject-no-content-type` || die "couldn't find new content";
+$content = file_content("$RT::BasePath/lib/t/data/russian-subject-no-content-type");
$parser->ParseMIMEEntityFromScalar($content);
@@ -362,8 +376,8 @@ $tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick= $tickets->First();
ok ($tick->Id, "found ticket ".$tick->Id);
-ok ($tick->Transactions->First->Attachments->First->ContentType =~ /text\/plain/, "We recorded the content type right");
-ok ($tick->Transactions->First->Attachments->Count ==1 , "Has one attachment, presumably a text-plain");
+ok (first_attach($tick)->ContentType =~ /text\/plain/, "We recorded the content type right");
+ok (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/;
@@ -375,7 +389,7 @@ sub text_plain_russian_redef_sendmessage {
my $subject = $MIME->head->get("subject");
chomp($subject);
#is( $subject , /^=\?KOI8-R\?B\?W2V4YW1wbGUuY39tICM3XSDUxdPUINTF09Q=\?=/ , "The $subject is encoded correctly");
- };
+ };
';
}
@@ -386,7 +400,7 @@ $RT::EmailOutputEncoding = 'utf-8';
# {{{ test a message containing a nested RFC 822 message
- $content = `cat $RT::BasePath/lib/t/data/nested-rfc-822` || die "couldn't find new content";
+ $content = file_content("$RT::BasePath/lib/t/data/nested-rfc-822");
ok ($content, "Loaded nested-rfc-822 to test");
$parser->ParseMIMEEntityFromScalar($content);
@@ -402,8 +416,8 @@ $tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick= $tickets->First();
ok ($tick->Id, "found ticket ".$tick->Id);
is ($tick->Subject, "[Jonas Liljegren] Re: [Para] Niv\x{e5}er?");
-ok ($tick->Transactions->First->Attachments->First->ContentType =~ /multipart\/mixed/, "We recorded the content type right");
-is ($tick->Transactions->First->Attachments->Count , 5 , "Has one attachment, presumably a text-plain and a message RFC 822 and another plain");
+ok (first_attach($tick)->ContentType =~ /multipart\/mixed/, "We recorded the content type right");
+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 {
@@ -414,9 +428,9 @@ sub text_plain_nested_redef_sendmessage {
my $subject = $MIME->head->get("subject");
$subject = MIME::Base64::decode_base64( $subject);
chomp($subject);
- # TODO, why does this test fail
+ # TODO, why does this test fail
#ok($subject =~ qr{Niv\x{e5}er}, "The subject matches the word - $subject");
- 1;
+ 1;
}';
}
@@ -425,7 +439,7 @@ sub text_plain_nested_redef_sendmessage {
# {{{ test a multipart alternative containing a uuencoded mesage generated by lotus notes
- $content = `cat $RT::BasePath/lib/t/data/notes-uuencoded` || die "couldn't find new content";
+ $content = file_content("$RT::BasePath/lib/t/data/notes-uuencoded");
$parser->ParseMIMEEntityFromScalar($content);
@@ -441,8 +455,8 @@ $tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick= $tickets->First();
ok ($tick->Id, "found ticket ".$tick->Id);
-ok ($tick->Transactions->First->Content =~ /from Lotus Notes/, "We recorded the content right");
-is ($tick->Transactions->First->Attachments->Count , 3 , "Has three attachments");
+ok (first_txn($tick)->Content =~ /from Lotus Notes/, "We recorded the content right");
+is (count_attachs($tick) , 3 , "Has three attachments");
sub notes_redef_sendmessage {
no warnings qw/redefine/;
@@ -453,7 +467,7 @@ sub notes_redef_sendmessage {
# {{{ test a multipart that crashes the file-based mime-parser works
- $content = `cat $RT::BasePath/lib/t/data/crashes-file-based-parser` || die "couldn't find new content";
+ $content = file_content("$RT::BasePath/lib/t/data/crashes-file-based-parser");
$parser->ParseMIMEEntityFromScalar($content);
@@ -469,8 +483,8 @@ $tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick= $tickets->First();
ok ($tick->Id, "found ticket ".$tick->Id);
-ok ($tick->Transactions->First->Content =~ /FYI/, "We recorded the content right");
-is ($tick->Transactions->First->Attachments->Count , 5 , "Has three attachments");
+ok (first_txn($tick)->Content =~ /FYI/, "We recorded the content right");
+is (count_attachs($tick) , 5 , "Has three attachments");
sub crashes_redef_sendmessage {
no warnings qw/redefine/;
@@ -483,7 +497,7 @@ sub crashes_redef_sendmessage {
# {{{ test a multi-line RT-Send-CC header
- $content = `cat $RT::BasePath/lib/t/data/rt-send-cc` || die "couldn't find new content";
+ $content = file_content("$RT::BasePath/lib/t/data/rt-send-cc");
$parser->ParseMIMEEntityFromScalar($content);
@@ -497,7 +511,7 @@ $tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
$tick= $tickets->First();
ok ($tick->Id, "found ticket ".$tick->Id);
-my $cc = $tick->Transactions->First->Attachments->First->GetHeader('RT-Send-Cc');
+my $cc = first_attach($tick)->GetHeader('RT-Send-Cc');
ok ($cc =~ /test1/, "Found test 1");
ok ($cc =~ /test2/, "Found test 2");
ok ($cc =~ /test3/, "Found test 3");
@@ -506,6 +520,30 @@ ok ($cc =~ /test5/, "Found test 5");
# }}}
+diag q{regression test for #5248 from rt3.fsck.com} if $ENV{TEST_VERBOSE};
+{
+ my $content = file_content("$RT::BasePath/lib/t/data/subject-with-folding-ws");
+ my ($status, $msg, $ticket) = RT::Interface::Email::Gateway(
+ { message => $content, queue => 1, action => 'correspond' }
+ );
+ ok ($status, 'created ticket') or diag "error: $msg";
+ ok ($ticket->id, "found ticket ". $ticket->id);
+ is ($ticket->Subject, 'test', 'correct subject');
+}
+
+diag q{regression test for #5248 from rt3.fsck.com} if $ENV{TEST_VERBOSE};
+{
+ my $content = file_content("$RT::BasePath/lib/t/data/very-long-subject");
+ my ($status, $msg, $ticket) = RT::Interface::Email::Gateway(
+ { message => $content, queue => 1, action => 'correspond' }
+ );
+ ok ($status, 'created ticket') or diag "error: $msg";
+ ok ($ticket->id, "found ticket ". $ticket->id);
+ is ($ticket->Subject, '0123456789'x20, 'correct subject');
+}
+
+
+
# Don't taint the environment
$everyone->PrincipalObj->RevokeRight(Right =>'SuperUser');
1;
diff --git a/rt/lib/t/regression/06-mime_decoding.t b/rt/lib/t/regression/06-mime_decoding.t
new file mode 100644
index 0000000..7780e8c
--- /dev/null
+++ b/rt/lib/t/regression/06-mime_decoding.t
@@ -0,0 +1,54 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use Test::More tests => 6;
+
+use_ok("RT");
+
+RT::LoadConfig();
+RT::Init();
+
+use_ok('RT::I18N');
+
+diag q{'=' char in a leading part before an encoded part} if $ENV{TEST_VERBOSE};
+{
+ my $str = 'key="plain"; key="=?UTF-8?B?0LzQvtC5X9GE0LDQudC7LmJpbg==?="';
+ is(
+ RT::I18N::DecodeMIMEWordsToUTF8($str),
+ 'key="plain"; key="׀¼׀¾׀¹_ׁ„׀°׀¹׀».bin"',
+ "right decoding"
+ );
+}
+
+diag q{not compliant with standards, but MUAs send such field when attachment has non-ascii in name}
+ if $ENV{TEST_VERBOSE};
+{
+ my $str = 'attachment; filename="=?UTF-8?B?0LzQvtC5X9GE0LDQudC7LmJpbg==?="';
+ is(
+ RT::I18N::DecodeMIMEWordsToUTF8($str),
+ 'attachment; filename="׀¼׀¾׀¹_ׁ„׀°׀¹׀».bin"',
+ "right decoding"
+ );
+}
+
+diag q{'=' char in a trailing part after an encoded part} if $ENV{TEST_VERBOSE};
+{
+ my $str = 'attachment; filename="=?UTF-8?B?0LzQvtC5X9GE0LDQudC7LmJpbg==?="; some_prop="value"';
+ is(
+ RT::I18N::DecodeMIMEWordsToUTF8($str),
+ 'attachment; filename="׀¼׀¾׀¹_ׁ„׀°׀¹׀».bin"; some_prop="value"',
+ "right decoding"
+ );
+}
+
+diag q{regression test for #5248 from rt3.fsck.com} if $ENV{TEST_VERBOSE};
+{
+ 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?=};
+ is(
+ RT::I18N::DecodeMIMEWordsToUTF8($str),
+ qq{Subject: Re: [XXXXXX#269] [Comment] Frage zu XXXXXX--xxxxxx / Xxxxxֳ¼xxxxxxxxxx},
+ "right decoding"
+ );
+}
+
diff --git a/rt/lib/t/regression/06mailgateway.t b/rt/lib/t/regression/06mailgateway.t
index 1bdc38a..5fc5029 100644
--- a/rt/lib/t/regression/06mailgateway.t
+++ b/rt/lib/t/regression/06mailgateway.t
@@ -52,13 +52,20 @@ rt-mailgate - Mail interface to RT3.
=cut
use strict;
-use Test::More tests => 57;
+use Test::More tests => 109;
+
use RT;
RT::LoadConfig();
RT::Init();
use RT::I18N;
+use Digest::MD5 qw(md5_base64);
+
+no warnings 'once';
+my $url = join( ':', grep $_, "http://localhost", $RT::WebPort ) . $RT::WebPath ."/";
+
# Make sure that when we call the mailgate wrong, it tempfails
+$! = 0;
ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url http://this.test.for.non-connection.is.expected.to.generate.an.error"), "Opened the mailgate - The error below is expected - $@");
print MAIL <<EOF;
From: root\@localhost
@@ -75,7 +82,8 @@ is ( $? >> 8, 75, "The error message above is expected The mail gateway exited w
# {{{ Test new ticket creation by root who is privileged and superuser
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $RT::WebURL --queue general --action correspond"), "Opened the mailgate - $@");
+$! = 0;
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --debug --url $url --queue general --action correspond"), "Opened the mailgate - $!");
print MAIL <<EOF;
From: root\@localhost
To: rt\@$RT::rtname
@@ -100,10 +108,37 @@ ok ($tick->Subject eq 'This is a test of new ticket creation', "Created the tick
# }}}
+# {{{ Test new ticket creation without --action argument
+
+$! = 0;
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --debug --url $url --queue general"), "Opened the mailgate - $!");
+print MAIL <<EOF;
+From: root\@localhost
+To: rt\@$RT::rtname
+Subject: using mailgate without --action arg
+
+Blah!
+Foob!
+EOF
+close (MAIL);
+
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
+
+$tickets = RT::Tickets->new($RT::SystemUser);
+$tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
+$tickets->Limit(FIELD => 'id', OPERATOR => '>', VALUE => '0');
+$tick = $tickets->First;
+isa_ok ($tick,'RT::Ticket');
+ok ($tick->Id, "found ticket ".$tick->Id);
+is ($tick->Subject, 'using mailgate without --action arg', "using mailgate without --action arg");
+
+# }}}
# {{{This is a test of new ticket creation as an unknown user
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $RT::WebURL --queue general --action correspond"), "Opened the mailgate - $@");
+$! = 0;
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $!");
print MAIL <<EOF;
From: doesnotexist\@$RT::rtname
To: rt\@$RT::rtname
@@ -124,7 +159,7 @@ ok ($tick->Id, "found ticket ".$tick->Id);
ok ($tick->Subject ne '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);
$u->Load("doesnotexist\@$RT::rtname");
-ok( $u->Id == 0, " user does not exist and was not created by failed ticket submission");
+ok( !$u->Id, " user does not exist and was not created by failed ticket submission");
# }}}
@@ -139,7 +174,8 @@ my ($val,$msg) = $g->PrincipalObj->GrantRight(Right => 'CreateTicket');
ok ($val, "Granted everybody the right to create tickets - $msg");
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $RT::WebURL --queue general --action correspond"), "Opened the mailgate - $@");
+$! = 0;
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $!");
print MAIL <<EOF;
From: doesnotexist\@$RT::rtname
To: rt\@$RT::rtname
@@ -172,7 +208,8 @@ ok( $u->Id != 0, " user does not exist and was created by ticket submission");
#($val,$msg) = $g->PrincipalObj->GrantRight(Right => 'CreateTicket');
#ok ($val, "Granted everybody the right to create tickets - $msg");
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $RT::WebURL --queue general --action correspond"), "Opened the mailgate - $@");
+$! = 0;
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $!");
print MAIL <<EOF;
From: doesnotexist-2\@$RT::rtname
To: rt\@$RT::rtname
@@ -187,7 +224,7 @@ is ($? >> 8, 0, "The mail gateway exited normally. yay");
$u = RT::User->new($RT::SystemUser);
$u->Load('doesnotexist-2@$RT::rtname');
-ok( $u->Id == 0, " user does not exist and was not created by ticket correspondence submission");
+ok( !$u->Id, " user does not exist and was not created by ticket correspondence submission");
# }}}
@@ -197,7 +234,8 @@ ok( $u->Id == 0, " user does not exist and was not created by ticket corresponde
($val,$msg) = $g->PrincipalObj->GrantRight(Right => 'ReplyToTicket');
ok ($val, "Granted everybody the right to reply to tickets - $msg");
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $RT::WebURL --queue general --action correspond"), "Opened the mailgate - $@");
+$! = 0;
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $!");
print MAIL <<EOF;
From: doesnotexist-2\@$RT::rtname
To: rt\@$RT::rtname
@@ -223,7 +261,8 @@ ok( $u->Id != 0, " user exists and was created by ticket correspondence submissi
#($val,$msg) = $g->PrincipalObj->GrantRight(Right => 'CreateTicket');
#ok ($val, "Granted everybody the right to create tickets - $msg");
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $RT::WebURL --queue general --action comment"), "Opened the mailgate - $@");
+$! = 0;
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action comment"), "Opened the mailgate - $!");
print MAIL <<EOF;
From: doesnotexist-3\@$RT::rtname
To: rt\@$RT::rtname
@@ -239,7 +278,7 @@ is ($? >> 8, 0, "The mail gateway exited normally. yay");
$u = RT::User->new($RT::SystemUser);
$u->Load("doesnotexist-3\@$RT::rtname");
-ok( $u->Id == 0, " user does not exist and was not created by ticket comment submission");
+ok( !$u->Id, " user does not exist and was not created by ticket comment submission");
# }}}
# {{{ can another random reply to a ticket after being granted privs? answer should be yes
@@ -248,7 +287,8 @@ ok( $u->Id == 0, " user does not exist and was not created by ticket comment sub
($val,$msg) = $g->PrincipalObj->GrantRight(Right => 'CommentOnTicket');
ok ($val, "Granted everybody the right to reply to tickets - $msg");
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $RT::WebURL --queue general --action comment"), "Opened the mailgate - $@");
+$! = 0;
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action comment"), "Opened the mailgate - $!");
print MAIL <<EOF;
From: doesnotexist-3\@$RT::rtname
To: rt\@$RT::rtname
@@ -289,7 +329,8 @@ $entity->attach(Path => $LOGO_FILE,
Encoding => 'base64');
# Create a ticket with a binary attachment
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $RT::WebURL --queue general --action correspond"), "Opened the mailgate - $@");
+$! = 0;
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $!");
$entity->print(\*MAIL);
@@ -310,8 +351,7 @@ my $file = `cat $LOGO_FILE`;
ok ($file, "Read in the logo image");
- use Digest::MD5;
-warn "for the raw file the content is ".Digest::MD5::md5_base64($file);
+diag( "for the raw file the content is ". md5_base64($file) );
@@ -323,7 +363,7 @@ my $attachment = $attachments->First;
ok($attachment->Id);
my $acontent = $attachment->Content;
- warn "coming from the database, the content is ".Digest::MD5::md5_base64($acontent);
+diag( "coming from the database, the content is ". md5_base64($acontent) );
is( $acontent, $file, 'The attachment isn\'t screwed up in the database.');
# Log in as root
@@ -334,7 +374,7 @@ use LWP::UserAgent;
# Grab the binary attachment via the web ui
my $ua = LWP::UserAgent->new();
-my $full_url = "$RT::WebURL/Ticket/Attachment/".$attachment->TransactionId."/".$attachment->id."/bplogo.gif?&user=root&pass=password";
+my $full_url = "$url/Ticket/Attachment/".$attachment->TransactionId."/".$attachment->id."/bplogo.gif?&user=root&pass=password";
my $r = $ua->get( $full_url);
@@ -347,7 +387,8 @@ is($file, $r->content, 'The attachment isn\'t screwed up in download');
# {{{ Simple I18N testing
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $RT::WebURL --queue general --action correspond"), "Opened the mailgate - $@");
+$! = 0;
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $!");
print MAIL <<EOF;
From: root\@localhost
@@ -381,7 +422,8 @@ is ($unitick->Transactions->First->Content, $unitick->Transactions->First->Attac
ok($unitick->Transactions->First->Attachments->First->Content =~ /$unistring/i, $unitick->Id." appears to be unicode ". $unitick->Transactions->First->Attachments->First->Id);
# supposedly I18N fails on the second message sent in.
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $RT::WebURL --queue general --action correspond"), "Opened the mailgate - $@");
+$! = 0;
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue general --action correspond"), "Opened the mailgate - $!");
print MAIL <<EOF;
From: root\@localhost
@@ -420,20 +462,28 @@ ok ($tick2->Transactions->First->Content =~ $unistring, "It appears to be unicod
($val,$msg) = $g->PrincipalObj->RevokeRight(Right => 'CreateTicket');
ok ($val, $msg);
-=for later
+##=for later
-TODO: {
+SKIP: {
+skip "Advanced mailgate actions require an unsafe configuration", 47 unless $RT::UnsafeEmailCommands;
+
+#create new queue to be shure we don't mess with rights
+use RT::Queue;
+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;
$tick = RT::Ticket->new($RT::SystemUser);
-my ($id) = $tick->Create( Queue => 'general', Subject => 'test');
+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' );
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $RT::WebURL --queue general --action take"), "Opened the mailgate - $@");
+$! = 0;
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue ext-mailgate --action take"), "Opened the mailgate - $!");
print MAIL <<EOF;
From: root\@localhost
Subject: [$RT::rtname \#$id] test
@@ -450,15 +500,15 @@ is( $tick->OwnerObj->EmailAddress, 'root@localhost', 'successfuly take ticket vi
# check that there is no text transactions writen
is( $tick->Transactions->Count, 2, 'no superfluous transactions');
-my $status = '';
+my $status;
($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');
- local $TODO = "Advanced mailgate actions require an unsafe configuration";
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $RT::WebURL --queue general --action take-correspond"), "Opened the mailgate - $@");
+$! = 0;
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $RT::WebURL --queue ext-mailgate --action take-correspond"), "Opened the mailgate - $@");
print MAIL <<EOF;
From: root\@localhost
Subject: [$RT::rtname \#$id] correspondence
@@ -468,17 +518,21 @@ EOF
close (MAIL);
is ($? >> 8, 0, "The mail gateway exited normally");
+DBIx::SearchBuilder::Record::Cachable->FlushCache;
+
$tick = RT::Ticket->new($RT::SystemUser);
$tick->Load( $id );
-is( $tick->Id, $id, 'load correct ticket');
+is( $tick->Id, $id, "load correct ticket #$id");
is( $tick->OwnerObj->EmailAddress, 'root@localhost', 'successfuly take ticket via email');
my $txns = $tick->Transactions;
$txns->Limit( FIELD => 'Type', VALUE => 'Correspond');
-is( $txns->Last->Subject, "[$RT::rtname \#$id] correspondence", 'successfuly add correspond within take via email' );
+$txns->OrderBy( FIELD => 'id', ORDER => 'DESC' );
# +1 because of auto open
is( $tick->Transactions->Count, 6, 'no superfluous transactions');
+is( $txns->First->Subject, "[$RT::rtname \#$id] correspondence", 'successfuly add correspond within take via email' );
-ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $RT::WebURL --queue general --action resolve"), "Opened the mailgate - $@");
+$! = 0;
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue ext-mailgate --action resolve --debug"), "Opened the mailgate - $!");
print MAIL <<EOF;
From: root\@localhost
Subject: [$RT::rtname \#$id] test
@@ -495,10 +549,115 @@ 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 ($uid) = $user->Create( Name => 'ext-mailgate',
+ EmailAddress => 'ext-mailgate@localhost',
+ Privileged => 1,
+ Password => 'qwe123',
+ );
+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);
+($id) = $tick->Create( Queue => $qid, Subject => 'test' );
+ok( $id, 'create new ticket' );
+
+$! = 0;
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue ext-mailgate --action take"), "Opened the mailgate - $!");
+print MAIL <<EOF;
+From: ext-mailgate\@localhost
+Subject: [example.com \#$id] test
+
+EOF
+close (MAIL);
+is ( $? >> 8, 0, "mailgate exited normally" );
+DBIx::SearchBuilder::Record::Cachable->FlushCache;
+
+cmp_ok( $tick->Owner, '!=', $user->id, "we didn't change owner" );
+
+($status, $msg) = $user->PrincipalObj->GrantRight( Object => $queue, Right => 'ReplyToTicket' );
+ok( $status, "successfuly granted right: $msg" );
+my $ace_id = $status;
+ok( $user->HasRight( Right => 'ReplyToTicket', Object => $tick ), "User can reply to ticket" );
+
+$! = 0;
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue ext-mailgate --action correspond-take"), "Opened the mailgate - $!");
+print MAIL <<EOF;
+From: ext-mailgate\@localhost
+Subject: [example.com \#$id] test
+
+correspond-take
+EOF
+close (MAIL);
+is ( $? >> 8, 0, "mailgate exited normally" );
+DBIx::SearchBuilder::Record::Cachable->FlushCache;
+
+cmp_ok( $tick->Owner, '!=', $user->id, "we didn't change owner" );
+is( $tick->Transactions->Count, 3, "one transactions added" );
+
+$! = 0;
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue ext-mailgate --action take-correspond"), "Opened the mailgate - $!");
+print MAIL <<EOF;
+From: ext-mailgate\@localhost
+Subject: [example.com \#$id] test
+
+correspond-take
+EOF
+close (MAIL);
+is ( $? >> 8, 0, "mailgate exited normally" );
+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" );
+
+# revoke ReplyToTicket right
+use RT::ACE;
+my $ace = RT::ACE->new($RT::SystemUser);
+$ace->Load( $ace_id );
+$ace->Delete;
+my $acl = RT::ACL->new($RT::SystemUser);
+$acl->Limit( FIELD => 'RightName', VALUE => 'ReplyToTicket' );
+$acl->LimitToObject( $RT::System );
+while( my $ace = $acl->Next ) {
+ $ace->Delete;
+}
+
+ok( !$user->HasRight( Right => 'ReplyToTicket', Object => $tick ), "User can't reply to ticket any more" );
+
+
+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_id, $msg) = $group->PrincipalObj->GrantRight( Right => 'ReplyToTicket', Object => $queue );
+ok( $ace_id, "Granted queue owners role group with ReplyToTicket right" );
+
+($status, $msg) = $user->PrincipalObj->GrantRight( Object => $queue, Right => 'OwnTicket' );
+ok( $status, "successfuly granted right: $msg" );
+($status, $msg) = $user->PrincipalObj->GrantRight( Object => $queue, Right => 'TakeTicket' );
+ok( $status, "successfuly granted right: $msg" );
+
+$! = 0;
+ok(open(MAIL, "|$RT::BinPath/rt-mailgate --url $url --queue ext-mailgate --action take-correspond"), "Opened the mailgate - $!");
+print MAIL <<EOF;
+From: ext-mailgate\@localhost
+Subject: [example.com \#$id] test
+
+take-correspond with reply right granted to owner role
+EOF
+close (MAIL);
+is ( $? >> 8, 0, "mailgate exited normally" );
+DBIx::SearchBuilder::Record::Cachable->FlushCache;
+
+$tick->Load( $id );
+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" );
-=cut
# }}}
+};
+
1;
+
diff --git a/rt/lib/t/regression/07acl.t b/rt/lib/t/regression/07acl.t
index e30a59b..efd8701 100644
--- a/rt/lib/t/regression/07acl.t
+++ b/rt/lib/t/regression/07acl.t
@@ -1,9 +1,9 @@
#!/usr/bin/perl -w
-
+use strict;
use WWW::Mechanize;
use HTTP::Cookies;
-use Test::More qw/no_plan/;
+use Test::More tests => 34;
use RT;
RT::LoadConfig();
RT::Init();
@@ -20,6 +20,7 @@ ok($ret, "ACL test password set. $msg");
# Now test the web interface, making sure objects come and go as
# required.
+
my $cookie_jar = HTTP::Cookies->new;
my $agent = WWW::Mechanize->new();
@@ -27,62 +28,53 @@ my $agent = WWW::Mechanize->new();
$agent->cookie_jar($cookie_jar);
-
+no warnings 'once';
# get the top page
-my $url = $RT::WebURL;
-$agent->get($url);
-
-is ($agent->{'status'}, 200, "Loaded a page - $RT::WebURL");
-# {{{ test a login
-
-# follow the link marked "Login"
-
-ok($agent->{form}->find_input('user'));
-
-ok($agent->{form}->find_input('pass'));
-ok ($agent->{'content'} =~ /username:/i);
-$agent->field( 'user' => 'customer-'.$$ );
-$agent->field( 'pass' => 'customer' );
-# the field isn't named, so we have to click link 0
-$agent->click(0);
-is($agent->{'status'}, 200, "Fetched the page ok");
-ok($agent->{'content'} =~ /Logout/i, "Found a logout link");
+login($agent, $user_obj);
# Test for absence of Configure and Preferences tabs.
-ok(!$agent->find_link( url => "$RT::WebPath/Admin/",
+ok(!$agent->find_link( url => $RT::WebPath . "/Admin/",
text => 'Configuration'), "No config tab" );
-ok(!$agent->find_link( url => "$RT::WebPath/User/Prefs.html",
+ok(!$agent->find_link( url => $RT::WebPath . "/User/Prefs.html",
text => 'Preferences'), "No prefs pane" );
# Now test for their presence, one at a time. Sleep for a bit after
# ACL changes, thanks to the 10s ACL cache.
-$user_obj->PrincipalObj->GrantRight(Right => 'ShowConfigTab');
-$agent->reload();
+my ($grantid,$grantmsg) =$user_obj->PrincipalObj->GrantRight(Right => 'ShowConfigTab', Object => $RT::System);
+
+ok($grantid,$grantmsg);
+
+$agent->reload;
+
ok($agent->{'content'} =~ /Logout/i, "Reloaded page successfully");
-ok($agent->find_link( url => "$RT::WebPath/Admin/",
+ok($agent->find_link( url => $RT::WebPath . "/Admin/",
text => 'Configuration'), "Found config tab" );
-$user_obj->PrincipalObj->RevokeRight(Right => 'ShowConfigTab');
-$user_obj->PrincipalObj->GrantRight(Right => 'ModifySelf');
+my ($revokeid,$revokemsg) =$user_obj->PrincipalObj->RevokeRight(Right => 'ShowConfigTab');
+ok ($revokeid,$revokemsg);
+($grantid,$grantmsg) =$user_obj->PrincipalObj->GrantRight(Right => 'ModifySelf');
+ok ($grantid,$grantmsg);
$agent->reload();
ok($agent->{'content'} =~ /Logout/i, "Reloaded page successfully");
-ok($agent->find_link( url => "$RT::WebPath/User/Prefs.html",
+ok($agent->find_link( url => $RT::WebPath . "/User/Prefs.html",
text => 'Preferences'), "Found prefs pane" );
-$user_obj->PrincipalObj->RevokeRight(Right => 'ModifySelf');
-
+($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",
+$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");
-$user_obj->PrincipalObj->GrantRight(Right => 'LoadSavedSearch');
+($grantid,$grantmsg) = $user_obj->PrincipalObj->GrantRight(Right => 'LoadSavedSearch');
+ok($grantid,$grantmsg);
$agent->reload();
ok($agent->{'content'} =~ /Load saved search/i, "Search loading box exists");
ok($agent->{'content'} !~ /input\s+type=.submit.\s+name=.Save./i,
"Still no saved searches box");
-$user_obj->PrincipalObj->GrantRight(Right => 'CreateSavedSearch');
+($grantid,$grantmsg) =$user_obj->PrincipalObj->GrantRight(Right => 'CreateSavedSearch');
+ok ($grantid,$grantmsg);
$agent->reload();
ok($agent->{'content'} =~ /Load saved search/i,
"Search loading box still exists");
@@ -93,22 +85,24 @@ ok($agent->{'content'} =~ /input\s+type=.submit.\s+name=.Save./i,
# via SelectOwner.
my $queue_obj = RT::Queue->new($RT::SystemUser);
-($ret, $msg) = $queue_obj->Create(Name => 'CustomerQueue',
+($ret, $msg) = $queue_obj->Create(Name => 'CustomerQueue-'.$$,
Description => 'queue for SelectOwner testing');
ok($ret, "SelectOwner test queue creation. $msg");
my $group_obj = RT::Group->new($RT::SystemUser);
-($ret, $msg) = $group_obj->CreateUserDefinedGroup(Name => 'CustomerGroup',
+($ret, $msg) = $group_obj->CreateUserDefinedGroup(Name => 'CustomerGroup-'.$$,
Description => 'group for SelectOwner testing');
ok($ret, "SelectOwner test group creation. $msg");
# Add our customer to the customer group, and give it queue rights.
($ret, $msg) = $group_obj->AddMember($user_obj->PrincipalObj->Id());
ok($ret, "Added customer to its group. $msg");
-$group_obj->PrincipalObj->GrantRight(Right => 'OwnTicket',
+($grantid,$grantmsg) =$group_obj->PrincipalObj->GrantRight(Right => 'OwnTicket',
Object => $queue_obj);
-$group_obj->PrincipalObj->GrantRight(Right => 'SeeQueue',
+
+ok($grantid,$grantmsg);
+($grantid,$grantmsg) =$group_obj->PrincipalObj->GrantRight(Right => 'SeeQueue',
Object => $queue_obj);
-
+ok ($grantid,$grantmsg);
# Now. When we look at the search page we should be able to see
# ourself in the list of possible owners.
@@ -117,4 +111,28 @@ ok($agent->form_name('BuildQuery'), "Yep, form is still there");
my $input = $agent->current_form->find_input('ValueOfActor');
ok(grep(/customer-$$/, $input->value_names()), "Found self in the actor listing");
+sub login {
+ my $agent = shift;
+
+ my $url = $RT::WebURL;
+ $agent->get($url);
+ is( $agent->{'status'}, 200,
+ "Loaded a page - $url" );
+
+ # {{{ test a login
+
+ # follow the link marked "Login"
+
+ ok( $agent->{form}->find_input('user') );
+
+ ok( $agent->{form}->find_input('pass') );
+ ok( $agent->{'content'} =~ /username:/i );
+ $agent->field( 'user' => $user_obj->Name );
+ $agent->field( 'pass' => 'customer' );
+
+ # the field isn't named, so we have to click link 0
+ $agent->click(0);
+ is( $agent->{'status'}, 200, "Fetched the page ok" );
+ ok( $agent->{'content'} =~ /Logout/i, "Found a logout link" );
+}
1;
diff --git a/rt/lib/t/regression/07rights.t b/rt/lib/t/regression/07rights.t
index d346277..6c35a07 100644
--- a/rt/lib/t/regression/07rights.t
+++ b/rt/lib/t/regression/07rights.t
@@ -112,7 +112,7 @@ ok( $user->HasRight( Right => 'ReplyToTicket', Object => $ticket ), "user is own
$group = RT::Group->new( $RT::SystemUser );
ok( $group->LoadQueueRoleGroup( Queue => $queue_id, Type=> 'AdminCc' ), "load queue AdminCc role group" );
$ace = RT::ACE->new( $RT::SystemUser );
-my ($ace_id, $msg) = $group->PrincipalObj->GrantRight( Right => 'ModifyTicket', Object => $queue );
+($ace_id, $msg) = $group->PrincipalObj->GrantRight( Right => 'ModifyTicket', Object => $queue );
ok( $ace_id, "Granted queue AdminCc role group with ModifyTicket right: $msg" );
ok( $group->PrincipalObj->HasRight( Right => 'ModifyTicket', Object => $queue ), "role group can modify ticket" );
ok( !$user->HasRight( Right => 'ModifyTicket', Object => $ticket ), "user is not AdminCc and can't modify ticket" );
diff --git a/rt/lib/t/regression/08web_cf_access.t b/rt/lib/t/regression/08web_cf_access.t
index 012d733..c352bbc 100644
--- a/rt/lib/t/regression/08web_cf_access.t
+++ b/rt/lib/t/regression/08web_cf_access.t
@@ -2,13 +2,14 @@
use strict;
use Test::More tests => 15;
-use RT;
-RT::LoadConfig;
-RT::Init;
+BEGIN {
+ use RT;
+ RT::LoadConfig;
+ RT::Init;
+}
use Test::WWW::Mechanize;
-$RT::WebURL ||= 0; # avoid stupid warning
-my $BaseURL = $RT::WebURL;
+use constant BaseURL => $RT::WebURL;
use constant ImageFile => $RT::MasonComponentRoot .'/NoAuth/images/bplogo.gif';
use constant ImageFileContent => do {
local $/;
@@ -20,7 +21,7 @@ use constant ImageFileContent => do {
my $m = Test::WWW::Mechanize->new;
isa_ok($m, 'Test::WWW::Mechanize');
-$m->get( $BaseURL."?user=root;pass=password" );
+$m->get( BaseURL."?user=root;pass=password" );
$m->content_like(qr/Logout/, 'we did log in');
$m->follow_link( text => 'Configuration' );
$m->title_is(q/RT Administration/, 'admin screen');
@@ -85,7 +86,7 @@ $m->title_like(qr/testing img cf creation/, "its title is the Subject");
$m->follow_link( text => 'bplogo.gif' );
$m->content_is(ImageFileContent, "it links to the uploaded image");
-$m->get( $BaseURL );
+$m->get( BaseURL );
$m->follow_link( text => 'Tickets' );
$m->follow_link( text => 'New Query' );
diff --git a/rt/lib/t/regression/12-search.t b/rt/lib/t/regression/12-search.t
index 9cc4aa4..210d4fe 100644
--- a/rt/lib/t/regression/12-search.t
+++ b/rt/lib/t/regression/12-search.t
@@ -6,7 +6,7 @@
use strict;
use warnings;
-use Test::More tests => 35;
+use Test::More tests => 44;
use_ok('RT');
RT::LoadConfig();
RT::Init();
@@ -38,6 +38,24 @@ ok($cf3->id, "Created the SearchTest3 CF");
my $cflabel3 = "CustomField-".$cf3->id;
+# There was a bug involving a missing join to ObjectCustomFields that
+# caused spurious results on negative searches if another custom field
+# with the same name existed on a different queue. Hence, we make
+# duplicate CFs on a different queue here
+my $dup = RT::Queue->new($RT::SystemUser);
+$dup->Create(Name => $queue . "-Copy");
+ok ($dup->id, "Created the duplicate queue");
+my $dupcf = RT::CustomField->new($RT::SystemUser);
+$dupcf->Create(Name => 'SearchTest', Type => 'Freeform', MaxValues => 0, Queue => $dup->id);
+ok($dupcf->id, "Created the duplicate SearchTest CF");
+$dupcf = RT::CustomField->new($RT::SystemUser);
+$dupcf->Create(Name => 'SearchTest2', Type => 'Freeform', MaxValues => 0, Queue => $dup->id);
+ok($dupcf->id, "Created the SearchTest2 CF");
+$dupcf = RT::CustomField->new($RT::SystemUser);
+$dupcf->Create(Name => 'SearchTest3', Type => 'Freeform', MaxValues => 0, Queue => $dup->id);
+ok($dupcf->id, "Created the SearchTest3 CF");
+
+
# setup some tickets
# we'll need a small pile of them, to test various combinations and nulls.
# there's probably a way to think harder and do this with fewer
@@ -148,8 +166,7 @@ is($tix->Count, 5, "matched LIKE subject");
$tix = RT::Tickets->new($RT::SystemUser);
$tix->FromSQL("Queue = '$queue' AND CF.SearchTest IS NULL");
-
- is($tix->Count, 2, "IS null CF");
+is($tix->Count, 2, "IS null CF");
$tix = RT::Tickets->new($RT::SystemUser);
$tix->FromSQL("Queue = '$queue' AND Requestors LIKE 'search1'");
@@ -163,14 +180,9 @@ $tix = RT::Tickets->new($RT::SystemUser);
$tix->FromSQL("Queue = '$queue' AND Requestors LIKE 'search'");
is($tix->Count, 6, "LIKE requestor");
-TODO: {
-
- local $TODO = "Can't search for 'no requestor";
- $tix = RT::Tickets->new($RT::SystemUser);
- $tix->FromSQL("Queue = '$queue' AND Requestors IS NULL");
- is($tix->Count, 1, "Search for no requestor");
-
-};
+$tix = RT::Tickets->new($RT::SystemUser);
+$tix->FromSQL("Queue = '$queue' AND Requestors IS NULL");
+is($tix->Count, 1, "Search for no requestor");
$tix = RT::Tickets->new($RT::SystemUser);
$tix->FromSQL("Queue = '$queue' AND Subject = 'SearchTest1'");
@@ -223,13 +235,32 @@ is($tix->Count, 4, "like cf and like subject");
$tix = RT::Tickets->new($RT::SystemUser);
$tix->FromSQL("CF.SearchTest IS NULL AND CF.SearchTest2 = 'bar2'");
-
- is($tix->Count, 1, "null cf and is cf");
+is($tix->Count, 1, "null cf and is cf");
$tix = RT::Tickets->new($RT::SystemUser);
$tix->FromSQL("Queue = '$queue' AND CF.SearchTest IS NULL AND CF.SearchTest2 IS NULL");
+is($tix->Count, 1, "null cf and null cf");
- is($tix->Count, 1, "null cf and null cf");
+# tests with the same CF listed twice
+$tix = RT::Tickets->new($RT::SystemUser);
+$tix->FromSQL("CF.{SearchTest} = 'foo1'");
+is($tix->Count, 1, "is cf.{name} format");
+
+$tix = RT::Tickets->new($RT::SystemUser);
+$tix->FromSQL("CF.SearchTest = 'foo1' OR CF.SearchTest = 'foo3'");
+is($tix->Count, 2, "is cf1 or is cf1");
+
+$tix = RT::Tickets->new($RT::SystemUser);
+$tix->FromSQL("CF.SearchTest = 'foo1' OR CF.SearchTest IS NULL");
+is($tix->Count, 3, "is cf1 or null cf1");
+
+$tix = RT::Tickets->new($RT::SystemUser);
+$tix->FromSQL("(CF.SearchTest = 'foo1' OR CF.SearchTest = 'foo3') AND (CF.SearchTest2 = 'bar1' OR CF.SearchTest2 = 'bar2')");
+is($tix->Count, 1, "(is cf1 or is cf1) and (is cf2 or is cf2)");
+
+$tix = RT::Tickets->new($RT::SystemUser);
+$tix->FromSQL("CF.SearchTest = 'foo1' OR CF.SearchTest = 'foo3' OR CF.SearchTest2 = 'bar1' OR CF.SearchTest2 = 'bar2'");
+is($tix->Count, 3, "is cf1 or is cf1 or is cf2 or is cf2");
diff --git a/rt/lib/t/regression/13-attribute-tests.t b/rt/lib/t/regression/13-attribute-tests.t
index 945bbcf..fdac94e 100644
--- a/rt/lib/t/regression/13-attribute-tests.t
+++ b/rt/lib/t/regression/13-attribute-tests.t
@@ -1,5 +1,6 @@
-
-use Test::More tests => 24;
+use strict;
+use warnings;
+use Test::More tests => 34;
use RT;
RT::LoadConfig();
RT::Init();
@@ -19,6 +20,8 @@ ok($user->id, "Created a test user");
ok(1, $user->Attributes->BuildSelectQuery);
my $attr = $user->Attributes;
+# XXX: Order by id as some tests depend on it
+$attr->OrderByCols({ FIELD => 'id' });
ok(1, $attr->BuildSelectQuery);
@@ -28,6 +31,12 @@ ok (UNIVERSAL::isa($attr,'RT::Attributes'), 'got the attributes object');
($id, $msg) = $user->AddAttribute(Name => 'TestAttr', Content => 'The attribute has content');
ok ($id, $msg);
is ($attr->Count,1, " One attr after adidng a first one");
+
+my $first_attr = $user->FirstAttribute('TestAttr');
+ok($first_attr, "got some sort of attribute");
+isa_ok($first_attr, 'RT::Attribute');
+is($first_attr->Content, 'The attribute has content', "got the right content back");
+
($id, $msg) = $attr->DeleteEntry(Name => $runid);
ok(!$id, "Deleted non-existant entry - $msg");
is ($attr->Count,1, "1 attr after deleting an empty attr");
@@ -37,11 +46,22 @@ is ("@names", "TestAttr");
($id, $msg) = $user->AddAttribute(Name => $runid, Content => "First");
+ok($id, $msg);
+
+my $runid_attr = $user->FirstAttribute($runid);
+ok($runid_attr, "got some sort of attribute");
+isa_ok($runid_attr, 'RT::Attribute');
+is($runid_attr->Content, 'First', "got the right content back");
is ($attr->Count,2, " Two attrs after adding an attribute named $runid");
($id, $msg) = $user->AddAttribute(Name => $runid, Content => "Second");
ok($id, $msg);
+$runid_attr = $user->FirstAttribute($runid);
+ok($runid_attr, "got some sort of attribute");
+isa_ok($runid_attr, 'RT::Attribute');
+is($runid_attr->Content, 'First', "got the first content back still");
+
is ($attr->Count,3, " Three attrs after adding a secondvalue to $runid");
($id, $msg) = $attr->DeleteEntry(Name => $runid, Content => "First");
ok($id, $msg);
diff --git a/rt/lib/t/regression/14linking.t b/rt/lib/t/regression/14linking.t
index 6fdf614..c8e57ea 100644
--- a/rt/lib/t/regression/14linking.t
+++ b/rt/lib/t/regression/14linking.t
@@ -1,4 +1,4 @@
-use Test::More tests => '39';
+use Test::More tests => '70';
use_ok('RT');
use_ok('RT::Ticket');
use_ok('RT::ScripConditions');
@@ -12,7 +12,9 @@ RT::Init();
use File::Temp qw/tempfile/;
my ($fh, $filename) = tempfile( UNLINK => 1, SUFFIX => '.rt');
my $link_scrips_orig = $RT::LinkTransactionsRun1Scrip;
+my $link_acl_chacks_orig = $RT::StrictLinkACL;
$RT::LinkTransactionsRun1Scrip = 1;
+$RT::StrictLinkACL = 1;
my $condition = RT::ScripCondition->new( $RT::SystemUser );
$condition->Load('User Defined');
@@ -68,32 +70,123 @@ my $scrip = RT::Scrip->new($RT::SystemUser);
ok($id, "Scrip created");
my $u1 = RT::User->new($RT::SystemUser);
-($id,$msg) =$u1->Create(Name => "LinkTestUser.$$");
-
+($id,$msg) = $u1->Create(Name => "LinkTestUser.$$");
ok ($id,$msg);
+my $creator = RT::CurrentUser->new($u1->id);
+
($id,$msg) = $u1->PrincipalObj->GrantRight ( Object => $q1, Right => 'CreateTicket');
ok ($id,$msg);
+
+diag('Create tickets without rights to link') if $ENV{'TEST_VERBOSE'};
+{
+ # on q2 we have no rights, yet
+ my $parent = RT::Ticket->new( $RT::SystemUser );
+ ($id,$tid,$msg) = $parent->Create( Subject => 'Link test 1', Queue => $q2->id );
+ ok($id,$msg);
+ my $child = RT::Ticket->new( $creator );
+ ($id,$tid,$msg) = $child->Create( Subject => 'Link test 1', Queue => $q1->id, MemberOf => $parent->id );
+ ok($id,$msg);
+ $child->CurrentUser( $RT::SystemUser );
+ is($child->_Links('Base')->Count, 0, 'link was not created, no permissions');
+ is($child->_Links('Target')->Count, 0, 'link was not create, no permissions');
+}
+
+diag('Create tickets with rights checks on one end of a link') if $ENV{'TEST_VERBOSE'};
+{
+ # on q2 we have no rights, but use checking one only on thing
+ local $RT::StrictLinkACL = 0;
+ my $parent = RT::Ticket->new( $RT::SystemUser );
+ ($id,$tid,$msg) = $parent->Create( Subject => 'Link test 1', Queue => $q2->id );
+ ok($id,$msg);
+ my $child = RT::Ticket->new( $creator );
+ ($id,$tid,$msg) = $child->Create( Subject => 'Link test 1', Queue => $q1->id, MemberOf => $parent->id );
+ ok($id,$msg);
+ $child->CurrentUser( $RT::SystemUser );
+ is($child->_Links('Base')->Count, 1, 'link was created');
+ is($child->_Links('Target')->Count, 0, 'link was created only one');
+ # no scrip run on second ticket accroding to config option
+ is(link_count($filename), 0, "scrips ok");
+}
+
($id,$msg) = $u1->PrincipalObj->GrantRight ( Object => $q1, Right => 'ModifyTicket');
ok ($id,$msg);
-my $tid;
+diag('try to add link without rights') if $ENV{'TEST_VERBOSE'};
+{
+ # on q2 we have no rights, yet
+ my $parent = RT::Ticket->new( $RT::SystemUser );
+ ($id,$tid,$msg) = $parent->Create( Subject => 'Link test 1', Queue => $q2->id );
+ ok($id,$msg);
+ my $child = RT::Ticket->new( $creator );
+ ($id,$tid,$msg) = $child->Create( Subject => 'Link test 1', Queue => $q1->id );
+ ok($id,$msg);
+ my ($id, $msg) = $child->AddLink(Type => 'MemberOf', Target => $parent->id);
+ ok(!$id, $msg);
+ is(link_count($filename), 0, "scrips ok");
+ $child->CurrentUser( $RT::SystemUser );
+ is($child->_Links('Base')->Count, 0, 'link was not created, no permissions');
+ is($child->_Links('Target')->Count, 0, 'link was not create, no permissions');
+}
-my $creator = RT::CurrentUser->new($u1->id);
+diag('add link with rights only on base') if $ENV{'TEST_VERBOSE'};
+{
+ # on q2 we have no rights, but use checking one only on thing
+ local $RT::StrictLinkACL = 0;
+ my $parent = RT::Ticket->new( $RT::SystemUser );
+ ($id,$tid,$msg) = $parent->Create( Subject => 'Link test 1', Queue => $q2->id );
+ ok($id,$msg);
+ my $child = RT::Ticket->new( $creator );
+ ($id,$tid,$msg) = $child->Create( Subject => 'Link test 1', Queue => $q1->id );
+ ok($id,$msg);
+ my ($id, $msg) = $child->AddLink(Type => 'MemberOf', Target => $parent->id);
+ ok($id, $msg);
+ is(link_count($filename), 1, "scrips ok");
+ $child->CurrentUser( $RT::SystemUser );
+ is($child->_Links('Base')->Count, 1, 'link was created');
+ is($child->_Links('Target')->Count, 0, 'link was created only one');
+ $child->CurrentUser( $creator );
+
+ # turn off feature and try to delete link, we should fail
+ $RT::StrictLinkACL = 1;
+ my ($id, $msg) = $child->AddLink(Type => 'MemberOf', Target => $parent->id);
+ ok(!$id, $msg);
+ is(link_count($filename), 1, "scrips ok");
+ $child->CurrentUser( $RT::SystemUser );
+ $child->_Links('Base')->_DoCount;
+ is($child->_Links('Base')->Count, 1, 'link was not deleted');
+ $child->CurrentUser( $creator );
+
+ # try to delete link, we should success as feature is active
+ $RT::StrictLinkACL = 0;
+ my ($id, $msg) = $child->DeleteLink(Type => 'MemberOf', Target => $parent->id);
+ ok($id, $msg);
+ is(link_count($filename), 0, "scrips ok");
+ $child->CurrentUser( $RT::SystemUser );
+ $child->_Links('Base')->_DoCount;
+ is($child->_Links('Base')->Count, 0, 'link was deleted');
+}
+my $tid;
my $ticket = RT::Ticket->new( $creator);
ok($ticket->isa('RT::Ticket'));
($id,$tid, $msg) = $ticket->Create(Subject => 'Link test 1', Queue => $q1->id);
ok ($id,$msg);
+diag('try link to itself') if $ENV{'TEST_VERBOSE'};
+{
+ my ($id, $msg) = $ticket->AddLink(Type => 'RefersTo', Target => $ticket->id);
+ ok(!$id, $msg);
+ is(link_count($filename), 0, "scrips ok");
+}
my $ticket2 = RT::Ticket->new($RT::SystemUser);
($id, $tid, $msg) = $ticket2->Create(Subject => 'Link test 2', Queue => $q2->id);
ok ($id, $msg);
-
($id,$msg) =$ticket->AddLink(Type => 'RefersTo', Target => $ticket2->id);
ok(!$id,$msg);
ok(link_count($filename) == 0, "scrips ok");
+
($id,$msg) = $u1->PrincipalObj->GrantRight ( Object => $q2, Right => 'CreateTicket');
ok ($id,$msg);
($id,$msg) = $u1->PrincipalObj->GrantRight ( Object => $q2, Right => 'ModifyTicket');
@@ -104,6 +197,9 @@ ok(link_count($filename) == 1, "scrips ok");
($id,$msg) =$ticket->AddLink(Type => 'RefersTo', Target => -1);
ok(!$id,$msg);
ok(link_count($filename) == 1, "scrips ok");
+($id,$msg) = $ticket->AddLink(Type => 'RefersTo', Target => $ticket2->id);
+ok($id,$msg);
+is(link_count($filename), 1, "scrips ok");
my $transactions = $ticket2->Transactions;
$transactions->Limit( FIELD => 'Type', VALUE => 'AddLink' );
@@ -121,6 +217,7 @@ ok( $transactions->First->Field eq 'ReferredToBy');
ok( $transactions->First->OldValue eq $ticket->URI );
$RT::LinkTransactionsRun1Scrip = 0;
+
($id,$msg) =$ticket->AddLink(Type => 'RefersTo', Target => $ticket2->id);
ok($id,$msg);
ok(link_count($filename) == 2, "scrips ok");
@@ -130,6 +227,9 @@ ok(link_count($filename) == 0, "scrips ok");
# restore
$RT::LinkTransactionsRun1Scrip = $link_scrips_orig;
+$RT::StrictLinkACL = $link_acl_checks_orig;
+
+exit(0);
sub link_count {
diff --git a/rt/lib/t/regression/15cf_combo_cascade.t b/rt/lib/t/regression/15cf_combo_cascade.t
new file mode 100644
index 0000000..df663a1
--- /dev/null
+++ b/rt/lib/t/regression/15cf_combo_cascade.t
@@ -0,0 +1,49 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use Test::More tests => 11;
+
+use RT;
+RT::LoadConfig();
+RT::Init();
+
+sub fails { ok(!$_[0], "This should fail: $_[1]") }
+sub works { ok($_[0], $_[1] || 'This works') }
+
+sub new (*) {
+ my $class = shift;
+ return $class->new($RT::SystemUser);
+}
+
+my $q = new(RT::Queue);
+works($q->Create(Name => "CF-Pattern-".$$));
+
+my $cf = new(RT::CustomField);
+my @cf_args = (Name => $q->Name, Type => 'Combobox', Queue => $q->id);
+
+works($cf->Create(@cf_args));
+
+# Set some CFVs with Category markers
+
+my $t = new(RT::Ticket);
+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');
+
+1;
diff --git a/rt/lib/t/regression/15cf_pattern.t b/rt/lib/t/regression/15cf_pattern.t
new file mode 100644
index 0000000..ea2b5b8
--- /dev/null
+++ b/rt/lib/t/regression/15cf_pattern.t
@@ -0,0 +1,54 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use Test::More tests => 17;
+
+use RT;
+RT::LoadConfig();
+RT::Init();
+
+sub fails { ok(!$_[0], "This should fail: $_[1]") }
+sub works { ok($_[0], $_[1] || 'This works') }
+
+sub new (*) {
+ my $class = shift;
+ return $class->new($RT::SystemUser);
+}
+
+my $q = new(RT::Queue);
+works($q->Create(Name => "CF-Pattern-".$$));
+
+my $cf = new(RT::CustomField);
+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 = new(RT::Ticket);
+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('...'));
+
+1;
diff --git a/rt/lib/t/regression/17custom_search.t b/rt/lib/t/regression/17custom_search.t
new file mode 100644
index 0000000..8e53f44
--- /dev/null
+++ b/rt/lib/t/regression/17custom_search.t
@@ -0,0 +1,88 @@
+#!/usr/bin/perl -w
+use strict;
+
+use Test::More tests => 10;
+BEGIN {
+ use RT;
+ RT::LoadConfig;
+ RT::Init;
+}
+use Test::WWW::Mechanize;
+
+use constant BaseURL => $RT::WebURL;
+
+# reset preferences for easier test?
+
+my $t = RT::Ticket->new($RT::SystemUser);
+$t->Create(Subject => 'for custom search', Queue => 'general',
+ Owner => 'root', Requestor => 'customsearch@localhost');
+ok(my $id = $t->id, 'created ticket for custom search');
+
+my $m = Test::WWW::Mechanize->new ( autocheck => 1 );
+isa_ok($m, 'Test::WWW::Mechanize');
+
+$m->get( BaseURL."?user=root;pass=password" );
+$m->content_like(qr/Logout/, 'we did log in');
+
+my $t_link = $m->find_link( text => "for custom search" );
+like ($t_link->url, qr/$id/, 'link to the ticket we created');
+
+$m->content_lacks ('customsearch@localhost', 'requestor not displayed ');
+$m->get ( BaseURL.'Prefs/MyRT.html' );
+my $cus_hp = $m->find_link( text => "My Tickets" );
+my $cus_qs = $m->find_link( text => "Quick search" );
+$m->get ($cus_hp);
+$m->content_like (qr'highest priority tickets');
+
+# add Requestor to the fields
+$m->form_name ('BuildQuery');
+# can't use submit form for mutli-valued select as it uses set_fields
+$m->field (SelectDisplayColumns => ['Requestors']);
+$m->click_button (name => 'AddCol') ;
+
+$m->form_name ('BuildQuery');
+$m->click_button (name => 'Save');
+
+$m->get( BaseURL );
+$m->content_contains ('customsearch@localhost', 'requestor now displayed ');
+
+
+# now remove Requestor from the fields
+$m->get ($cus_hp);
+
+$m->form_name ('BuildQuery');
+$m->field (CurrentDisplayColumns => 'Requestors');
+$m->click_button (name => 'RemoveCol') ;
+
+$m->form_name ('BuildQuery');
+$m->click_button (name => 'Save');
+
+$m->get( BaseURL );
+$m->content_lacks ('customsearch@localhost', 'requestor not displayed ');
+
+
+# try to disable General from quick search
+
+# Note that there's a small problem in the current implementation,
+# since ticked quese are wanted, we do the invesrsion. So any
+# queue added during the quicksearch setting will be unticked.
+my $nlinks = $#{$m->find_all_links( text => "General" )};
+warn $nlinks;
+$m->get ($cus_qs);
+$m->form_name ('Preferences');
+$m->untick('Want-General', '1');
+$m->click_button (name => 'Save');
+
+$m->get( BaseURL );
+is ($#{$m->find_all_links( text => "General" )}, $nlinks - 1,
+ 'General gone from quicksearch list');
+
+# get it back
+$m->get ($cus_qs);
+$m->form_name ('Preferences');
+$m->tick('Want-General', '1');
+$m->click_button (name => 'Save');
+
+$m->get( BaseURL );
+is ($#{$m->find_all_links( text => "General" )}, $nlinks,
+ 'General back in quicksearch list');
diff --git a/rt/lib/t/regression/18custom_frontpage.t b/rt/lib/t/regression/18custom_frontpage.t
new file mode 100644
index 0000000..cf77e35
--- /dev/null
+++ b/rt/lib/t/regression/18custom_frontpage.t
@@ -0,0 +1,75 @@
+#!/usr/bin/perl -w
+use strict;
+
+use Test::More tests => 7;
+BEGIN {
+ use RT;
+ RT::LoadConfig;
+ RT::Init;
+}
+use Test::WWW::Mechanize;
+
+use constant BaseURL => $RT::WebURL;
+
+
+my $user_obj = RT::User->new($RT::SystemUser);
+my ($ret, $msg) = $user_obj->LoadOrCreateByEmail('customer@example.com');
+ok($ret, 'ACL test user creation');
+$user_obj->SetName('customer');
+$user_obj->SetPrivileged(1);
+($ret, $msg) = $user_obj->SetPassword('customer');
+$user_obj->PrincipalObj->GrantRight(Right => 'LoadSavedSearch');
+$user_obj->PrincipalObj->GrantRight(Right => 'EditSavedSearch');
+$user_obj->PrincipalObj->GrantRight(Right => 'CreateSavedSearch');
+$user_obj->PrincipalObj->GrantRight(Right => 'ModifySelf');
+
+my $m = Test::WWW::Mechanize->new ( autocheck => 1 );
+isa_ok($m, 'Test::WWW::Mechanize');
+
+$m->get( BaseURL."?user=customer;pass=customer" );
+
+$m->content_like(qr/Logout/, 'we did log in');
+
+$m->get ( BaseURL."Search/Build.html");
+
+#create a saved search
+$m->form_name ('BuildQuery');
+
+$m->field ( "ValueOfAttachment" => 'stupid');
+$m->field ( "Description" => 'stupid tickets');
+$m->click_button (name => 'Save');
+
+$m->get ( BaseURL.'Prefs/MyRT.html' );
+$m->content_like (qr/stupid tickets/, 'saved search listed in rt at a glance items');
+
+$m->follow_link (text => 'Logout');
+
+$m->get( BaseURL."?user=root;pass=password" );
+$m->content_like(qr/Logout/, 'we did log in');
+
+$m->get ( BaseURL.'Prefs/MyRT.html' );
+$m->form_name ('SelectionBox-body');
+# can't use submit form for mutli-valued select as it uses set_fields
+$m->field ('body-Selected' => ['component-QuickCreate', 'system-Unowned Tickets', 'system-My Tickets']);
+$m->click_button (name => 'remove');
+$m->form_name ('SelectionBox-body');
+#$m->click_button (name => 'body-Save');
+$m->get ( BaseURL );
+$m->content_lacks ('highest priority tickets', 'remove everything from body pane');
+
+$m->get ( BaseURL.'Prefs/MyRT.html' );
+$m->form_name ('SelectionBox-body');
+$m->field ('body-Available' => ['component-QuickCreate', 'system-Unowned Tickets', 'system-My Tickets']);
+$m->click_button (name => 'add');
+
+$m->form_name ('SelectionBox-body');
+$m->field ('body-Selected' => ['component-QuickCreate']);
+$m->click_button (name => 'movedown');
+
+$m->form_name ('SelectionBox-body');
+$m->click_button (name => 'movedown');
+
+$m->form_name ('SelectionBox-body');
+#$m->click_button (name => 'body-Save');
+$m->get ( BaseURL );
+$m->content_like (qr'highest priority tickets', 'adds them back');
diff --git a/rt/lib/t/regression/19quicksearch.t b/rt/lib/t/regression/19quicksearch.t
new file mode 100644
index 0000000..7744787
--- /dev/null
+++ b/rt/lib/t/regression/19quicksearch.t
@@ -0,0 +1,39 @@
+
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+
+use Test::More qw/no_plan/;
+use_ok('RT');
+RT::LoadConfig();
+RT::Init();
+
+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 $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' )",
+ "fulltext:jesse" => "( Content LIKE 'jesse' )",
+ $queue => "( Queue = '$queue' )",
+ "root $queue" => "( Owner = 'root' ) AND ( Queue = '$queue' )",
+ "notauser $queue" => "( Queue = '$queue' ) AND ( Subject LIKE 'notauser' )",
+ "notauser $queue root" => "( Owner = 'root' ) AND ( Queue = '$queue' ) AND ( Subject LIKE 'notauser' )");
+
+while (my ($from, $to) = splice @tests, 0, 2) {
+ is($quick->QueryToSQL($from), $to, "<$from> -> <$to>");
+}
diff --git a/rt/lib/t/regression/20-sort-by-requestor.t b/rt/lib/t/regression/20-sort-by-requestor.t
new file mode 100644
index 0000000..e6903b4
--- /dev/null
+++ b/rt/lib/t/regression/20-sort-by-requestor.t
@@ -0,0 +1,143 @@
+#!/usr/bin/perl -w
+use strict; use warnings;
+
+use Test::More qw/no_plan/;
+use_ok('RT');
+RT::LoadConfig();
+RT::Init();
+use RT::Ticket;
+
+my $q = RT::Queue->new($RT::SystemUser);
+my $queue = 'SearchTests-'.rand(200);
+$q->Create(Name => $queue);
+
+my @requestors = ( ('bravo@example.com') x 6, ('alpha@example.com') x 6,
+ ('delta@example.com') x 6, ('charlie@example.com') x 6,
+ (undef) x 6);
+my @subjects = ("first test", "second test", "third test", "fourth test", "fifth test") x 6;
+while (@requestors) {
+ my $t = RT::Ticket->new($RT::SystemUser);
+ my ( $id, undef $msg ) = $t->Create(
+ Queue => $q->id,
+ Subject => shift @subjects,
+ Requestor => [ shift @requestors ]
+ );
+ ok( $id, $msg );
+}
+
+{
+ my $tix = RT::Tickets->new($RT::SystemUser);
+ $tix->FromSQL("Queue = '$queue'");
+ is($tix->Count, 30, "found thirty tickets");
+}
+
+{
+ my $tix = RT::Tickets->new($RT::SystemUser);
+ $tix->FromSQL("Queue = '$queue' AND requestor = 'alpha\@example.com'");
+ $tix->OrderByCols({ FIELD => "Subject" });
+ my @subjects;
+ while (my $t = $tix->Next) { push @subjects, $t->Subject; }
+ is(@subjects, 6, "found six tickets");
+ is_deeply( \@subjects, [ sort @subjects ], "Subjects are sorted");
+}
+
+sub check_emails_order
+{
+ my ($tix,$count,$order) = (@_);
+ my @mails;
+ while (my $t = $tix->Next) { push @mails, $t->RequestorAddresses; }
+ is(@mails, $count, "found $count tickets for ". $tix->Query);
+ my @required_order;
+ if( $order =~ /asc/i ) {
+ @required_order = sort { $a? ($b? ($a cmp $b) : -1) : 1} @mails;
+ } else {
+ @required_order = sort { $a? ($b? ($b cmp $a) : -1) : 1} @mails;
+ }
+ foreach( reverse splice @mails ) {
+ if( $_ ) { unshift @mails, $_ }
+ else { push @mails, $_ }
+ }
+ is_deeply( \@mails, \@required_order, "Addresses are sorted");
+}
+
+{
+ my $tix = RT::Tickets->new($RT::SystemUser);
+ $tix->FromSQL("Queue = '$queue' AND subject = 'first test' AND Requestor.EmailAddress LIKE 'example.com'");
+ $tix->OrderByCols({ FIELD => "Requestor.EmailAddress" });
+ check_emails_order($tix, 5, 'ASC');
+ $tix->OrderByCols({ FIELD => "Requestor.EmailAddress", ORDER => 'DESC' });
+ check_emails_order($tix, 5, 'DESC');
+}
+
+{
+ my $tix = RT::Tickets->new($RT::SystemUser);
+ $tix->FromSQL("Queue = '$queue' AND Subject = 'first test'");
+ $tix->OrderByCols({ FIELD => "Requestor.EmailAddress" });
+ check_emails_order($tix, 6, 'ASC');
+ $tix->OrderByCols({ FIELD => "Requestor.EmailAddress", ORDER => 'DESC' });
+ check_emails_order($tix, 6, 'DESC');
+}
+
+
+{
+ my $tix = RT::Tickets->new($RT::SystemUser);
+ $tix->FromSQL("Queue = '$queue' AND Subject = 'first test'");
+ $tix->OrderByCols({ FIELD => "Requestor.EmailAddress" });
+ check_emails_order($tix, 6, 'ASC');
+ $tix->OrderByCols({ FIELD => "Requestor.EmailAddress", ORDER => 'DESC' });
+ check_emails_order($tix, 6, 'DESC');
+}
+
+{
+ # create ticket with group as member of the requestors group
+ my $t = RT::Ticket->new($RT::SystemUser);
+ my ( $id, $msg ) = $t->Create(
+ Queue => $q->id,
+ Subject => "first test",
+ Requestor => 'badaboom@example.com',
+ );
+ ok( $id, "ticket created" ) or diag( "error: $msg" );
+
+ my $g = RT::Group->new($RT::SystemUser);
+
+ my ($gid);
+ ($gid, $msg) = $g->CreateUserDefinedGroup(Name => '20-sort-by-requestor.t-'.rand(200));
+ ok($gid, "created group") or diag("error: $msg");
+
+ ($id, $msg) = $t->Requestors->AddMember( $gid );
+ ok($id, "added group to requestors group") or diag("error: $msg");
+}
+
+ my $tix = RT::Tickets->new($RT::SystemUser);
+ $tix->FromSQL("Queue = '$queue' AND Subject = 'first test'");
+TODO: {
+ local $TODO = "if group has non users members we get wrong order";
+ $tix->OrderByCols({ FIELD => "Requestor.EmailAddress" });
+ check_emails_order($tix, 7, 'ASC');
+}
+ $tix->OrderByCols({ FIELD => "Requestor.EmailAddress", ORDER => 'DESC' });
+ check_emails_order($tix, 7, 'DESC');
+
+{
+ my $tix = RT::Tickets->new($RT::SystemUser);
+ $tix->FromSQL("Queue = '$queue'");
+ $tix->OrderByCols({ FIELD => "Requestor.EmailAddress" });
+ $tix->RowsPerPage(30);
+ my @mails;
+ while (my $t = $tix->Next) { push @mails, $t->RequestorAddresses; }
+ is(@mails, 30, "found thirty tickets");
+ is_deeply( [grep {$_} @mails], [ sort grep {$_} @mails ], "Paging works (exclude nulls, which are db-dependant)");
+}
+
+{
+ my $tix = RT::Tickets->new($RT::SystemUser);
+ $tix->FromSQL("Queue = '$queue'");
+ $tix->OrderByCols({ FIELD => "Requestor.EmailAddress" });
+ $tix->RowsPerPage(30);
+ my @mails;
+ while (my $t = $tix->Next) { push @mails, $t->RequestorAddresses; }
+ is(@mails, 30, "found thirty tickets");
+ is_deeply( [grep {$_} @mails], [ sort grep {$_} @mails ], "Paging works (exclude nulls, which are db-dependant)");
+}
+
+# vim:ft=perl:
diff --git a/rt/lib/t/regression/21query-builder.t b/rt/lib/t/regression/21query-builder.t
index be04599..7f9990a 100644
--- a/rt/lib/t/regression/21query-builder.t
+++ b/rt/lib/t/regression/21query-builder.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl
use strict;
-use Test::More tests => 31;
+use Test::More tests => 39;
use Test::WWW::Mechanize;
use HTTP::Request::Common;
use HTTP::Cookies;
@@ -16,7 +16,20 @@ my $agent = Test::WWW::Mechanize->new();
$agent->cookie_jar($cookie_jar);
use RT;
-RT::LoadConfig;
+RT::LoadConfig();
+RT::Init();
+
+# create a regression queue if it doesn't exist
+{
+ my $queue = RT::Queue->new( $RT::SystemUser );
+ $queue->Load( 'Regression' );
+ if ( $queue->id ) {
+ ok(1, "queue 'Regression' exists");
+ } else {
+ $queue->Create( Name => 'Regression' );
+ ok($queue->id, "created queue 'Regression'");
+ }
+}
# get the top page
my $url = $RT::WebURL;
@@ -65,6 +78,7 @@ $agent->submit();
ok($agent->form_name('BuildQuery'), "found the form a third time");
sub getQueryFromForm {
+ $agent->form_name('BuildQuery');
# This pulls out the "hidden input" query from the page
my $q = $agent->current_form->find_input("Query")->value;
$q =~ s/^\s+//g;
@@ -126,38 +140,37 @@ $agent->select("clauses", ["1"]);
$agent->click("Up");
ok($agent->form_name('BuildQuery'), "found the form again");
-TODO: {
- local $TODO = "query builder incorrectly changes OR to AND";
- is(getQueryFromForm, "( id > 1234 ) OR Queue != 'Regression'", "moved up");
-}
+is(getQueryFromForm, "( id > 1234 ) OR Queue != 'Regression'", "moved up");
$agent->select("clauses", ["0"]); # this is a null clause
-
$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");
$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");
$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 selected');
-TODO: {
- local $TODO = "query builder incorrectly changes OR to AND";
- is(getQueryFromForm, "( id > 1234 AND Status = 'stalled' ) OR Queue != 'Regression'", "added new one");
+is( getQueryFromForm, "( id > 1234 AND Status = 'stalled' ) OR Queue != 'Regression'", "added new one" );
+
+# 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");
+ $agent->field("Query", "Status = 'new' OR ( Status = 'open' AND Subject LIKE 'office' )");
+ $agent->submit;
+ is( getQueryFromForm,
+ "Status = 'new' OR ( Status = 'open' AND Subject LIKE 'office' )",
+ "no aggregators change"
+ );
}
-
-
# - new items go one level down
# - add items at currently selected level
# - if nothing is selected, add at end, one level down
@@ -200,5 +213,32 @@ TODO: {
# }}}
+# create a custom field with nonascii name and try to add a condition
+{
+ my $cf = RT::CustomField->new( $RT::SystemUser );
+ $cf->LoadByName( Name => "\x{442}", Queue => 0 );
+ if ( $cf->id ) {
+ is($cf->Type, 'Freeform', 'loaded and type is correct');
+ } else {
+ my ($return, $msg) = $cf->Create(
+ Name => "\x{442}",
+ Queue => 0,
+ Type => 'Freeform',
+ );
+ ok($return, 'created CF') or diag "error: $msg";
+ }
+
+ my $response = $agent->get($url."Search/Build.html?NewQuery=1");
+ ok( $response->is_success, "Fetched " . $url."Search/Build.html" );
+
+ ok($agent->form_name('BuildQuery'), "found the form once");
+ $agent->field("ValueOf'CF.{\321\202}'", "\321\201");
+ $agent->submit();
+ is( getQueryFromForm,
+ "'CF.{\321\202}' LIKE '\321\201'",
+ "no changes, no duplicate condition with badly encoded text"
+ );
+
+}
1;
diff --git a/rt/lib/t/regression/22search_tix_by_txn.t b/rt/lib/t/regression/22search_tix_by_txn.t
index 958273c..bec61b5 100644
--- a/rt/lib/t/regression/22search_tix_by_txn.t
+++ b/rt/lib/t/regression/22search_tix_by_txn.t
@@ -1,6 +1,12 @@
-#use Test::More tests => 26;
-use Test::More qw/no_plan/;
-$ENV{'TZ'} = 'GMT';
+#!/usr/bin/perl
+
+use warnings;
+use strict;
+
+use Test::More tests => 10;
+
+BEGIN{ $ENV{'TZ'} = 'GMT'};
+
use RT;
RT::LoadConfig();
RT::Init();
@@ -29,4 +35,4 @@ is($txnobj->CreatedObj->ISO,'2005-08-05 20:00:56');
$tix->FromSQL(qq{Updated = "2005-08-05" AND Subject = "$SUBJECT"});
is( $tix->Count, 1);
-1;
+
diff --git a/rt/lib/t/regression/22search_tix_by_watcher.t b/rt/lib/t/regression/22search_tix_by_watcher.t
index dd87de9..1df7e72 100644
--- a/rt/lib/t/regression/22search_tix_by_watcher.t
+++ b/rt/lib/t/regression/22search_tix_by_watcher.t
@@ -1,23 +1,19 @@
#!/usr/bin/perl -w
+
use strict;
use warnings;
-use Test::More qw/no_plan/;
+use Test::More tests => 79;
use_ok('RT');
RT::LoadConfig();
RT::Init();
use RT::Ticket;
-my $q = RT::Queue->new($RT::SystemUser);
-my $queue = 'SearchTests-'.rand(200);
-$q->Create(Name => $queue);
-
-my @data = (
- { Subject => '1', Requestor => 'bravo@example.com' },
- { Subject => '2', Cc => 'alpha@example.com' },
-);
+my $q = RT::Queue->new( $RT::SystemUser );
+my $queue = 'SearchTests-'. rand(200);
+$q->Create( Name => $queue );
-my $total = 0;
+my ($total, @data, @tickets, %test) = (0, ());
sub add_tix_from_data {
my @res = ();
@@ -33,102 +29,111 @@ sub add_tix_from_data {
}
return @res;
}
-add_tix_from_data();
-{
- my $tix = RT::Tickets->new($RT::SystemUser);
- $tix->FromSQL("Queue = '$queue'");
- is($tix->Count, $total, "found $total tickets");
-}
+sub run_tests {
+ my $query_prefix = join ' OR ', map 'id = '. $_->id, @tickets;
+ foreach my $key ( sort keys %test ) {
+ my $tix = RT::Tickets->new($RT::SystemUser);
+ $tix->FromSQL( "( $query_prefix ) AND ( $key )" );
-{
- my $tix = RT::Tickets->new($RT::SystemUser);
- $tix->FromSQL("Queue = '$queue' AND Requestor = 'bravo\@example.com'");
- is($tix->Count, 1, "found ticket(s)");
- is($tix->First->RequestorAddresses, 'bravo@example.com',"correct requestor");
-}
+ my $error = 0;
-{
- my $tix = RT::Tickets->new($RT::SystemUser);
- $tix->FromSQL("Queue = '$queue' AND Cc = 'alpha\@example.com'");
- is($tix->Count, 1, "found ticket(s)");
- is($tix->First->CcAddresses, 'alpha@example.com', "correct Cc");
-}
+ my $count = 0;
+ $count++ foreach grep $_, values %{ $test{$key} };
+ TODO: {
+ local $TODO = "we can't generate this query yet";
+ is($tix->Count, $count, "found correct number of ticket(s) by '$key'") or $error = 1;
+ };
-{
- my $tix = RT::Tickets->new($RT::SystemUser);
- $tix->FromSQL("Queue = '$queue' AND (Cc = 'alpha\@example.com' OR Requestor = 'bravo\@example.com')");
- is($tix->Count, 2, "found ticket(s)");
- my @mails;
- while (my $t = $tix->Next) {
- push @mails, $t->RequestorAddresses;
- push @mails, $t->CcAddresses;
+ my $good_tickets = 1;
+ while ( my $ticket = $tix->Next ) {
+ next if $test{$key}->{ $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 '$key'" ) or $error = 1;
+
+ diag "Wrong SQL query for '$key':". $tix->BuildSelectQuery if $error;
}
- @mails = sort grep $_, @mails;
- is_deeply(\@mails, ['alpha@example.com', 'bravo@example.com'], "correct addresses");
}
-{
- my $tix = RT::Tickets->new($RT::SystemUser);
- $tix->FromSQL("Queue = '$queue' AND (Cc = 'alpha\@example.com' AND Requestor = 'bravo\@example.com')");
- is($tix->Count, 0, "found ticket(s)");
-}
+@data = (
+ { Subject => 'xy', Requestor => ['x@example.com', 'y@example.com'] },
+ { Subject => 'x', Requestor => 'x@example.com' },
+ { Subject => 'y', Requestor => 'y@example.com' },
+ { Subject => '-', },
+ { Subject => 'z', Requestor => 'z@example.com' },
+);
+%test = (
+ 'Requestor = "x@example.com"' => { xy => 1, x => 1, y => 0, '-' => 0, z => 0 },
+ 'Requestor != "x@example.com"' => { xy => 0, x => 0, y => 1, '-' => 1, z => 1 },
-{
- my $tix = RT::Tickets->new($RT::SystemUser);
- $tix->FromSQL("Queue = '$queue' AND Cc != 'alpha\@example.com'");
- is($tix->Count, 1, "found ticket(s)");
- is($tix->First->RequestorAddresses, 'bravo@example.com',"correct requestor");
-}
+ 'Requestor = "y@example.com"' => { xy => 1, x => 0, y => 1, '-' => 0, z => 0 },
+ 'Requestor != "y@example.com"' => { xy => 0, x => 1, y => 0, '-' => 1, z => 1 },
-@data = ( { Subject => '3' } );
-add_tix_from_data();
+ 'Requestor LIKE "@example.com"' => { xy => 1, x => 1, y => 1, '-' => 0, z => 1 },
+ 'Requestor NOT LIKE "@example.com"' => { xy => 0, x => 0, y => 0, '-' => 1, z => 0 },
-{
- my $tix = RT::Tickets->new($RT::SystemUser);
- $tix->FromSQL("Queue = '$queue' AND Cc != 'alpha\@example.com'");
- is($tix->Count, 2, "found ticket(s)");
- my @mails;
- while (my $t = $tix->Next) { push @mails, ($t->CcAddresses||'') }
- is( scalar(grep 'alpha@example.com' eq $_, @mails), 0, "no tickets with non required data");
-}
+ 'Requestor IS NULL' => { xy => 0, x => 0, y => 0, '-' => 1, z => 0 },
+ 'Requestor IS NOT NULL' => { xy => 1, x => 1, y => 1, '-' => 0, z => 1 },
-{
- # has no requestor search
- my $tix = RT::Tickets->new($RT::SystemUser);
- $tix->FromSQL("Queue = '$queue' AND Requestor IS NULL");
- is($tix->Count, 2, "found ticket(s)");
- my @mails;
- while (my $t = $tix->Next) { push @mails, ($t->RequestorAddresses||'') }
- is( scalar(grep $_, @mails), 0, "no tickets with non required data");
-}
+ 'Requestor = "x@example.com" AND Requestor = "y@example.com"' => { xy => 1, x => 0, y => 0, '-' => 0, z => 0 },
+ 'Requestor = "x@example.com" OR Requestor = "y@example.com"' => { xy => 1, x => 1, y => 1, '-' => 0, z => 0 },
+
+ 'Requestor != "x@example.com" AND Requestor != "y@example.com"' => { xy => 0, x => 0, y => 0, '-' => 1, z => 1 },
+ 'Requestor != "x@example.com" OR Requestor != "y@example.com"' => { xy => 0, x => 1, y => 1, '-' => 1, z => 1 },
+
+ 'Requestor = "x@example.com" AND Requestor != "y@example.com"' => { xy => 0, x => 1, y => 0, '-' => 0, z => 0 },
+ 'Requestor = "x@example.com" OR Requestor != "y@example.com"' => { xy => 1, x => 1, y => 0, '-' => 1, z => 1 },
+ 'Requestor != "x@example.com" AND Requestor = "y@example.com"' => { xy => 0, x => 0, y => 1, '-' => 0, z => 0 },
+ 'Requestor != "x@example.com" OR Requestor = "y@example.com"' => { xy => 1, x => 0, y => 1, '-' => 1, z => 1 },
+);
+@tickets = add_tix_from_data();
{
- # has at least one requestor search
my $tix = RT::Tickets->new($RT::SystemUser);
- $tix->FromSQL("Queue = '$queue' AND Requestor IS NOT NULL");
- is($tix->Count, 1, "found ticket(s)");
- my @mails;
- while (my $t = $tix->Next) { push @mails, ($t->RequestorAddresses||'') }
- is( scalar(grep !$_, @mails), 0, "no tickets with non required data");
+ $tix->FromSQL("Queue = '$queue'");
+ is($tix->Count, $total, "found $total tickets");
}
+run_tests();
-@data = ( { Subject => '3', Requestor => 'charly@example.com' } );
-add_tix_from_data();
-
+@data = (
+ { Subject => 'xy', Cc => ['x@example.com'], Requestor => [ 'y@example.com' ] },
+ { Subject => 'x-', Cc => ['x@example.com'], Requestor => [] },
+ { Subject => '-y', Cc => [], Requestor => [ 'y@example.com' ] },
+ { Subject => '-', },
+ { Subject => 'zz', Cc => ['z@example.com'], Requestor => [ 'z@example.com' ] },
+ { Subject => 'z-', Cc => ['z@example.com'], Requestor => [] },
+ { Subject => '-z', Cc => [], Requestor => [ 'z@example.com' ] },
+);
+%test = (
+ 'Cc = "x@example.com" AND Requestor = "y@example.com"' =>
+ { xy => 1, 'x-' => 0, '-y' => 0, '-' => 0, zz => 0, 'z-' => 0, '-z' => 0 },
+ 'Cc = "x@example.com" OR Requestor = "y@example.com"' =>
+ { xy => 1, 'x-' => 1, '-y' => 1, '-' => 0, zz => 0, 'z-' => 0, '-z' => 0 },
+
+ 'Cc != "x@example.com" AND Requestor = "y@example.com"' =>
+ { xy => 0, 'x-' => 0, '-y' => 1, '-' => 0, zz => 0, 'z-' => 0, '-z' => 0 },
+ 'Cc != "x@example.com" OR Requestor = "y@example.com"' =>
+ { xy => 1, 'x-' => 0, '-y' => 1, '-' => 1, zz => 1, 'z-' => 1, '-z' => 1 },
+
+ 'Cc IS NULL AND Requestor = "y@example.com"' =>
+ { xy => 0, 'x-' => 0, '-y' => 1, '-' => 0, zz => 0, 'z-' => 0, '-z' => 0 },
+ 'Cc IS NULL OR Requestor = "y@example.com"' =>
+ { xy => 1, 'x-' => 0, '-y' => 1, '-' => 1, zz => 0, 'z-' => 0, '-z' => 1 },
+
+ 'Cc IS NOT NULL AND Requestor = "y@example.com"' =>
+ { xy => 1, 'x-' => 0, '-y' => 0, '-' => 0, zz => 0, 'z-' => 0, '-z' => 0 },
+ 'Cc IS NOT NULL OR Requestor = "y@example.com"' =>
+ { xy => 1, 'x-' => 1, '-y' => 1, '-' => 0, zz => 1, 'z-' => 1, '-z' => 0 },
+);
+@tickets = add_tix_from_data();
{
- # has no requestor search
my $tix = RT::Tickets->new($RT::SystemUser);
- $tix->FromSQL("Queue = '$queue' AND
- (Requestor = 'bravo\@example.com' OR Requestor = 'charly\@example.com')");
- is($tix->Count, 2, "found ticket(s)");
- my @mails;
- while (my $t = $tix->Next) { push @mails, ($t->RequestorAddresses||'') }
- is_deeply( [sort @mails],
- ['bravo@example.com', 'charly@example.com'],
- "requestor addresses are correct"
- );
+ $tix->FromSQL("Queue = '$queue'");
+ is($tix->Count, $total, "found $total tickets");
}
+run_tests();
# owner is special watcher because reference is duplicated in two places,
# owner was an ENUM field now it's WATCHERFIELD, but should support old
@@ -137,12 +142,12 @@ my $nobody = RT::Nobody();
{
my $tix = RT::Tickets->new($RT::SystemUser);
$tix->FromSQL("Queue = '$queue' AND Owner = '". $nobody->id ."'");
- is($tix->Count, 4, "found ticket(s)");
+ ok($tix->Count, "found ticket(s)");
}
{
my $tix = RT::Tickets->new($RT::SystemUser);
$tix->FromSQL("Queue = '$queue' AND Owner = '". $nobody->Name ."'");
- is($tix->Count, 4, "found ticket(s)");
+ ok($tix->Count, "found ticket(s)");
}
{
my $tix = RT::Tickets->new($RT::SystemUser);
@@ -158,7 +163,7 @@ my $nobody = RT::Nobody();
{
my $tix = RT::Tickets->new($RT::SystemUser);
$tix->FromSQL("Queue = '$queue' AND Owner.Name LIKE 'nob'");
- is($tix->Count, 4, "found ticket(s)");
+ ok($tix->Count, "found ticket(s)");
}
{
@@ -176,7 +181,7 @@ my $nobody = RT::Nobody();
my $tix = RT::Tickets->new($RT::SystemUser);
$tix->FromSQL("Queue = '$queue' AND Owner = 'Nobody'");
- is($tix->Count, 4, "found ticket(s)");
+ is($tix->Count, $total, "found ticket(s)");
}
{
@@ -189,7 +194,7 @@ my $nobody = RT::Nobody();
ok($id, "granted OwnTicket right to Everyone on '$queue'") or diag("error: $msg");
my $u = RT::User->new( $RT::SystemUser );
- $u->LoadByCols( EmailAddress => 'alpha@example.com' );
+ $u->LoadOrCreateByEmail('alpha@example.com');
ok($u->id, "loaded user");
@data = ( { Subject => '4', Owner => $u->id } );
my($t) = add_tix_from_data();
@@ -197,7 +202,7 @@ my $nobody = RT::Nobody();
my $u_alpha_id = $u->id;
$u = RT::User->new( $RT::SystemUser );
- $u->LoadByCols( EmailAddress => 'bravo@example.com' );
+ $u->LoadOrCreateByEmail('bravo@example.com');
ok($u->id, "loaded user");
@data = ( { Subject => '5', Owner => $u->id } );
($t) = add_tix_from_data();
@@ -212,4 +217,5 @@ my $nobody = RT::Nobody();
is($tix->Count, 2, "found ticket(s)");
}
+
exit(0)
diff --git a/rt/lib/t/regression/23-batch-upload-csv.t b/rt/lib/t/regression/23-batch-upload-csv.t
new file mode 100644
index 0000000..fc9436a
--- /dev/null
+++ b/rt/lib/t/regression/23-batch-upload-csv.t
@@ -0,0 +1,47 @@
+#!/usr/bin/perl -w
+use strict; use warnings;
+
+use Test::More qw/no_plan/;
+use_ok('RT');
+RT::LoadConfig();
+RT::Init();
+use_ok('RT::Action::CreateTickets');
+
+my $QUEUE = 'uploadtest-'.$$;
+
+my $queue_obj = RT::Queue->new($RT::SystemUser);
+$queue_obj->Create(Name => $QUEUE);
+
+my $cf = RT::CustomField->new($RT::SystemUser);
+my ($val,$msg) = $cf->Create(Name => 'Work Package-'.$$, Type => 'Freeform', LookupType => RT::Ticket->CustomFieldLookupType, MaxValues => 1);
+ok($cf->id);
+ok($val,$msg);
+($val, $msg) = $cf->AddToObject($queue_obj);
+ok($val,$msg);
+ok($queue_obj->TicketCustomFields()->Count, "We have a custom field, at least");
+
+
+my $data = <<EOF;
+id,Queue,Subject,Status,Requestor,@{[$cf->Name]}
+create-1,$QUEUE,hi,new,root,2.0
+create-2,$QUEUE,hello,new,root,3.0
+EOF
+
+my $action = RT::Action::CreateTickets->new(CurrentUser => RT::CurrentUser->new('root'));
+ok ($action->CurrentUser->id , "WE have a current user");
+
+$action->Parse(Content => $data);
+my @results = $action->CreateByTemplate();
+
+my $tix = RT::Tickets->new($RT::SystemUser);
+$tix->FromSQL ("Queue = '". $QUEUE."'");
+$tix->OrderBy( FIELD => 'id', ORDER => 'ASC' );
+ok($tix->Count);
+my $first = $tix->First();
+is($first->Subject(), 'hi');
+is($first->FirstCustomFieldValue($cf->id), '2.0');
+
+my $second = $tix->Next;
+is($second->Subject(), 'hello');
+is($second->FirstCustomFieldValue($cf->id), '3.0');
+1;
diff --git a/rt/lib/t/regression/23-web_attachments.t b/rt/lib/t/regression/23-web_attachments.t
new file mode 100644
index 0000000..adc38ad
--- /dev/null
+++ b/rt/lib/t/regression/23-web_attachments.t
@@ -0,0 +1,60 @@
+#!/usr/bin/perl -w
+use strict;
+
+use Test::More tests => 15;
+use RT;
+RT::LoadConfig;
+RT::Init;
+use Test::WWW::Mechanize;
+
+$RT::WebURL ||= 0; # avoid stupid warning
+my $BaseURL = $RT::WebURL;
+use constant LogoFile => $RT::MasonComponentRoot .'/NoAuth/images/bplogo.gif';
+use constant FaviconFile => $RT::MasonComponentRoot .'/NoAuth/images/favicon.png';
+
+my $queue_name = 'General';
+
+my $m = Test::WWW::Mechanize->new;
+isa_ok($m, 'Test::WWW::Mechanize');
+
+$m->get_ok( $BaseURL."?user=root;pass=password" );
+$m->content_like(qr/Logout/, 'we did log in');
+
+my $qid;
+{
+ $m->content =~ /<SELECT\s+NAME\s*="Queue"\s*>.*?<OPTION\s+VALUE="(\d+)".*?>\s*\Q$queue_name\E\s*<\/OPTION>/msig;
+ ok( $qid = $1, "found id of the '$queue_name' queue");
+}
+
+$m->form_name('CreateTicketInQueue');
+$m->field('Queue', $qid);
+$m->submit;
+is($m->status, 200, "request successful");
+$m->content_like(qr/Create a new ticket/, 'ticket create page');
+
+$m->form_name('TicketCreate');
+$m->field('Subject', 'Attachments test');
+$m->field('Attach', LogoFile);
+$m->field('Content', 'Some content');
+$m->submit;
+is($m->status, 200, "request successful");
+
+$m->content_like(qr/Attachments test/, 'we have subject on the page');
+$m->content_like(qr/Some content/, 'and content');
+$m->content_like(qr/Download bplogo\.gif/, 'page has file name');
+
+$m->follow_link_ok({text => 'Reply'}, "reply to the ticket");
+$m->form_name('TicketUpdate');
+$m->field('Attach', LogoFile);
+$m->click('AddMoreAttach');
+is($m->status, 200, "request successful");
+
+$m->form_name('TicketUpdate');
+$m->field('Attach', FaviconFile);
+$m->field('UpdateContent', 'Message');
+$m->click('SubmitTicket');
+is($m->status, 200, "request successful");
+
+$m->content_like(qr/Download bplogo\.gif/, 'page has file name');
+$m->content_like(qr/Download favicon\.png/, 'page has file name');
+
diff --git a/rt/lib/t/regression/23cfsort.t b/rt/lib/t/regression/23cfsort.t
new file mode 100644
index 0000000..e90fa36
--- /dev/null
+++ b/rt/lib/t/regression/23cfsort.t
@@ -0,0 +1,143 @@
+#!/usr/bin/perl
+
+use Test::More tests => 15;
+use RT;
+RT::LoadConfig();
+RT::Init();
+
+use strict;
+use warnings;
+
+use RT::Tickets;
+use RT::Queue;
+use RT::CustomField;
+
+my($ret,$msg);
+
+
+# Test Sorting by custom fields.
+
+# ---- Create a queue to test with.
+my $queue = "CFSortQueue-$$";
+my $queue_obj = RT::Queue->new($RT::SystemUser);
+($ret, $msg) = $queue_obj->Create(Name => $queue,
+ Description => 'queue for custom field sort testing');
+ok($ret, "$queue test queue creation. $msg");
+
+# ---- Create some custom fields. We're not currently using all of
+# them to test with, but the more the merrier.
+my $cfO = RT::CustomField->new($RT::SystemUser);
+my $cfA = RT::CustomField->new($RT::SystemUser);
+my $cfB = RT::CustomField->new($RT::SystemUser);
+my $cfC = RT::CustomField->new($RT::SystemUser);
+
+($ret, $msg) = $cfO->Create( Name => 'Order',
+ Queue => 0,
+ SortOrder => 1,
+ Description => q[Something to compare results for, since we can't guarantee ticket ID],
+ Type=> 'FreeformSingle');
+ok($ret, "Custom Field Order created");
+
+($ret, $msg) = $cfA->Create( Name => 'Alpha',
+ Queue => $queue_obj->id,
+ SortOrder => 1,
+ Description => 'A Testing custom field',
+ Type=> 'FreeformSingle');
+ok($ret, "Custom Field Alpha created");
+
+($ret, $msg) = $cfB->Create( Name => 'Beta',
+ Queue => $queue_obj->id,
+ Description => 'A Testing custom field',
+ Type=> 'FreeformSingle');
+ok($ret, "Custom Field Beta created");
+
+($ret, $msg) = $cfC->Create( Name => 'Charlie',
+ Queue => $queue_obj->id,
+ Description => 'A Testing custom field',
+ Type=> 'FreeformSingle');
+ok($ret, "Custom Field Charlie created");
+
+# ----- Create some tickets to test with. Assign them some values to
+# make it easy to sort with.
+my $t1 = RT::Ticket->new($RT::SystemUser);
+$t1->Create( Queue => $queue_obj->Id,
+ Subject => 'One',
+ );
+$t1->AddCustomFieldValue(Field => $cfO->Id, Value => '1');
+$t1->AddCustomFieldValue(Field => $cfA->Id, Value => '2');
+$t1->AddCustomFieldValue(Field => $cfB->Id, Value => '1');
+$t1->AddCustomFieldValue(Field => $cfC->Id, Value => 'BBB');
+
+my $t2 = RT::Ticket->new($RT::SystemUser);
+$t2->Create( Queue => $queue_obj->Id,
+ Subject => 'Two',
+ );
+$t2->AddCustomFieldValue(Field => $cfO->Id, Value => '2');
+$t2->AddCustomFieldValue(Field => $cfA->Id, Value => '1');
+$t2->AddCustomFieldValue(Field => $cfB->Id, Value => '2');
+$t2->AddCustomFieldValue(Field => $cfC->Id, Value => 'AAA');
+
+# helper
+sub check_order {
+ my ($tx, @order) = @_;
+ my @results;
+ while (my $t = $tx->Next) {
+ push @results, $t->CustomFieldValues($cfO->Id)->First->Content;
+ }
+ my $results = join (" ",@results);
+ my $order = join(" ",@order);
+ is( $results, $order , "Ordered correctly: $order");
+}
+
+# The real tests start here
+my $tx = new RT::Tickets( $RT::SystemUser );
+
+
+# Make sure we can sort in both directions on a queue specific field.
+$tx->FromSQL(qq[queue="$queue"] );
+$tx->OrderBy( FIELD => "CF.${queue}.{Charlie}", ORDER => 'DES' );
+is($tx->Count,2 ,"We found 2 tickets when lookign for cf charlie");
+check_order( $tx, 1, 2);
+
+$tx = new RT::Tickets( $RT::SystemUser );
+$tx->FromSQL(qq[queue="$queue"] );
+$tx->OrderBy( FIELD => "CF.${queue}.{Charlie}", ORDER => 'ASC' );
+is($tx->Count,2, "We found two tickets when sorting by cf charlie without limiting to it" );
+check_order( $tx, 2, 1);
+
+# When ordering by _global_ CustomFields, if more than one queue has a
+# CF named Charlie, things will go bad. So, these results are uniqued
+# in Tickets_Overlay.
+$tx = new RT::Tickets( $RT::SystemUser );
+$tx->FromSQL(qq[queue="$queue"] );
+$tx->OrderBy( FIELD => "CF.{Charlie}", ORDER => 'DES' );
+is($tx->Count,2);
+check_order( $tx, 1, 2);
+
+# Add a new ticket, to test sorting on multiple columns.
+my $t3 = RT::Ticket->new($RT::SystemUser);
+$t3->Create( Queue => $queue_obj->Id,
+ Subject => 'Three',
+ );
+$t3->AddCustomFieldValue(Field => $cfO->Id, Value => '3');
+$t3->AddCustomFieldValue(Field => $cfA->Id, Value => '3');
+$t3->AddCustomFieldValue(Field => $cfB->Id, Value => '2');
+$t3->AddCustomFieldValue(Field => $cfC->Id, Value => 'AAA');
+
+$tx = new RT::Tickets( $RT::SystemUser );
+$tx->FromSQL(qq[queue="$queue"] );
+$tx->OrderByCols({FIELD => "CF.${queue}.{Charlie}", ORDER => 'ASC'},
+ {FIELD => "CF.${queue}.{Alpha}", ORDER => 'DES'}
+ );
+is($tx->Count,3);
+check_order( $tx, 3, 2, 1);
+
+# Reverse the order of the secondary column, which changes the order
+# of the first two tickets.
+$tx = new RT::Tickets( $RT::SystemUser );
+$tx->FromSQL(qq[queue="$queue"] );
+$tx->OrderByCols({FIELD => "CF.${queue}.{Charlie}", ORDER => 'ASC'},
+ {FIELD => "CF.${queue}.{Alpha}", ORDER => 'ASC'}
+ );
+is($tx->Count,3);
+check_order( $tx, 2, 3, 1);
diff --git a/rt/lib/t/regression/24pawsort.t b/rt/lib/t/regression/24pawsort.t
new file mode 100644
index 0000000..665c325
--- /dev/null
+++ b/rt/lib/t/regression/24pawsort.t
@@ -0,0 +1,104 @@
+#!/usr/bin/perl
+
+use Test::More qw/no_plan/;
+use RT;
+RT::LoadConfig();
+RT::Init();
+
+use strict;
+use warnings;
+
+use RT::Tickets;
+use RT::Queue;
+use RT::CustomField;
+
+my($ret,$msg);
+
+# Test Paw Sort
+
+
+
+# ---- Create a queue to test with.
+my $queue = "PAWSortQueue-$$";
+my $queue_obj = RT::Queue->new($RT::SystemUser);
+($ret, $msg) = $queue_obj->Create(Name => $queue,
+ Description => 'queue for custom field sort testing');
+ok($ret, "$queue test queue creation. $msg");
+
+
+# ---- Create some users
+
+my $me = RT::User->new($RT::SystemUser);
+($ret, $msg) = $me->Create(Name => "Me$$", EmailAddress => $$.'create-me-1@example.com');
+($ret, $msg) = $me->PrincipalObj->GrantRight(Object =>$queue_obj, Right => 'OwnTicket');
+($ret, $msg) = $me->PrincipalObj->GrantRight(Object =>$queue_obj, Right => 'SeeQueue');
+($ret, $msg) = $me->PrincipalObj->GrantRight(Object =>$queue_obj, Right => 'ShowTicket');
+my $you = RT::User->new($RT::SystemUser);
+($ret, $msg) = $you->Create(Name => "You$$", EmailAddress => $$.'create-you-1@example.com');
+($ret, $msg) = $you->PrincipalObj->GrantRight(Object =>$queue_obj, Right => 'OwnTicket');
+($ret, $msg) = $you->PrincipalObj->GrantRight(Object =>$queue_obj, Right => 'SeeQueue');
+($ret, $msg) = $you->PrincipalObj->GrantRight(Object =>$queue_obj, Right => 'ShowTicket');
+
+my $nobody = RT::User->new($RT::SystemUser);
+$nobody->Load('nobody');
+
+
+# ----- Create some tickets to test with. Assign them some values to
+# make it easy to sort with.
+
+my @tickets = (
+ [qw[1 10], $me],
+ [qw[2 20], $me],
+ [qw[3 20], $you],
+ [qw[4 30], $you],
+ [qw[5 5], $nobody],
+ [qw[6 55], $nobody],
+ );
+for (@tickets) {
+ my $t = RT::Ticket->new($RT::SystemUser);
+ $t->Create( Queue => $queue_obj->Id,
+ Subject => $_->[0],
+ Owner => $_->[2]->Id,
+ Priority => $_->[1],
+ );
+}
+
+sub check_order {
+ my ($tx, @order) = @_;
+ my @results;
+ while (my $t = $tx->Next) {
+ push @results, $t->Subject;
+ }
+ my $results = join (" ",@results);
+ my $order = join(" ",@order);
+ is( $results, $order );
+}
+
+
+# The real tests start here
+
+my $cme = new RT::CurrentUser( $me );
+my $metx = new RT::Tickets( $cme );
+# Make sure we can sort in both directions on a queue specific field.
+$metx->FromSQL(qq[queue="$queue"] );
+$metx->OrderBy( FIELD => "Custom.Ownership", ORDER => 'ASC' );
+is($metx->Count,6);
+check_order( $metx, qw[2 1 6 5 4 3]);
+
+$metx->OrderBy( FIELD => "Custom.Ownership", ORDER => 'DESC' );
+is($metx->Count,6);
+check_order( $metx, reverse qw[2 1 6 5 4 3]);
+
+
+
+my $cyou = new RT::CurrentUser( $you );
+my $youtx = new RT::Tickets( $cyou );
+# Make sure we can sort in both directions on a queue specific field.
+$youtx->FromSQL(qq[queue="$queue"] );
+$youtx->OrderBy( FIELD => "Custom.Ownership", ORDER => 'ASC' );
+is($youtx->Count,6);
+check_order( $youtx, qw[4 3 6 5 2 1]);
+
+__END__
+
+
diff --git a/rt/lib/t/regression/25scrip_order.t b/rt/lib/t/regression/25scrip_order.t
new file mode 100644
index 0000000..0e11989
--- /dev/null
+++ b/rt/lib/t/regression/25scrip_order.t
@@ -0,0 +1,57 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Test::More tests => 7;
+
+use RT;
+RT::LoadConfig();
+RT::Init;
+
+# {{{ test scrip ordering based on description
+
+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 $id, $msg) = $priority_ten_scrip->Create(
+ Description => "10 set priority $$",
+ Queue => $queue_id,
+ ScripCondition => 'On Create',
+ ScripAction => 'User Defined',
+ CustomPrepareCode => '$RT::Logger->debug("Setting priority to 10..."); return 1;',
+ CustomCommitCode => '$self->TicketObj->SetPriority(10);',
+ Template => 'Blank',
+ Stage => 'TransactionCreate',
+);
+ok($id, "Created priority-10 scrip? ".$msg);
+
+my $priority_five_scrip = RT::Scrip->new($RT::SystemUser);
+($id, $msg) = $priority_ten_scrip->Create(
+ Description => "05 set priority $$",
+ Queue => $queue_id,
+ ScripCondition => 'On Create',
+ ScripAction => 'User Defined',
+ CustomPrepareCode => '$RT::Logger->debug("Setting priority to 5..."); return 1;',
+ CustomCommitCode => '$self->TicketObj->SetPriority(5);',
+ Template => 'Blank',
+ Stage => 'TransactionCreate',
+);
+ok($id, "Created priority-5 scrip? ".$msg);
+
+my $ticket = RT::Ticket->new($RT::SystemUser);
+($id, $msg) = $ticket->Create(
+ Queue => $queue_id,
+ Requestor => 'order@example.com',
+ Subject => "Scrip order test $$",
+);
+ok($ticket->id, "Created ticket? id=$id");
+
+ok($ticket->Priority != 0, "Ticket shouldn't be priority 0");
+ok($ticket->Priority != 5, "Ticket shouldn't be priority 5");
+ok($ticket->Priority == 10, "Ticket should be priority 10");
+
+# }}}
+
+1;
diff --git a/rt/lib/t/regression/26command_line.t b/rt/lib/t/regression/26command_line.t
new file mode 100644
index 0000000..841e2d1
--- /dev/null
+++ b/rt/lib/t/regression/26command_line.t
@@ -0,0 +1,415 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Test::Expect;
+#use Test::More qw/no_plan/;
+use Test::More tests => 202;
+
+use RT;
+RT::LoadConfig();
+RT::Init;
+
+use RT::User;
+use RT::Queue;
+
+my $rt_tool_path = "$RT::BinPath/rt";
+
+# {{{ test configuration options
+
+# config directives:
+# (in $CWD/.rtrc)
+# - server <URL> URL to RT server.
+# - user <username> RT username.
+# - passwd <passwd> RT user's password.
+# - query <RT Query> Default RT Query for list action
+# - orderby <order> Default RT order for list action
+#
+# Blank and #-commented lines are ignored.
+
+# environment variables
+# The following environment variables override any corresponding
+# values defined in configuration files:
+#
+# - RTUSER
+$ENV{'RTUSER'} = 'root';
+# - RTPASSWD
+$ENV{'RTPASSWD'} = 'password';
+# - RTSERVER
+$RT::Logger->debug("Connecting to server at $RT::WebBaseURL...");
+$ENV{'RTSERVER'} = $RT::WebBaseURL;
+# - RTDEBUG Numeric debug level. (Set to 3 for full logs.)
+$ENV{'RTDEBUG'} = '1';
+# - RTCONFIG Specifies a name other than ".rtrc" for the
+# configuration file.
+#
+# - RTQUERY Default RT Query for rt list
+# - RTORDERBY Default order for rt list
+
+
+# }}}
+
+# {{{ test ticket manipulation
+
+# create a ticket
+expect_run(
+ command => "$rt_tool_path shell",
+ prompt => 'rt> ',
+ quit => 'quit',
+);
+expect_send(q{create -t ticket set subject='new ticket' add cc=foo@example.com}, "Creating a ticket...");
+expect_like(qr/Ticket \d+ created/, "Created the ticket");
+expect_handle->before() =~ /Ticket (\d+) created/;
+my $ticket_id = $1;
+ok($ticket_id, "Got ticket id=$ticket_id");
+expect_send(q{create -t ticket set subject='new ticket'}, "Creating a ticket as just a subject...");
+expect_like(qr/Ticket \d+ created/, "Created the ticket");
+
+# make sure we can request things as 'rt foo'
+expect_send(q{rt create -t ticket set subject='rt ticket'}, "Creating a ticket with 'rt create'...");
+expect_like(qr/Ticket \d+ created/, "Created the ticket");
+
+# {{{ test queue manipulation
+
+# creating queues
+expect_send("create -t queue set Name='NewQueue$$'", 'Creating a queue...');
+expect_like(qr/Queue \d+ created/, 'Created the queue');
+expect_handle->before() =~ /Queue (\d+) created/;
+my $queue_id = $1;
+ok($queue_id, "Got queue id=$queue_id");
+# updating users
+expect_send("edit queue/$queue_id set Name='EditedQueue$$'", 'Editing the queue');
+expect_like(qr/Queue $queue_id updated/, 'Edited the queue');
+expect_send("show queue/$queue_id", 'Showing the queue...');
+expect_like(qr/id: queue\/$queue_id/, 'Saw the queue');
+expect_like(qr/Name: EditedQueue$$/, 'Saw the modification');
+TODO: {
+ todo_skip "Listing non-ticket items doesn't work", 2;
+ expect_send("list -t queue 'id > 0'", 'Listing the queues...');
+ expect_like(qr/$queue_id: EditedQueue$$/, 'Found the queue');
+}
+
+# }}}
+
+# add a comment to ticket
+ expect_send("comment -m 'comment-$$' $ticket_id", "Adding a comment...");
+ expect_like(qr/Message recorded/, "Added the comment");
+ ### should test to make sure it actually got added
+ # add correspondance to ticket (?)
+ expect_send("correspond -m 'correspond-$$' $ticket_id", "Adding correspondence...");
+ expect_like(qr/Message recorded/, "Added the correspondence");
+ ### should test to make sure it actually got added
+
+ # add attachments to a ticket
+ # text attachment
+ check_attachment("$RT::BasePath/lib/t/data/lorem-ipsum");
+ # binary attachment
+ check_attachment($RT::MasonComponentRoot.'/NoAuth/images/bplogo.gif');
+
+# change a ticket's Owner
+expect_send("edit ticket/$ticket_id set owner=root", 'Changing owner...');
+expect_like(qr/Ticket $ticket_id updated/, 'Changed owner');
+expect_send("show ticket/$ticket_id -f owner", 'Verifying change...');
+expect_like(qr/Owner: root/, 'Verified change');
+# change a ticket's Requestor
+expect_send("edit ticket/$ticket_id set requestors=foo\@example.com", 'Changing Requestor...');
+expect_like(qr/Ticket $ticket_id updated/, 'Changed Requestor');
+expect_send("show ticket/$ticket_id -f requestors", 'Verifying change...');
+expect_like(qr/Requestors: foo\@example.com/, 'Verified change');
+# change a ticket's Cc
+expect_send("edit ticket/$ticket_id set cc=bar\@example.com", 'Changing Cc...');
+expect_like(qr/Ticket $ticket_id updated/, 'Changed Cc');
+expect_send("show ticket/$ticket_id -f cc", 'Verifying change...');
+expect_like(qr/Cc: bar\@example.com/, 'Verified change');
+# change a ticket's priority
+expect_send("edit ticket/$ticket_id set priority=10", 'Changing priority...');
+expect_like(qr/Ticket $ticket_id updated/, 'Changed priority');
+expect_send("show ticket/$ticket_id -f priority", 'Verifying change...');
+expect_like(qr/Priority: 10/, 'Verified change');
+# move a ticket to a different queue
+expect_send("edit ticket/$ticket_id set queue=EditedQueue$$", 'Changing queue...');
+expect_like(qr/Ticket $ticket_id updated/, 'Changed queue');
+expect_send("show ticket/$ticket_id -f queue", 'Verifying change...');
+expect_like(qr/Queue: EditedQueue$$/, 'Verified change');
+# cannot move ticket to a nonexistent queue
+expect_send("edit ticket/$ticket_id set queue=nonexistent-$$", 'Changing to nonexistent queue...');
+expect_like(qr/queue does not exist/i, 'Errored out');
+expect_send("show ticket/$ticket_id -f queue", 'Verifying lack of change...');
+expect_like(qr/Queue: EditedQueue$$/, 'Verified lack of change');
+# ...
+# change a ticket's ...[other properties]...
+# ...
+# stall a ticket
+expect_send("edit ticket/$ticket_id set status=stalled", 'Changing status to "stalled"...');
+expect_like(qr/Ticket $ticket_id updated/, 'Changed status');
+expect_send("show ticket/$ticket_id -f status", 'Verifying change...');
+expect_like(qr/Status: stalled/, 'Verified change');
+# resolve a ticket
+expect_send("edit ticket/$ticket_id set status=resolved", 'Changing status to "resolved"...');
+expect_like(qr/Ticket $ticket_id updated/, 'Changed status');
+expect_send("show ticket/$ticket_id -f status", 'Verifying change...');
+expect_like(qr/Status: resolved/, 'Verified change');
+# try to set status to an illegal value
+expect_send("edit ticket/$ticket_id set status=quux", 'Changing status to an illegal value...');
+expect_like(qr/illegal value/i, 'Errored out');
+expect_send("show ticket/$ticket_id -f status", 'Verifying lack of change...');
+expect_like(qr/Status: resolved/, 'Verified change');
+
+# }}}
+
+# {{{ display
+
+# show ticket list
+expect_send("ls -s -t ticket -o +id \"Status='resolved'\"", 'Listing resolved tickets...');
+expect_like(qr/$ticket_id: new ticket/, 'Found our ticket');
+# show ticket list verbosely
+expect_send("ls -l -t ticket -o +id \"Status='resolved'\"", 'Listing resolved tickets verbosely...');
+expect_like(qr/id: ticket\/$ticket_id/, 'Found our ticket');
+# show ticket
+expect_send("show -t ticket $ticket_id", 'Showing our ticket...');
+expect_like(qr/id: ticket\/$ticket_id/, 'Got our ticket');
+# show ticket history
+expect_send("show ticket/$ticket_id/history", 'Showing our ticket\'s history...');
+expect_like(qr/Ticket created by root/, 'Got our history');
+TODO: {
+ local $TODO = "Cannot show verbose ticket history right now";
+ # show ticket history verbosely
+ expect_send("show -v ticket/$ticket_id/history", 'Showing our ticket\'s history verbosely...');
+ expect_like(qr/Ticket created by root/, 'Got our history');
+}
+# get attachments from a ticket
+expect_send("show ticket/$ticket_id/attachments", 'Showing ticket attachments...');
+expect_like(qr/id: ticket\/$ticket_id\/attachments/, 'Got our ticket\'s attachments');
+expect_like(qr/Attachments: \d+:\s*\(\S+ \/ \d+\w+\)/, 'Our ticket has an attachment');
+expect_handle->before() =~ /Attachments: (\d+):\s*\((\S+)/;
+my $attachment_id = $1;
+my $attachment_type = $2;
+ok($attachment_id, "Got attachment id=$attachment_id $attachment_type");
+expect_send("show ticket/$ticket_id/attachments/$attachment_id", "Showing attachment $attachment_id...");
+expect_like(qr/ContentType: $attachment_type/, 'Got the attachment');
+
+# }}}
+
+# {{{ test user manipulation
+
+# creating users
+expect_send("create -t user set Name='NewUser$$' EmailAddress='fbar$$\@example.com'", 'Creating a user...');
+expect_like(qr/User \d+ created/, 'Created the user');
+expect_handle->before() =~ /User (\d+) created/;
+my $user_id = $1;
+ok($user_id, "Got user id=$user_id");
+# updating users
+expect_send("edit user/$user_id set Name='EditedUser$$'", 'Editing the user');
+expect_like(qr/User $user_id updated/, 'Edited the user');
+expect_send("show user/$user_id", 'Showing the user...');
+expect_like(qr/id: user\/$user_id/, 'Saw the user');
+expect_like(qr/Name: EditedUser$$/, 'Saw the modification');
+TODO: {
+ todo_skip "Listing non-ticket items doesn't work", 2;
+ expect_send("list -t user 'id > 0'", 'Listing the users...');
+ expect_like(qr/$user_id: EditedUser$$/, 'Found the user');
+}
+
+# }}}
+
+# {{{ test group manipulation
+
+TODO: {
+todo_skip "Group manipulation doesn't work right now", 8;
+# creating groups
+expect_send("create -t group set Name='NewGroup$$'", 'Creating a group...');
+expect_like(qr/Group \d+ created/, 'Created the group');
+expect_handle->before() =~ /Group (\d+) created/;
+my $group_id = $1;
+ok($group_id, "Got group id=$group_id");
+# updating groups
+expect_send("edit group/$group_id set Name='EditedGroup$$'", 'Editing the group');
+expect_like(qr/Group $group_id updated/, 'Edited the group');
+expect_send("show group/$group_id", 'Showing the group...');
+expect_like(qr/id: group\/$group_id/, 'Saw the group');
+expect_like(qr/Name: EditedGroup$$/, 'Saw the modification');
+TODO: {
+ local $TODO = "Listing non-ticket items doesn't work";
+ expect_send("list -t group 'id > 0'", 'Listing the groups...');
+ expect_like(qr/$group_id: EditedGroup$$/, 'Found the group');
+}
+}
+
+# }}}
+
+TODO: {
+todo_skip "Custom field manipulation not yet implemented", 8;
+# {{{ test custom field manipulation
+
+# creating custom fields
+expect_send("create -t custom_field set Name='NewCF$$'", 'Creating a custom field...');
+expect_like(qr/Custom Field \d+ created/, 'Created the custom field');
+expect_handle->before() =~ /Custom Field (\d+) created/;
+my $cf_id = $1;
+ok($cf_id, "Got custom field id=$cf_id");
+# updating custom fields
+expect_send("edit cf/$cf_id set Name='EditedCF$$'", 'Editing the custom field');
+expect_like(qr/Custom field $cf_id updated/, 'Edited the custom field');
+expect_send("show cf/$cf_id", 'Showing the queue...');
+expect_like(qr/id: custom_field\/$cf_id/, 'Saw the custom field');
+expect_like(qr/Name: EditedCF$$/, 'Saw the modification');
+TODO: {
+ todo_skip "Listing non-ticket items doesn't work", 2;
+ expect_send("list -t custom_field 'id > 0'", 'Listing the CFs...');
+ expect_like(qr/$cf_id: EditedCF$$/, 'Found the custom field');
+}
+}
+
+# }}}
+
+# {{{ test merging tickets
+expect_send("create -t ticket set subject='CLIMergeTest1-$$'", 'Creating first ticket to merge...');
+expect_like(qr/Ticket \d+ created/, 'Created first ticket');
+expect_handle->before() =~ /Ticket (\d+) created/;
+my $merge_ticket_A = $1;
+ok($merge_ticket_A, "Got first ticket to merge id=$merge_ticket_A");
+expect_send("create -t ticket set subject='CLIMergeTest2-$$'", 'Creating second ticket to merge...');
+expect_like(qr/Ticket \d+ created/, 'Created second ticket');
+expect_handle->before() =~ /Ticket (\d+) created/;
+my $merge_ticket_B = $1;
+ok($merge_ticket_B, "Got second ticket to merge id=$merge_ticket_B");
+expect_send("merge $merge_ticket_B $merge_ticket_A", 'Merging the tickets...');
+expect_like(qr/Merge completed/, 'Merged the tickets');
+expect_send("show ticket/$merge_ticket_A/history", 'Checking merge on first ticket');
+expect_like(qr/Merged into ticket #$merge_ticket_A by root/, 'Merge recorded in first ticket');
+expect_send("show ticket/$merge_ticket_B/history", 'Checking merge on second ticket');
+expect_like(qr/Merged into ticket #$merge_ticket_A by root/, 'Merge recorded in second ticket');
+# }}}
+
+# {{{ test taking/stealing tickets
+{
+ # create a user; give them privileges to take and steal
+ ### TODO: implement 'grant' in the CLI tool; use that here instead.
+ ### this breaks the abstraction barrier, like, a lot.
+ my $steal_user = RT::User->new($RT::SystemUser);
+ my ($steal_user_id, $msg) = $steal_user->Create( Name => "fooser$$",
+ EmailAddress => "fooser$$\@localhost",
+ Privileged => 1,
+ Password => 'foobar',
+ );
+ ok($steal_user_id, "Created the user? $msg");
+ my $steal_queue = RT::Queue->new($RT::SystemUser);
+ my $steal_queue_id;
+ ($steal_queue_id, $msg) = $steal_queue->Create( Name => "Steal$$" );
+ ok($steal_queue_id, "Got the queue? $msg");
+ ok($steal_queue->id, "queue obj has id");
+ my $status;
+ ($status, $msg) = $steal_user->PrincipalObj->GrantRight( Right => 'ShowTicket', Object => $steal_queue );
+ ok($status, "Gave 'SeeTicket' to our user? $msg");
+ ($status, $msg) = $steal_user->PrincipalObj->GrantRight( Right => 'OwnTicket', Object => $steal_queue );
+ ok($status, "Gave 'OwnTicket' to our user? $msg");
+ ($status, $msg) = $steal_user->PrincipalObj->GrantRight( Right => 'StealTicket', Object => $steal_queue );
+ ok($status, "Gave 'StealTicket' to our user? $msg");
+ ($status, $msg) = $steal_user->PrincipalObj->GrantRight( Right => 'TakeTicket', Object => $steal_queue );
+ ok($status, "Gave 'TakeTicket' to our user? $msg");
+
+ # create a ticket to take/steal
+ expect_send("create -t ticket set queue=$steal_queue_id subject='CLIStealTest-$$'", 'Creating ticket to steal...');
+ expect_like(qr/Ticket \d+ created/, 'Created ticket');
+ expect_handle->before() =~ /Ticket (\d+) created/;
+ my $steal_ticket_id = $1;
+ ok($steal_ticket_id, "Got ticket to steal id=$steal_ticket_id");
+
+ # root takes the ticket
+ expect_send("take $steal_ticket_id", 'root takes the ticket...');
+ expect_like(qr/Owner changed from Nobody to root/, 'root took the ticket');
+
+ # log in as the non-root user
+ #expect_quit(); # this is apparently unnecessary, but I'll leave it in
+ # until I'm sure
+ $ENV{'RTUSER'} = "fooser$$";
+ $ENV{'RTPASSWD'} = 'foobar';
+ expect_run( command => "$rt_tool_path shell", prompt => 'rt> ', quit => 'quit',);
+
+ # user tries to take the ticket, fails
+ # shouldn't be able to 'take' a ticket which someone else has taken out from
+ # under you; that should produce an error. should have to explicitly
+ # 'steal' it back from them. 'steal' can automatically 'take' a ticket,
+ # though.
+ expect_send("take $steal_ticket_id", 'user tries to take the ticket...');
+ expect_like(qr/You can only take tickets that are unowned/, '...and fails.');
+ expect_send("show ticket/$steal_ticket_id -f owner", 'Double-checking...');
+ expect_like(qr/Owner: root/, '...no change.');
+
+ # user steals the ticket
+ expect_send("steal $steal_ticket_id", 'user tries to *steal* the ticket...');
+ expect_like(qr/Owner changed from root to fooser$$/, '...and succeeds!');
+ expect_send("show ticket/$steal_ticket_id -f owner", 'Double-checking...');
+ expect_like(qr/Owner: fooser$$/, '...yup, it worked.');
+
+ # log back in as root
+ #expect_quit(); # ditto
+ $ENV{'RTUSER'} = 'root';
+ $ENV{'RTPASSWD'} = 'password';
+ expect_run( command => "$rt_tool_path shell", prompt => 'rt> ', quit => 'quit',);
+
+ # root steals the ticket back
+ expect_send("steal $steal_ticket_id", 'root steals the ticket back...');
+ expect_like(qr/Owner changed from fooser$$ to root/, '...and succeeds.');
+}
+# }}}
+
+# {{{ test ticket linking
+ my @link_relns = ( 'DependsOn', 'DependedOnBy', 'RefersTo', 'ReferredToBy',
+ 'MemberOf', 'HasMember', );
+ my %display_relns = map { $_ => $_ } @link_relns;
+ $display_relns{HasMember} = 'Members';
+
+ my $link1_id = ok_create_ticket( "LinkTicket1-$$" );
+ my $link2_id = ok_create_ticket( "LinkTicket2-$$" );
+
+ foreach my $reln (@link_relns) {
+ # create link
+ expect_send("link $link1_id $reln $link2_id", "Link by $reln...");
+ expect_like(qr/Created link $link1_id $reln $link2_id/, 'Linked');
+ expect_send("show ticket/$link1_id/links", "Checking creation of $reln...");
+ expect_like(qr/$display_relns{reln}: [\w\d\.\-]+:\/\/[\w\d\.]+\/ticket\/$link2_id/, "Created link $reln");
+
+ # delete link
+ expect_send("link -d $link1_id $reln $link2_id", "Delete $reln...");
+ expect_like(qr/Deleted link $link1_id $reln $link2_id/, 'Deleted');
+ expect_send("show ticket/$link1_id/links", "Checking removal of $reln...");
+ ok( expect_handle->before() !~ /\Q$display_relns{$reln}: \E[\w\d\.\-]+:\/\/[w\d\.]+\/ticket\/$link2_id/, "Removed link $reln" );
+ #expect_unlike(qr/\Q$reln: \E[\w\d\.]+\Q://\E[w\d\.]+\/ticket\/$link2_id/, "Removed link $reln");
+
+ }
+# }}}
+
+
+# helper function
+sub ok_create_ticket {
+ my $subject = shift;
+
+ expect_send("create -t ticket set subject='$subject'", 'Creating ticket...');
+ expect_like(qr/Ticket \d+ created/, "Created ticket '$subject'");
+ expect_handle->before() =~ /Ticket (\d+) created/;
+ my $id = $1;
+ ok($id, "Got ticket id=$id");
+
+ return $id;
+}
+
+# wrap up all the file handling stuff for attachment testing
+sub check_attachment {
+ my $attachment_path = shift;
+ (my $filename = $attachment_path) =~ s/.*\/(.*?)$/$1/;
+ expect_send("comment -m 'attach file' -a $attachment_path $ticket_id", "Adding an attachment ($filename)");
+ expect_like(qr/Message recorded/, "Added the attachment");
+ expect_send("show ticket/$ticket_id/attachments","Finding Attachment");
+ my $attachment_regex = qr/(\d+):\s+$filename/;
+ expect_like($attachment_regex,"Attachment Uploaded");
+ expect_handle->before() =~ $attachment_regex;
+ my $attachment_id = $1;
+ expect_send("show ticket/$ticket_id/attachments/$attachment_id/content","Fetching Attachment");
+ open (my $fh, $attachment_path) or die "Can't open $attachment_path: $!";
+ my $attachment_content = do { local($/); <$fh> };
+ close $fh;
+ chomp $attachment_content;
+ expect_is($attachment_content,"Attachment contains original text");
+}
+
+1;
diff --git a/rt/lib/t/regression/27verp.t b/rt/lib/t/regression/27verp.t
new file mode 100644
index 0000000..856681b
--- /dev/null
+++ b/rt/lib/t/regression/27verp.t
@@ -0,0 +1,9 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Test::More tests => 1;
+
+TODO: {
+ todo_skip "No tests written for VERP yet", 1;
+ ok(1,"a test to skip");
+}