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