[Bps-public-commit] r12167 - in sd/trunk: . bin lib/App/SD/Model lib/App/SD/Replica/RT t

jesse at bestpractical.com jesse at bestpractical.com
Thu May 8 17:47:49 EDT 2008


Author: jesse
Date: Thu May  8 17:47:48 2008
New Revision: 12167

Modified:
   sd/trunk/   (props changed)
   sd/trunk/bin/sd
   sd/trunk/lib/App/SD/Model/Attachment.pm
   sd/trunk/lib/App/SD/Replica/RT.pm
   sd/trunk/lib/App/SD/Replica/RT/PullEncoder.pm
   sd/trunk/t/attachment-content.t
   sd/trunk/t/sd-attachments.t
   sd/trunk/t/sd-rt.t

Log:
 r30665 at 106 (orig r12158):  jesse | 2008-05-08 17:37:08 -0400
 - Merged from local
  r30662 at 106:  jesse | 2008-05-08 17:36:57 -0400
  * Added support for round-tripping attachments to rt. 
  
 


Modified: sd/trunk/bin/sd
==============================================================================
--- sd/trunk/bin/sd	(original)
+++ sd/trunk/bin/sd	Thu May  8 17:47:48 2008
@@ -27,6 +27,8 @@
 }
 # override args to feed in that ticket's uuid as an argument to the comment
 
+
+
 package App::SD::CLI::Command::Attachment;
 use constant record_class => 'App::SD::Model::Attachment';
 
@@ -38,8 +40,9 @@
     my $self = shift;
 
     if  (my $file = file(delete $self->args->{'file'})) {
-        $self->args->{'tricksy'} = 'abc';
-        $self->args->{'content'} = $file->slurp();
+        my $content = $file->slurp();
+        chomp $content;
+        $self->args->{'content'} = $content;
         $self->args->{'name'} = $file->basename;
     }
 
@@ -128,24 +131,6 @@
 
 }
 
-package App::SD::CLI::Command::Ticket::Attachments;
-use base qw/App::SD::CLI::Command::Ticket/;
-
-sub run {
-    my $self = shift;
-    my $record = $self->_get_record();
-    $record->load( uuid => $self->cli->uuid );
-    unless (@{$record->attachments}) {
-        print "No attachments found\n";
-    }
-
-    for (@{$record->attachments}) {
-        print "attachment id: ".$_->uuid."\n";
-        print "name: ".$_->prop('name')."\n";
-        print "content_type: ".$_->prop('content_type')."\n";
-    }
-
-}
 
 package App::SD::CLI::Command::Merge;
 use base qw/App::SD::CLI::Command Prophet::CLI::Command::Merge/;

Modified: sd/trunk/lib/App/SD/Model/Attachment.pm
==============================================================================
--- sd/trunk/lib/App/SD/Model/Attachment.pm	(original)
+++ sd/trunk/lib/App/SD/Model/Attachment.pm	Thu May  8 17:47:48 2008
@@ -8,7 +8,7 @@
 use constant collection_class => 'App::SD::Collection::Attachment';
 use constant record_type => 'attachment';
 
-use constant summary_format => '%u %s';
+use constant summary_format => '%u %s %s';
 use constant summary_props => qw(name content_type);
 
 __PACKAGE__->register_reference( ticket => 'App::SD::Model::Ticket');

Modified: sd/trunk/lib/App/SD/Replica/RT.pm
==============================================================================
--- sd/trunk/lib/App/SD/Replica/RT.pm	(original)
+++ sd/trunk/lib/App/SD/Replica/RT.pm	Thu May  8 17:47:48 2008
@@ -5,15 +5,15 @@
 use base qw/Prophet::ForeignReplica/;
 use Params::Validate qw(:all);
 use UNIVERSAL::require;
+    use File::Temp ();
+    use Path::Class;
 use Prophet::ChangeSet;
 
-
 use Memoize;
 use constant scheme => 'rt';
 
 __PACKAGE__->mk_accessors(qw/rt rt_url rt_queue rt_query/);
 
