diff options
Diffstat (limited to 'rt/lib/t/regression')
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 000000000..96674cacf --- /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 6d10221c1..a402c7376 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 d3376d011..3b8619b66 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 '300'/, "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 f2e62c98d..29e56d67b 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 09e6e6f84..a175ffaee 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. ¨auts_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 000000000..7780e8c0d --- /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 1bdc38a69..5fc502926 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 e30a59bef..efd87016d 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 d34627705..6c35a0717 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 012d73381..c352bbcf8 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 9cc4aa441..210d4fe33 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 945bbcfb0..fdac94e63 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 6fdf61405..c8e57eadd 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 000000000..df663a1bd --- /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 000000000..ea2b5b858 --- /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 000000000..8e53f4486 --- /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 000000000..cf77e35cc --- /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 000000000..7744787c0 --- /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 000000000..e6903b433 --- /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 be04599bc..7f9990a30 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 958273c5c..bec61b5ad 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 dd87de989..1df7e72b2 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 000000000..fc9436a20 --- /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 000000000..adc38adb5 --- /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 000000000..e90fa36b2 --- /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 000000000..665c325a6 --- /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 000000000..0e11989e6 --- /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 000000000..841e2d1c2 --- /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 000000000..856681be1 --- /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"); +} |