1#!/usr/bin/perl -w 2 3# to run: 4# RT_DBA_USER=root RT_DBA_PASSWORD= prove -lv -I/opt/rt3/lib t/basic.t 5use strict; 6 7use Prophet::Test; 8 9BEGIN { 10 unless (eval 'use RT::Test tests => "no_declare"; 1') { 11 diag $@ if $ENV{'TEST_VERBOSE'}; 12 plan skip_all => 'requires RT 3.8 or newer to run tests.'; 13 } 14} 15 16plan tests => 41; 17use App::SD::Test; 18 19no warnings 'once'; 20 21RT::Handle->InsertData( $RT::EtcPath . '/initialdata' ); 22 23BEGIN { 24 require File::Temp; 25 $ENV{'PROPHET_REPO'} = $ENV{'SD_REPO'} 26 = File::Temp::tempdir( CLEANUP => 1 ) . '/_svb'; 27 diag "export SD_REPO=" . $ENV{'PROPHET_REPO'} . "\n"; 28} 29 30my $IMAGE_FILE = qw|t/data/bplogo.gif|; 31 32$RT::Test::SKIP_REQUEST_WORK_AROUND = 1; 33 34my ( $url, $m ) = RT::Test->started_ok; 35 36use RT::Client::REST; 37use RT::Client::REST::Ticket; 38my $rt = RT::Client::REST->new( server => $url ); 39$rt->login( username => 'root', password => 'password' ); 40 41$url =~ s|http://|http://root:password@|; 42my $sd_rt_url = "rt:$url|General|Status!='resolved'"; 43 44my $ticket = RT::Client::REST::Ticket->new( 45 rt => $rt, 46 queue => 'General', 47 status => 'new', 48 subject => 'Fly Man', 49)->store( text => "Ticket Comment" ); 50 51my $flyman_rt_id = $ticket->id; 52 53my ( $ret, $out, $err ); 54( $ret, $out, $err ) 55 = run_script( 'sd', 56 [ 'clone', '--from', $sd_rt_url, '--non-interactive' ] ); 57my ( $yatta_id, $flyman_id ); 58diag($err) if ($err); 59run_output_matches( 60 'sd', 61 [ 'ticket', 'list', '--regex', '.' ], 62 [qr/(.*?)(?{ $flyman_id = $1 }) Fly Man new/] 63); 64RT::Client::REST::Ticket->new( 65 rt => $rt, 66 id => $ticket->id, 67 status => 'open', 68)->store(); 69 70( $ret, $out, $err ) = run_script( 'sd', [ 'pull', '--from', $sd_rt_url ] ); 71diag($err); 72 73run_output_matches( 74 'sd', 75 [ 'ticket', 'list', '--regex', '.' ], 76 ["$flyman_id Fly Man open"] 77); 78 79# create from sd and push 80 81run_output_matches( 82 'sd', 83 [ 'ticket', 'create', '--', '--summary', 'YATTA', '--status', 'new' ], 84 [qr/Created ticket (\d+)(?{ $yatta_id = $1 })/] 85); 86 87run_output_matches_unordered( 88 'sd', 89 [ 'ticket', 'list', '--regex', '.' ], 90 [ sort "$yatta_id YATTA new", "$flyman_id Fly Man open" ] 91); 92 93( $ret, $out, $err ) = run_script( 'sd', [ 'push', '--to', $sd_rt_url ] ); 94diag($out); 95diag($err); 96my @tix = $rt->search( 97 type => 'ticket', 98 query => "Subject='YATTA'" 99); 100 101ok( scalar @tix, 'YATTA pushed' ); 102 103( $ret, $out, $err ) = run_script( 'sd', [ 'pull', '--from', $sd_rt_url ] ); 104 105run_output_matches_unordered( 106 'sd', 107 [ 'ticket', 'list', '--regex', '.' ], 108 [ "$yatta_id YATTA new", "$flyman_id Fly Man open", ] 109); 110 111RT::Client::REST::Ticket->new( 112 rt => $rt, 113 id => $ticket->id, 114 status => 'stalled', 115)->store(); 116diag("Making ".$ticket->id." stalled"); 117( $ret, $out, $err ) = run_script( 'sd', [ 'pull', '--from', $sd_rt_url ] ); 118diag($out); 119diag($err); 120run_output_matches_unordered( 121 'sd', 122 [ 'ticket', 'list', '--regex', '.' ], 123 [ "$yatta_id YATTA new", "$flyman_id Fly Man stalled", ] 124); 125( $ret, $out, $err ) = run_script( 'sd', [ 'ticket' ,'list', '--regex', '.']); 126 127diag($out); 128diag($err); 129 130RT::Client::REST::Ticket->new( 131 rt => $rt, 132 id => $tix[0], 133 status => 'open', 134)->store(); 135 136diag("===> bad pull"); 137( $ret, $out, $err ) = run_script( 'sd', [ 'pull', '--from', $sd_rt_url ] ); 138run_output_matches_unordered( 139 'sd', 140 [ 'ticket', 'list', '--regex', '.' ], 141 [ "$yatta_id YATTA open", "$flyman_id Fly Man stalled", ] 142); 143 144my $tick = RT::Client::REST::Ticket->new( 145 rt => $rt, 146 id => $tix[0] 147)->retrieve; 148 149my ( $val, $msg ) = $tick->comment( 150 message => 'this is a comment', 151 attachments => [$IMAGE_FILE] 152); 153 154my @attachments = get_rt_ticket_attachments( $tix[0] ); 155 156is( scalar @attachments, 1, "Found our one attachment" ); 157 158( $ret, $out, $err ) = run_script( 'sd', [ 'pull', '--from', $sd_rt_url ] ); 159run_output_matches_unordered( 160 'sd', 161 [ 'ticket', 'list', '--regex', '.' ], 162 [ "$yatta_id YATTA open", "$flyman_id Fly Man stalled", ] 163); 164 165diag("check to see if YATTA has an attachment"); 166 167my $rt_attach_id; 168run_output_matches( 169 sd => [ qw/ticket attachment list --id/, $yatta_id ], 170 [qr/(.*?)(?{ $rt_attach_id = $1 }) bplogo.gif image\/gif/] 171); 172ok($rt_attach_id); 173 174diag( 175 "Check to see if YATTA's attachment is binary-identical to the original one" 176); 177 178my $image_data = Prophet::Util->slurp( $IMAGE_FILE ); 179my ( $contentret, $stdout, $stderr ) 180 = run_script( 'sd', [ qw/attachment content --id/, $rt_attach_id ] ); 181ok( $contentret, "Ran the script ok" ); 182utf8::decode($stdout); 183is( $stdout, $image_data, "We roundtripped some binary" ); 184is( $stderr, '' ); 185 186diag("Add an attachment to YATTA"); 187 188my $MAKEFILE_CONTENT = Prophet::Util->slurp('Makefile.PL'); 189chomp($MAKEFILE_CONTENT); 190my $makefile_attach_uuid; 191run_output_matches( 192 'sd', 193 [ qw/ticket attachment create --id/, $yatta_id, '--file', 'Makefile.PL' ], 194 [qr/Created attachment (\d+) \((.*?)(?{ $makefile_attach_uuid = $2})\)/], 195 [], 196 "Added a attachment" 197); 198 199my ( $makefileret, $makefileout, $makefilerr ) 200 = run_script( 'sd', 201 [ qw/attachment content --uuid/, $makefile_attach_uuid ] ); 202is( $makefileout, $MAKEFILE_CONTENT, "We inserted the makefile correctly" ); 203 204diag("Push the attachment to RT"); 205 206( $ret, $out, $err ) = run_script( 'sd', [ 'push', '--to', $sd_rt_url ] ); 207 208diag("Check to see if the RT ticket has two attachments"); 209my @two_attachments = sort { $a->file_name cmp $b->file_name } 210 get_rt_ticket_attachments( $tix[0] ); 211is( scalar @two_attachments, 2, " I have two attachments on the RT side!" ); 212 213my $makefile = shift @two_attachments; 214my $logo = shift @two_attachments; 215 216is( $logo->file_name, 'bplogo.gif' ); 217is( $makefile->file_name, 'Makefile.PL' ); 218is( $makefile->content, $MAKEFILE_CONTENT, 219 " The makefile's content was roundtripped ot rt ok" ); 220 221is( $logo->content, 222 scalar Prophet::Util->slurp( $IMAGE_FILE ), 223 " The image's content was roundtripped ot rt ok" 224); 225 226#diag $uuid; 227# testing adding CCs to tickets 228 229$tick->add_cc('hiro@example.com'); # stored 230my ( $tval, $tmsg ) = $tick->store; 231ok( $tval, $tmsg ); 232 233my $fetched_tick = RT::Client::REST::Ticket->new( 234 rt => $rt, 235 id => $tick->id 236)->retrieve; 237 238diag( $fetched_tick->subject ); 239my (@x) = $fetched_tick->cc; 240is_deeply( \@x, ['hiro@example.com'] ); 241( $ret, $out, $err ) = run_script( 'sd', [ 'pull', '--from', $sd_rt_url ] ); 242ok( $ret, $out ); 243 244( $ret, $out, $err ) 245 = run_script( 'sd', [ 'ticket', 'show', '--verbose', '--id', $yatta_id ] ); 246 247like( $out, qr/cc:\s+set\s+to\s+hiro\@example.com/ ); 248 249diag("resolve and comment on a ticket"); 250 251$ticket = RT::Client::REST::Ticket->new( 252 rt => $rt, 253 queue => 'General', 254 status => 'new', 255 subject => 'helium', 256)->store( text => "Ticket Comment" ); 257 258( $ret, $out, $err ) = run_script( 'sd', [ 'pull', '--from', $sd_rt_url ] ); 259ok( $ret, $out ); 260 261my $helium_id; 262run_output_matches( 263 'sd', 264 [ 'ticket', 'list', '--regex', 'helium' ], 265 [qr/(.*?)(?{ $helium_id = $1 }) helium new/] 266); 267 268( $ret, $out, $err ) 269 = run_script( 'sd', 270 [ 'ticket', 'comment', $helium_id, '--content', 'helium is a noble gas' ] ); 271ok( $ret, $out ); 272like( $out, qr/Created comment/ ); 273 274 275{ # resolve a ticket 276 ( $ret, $out, $err ) 277 = run_script( 'sd', [ 'ticket', 'resolve', $helium_id ] ); 278 ok( $ret, $out ); 279 like( $out, qr/Ticket .* updated/ ); 280 281 ( $ret, $out, $err ) = run_script( 'sd', [ 'push', '--to', $sd_rt_url ] ); 282 ok( $ret, $out ); 283 284 ( $ret, $out, $err ) = run_script( 'sd', [ 'pull', '--from', $sd_rt_url ] ); 285 ok( $ret, $out ); 286 287 my $fetched_ticket = RT::Client::REST::Ticket->new( 288 rt => $rt, 289 id => $ticket->id 290 )->retrieve; 291 292 is( $fetched_ticket->status, "resolved" ); 293} 294 295{ # delete a ticket for reals 296 ( $ret, $out, $err ) 297 = run_script( 'sd', [ 'ticket','delete', $flyman_id]); 298 ok( $ret, $out ); 299 like( $out, qr/Ticket .* deleted/i ); 300 301 ( $ret, $out, $err ) = run_script( 'sd', [ 'push', '--to', $sd_rt_url ] ); 302 ok( $ret, $out ); 303 diag($out); 304 ( $ret, $out, $err ) = run_script( 'sd', [ 'pull', '--from', $sd_rt_url ] ); 305 ok( $ret, $out ); 306 307 my $fetched_ticket = RT::Client::REST::Ticket->new( 308 rt => $rt, 309 id => $flyman_rt_id 310 )->retrieve; 311 TODO: { 312 local $TODO = "Deleting tickets in RT still doesn't play nicely with SD"; 313 is( $fetched_ticket->status, "deleted" ); 314} 315} 316 317 318 319 320 321 322sub get_rt_ticket_attachments { 323 my $ticket = shift; 324 325 my $attachments = RT::Client::REST::Ticket->new( rt => $rt, id => $ticket ) 326 ->attachments(); 327 my $iterator = $attachments->get_iterator; 328 my @attachments; 329 while ( my $att = &$iterator ) { 330 if ( $att->file_name ) { 331 push @attachments, $att; 332 } 333 } 334 return @attachments; 335} 336 3371; 338 339