-
 =head1 NOTES ON PUSH
 
 If the remote storage (RT) can not represent a whole changeset along with the prophet changeset uuid, then we need to 
@@ -71,14 +71,12 @@
 
 sub setup {
     my $self = shift;
-    
+
     # Require rather than use to defer load
-    require RT::Client::REST       ;
-    require RT::Client::REST::User ;
+    require RT::Client::REST;
+    require RT::Client::REST::User;
     require RT::Client::REST::Ticket;
 
-
-
     my ( $server, $type, $query ) = $self->{url} =~ m/^(.*?)\|(.*?)\|(.*)$/
         or die "Can't parse rt server spec";
     my $uri = URI->new($server);
@@ -92,17 +90,19 @@
     $self->rt_query( $query . " AND Queue = '$type'" );
     $self->rt( RT::Client::REST->new( server => $server ) );
 
-    ( $username, $password ) = $self->prompt_for_login( $uri, $username ) unless $password;
+    ( $username, $password ) = $self->prompt_for_login( $uri, $username )
+        unless $password;
 
     $self->rt->login( username => $username, password => $password );
 
-        $self->SUPER::setup(@_);
+    $self->SUPER::setup(@_);
 
 }
 
 sub record_pushed_transactions {
     my $self = shift;
-    my %args = validate( @_, { ticket => 1, changeset => { isa => 'Prophet::ChangeSet' } } );
+    my %args = validate( @_,
+        { ticket => 1, changeset => { isa => 'Prophet::ChangeSet' } } );
 
     for my $txn (
         reverse RT::Client::REST::Ticket->new(
@@ -111,8 +111,14 @@
         )->transactions->get_iterator->()
         )
     {
-        last if $txn->id <= $self->last_changeset_from_source( $args{changeset}->original_source_uuid );
-        $self->record_pushed_transaction( transaction => $txn->id, changeset => $args{'changeset'} );
+        last
+            if $txn->id <= $self->last_changeset_from_source(
+                    $args{changeset}->original_source_uuid
+            );
+        $self->record_pushed_transaction(
+            transaction => $txn->id,
+            changeset   => $args{'changeset'}
+        );
     }
 }
 
