[Bps-public-commit] RT-Extension-NHD branch, master, updated. d4f65312f9d832c22f49f3a778713b7c13e13273

Ruslan Zakirov ruz at bestpractical.com
Mon Oct 3 05:52:24 EDT 2011


The branch, master has been updated
       via  d4f65312f9d832c22f49f3a778713b7c13e13273 (commit)
       via  cd636df1781eeef832247329fa362fc003b6c35a (commit)
      from  40d221b84e230db3c6a558a9d6c8dae1f0c2d570 (commit)

Summary of changes:
 TODO                             |    8 +++
 lib/RT/Extension/NHD.pm          |   29 ++++++++++-
 lib/RT/Extension/NHD/Test/Web.pm |   11 +----
 lib/RT/NHD/Agreement.pm          |   74 +++++++++++++++++++--------
 t/api/agreement.t                |  106 ++++++++++++++++++++++++++++++++++++++
 t/rest/agreement.t               |    6 +-
 6 files changed, 199 insertions(+), 35 deletions(-)
 create mode 100644 TODO

- Log -----------------------------------------------------------------
commit cd636df1781eeef832247329fa362fc003b6c35a
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Mon Oct 3 11:49:59 2011 +0200

    sync creates and updates with remote site

diff --git a/lib/RT/Extension/NHD.pm b/lib/RT/Extension/NHD.pm
index 3e8e06e..b80e06e 100644
--- a/lib/RT/Extension/NHD.pm
+++ b/lib/RT/Extension/NHD.pm
@@ -15,6 +15,8 @@ RT::Extension::NHD - Networked Help Desk protocol for Request Tracker
 
 use RT::NHD::Agreement;
 use JSON::Any;