@@ -136,7 +142,8 @@
 
 sub _txn_storage {
     my $self = shift;
-    return $self->state_handle->metadata_storage( $TXN_METATYPE, 'prophet-txn-source' );
+    return $self->state_handle->metadata_storage( $TXN_METATYPE,
+        'prophet-txn-source' );
 }
 
 sub prophet_has_seen_transaction {
@@ -147,11 +154,14 @@
 
 sub record_pushed_transaction {
     my $self = shift;
-    my %args = validate( @_, { transaction => 1, changeset => { isa => 'Prophet::ChangeSet' } } );
+    my %args = validate( @_,
+        { transaction => 1, changeset => { isa => 'Prophet::ChangeSet' } } );
 
     $self->_txn_storage->(
         $self->uuid . '-txn-' . $args{transaction},
-        join( ':', $args{changeset}->original_source_uuid, $args{changeset}->original_sequence_no )
+        join( ':',
+            $args{changeset}->original_source_uuid,
+            $args{changeset}->original_sequence_no )
     );
 }
 
@@ -163,34 +173,53 @@
 sub remote_id_for_uuid {
     my ( $self, $uuid_for_remote_id ) = @_;
 
+
     # XXX: should not access CLI handle
-    my $ticket = Prophet::Record->new( handle => Prophet::CLI->new->handle, type => 'ticket' );
+    my $ticket = Prophet::Record->new(
+        handle => Prophet::CLI->new->app_handle->handle,
+        type   => 'ticket'
+    );
     $ticket->load( uuid => $uuid_for_remote_id );
-    return $ticket->prop( $self->uuid . '-id' );
+    my $id =  $ticket->prop( $self->uuid . '-id' );
+    return $id;
+}
+
+sub _set_remote_id_for_uuid {
+    my $self = shift;
+    my %args = validate(
+        @_,
+        {   uuid      => 1,
+            remote_id => 1
+        }
+    );
+
+    # XXX: should not access CLI handle
+    my $ticket = Prophet::Record->new(
+        handle => Prophet::CLI->new->app_handle->handle,
+        type   => 'ticket'
+    );
+    $ticket->load( uuid => $args{'uuid'});
+    $ticket->set_props( props => {  $self->uuid.'-id' => $args{'remote_id'}});
+
 }
 
+
 sub uuid_for_remote_id {
     my ( $self, $id ) = @_;
-    return $self->_lookup_remote_id($id) || $self->uuid_for_url( $self->rt_url . "/ticket/$id" );
+    return $self->_lookup_uuid_for_remote_id($id) || $self->uuid_for_url( $self->rt_url . "/ticket/$id" );
 }
 
-sub _lookup_remote_id {
+sub _lookup_uuid_for_remote_id {
     my $self = shift;
     my ($id) = validate_pos( @_, 1 );
 
     return $self->_remote_id_storage( $self->uuid_for_url( $self->rt_url . "/ticket/$id" ) );
 }
 
-sub _set_remote_id {
+sub _set_uuid_for_remote_id {
     my $self = shift;
-    my %args = validate(
-        @_,
-        {   uuid      => 1,
-            remote_id => 1
-        }
-    );
-    return $self->_remote_id_storage( $self->uuid_for_url( $self->rt_url . "/ticket/" . $args{'remote_id'} ),
-        $args{uuid} );
+    my %args = validate( @_, {   uuid      => 1, remote_id => 1 });
+    return $self->_remote_id_storage( $self->uuid_for_url( $self->rt_url . "/ticket/" . $args{'remote_id'} ), $args{uuid});
 }
 
 sub record_pushed_ticket {
@@ -201,21 +230,37 @@
             remote_id => 1
         }
     );
-    $self->_set_remote_id(%args);
+    $self->_set_uuid_for_remote_id(%args);
+    $self->_set_remote_id_for_uuid(%args);
 }
 
 sub _integrate_change {
     my $self = shift;
-    my ( $change, $changeset ) = validate_pos( @_, { isa => 'Prophet::Change' }, { isa => 'Prophet::ChangeSet' } );
+    my ( $change, $changeset ) = validate_pos(
+        @_,
+        { isa => 'Prophet::Change' },
+        { isa => 'Prophet::ChangeSet' }
+    );
     my $id;
     eval {
-        if ( $change->record_type eq 'ticket' and $change->change_type eq 'add_file' )
+        if (    $change->record_type eq 'ticket'
+            and $change->change_type eq 'add_file' 
+    )
         {
             $id = $self->integrate_ticket_create( $change, $changeset );
-            $self->record_pushed_ticket( uuid => $change->record_uuid, remote_id => $id );
-
-        } elsif ( $change->record_type eq 'comment' ) {
-
+            $self->record_pushed_ticket(
+                uuid      => $change->record_uuid,
+                remote_id => $id
+            );
+
+        } elsif ( $change->record_type eq 'attachment'
+            and $change->change_type eq 'add_file' 
+        
+        ) {
+            $id = $self->integrate_attachment( $change, $changeset );
+        } elsif ( $change->record_type eq 'comment' 
+            and $change->change_type eq 'add_file' 
+        ) {
             $id = $self->integrate_comment( $change, $changeset );
         } elsif ( $change->record_type eq 'ticket' ) {
             $id = $self->integrate_ticket_update( $change, $changeset );
@@ -224,7 +269,10 @@
             return undef;
         }
 
-        $self->record_pushed_transactions( ticket => $id, changeset => $changeset );
+        $self->record_pushed_transactions(
+            ticket    => $id,
+            changeset => $changeset
+        );
 
     };
     warn $@ if $@;
@@ -233,7 +281,11 @@
 
 sub integrate_ticket_update {
     my $self = shift;
-    my ( $change, $changeset ) = validate_pos( @_, { isa => 'Prophet::Change' }, { isa => 'Prophet::ChangeSet' } );
+    my ( $change, $changeset ) = validate_pos(
+        @_,
+        { isa => 'Prophet::Change' },
+        { isa => 'Prophet::ChangeSet' }
+    );
 
     # Figure out the remote site's ticket ID for this change's record
     my $remote_ticket_id = $self->remote_id_for_uuid( $change->record_uuid );
@@ -248,7 +300,11 @@
 
 sub integrate_ticket_create {
     my $self = shift;
-    my ( $change, $changeset ) = validate_pos( @_, { isa => 'Prophet::Change' }, { isa => 'Prophet::ChangeSet' } );
+    my ( $change, $changeset ) = validate_pos(
+        @_,
+        { isa => 'Prophet::Change' },
+        { isa => 'Prophet::ChangeSet' }
+    );
 
     # Build up a ticket object out of all the record's attributes
     my $ticket = RT::Client::REST::Ticket->new(
@@ -262,26 +318,45 @@
 
 sub integrate_comment {
     my $self = shift;
-    my ($change) = validate_pos( @_, { isa => 'Prophet::Change' } );
+    my ($change, $changeset) = validate_pos( @_, { isa => 'Prophet::Change' }, {isa => 'Prophet::ChangeSet'} );
 
     # Figure out the remote site's ticket ID for this change's record
 
     my %props = map { $_->name => $_->new_value } $change->prop_changes;
 
-    my $id     = $self->remote_id_for_uuid( $props{'ticket'} );
-    my $ticket = RT::Client::REST::Ticket->new(
-        rt => $self->rt,
-        id => $id
-    );
-    if ( $props{'type'} eq 'comment' ) {
-        $ticket->comment( message => $props{'content'} );
-    } else {
-        $ticket->correspond( message => $props{'content'} );
+    my $ticket_id     = $self->remote_id_for_uuid( $props{'ticket'} );
+    my $ticket = RT::Client::REST::Ticket->new( rt => $self->rt, id => $ticket_id);
 
+    my %content = ( message => $props{'content'},   
+                );
+
+    if (  ($props{'type'} ||'') eq 'comment' ) {
+        $ticket->comment( %content);
+    } else {
+        $ticket->correspond(%content);
     }
-    return $id;
+    return $ticket_id;
+} 
+
+sub integrate_attachment {
+    my ($self, $change, $changeset ) = validate_pos( @_, { isa => 'App::SD::Replica::RT'}, { isa => 'Prophet::Change' }, { isa => 'Prophet::ChangeSet' });
+
+
+    my %props = map { $_->name => $_->new_value } $change->prop_changes;
+    my $ticket_id = $self->remote_id_for_uuid( $props{'ticket'});
+    my $ticket = RT::Client::REST::Ticket->new( rt => $self->rt, id => $ticket_id );
+
+    my $tempdir = File::Temp::tempdir( CLEANUP => 1 );
+    my $file = file( $tempdir => ( $props{'name'} || 'unnamed' ) );
+    my $fh = $file->openw;
+    print $fh $props{content};
+    close $fh;
+    my %content = ( message     => '(See attachments)', attachments => ["$file"]);
+    $ticket->correspond(%content);
+    return $ticket_id;
 }
 
+
 sub _recode_props_for_integrate {
     my $self = shift;
     my ($change) = validate_pos( @_, { isa => 'Prophet::Change' } );
@@ -326,7 +401,8 @@
     my $first_rev = ( $args{'after'} + 1 ) || 1;
 
     require App::SD::Replica::RT::PullEncoder;
-    my $recoder = App::SD::Replica::RT::PullEncoder->new( { sync_source => $self } );
+    my $recoder
+        = App::SD::Replica::RT::PullEncoder->new( { sync_source => $self } );
     for my $id ( $self->find_matching_tickets ) {
 
         # XXX: _recode_transactions should ignore txn-id <= $first_rev
@@ -334,7 +410,11 @@
             for @{
             $recoder->run(
                 ticket => $self->rt->show( type => 'ticket', id => $id ),
-                transactions => $self->find_matching_transactions( ticket => $id, starting_transaction => $first_rev )
+                transactions => $self->find_matching_transactions(
+                    ticket               => $id,
+                    starting_transaction => $first_rev
+                ),
+
             )
             };
     }
@@ -350,9 +430,26 @@
     my %args = validate( @_, { ticket => 1, starting_transaction => 1 } );
     my @txns;
     for my $txn ( sort $self->rt->get_transaction_ids( parent_id => $args{ticket} ) ) {
-        next if $txn < $args{'starting_transaction'};        # Skip things we've pushed
+        next if $txn < $args{'starting_transaction'}; # Skip things we've pushed
         next if $self->prophet_has_seen_transaction($txn);
-        push @txns, $self->rt->get_transaction( parent_id => $args{ticket}, id => $txn, type => 'ticket' );
+        my $txn_hash = $self->rt->get_transaction(
+            parent_id => $args{ticket},
+            id        => $txn,
+            type      => 'ticket'
+        );
+        if ( my $attachments = delete $txn_hash->{'Attachments'} ) {
+            foreach my $attach ( split( /\n/, $attachments ) ) {
+                next unless ( $attach =~ /^(\d+):/ );
+                my $id = $1;
+                my $a  = $self->rt->get_attachment( parent_id => $args{'ticket'}, id        => $id);
+
+                push( @{ $txn_hash->{_attachments} }, $a )
+                    if ( $a->{Filename} );
+
+            }
+
+        }
+        push @txns, $txn_hash;
     }
     return \@txns;
 }

Modified: sd/trunk/lib/App/SD/Replica/RT/PullEncoder.pm
==============================================================================
--- sd/trunk/lib/App/SD/Replica/RT/PullEncoder.pm	(original)
+++ sd/trunk/lib/App/SD/Replica/RT/PullEncoder.pm	Thu May  8 17:47:48 2008
@@ -14,7 +14,7 @@
 
 sub run {
     my $self = shift;
-    my %args = validate( @_, { ticket => 1, transactions => 1 } );
+    my %args = validate( @_, { ticket => 1, transactions => 1, attachments => 0 } );
 
     $args{'ticket'}->{'id'} =~ s/^ticket\///g;
 
@@ -26,8 +26,16 @@
 
     my @changesets;
     for my $txn ( sort { $b->{'id'} <=> $a->{'id'} } @{ $args{'transactions'} } ) {
-        delete $txn->{'OldValue'} if ( $txn->{'OldValue'} eq '');
-        delete $txn->{'NewValue'} if ( $txn->{'NewValue'} eq '');
+            my $changeset = $self->txn_to_changeset($txn, $ticket, $create_state);
+            unshift @changesets, $changeset unless $changeset->is_empty;
+        }
+
+    return \@changesets;
+}
+
+
+sub txn_to_changeset {
+    my ($self, $txn, $ticket, $create_state) = (@_);
 
         if ( my $sub = $self->can( '_recode_txn_' . $txn->{'Type'} ) ) {
             my $changeset = Prophet::ChangeSet->new(
@@ -41,25 +49,44 @@
                 next;
             }
 
-            $sub->(
-                $self,
-                ticket       => $ticket,
-                create_state => $create_state,
-                txn          => $txn,
-                changeset    => $changeset
-            );
+            delete $txn->{'OldValue'} if ( $txn->{'OldValue'} eq '');
+            delete $txn->{'NewValue'} if ( $txn->{'NewValue'} eq '');
+
+            $sub->( $self, ticket       => $ticket, create_state => $create_state, txn          => $txn, changeset    => $changeset);
             $self->translate_prop_names($changeset);
 
-            unshift @changesets, $changeset unless $changeset->is_empty;
+            if (my $attachments = delete $txn->{'_attachments'}) {
+               foreach my $attach (@$attachments) { 
+                    $self->_recode_attachment_create( ticket => $ticket, txn => $txn, changeset =>$changeset, attachment => $attach); 
+               }
+            }
+
+            return $changeset;
         } else {
-            warn "not handling txn type $txn->{Type} for $txn->{id} (Ticket $args{ticket}{id}) yet";
+            warn "not handling txn type $txn->{Type} for $txn->{id} yet";
             die YAML::Dump($txn);
         }
-
     }
-    return \@changesets;
+
+
+sub _recode_attachment_create {
+    my $self   = shift;
+    my %args   = validate( @_, { ticket => 1, txn => 1, changeset => 1, attachment => 1 } );
+    my $change = Prophet::Change->new(
+        {   record_type => 'attachment',
+            record_uuid => $self->sync_source->uuid_for_url( $self->sync_source->rt_url . "/attachment/" . $args{'attachment'}->{'id'} ),
+            change_type => 'add_file'
+        }
+    );
+    $change->add_prop_change( name => 'content_type', old  => undef, new  => $args{'attachment'}->{'ContentType'});
+    $change->add_prop_change( name => 'creator', old  => undef, new  => $self->resolve_user_id_to( email => $args{'attachment'}->{'Creator'}));
+    $change->add_prop_change( name => 'content', old  => undef, new  => $args{'attachment'}->{'Content'});
+    $change->add_prop_change( name => 'name', old  => undef, new  => $args{'attachment'}->{'Filename'});
+    $change->add_prop_change( name => 'ticket', old  => undef, new  => $args{ticket}->{uuid},);
+    $args{'changeset'}->add_change( { change => $change } );
 }
 
+
 sub _recode_txn_CommentEmailRecord { return; }
 
 sub _recode_txn_EmailRecord     { return; }
@@ -189,32 +216,14 @@
     my %args   = validate( @_, { ticket => 1, txn => 1, create_state => 1, changeset => 1 } );
     my $change = Prophet::Change->new(
         {   record_type => 'comment',
-            record_uuid =>
-                $self->sync_source->uuid_for_url( $self->sync_source->rt_url . "/transaction/" . $args{'txn'}->{'id'} ),
+            record_uuid => $self->sync_source->uuid_for_url( $self->sync_source->rt_url . "/transaction/" . $args{'txn'}->{'id'} ),
             change_type => 'add_file'
         }
     );
-    $change->add_prop_change(
-        name => 'type',
-        old  => undef,
-        new  => $args{'txn'}->{'Type'}
-    );
-
-    $change->add_prop_change(
-        name => 'creator',
-        old  => undef,
-        new  => $args{'txn'}->{'Creator'}
-    );
-    $change->add_prop_change(
-        name => 'content',
-        old  => undef,
-        new  => $args{'txn'}->{'Content'}
-    );
-    $change->add_prop_change(
-        name => 'ticket',
-        old  => undef,
-        new  => $args{ticket}->{uuid},
-    );
+    $change->add_prop_change( name => 'type', old  => undef, new  => $args{'txn'}->{'Type'});
+    $change->add_prop_change( name => 'creator', old  => undef, new  => $self->resolve_user_id_to( email => $args{'txn'}->{'Creator'}));
+    $change->add_prop_change( name => 'content', old  => undef, new  => $args{'txn'}->{'Content'});
+    $change->add_prop_change( name => 'ticket', old  => undef, new  => $args{ticket}->{uuid},);
     $args{'changeset'}->add_change( { change => $change } );
 }
 

Modified: sd/trunk/t/attachment-content.t
==============================================================================
--- sd/trunk/t/attachment-content.t	(original)
+++ sd/trunk/t/attachment-content.t	Thu May  8 17:47:48 2008
@@ -38,9 +38,8 @@
 run_output_matches('sd', [qw/ticket attachment create --uuid/, $yatta_uuid, '--file', $file], [qr/Created attachment (.*?)(?{ $attachment_uuid = $1})$/], [], "Added a attachment");
 ok($attachment_uuid);
 
-run_output_matches('sd', [qw/ticket attachments --uuid/, $yatta_uuid], [qr/^attachment id: $attachment_uuid/, 
-    'name: paper_order.doc', 
-    'content_type: text/plain' ], [], "Found the attachment, but doesn't show the content");
+run_output_matches('sd', [qw/ticket attachment list --uuid/, $yatta_uuid], [$attachment_uuid . " paper_order.doc text/plain"],
+    , [], "Found the attachment, but doesn't show the content");
 
 run_output_matches('sd', [qw/attachment content --uuid/, $attachment_uuid], ['5 tonnes of hard white'],[], "We got the content");
 
@@ -53,7 +52,6 @@
 run_output_matches('sd', [qw/ticket attachment create --uuid/, $yatta_uuid, '--file', $image_file], [qr/Created attachment (.*?)(?{ $image_attach = $1})$/], [], "Added a attachment");
 
 my $image_data = file($image_file)->slurp;
-
 my ($ret, $stdout, $stderr) = run_script('sd', [qw/attachment content --uuid/, $image_attach]);
 ok($ret, "Ran the script ok");
 is($stdout, $image_data, "We roundtripped some binary");

Modified: sd/trunk/t/sd-attachments.t
==============================================================================
--- sd/trunk/t/sd-attachments.t	(original)
+++ sd/trunk/t/sd-attachments.t	Thu May  8 17:47:48 2008
@@ -27,11 +27,7 @@
 run_output_matches('sd', [qw/ticket attachment create --uuid/, $yatta_uuid, '--name', "paper_order.doc"], [qr/Created attachment (.*?)(?{ $attachment_uuid = $1})$/], [], "Added a attachment");
 ok($attachment_uuid);
 
-run_output_matches('sd', [qw/ticket attachments --uuid/, $yatta_uuid], [qr/^attachment id: $attachment_uuid/, 
-    
-    'name: paper_order.doc', 
-    
-    'content_type: text/plain' ], [], "Found the attachment");
+run_output_matches('sd', [qw/ticket attachment list --uuid/, $yatta_uuid], [$attachment_uuid .  ' paper_order.doc text/plain',], [], "Found the attachment");
 
 run_output_matches(
     'sd',

Modified: sd/trunk/t/sd-rt.t
==============================================================================
--- sd/trunk/t/sd-rt.t	(original)
+++ sd/trunk/t/sd-rt.t	Thu May  8 17:47:48 2008
@@ -6,12 +6,13 @@
 use strict;
 
 use Test::More;
+use Path::Class;
 unless (eval 'use RT::Test; 1') {
     diag $@;
     plan skip_all => 'requires 3.7 or newer to run tests.';
 }
 
-eval 'use Prophet::Test tests => 11';
+eval 'use Prophet::Test tests => 23';
 
 no warnings 'once';
 
@@ -21,9 +22,13 @@
 BEGIN {
     require File::Temp;
     $ENV{'PROPHET_REPO'} = $ENV{'SD_REPO'} = File::Temp::tempdir( CLEANUP => 0 ) . '/_svb';
-    warn $ENV{'PROPHET_REPO'};
+    diag "export SD_REPO=".$ENV{'PROPHET_REPO'} ."\n";
 }
 
+
+my $IMAGE_FILE = qw|t/data/bplogo.gif|;
+
+
 my ( $url, $m ) = RT::Test->started_ok;
 
 use RT::Client::REST;
@@ -32,7 +37,6 @@
 $rt->login( username => 'root', password => 'password' );
 
 $url =~ s|http://|http://root:password@|;
-warn $url;
 my $sd_rt_url = "rt:$url|General|Status!='resolved'";
 
 my $ticket = RT::Client::REST::Ticket->new(
@@ -45,7 +49,8 @@
 my ( $ret, $out, $err );
 ( $ret, $out, $err ) = run_script( 'sd', [ 'pull', '--from',  $sd_rt_url ] );
 my ( $yatta_uuid, $flyman_uuid );
-run_output_matches( 'sd', [ 'ticket', 'list', '--regex', '.' ], [qr/(.*?)(?{ $flyman_uuid = $1 }) Fly Man new/] );
+run_output_matches( 'sd', [ 'ticket', 'list', '--regex', '.' ], 
+    [qr/(.*?)(?{ $flyman_uuid = $1 }) Fly Man new/] );
 RT::Client::REST::Ticket->new(
     rt     => $rt,
     id     => $ticket->id,
@@ -119,19 +124,11 @@
     rt => $rt,
     id => $tix[0])->retrieve;
 
-warn $tick->subject;
-warn $tick->status;
-my ($val,$msg) = $tick->comment( message => 'this is a comment', attachments => [qw|t/data/bplogo.gif|]);
-    
-    my $attachments = RT::Client::REST::Ticket->new( rt => $rt, id => $tix[0])->attachments();
-    my $iterator = $attachments->get_iterator;
-    my @attachments;
-    while (my $att = &$iterator) { 
-        if ( $att->file_name eq 'bplogo.gif'  ) {
-        push @attachments, $att ;
-        warn "goto ne";
-    }
-    }
+my ($val,$msg) = $tick->comment( message => 'this is a comment', attachments => [$IMAGE_FILE]);
+
+
+my @attachments = get_rt_ticket_attachments($tix[0]);
+
 is (scalar @attachments, 1, "Found our one attachment");
 
  
@@ -143,12 +140,71 @@
 );
 
 diag("check to see if YATTA has an attachment");
+
+
+my $rt_attach_uuid;
+run_output_matches( sd => [qw/ticket attachment list --uuid/, $yatta_uuid], [qr/(.*?)(?{ $rt_attach_uuid = $1 }) bplogo.gif image\/gif/] ); 
+
+ok($rt_attach_uuid);
+
 diag("Check to see if YATTA's attachment is binary-identical to the original one");
+
+my $image_data = file($IMAGE_FILE)->slurp;
+my ($contentret, $stdout, $stderr) = run_script('sd', [qw/attachment content --uuid/, $rt_attach_uuid]);
+ok($contentret, "Ran the script ok");
+is($stdout, $image_data, "We roundtripped some binary");
+is($stderr, '');
+
+
 diag("Add an attachment to YATTA");
+
+my $MAKEFILE_CONTENT =    file('Makefile.PL')->slurp;
+chomp($MAKEFILE_CONTENT); 
+my $makefile_attach_uuid;
+run_output_matches('sd', [qw/ticket attachment create --uuid/, $yatta_uuid, '--file', 'Makefile.PL'], [qr/Created attachment (.*?)(?{ $makefile_attach_uuid = $1})$/], [], "Added a attachment");
+
+
+
+my ($makefileret, $makefileout, $makefilerr) = run_script('sd', [qw/attachment content --uuid/, $makefile_attach_uuid]);
+is($makefileout, $MAKEFILE_CONTENT, "We inserted the makefile correctly");
+
 diag("Push the attachment to RT");
+
+( $ret, $out, $err ) = run_script( 'sd', [ 'push', '--to', $sd_rt_url ] );
+
 diag("Check to see if the RT ticket has two attachments");
+my @two_attachments = sort { $a->file_name cmp $b->file_name } get_rt_ticket_attachments($tix[0]);
+is(scalar @two_attachments, 2, " I have two attachments on the RT side!");
+
+my $makefile = shift @two_attachments;
+my $logo = shift @two_attachments;
+
+
+is ($logo->file_name, 'bplogo.gif');
+is ($makefile->file_name, 'Makefile.PL');
+is($makefile->content, $MAKEFILE_CONTENT , " The makefile's content was ropundtripped ot rt ok");
+
+is($logo->content, file($IMAGE_FILE)->slurp, " The image's content was ropundtripped ot rt ok");
+
 
 #diag $uuid;
 
+
+exit();
+
+
+sub get_rt_ticket_attachments {
+    my $ticket = shift;
+
+    my $attachments = RT::Client::REST::Ticket->new( rt => $rt, id => $ticket)->attachments();
+    my $iterator = $attachments->get_iterator;
+    my @attachments;
+    while (my $att = &$iterator) { 
+        if ( $att->file_name ) {
+        push @attachments, $att ;
+    }
+    }
+    return @attachments
+}
 1;
 



More information about the Bps-public-commit mailing list