+use LWP::UserAgent;
+use HTTP::Request;
 
 sub FromJSON {
     return JSON::Any->new->from_json( $_[1] );
@@ -32,7 +34,29 @@ sub CheckUUID {
     return 1;
 }
 
-my %HTTP_CODE = (
+sub JSONRequest {
+    my $self = shift;
+    my ($method, $uri, %args) = @_;
+
+    my $data;
+    $data = RT::Extension::NHD->ToJSON( delete $args{'Data'} )
+        unless uc($method) eq 'GET';
+    my %headers = %{ delete $args{'Headers'} || {} };
+    %headers = (
+        'X-Ticket-Sharing-Version' => '1',
+        'Content-Type' => 'text/x-json; charset="UTF-8"',
+        %headers,
+    );
+    my $request = HTTP::Request->new( $method, $uri, [%headers], $data );
+    return $self->SendRequest( $request );
+}
+
+sub SendRequest {
+    my $self = shift;
+    return LWP::UserAgent->new->request( shift );
+}
+
+our %HTTP_CODE = (
     'OK' => 200,
     'Created' => 201,
 
@@ -44,6 +68,7 @@ my %HTTP_CODE = (
     'Precondition Failed' => 412,
     'Unprocessable Entity' => 422,
 );
+our %HTTP_MESSAGE = reverse %HTTP_CODE;
 
 sub BadWebRequest {
     my $self = shift;
@@ -77,6 +102,8 @@ sub StopWebRequest {
 }
 
 my %METHOD_TO_ACTION = ( GET => 'show', POST => 'create', PUT => 'update' );
+my %ACTION_TO_METHOD = reverse %METHOD_TO_ACTION;
+sub ActionToWebMethod { return $ACTION_TO_METHOD{ lc $_[1] } };
 sub WebRequestAction {
     return $METHOD_TO_ACTION{ uc $HTML::Mason::Commands::r->method };
 }
diff --git a/lib/RT/Extension/NHD/Test/Web.pm b/lib/RT/Extension/NHD/Test/Web.pm
index 292ff46..280890f 100644
--- a/lib/RT/Extension/NHD/Test/Web.pm
+++ b/lib/RT/Extension/NHD/Test/Web.pm
@@ -20,16 +20,7 @@ sub json_request {
     my $self = shift;
     my ($method, $uri, %args) = @_;
     $uri = $self->rt_base_url .'NoAuth/NHD/1.0'. $uri;
-    my $data;
-    $data = RT::Extension::NHD->ToJSON( delete $args{'data'} )
-        unless $method eq 'GET';
-    my %headers = %{ $args{'headers'}||{}};
-    %headers = (
-        %headers,
-        'X-Ticket-Sharing-Version' => '1',
-    );
-    my $request = HTTP::Request->new( $method, $uri, [%headers], $data );
-    return $self->request( $request );
+    RT::Extension::NHD->JSONRequest( $method, $uri, %args );
 }
 
 1;
\ No newline at end of file
diff --git a/lib/RT/NHD/Agreement.pm b/lib/RT/NHD/Agreement.pm
index 60c2603..33e5954 100644
--- a/lib/RT/NHD/Agreement.pm
+++ b/lib/RT/NHD/Agreement.pm
@@ -40,7 +40,7 @@ sub Create {
     my @rv = $self->SUPER::Create( %args );
 
     if ( $we_are eq $by ) {
-        my ($status, $msg) = $self->SendUpdate;
+        my ($status, $msg) = $self->Send( 'create' );
         return $self->RollbackTransaction( "Couldn't send update to remote host: $msg" )
             unless $status;
     }
@@ -120,7 +120,7 @@ sub Update {
             unless $status;
     }
     if ( $by eq $we_are ) {
-        my ($status, $msg) = $self->SendUpdate( Fields => [keys %args] );
+        my ($status, $msg) = $self->Send( update => Fields => [keys %args] );
         return $self->RollbackTransaction( "Couldn't send update to remote host: $msg" )
             unless $status;
     }
@@ -129,9 +129,35 @@ sub Update {
     return (1, 'Updated');
 }
 
-sub SendUpdate {
+my %INVERT_ROLE = ( Receiver => 'Sender', Sender => 'Receiver' );
+
+sub Send {
     my $self = shift;
-    return (1, 'Updated remote host');
+    my $action = shift;
+    my %args = @_;
+
+    my $recipient = $INVERT_ROLE{ $self->WhoWeAre };
+    return (0, 'We are neither sender nor receiver')
+        unless $recipient;
+
+    my $method = RT::Extension::NHD->ActionToWebMethod( $action );
+    return (0, "Unknown action '$action'")
+        unless $method;
+
+    my $response = RT::Extension::NHD->JSONRequest(
+        $method => $self->$recipient() .'/agreements/'. $self->UUID,
+        Headers => {
+            'X-Ticket-Sharing-Token' => $self->UUID .':'. $self->AccessKey,
+        },
+        Data => $self->ForJSON( %args ),
+    );
+
+    unless ( $response && $response->is_success ) {
+        return (0, 'No response', $response) unless $response;
+        return (0, 'Request was not successful', $response);
+    }
+
+    return (1, 'Updated remote host', $response);
 }
 
 sub WhoWeAre {
@@ -231,32 +257,38 @@ sub _ValidateURI {
     return 1;
 }
 
+our %FIELDS_MAP = (
+    UUID => 'uuid',
+    Name => 'name',
+    Status => 'status',
+    Sender => 'sender_url',
+    Receiver => 'receiver_url',
+    AccessKey => 'access_key',
+    DeactivatedBy => 'deactivated_by',
+);
+
 sub FromJSON {
     my $self = shift;
     my ($args) = @_;
 
-    return {
-        UUID => $args->{'uuid'},
-        Name => $args->{'name'},
-        Status => $args->{'status'},
-        Sender => $args->{'sender_url'},
-        Receiver => $args->{'receiver_url'},
-        AccessKey => $args->{'access_key'},
-        DeactivatedBy => $args->{'deactivated_by'},
+    my %res;
+    while ( my ($k, $v) = each %FIELDS_MAP ) {
+        next unless exists $args->{$v};
+        $res{ $k } = $args->{$v};
     };
+
+    return \%res;
 }
 
 sub ForJSON {
     my $self = shift;
-    return {
-        uuid => $self->UUID,
-        name => $self->Name,
-        status => $self->Status,
-        sender_url => $self->Sender,
-        receiver_url => $self->Receiver,
-        access_key => $self->AccessKey,
-        deactivated_by => $self->DeactivatedBy,
-    };
+    my %args = @_;
+
+    my @fields = $args{'Fields'} ? @{$args{'Fields'}} : keys %FIELDS_MAP;
+
+    my %res;
+    $res{ $FIELDS_MAP{$_} } = $self->$_() foreach @fields;
+    return \%res;
 }
 
 sub TableAttributes {
diff --git a/t/api/agreement.t b/t/api/agreement.t
index 5cdbd08..fc58c79 100644
--- a/t/api/agreement.t
+++ b/t/api/agreement.t
@@ -6,6 +6,41 @@ use warnings;
 use RT::Extension::NHD::Test tests => 24;
 use Digest::SHA1 qw(sha1_hex);
 
+use_ok 'RT::Extension::NHD';
+
+{
+    my (@requests, @responses);
+
+    sub remote_requests { return splice @requests }
+
+    sub set_next_remote_response {
+        my $code = shift;
+        my %args = @_;
+
+        my $msg = $args{'Message'} || $RT::Extension::NHD::HTTP_MESSAGE{ $code }
+            || die "no message for code $code";
+
+        my %headers = %{ $args{'Headers'} || {} };
+        %headers = (
+            %headers,
+            'X-Ticket-Sharing-Version' => '1',
+        );
+        my $content = $args{'Data'};
+        $content = RT::Extension::NHD->ToJSON( $content )
+            if ref $content;
+        push @responses, HTTP::Response->new(
+            $code, $msg, [%headers], $content,
+        );
+    }
+
+    no strict 'subs';
+    *RT::Extension::NHD::SendRequest = sub {
+        my $self = shift;
+        push @requests, shift;
+        return shift @responses;
+    };
+}
+
 {
     my $agreement = RT::NHD::Agreement->new( RT->SystemUser );
     isa_ok($agreement, 'RT::NHD::Agreement');
@@ -50,6 +85,8 @@ my $i = 0;
     is( $agreement->Sender, $remote_url, 'correct value' );
     is( $agreement->Receiver, RT->Config->Get('NHD_WebURL'), 'correct value' );
     like( $agreement->AccessKey, qr{^[0-9a-f]{40}$}i, 'correct value' );
+
+    is scalar remote_requests(), 0, 'no outgoing requests';
 }
 
 # bad status
@@ -65,6 +102,7 @@ my $i = 0;
         AccessKey => sha1_hex( ''. ++$i ),
     );
     ok(!$id, "Couldn't create an agreement $uuid: $msg");
+    is scalar remote_requests(), 0, 'no outgoing requests';
 }
 
 # can only be created with pending status
@@ -80,6 +118,7 @@ my $i = 0;
         AccessKey => sha1_hex( ''. ++$i ),
     );
     ok(!$id, "Couldn't create an agreement $uuid: $msg");
+    is scalar remote_requests(), 0, 'no outgoing requests';
 }
 
 # simple update by sender we are receiver
@@ -103,6 +142,7 @@ my $i = 0;
     ok $status, 'updated URL of the sender by sender';
     is( $agreement->Name, 'Correct Test Company', 'correct value' );
     is( $agreement->AccessKey, sha1_hex( ''. $i ), 'correct value' );
+    is scalar remote_requests(), 0, 'no outgoing requests';
 }
 
 # update with error
@@ -127,5 +167,71 @@ my $i = 0;
     # make sure we're transactional
     is( $agreement->Name, 'Test Company', 'correct value' );
     is( $agreement->AccessKey, sha1_hex( ''. $i ), 'correct value' );
+    is scalar remote_requests(), 0, 'no outgoing requests';
+}
+
+# we are sending
+{
+    set_next_remote_response(201);
+
+    my $uuid = sha1_hex( ''. ++$i );
+
+    my $agreement = RT::NHD::Agreement->new( RT->SystemUser );
+    my ($id, $msg) = $agreement->Create(
+        UUID => $uuid,
+        Name => 'Test Company',
+        Status => 'pending',
+        Sender => RT->Config->Get('NHD_WebURL'),
+        Receiver => $remote_url,
+        AccessKey => sha1_hex( ''. ++$i ),
+    );
+    ok($id, "Created an agreement $uuid");
+
+    $agreement = RT::NHD::Agreement->new( RT->SystemUser );
+    $agreement->Load( $uuid );
+    ok( $agreement->id, 'loaded agreement' );
+
+    is( $agreement->UUID, $uuid, 'correct value' );
+    is( $agreement->Name, 'Test Company', 'correct value' );
+    is( $agreement->Status, 'pending', 'correct value' );
+    is( $agreement->Receiver, $remote_url, 'correct value' );
+    is( $agreement->Sender, RT->Config->Get('NHD_WebURL'), 'correct value' );
+    like( $agreement->AccessKey, qr{^[0-9a-f]{40}$}i, 'correct value' );
+
+    my @requests = remote_requests();
+    is scalar @requests, 1, 'one outgoing request';
+    is $requests[0]->uri, "$remote_url/agreements/$uuid";
+    is $requests[0]->method, "POST";
+    is $requests[0]->header('X-Ticket-Sharing-Version'), 1;
+    is $requests[0]->header('X-Ticket-Sharing-Token'),
+        $agreement->UUID .':'. $agreement->AccessKey;
+    is lc $requests[0]->header('Content-Type'), 'text/x-json; charset="utf-8"';
+    is_deeply(
+        RT::Extension::NHD->FromJSON( $requests[0]->content ),
+        $agreement->ForJSON,
+    );
+
+    set_next_remote_response(200);
+
+    (my $status, $msg) = $agreement->Update(
+        Name => 'Correct Test Company',
+        AccessKey => sha1_hex( ''. ++$i ),
+    );
+    ok $status, 'updated URL of the sender by sender' or "error: $msg";
+    is( $agreement->Name, 'Correct Test Company', 'correct value' );
+    is( $agreement->AccessKey, sha1_hex( ''. $i ), 'correct value' );
+
+    @requests = remote_requests();
+    is scalar @requests, 1, 'one outgoing request';
+    is $requests[0]->uri, "$remote_url/agreements/$uuid";
+    is $requests[0]->method, "PUT";
+    is $requests[0]->header('X-Ticket-Sharing-Version'), 1;
+    is $requests[0]->header('X-Ticket-Sharing-Token'),
+        $agreement->UUID .':'. sha1_hex( ''. ($i - 1) );
+    is lc $requests[0]->header('Content-Type'), 'text/x-json; charset="utf-8"';
+    is_deeply(
+        RT::Extension::NHD->FromJSON( $requests[0]->content ),
+        $agreement->ForJSON( Fields => ['Name', 'AccessKey'] ),
+    );
 }
 
diff --git a/t/rest/agreement.t b/t/rest/agreement.t
index 9f0bb43..7308bf5 100644
--- a/t/rest/agreement.t
+++ b/t/rest/agreement.t
@@ -17,10 +17,10 @@ my $i = 0;
 
     my $response = $m->json_request(
         POST => '/agreements/'. $uuid,
-        headers => {
+        Headers => {
             'X-Ticket-Sharing-Token' => "$uuid:$access_key",
         },
-        data => {
+        Data => {
             uuid => $uuid,
             name => 'Test Company',
             status => 'pending',
@@ -53,7 +53,7 @@ my $i = 0;
 
     $response = $m->json_request(
         GET => '/agreements/'. $uuid,
-        headers => {
+        Headers => {
             'X-Ticket-Sharing-Token' => "$uuid:$access_key",
         },
     );

commit d4f65312f9d832c22f49f3a778713b7c13e13273
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Mon Oct 3 11:52:15 2011 +0200

    add TODO message

diff --git a/TODO b/TODO
new file mode 100644
index 0000000..1d3f253
--- /dev/null
+++ b/TODO
@@ -0,0 +1,8 @@
+* in Agreement::Create make sure that the following situation
+  is denined: WhoWeAre == Sender and CurrentUserIs Receiver
+
+* Transactional Create
+
+* When AccessKey changes locally we send wrong auth token
+  to the other side
+

-----------------------------------------------------------------------



More information about the Bps-public-commit mailing list