fu: Close-up of Fu, bringing a scoop of water to her mouth (Default)
fu ([personal profile] fu) wrote in [site community profile] changelog2011-01-04 12:22 am

[dw-free] Routing should output text/plain errors for unknown ( and non-HTML ) formats

[commit: http://hg.dwscoalition.org/dw-free/rev/2ab32ff63973]

http://bugs.dwscoalition.org/show_bug.cgi?id=3171

Deprecate checkfriends; add new protocol method checkforupdates. See http
://dw-dev.dreamwidth.org/78628.html for more details.

Patch by [personal profile] fu.

Files modified:
  • cgi-bin/LJ/User.pm
  • cgi-bin/ljprotocol.pl
  • t/protocol.t
--------------------------------------------------------------------------------
diff -r 5288d9d5a226 -r 2ab32ff63973 cgi-bin/LJ/User.pm
--- a/cgi-bin/LJ/User.pm	Tue Jan 04 08:17:10 2011 +0800
+++ b/cgi-bin/LJ/User.pm	Tue Jan 04 08:21:24 2011 +0800
@@ -2098,7 +2098,7 @@ sub can_track_thread {
     return $_[0]->get_cap( 'track_thread' ) ? 1 : 0;
 }
 
-sub can_use_checkfriends {
+sub can_use_checkforupdates {
     return $_[0]->get_cap( 'checkfriends' ) ? 1 : 0;
 }
 
diff -r 5288d9d5a226 -r 2ab32ff63973 cgi-bin/ljprotocol.pl
--- a/cgi-bin/ljprotocol.pl	Tue Jan 04 08:17:10 2011 +0800
+++ b/cgi-bin/ljprotocol.pl	Tue Jan 04 08:21:24 2011 +0800
@@ -184,6 +184,7 @@ sub do_request
     if ($method eq "editcircle")       { return editcircle(@args);       }
     if ($method eq "friendof")         { return friendof(@args);         }
     if ($method eq "checkfriends")     { return checkfriends(@args);     }
+    if ($method eq "checkforupdates")  { return checkforupdates(@args);  }
     if ($method eq "getdaycounts")     { return getdaycounts(@args);     }
     if ($method eq "postevent")        { return postevent(@args);        }
     if ($method eq "editevent")        { return editevent(@args);        }
@@ -814,20 +815,20 @@ sub friendof
     return $res;
 }
 
-sub checkfriends
-{
-    my ($req, $err, $flags) = @_;
-    return undef unless authenticate($req, $err, $flags);
-    my $u = $flags->{'u'};
-    my $res = {};
-
-    # FIXME: not updated for WTF yet
-    return fail( $err, 507 );
+sub checkfriends {
+    return fail( $_[1], 504, "Use 'checkforupdates' instead." );
+}
+sub checkforupdates
+{
+    my ($req, $err, $flags) = @_;
+    return undef unless authenticate($req, $err, $flags);
+    my $u = $flags->{'u'};
+    my $res = {};
 
     # return immediately if they can't use this mode
-    unless ( $u->can_use_checkfriends ) {
+    unless ( $u->can_use_checkforupdates ) {
         $res->{'new'} = 0;
-        $res->{'interval'} = 36000;  # tell client to bugger off
+        $res->{'interval'} = 36000;
         return $res;
     }
 
@@ -843,23 +844,36 @@ sub checkfriends
     my $interval = LJ::get_cap_min($u, "checkfriends_interval");
     $res->{'interval'} = $interval;
 
-    my $mask;
-    if ($req->{'mask'} and $req->{'mask'} !~ /\D/) {
-        $mask = $req->{'mask'};
-    }
-
-    my $memkey = [$u->{'userid'},"checkfriends:$u->{userid}:$mask"];
+    my $filter;
+    if ( $req->{filter} ) {
+        $filter = $u->content_filters( name => $req->{filter} );
+        return fail( $err, 203, "Invalid filter name. Trying to check updates for a filter that does not exist." )
+            unless $filter;
+    }
+
+    my $memkey = [ $u->id, "checkforupdates:$u->{userid}:" . ( $filter ? $filter->id : "" ) ];
     my $update = LJ::MemCache::get($memkey);
     unless ($update) {
-        # TAG:FR:protocol:checkfriends (wants reading list of mask, not "friends")
-        my $fr = LJ::get_friends($u, $mask);
-        unless ($fr && %$fr) {
+        my @fr = $u->watched_userids;
+
+        # FIXME: see whether we can just get the list of users who are in the filter
+        if ( $filter ) {
+            my @filter_users;
+
+            foreach my $fid ( @fr ) {
+                push @filter_users, $fid
+                    if $filter->contains_userid( $fid );
+            }
+            @fr = @filter_users;
+        }
+
+        unless ( @fr ) {
             $res->{'new'} = 0;
             $res->{'lastupdate'} = $lastupdate;
             return $res;
         }
         if (@LJ::MEMCACHE_SERVERS) {
-            my $tu = LJ::get_timeupdate_multi({ memcache_only => 1 }, keys %$fr);
+            my $tu = LJ::get_timeupdate_multi({ memcache_only => 1 }, @fr);
             my $max = 0;
             while ($_ = each %$tu) {
                 $max = $tu->{$_} if $tu->{$_} > $max;
@@ -874,7 +888,7 @@ sub checkfriends
                 $res->{'lastupdate'} = $lastupdate;
                 return $res;
             }
-            my $list = join(", ", map { int($_) } keys %$fr);
+            my $list = join(", ", map { int($_) } @fr );
             if ($list) {
               my $sql = "SELECT MAX(timeupdate) FROM userusage ".
                   "WHERE userid IN ($list)";
@@ -3309,6 +3323,9 @@ sub do_request
     if ($req->{'mode'} eq "checkfriends") {
         return checkfriends($req, $res, $flags);
     }
+    if ($req->{'mode'} eq "checkforupdates") {
+        return checkforupdates($req, $res, $flags);
+    }
     if ($req->{'mode'} eq "getdaycounts") {
         return getdaycounts($req, $res, $flags);
     }
@@ -3607,6 +3624,28 @@ sub checkfriends
     $res->{'new'} = $rs->{'new'};
     $res->{'lastupdate'} = $rs->{'lastupdate'};
     $res->{'interval'} = $rs->{'interval'};
+    return 1;
+}
+
+## flat wrapper
+sub checkforupdates
+{
+    my ( $req, $res, $flags ) = @_;
+
+    my $err = 0;
+    my $rq = upgrade_request( $req );
+
+    my $rs = LJ::Protocol::do_request( "checkforupdates", $rq, \$err, $flags );
+    unless ( $rs ) {
+        $res->{success} = "FAIL";
+        $res->{errmsg} = LJ::Protocol::error_message( $err );
+        return 0;
+    }
+
+    $res->{success} = "OK";
+    $res->{new} = $rs->{new};
+    $res->{lastupdate} = $rs->{lastupdate};
+    $res->{interval} = $rs->{interval};
     return 1;
 }
 
diff -r 5288d9d5a226 -r 2ab32ff63973 t/protocol.t
--- a/t/protocol.t	Tue Jan 04 08:17:10 2011 +0800
+++ b/t/protocol.t	Tue Jan 04 08:21:24 2011 +0800
@@ -3,7 +3,7 @@ use warnings;
 use warnings;
 
 use Test::More;
-plan tests => 201;
+plan tests => 222;
 
 use lib "$ENV{LJHOME}/cgi-bin";
 require 'ljlib.pl';
@@ -49,27 +49,28 @@ my $do_request = sub {
 
 
 my $check_err = sub {
-    my ( $responsecode, $expectedcode, $testmsg ) = @_;
+    my ( $expectedcode, $testmsg ) = @_;
 
-    is( $responsecode, $expectedcode,
+    # code is either in the form of ###, or ###:description
+    like( $err, qr/^$expectedcode(?:$|[:])/,
         "$testmsg Protocol error ($err) = " . LJ::Protocol::error_message( $err ) );
 };
 
 my $success = sub {
-    my ( $responsecode, $testmsg ) = @_;
+    my ( $testmsg ) = @_;
 
-    is( $responsecode, 0, "$testmsg (success)" );
+    is( $err, 0, "$testmsg (success)" );
 };
 
 note( "getfriendgroups" );
 {
     ( $res, $err ) = $do_request->( "getfriendgroups" );
-    $check_err->( $err, 504, "'getfriendgroups' is deprecated." );
+    $check_err->( 504, "'getfriendgroups' is deprecated." );
     is( $res, undef, "No response expected." );
 
 
     ( $res, $err ) = $do_request->( "getfriendgroups", username => $u->user );
-    $check_err->( $err, 504, "'getfriendgroups' is deprecated." );
+    $check_err->( 504, "'getfriendgroups' is deprecated." );
     is( $res, undef, "No response expected." );
 }
 
@@ -79,12 +80,12 @@ note( "gettrustgroups" );
     #   username
 
     ( $res, $err ) = $do_request->( "gettrustgroups" );
-    $check_err->( $err, 200, "'gettrustgroups' needs a user." );
+    $check_err->( 200, "'gettrustgroups' needs a user." );
     is( $res, undef, "No response expected." );
 
 
     ( $res, $err ) = $do_request->( "gettrustgroups", username => $u->user );
-    $success->( $err, "'gettrustgroups' for user." );
+    $success->( "'gettrustgroups' for user." );
     ok( ref $res->{trustgroups} eq "ARRAY" && scalar @{$res->{trustgroups}} == 0, 
         "Empty trust groups list." );
 };
@@ -101,11 +102,11 @@ note( "getcircle" );
     #   includetrustedusers
 
     ( $res, $err ) = $do_request->( "getcircle" );
-     $check_err->( $err, 200, "'getcircle' needs a user." );
+     $check_err->( 200, "'getcircle' needs a user." );
     is( $res, undef, "No response expected." );
 
     ( $res, $err ) = $do_request->( "getcircle", username => $u->user );
-    $success->( $err, "'getcircle' for user." );
+    $success->( "'getcircle' for user." );
     is( scalar keys %$res, 0, "Empty circle; no arguments provided to select the subset of the circle." );
 
     my %circle_args = (
@@ -117,7 +118,7 @@ note( "getcircle" );
     );
     while( my ( $include, $val ) = each %circle_args ) {
         ( $res, $err ) = $do_request->( "getcircle", username => $u->user, $include => 1 );
-        $success->( $err, "'getcircle' => $include" );
+        $success->( "'getcircle' => $include" );
         is( scalar keys %$res, 1, "One key: " . (keys %$res)[0] );
         is( ref $res->{$val->[0]}, "ARRAY", "Returned an arrayref of this user's $include." );
 
@@ -144,7 +145,7 @@ note( "getcircle" );
 
         ( $res, $err ) = $do_request->( "getcircle", username => $u->user, $include => 1,
             limit => $LJ::MAX_WT_EDGES_LOAD + 1 );
-        $success->( $err, "'getcircle' => $include" );
+        $success->( "'getcircle' => $include" );
 
         # check that the users we got back are from the users we added
         # don't check the other way, since we are over limit
@@ -157,14 +158,14 @@ note( "getcircle" );
     }
 
     ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includetrustgroups => 1 );
-    $success->( $err, "'getcircle' => includetrustgroups" );
+    $success->( "'getcircle' => includetrustgroups" );
     is( scalar keys %$res, 1, "One key: " . (keys %$res)[0] );
     ok( ref $res->{trustgroups} eq "ARRAY" && scalar @{$res->{trustgroups}} == 0, 
         "Empty trust groups list." );
 
 
     ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includecontentfilters => 1 );
-    $success->( $err, "'getcircle' => includecontentfilters" );
+    $success->( "'getcircle' => includecontentfilters" );
     is( scalar keys %$res, 1, "One key: " . (keys %$res)[0] );
     ok( ref $res->{contentfilters} eq "ARRAY" && scalar @{$res->{contentfilters}} == 0, "Empty list of content filters for this user." );
 
@@ -183,12 +184,12 @@ note( "editcircle" );
     #     deletefromcontentfilters
 
     ( $res, $err ) = $do_request->( "editcircle", settrustgroups => 1 );
-    $check_err->( $err, 200, "'editcircle' needs a user." );
+    $check_err->( 200, "'editcircle' needs a user." );
     is( $res, undef, "No response expected." );
 
 
     ( $res, $err ) = $do_request->( "editcircle", username => $u->user, settrustgroups => 1 );
-    $success->( $err, "No valid action provided for editcircle; ignore." );
+    $success->( "No valid action provided for editcircle; ignore." );
     is( scalar keys %$res, 0, "No action taken." );
 
 
@@ -206,7 +207,7 @@ note( "editcircle" );
         }
     );
     ( $res, $err ) = $do_request->( "editcircle", username => $u->user, settrustgroups => \%trustgroups );
-    $success->( $err, "Set trust groups." );
+    $success->( "Set trust groups." );
     is( scalar keys %$res, 0, "No response expected." );
 
     ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includetrustgroups => 1 );
@@ -235,7 +236,7 @@ note( "editcircle" );
     $trustgroups{20} = $new;
 
     ( $res, $err ) = $do_request->( "editcircle", username => $u->user, settrustgroups => { 10 => $edited, 20 => $new } );
-    $success->( $err, "Edited trust groups; those not mentioned should not be affected." );
+    $success->( "Edited trust groups; those not mentioned should not be affected." );
     is( scalar keys %$res, 0, "No response expected." );
 
     ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includetrustgroups => 1 );
@@ -254,7 +255,7 @@ note( "editcircle" );
     delete $trustgroups{5};
     delete $trustgroups{10};
     ( $res, $err ) = $do_request->( "editcircle", username => $u->user, deletetrustgroups => [ 10, 5 ] );
-    $success->( $err, "Deleted a trust group." );
+    $success->( "Deleted a trust group." );
     is( scalar keys %$res, 0, "No response expected." );
 
     ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includetrustgroups => 1 );
@@ -271,7 +272,7 @@ note( "editcircle" );
 
     # now add / edit some users' status in your circle
     ( $res, $err ) = $do_request->( "editcircle", username => $u->user, add => [ { username => "invalidusername" } ] );
-    $check_err->( $err, 203, "Tried to edit invalid user." );
+    $check_err->( 203, "Tried to edit invalid user." );
     is( scalar keys %$res, 0, "No response expected." );
 
     # let's make our watch/trust mutual
@@ -355,7 +356,7 @@ note( "editcircle" );
     );
 
     ( $res, $err ) = $do_request->( "editcircle", username => $u->user, setcontentfilters => \%contentfilters );
-    $success->( $err, "Set content filters." );
+    $success->( "Set content filters." );
     is( scalar keys %$res, 1, "Response contains only the newly added content filters." );
     is( scalar @{$res->{addedcontentfilters}}, scalar keys %contentfilters, "Got back the newly-added content filters." );
 
@@ -384,7 +385,7 @@ note( "editcircle" );
     $contentfilters{3} = $new;
 
     ( $res, $err ) = $do_request->( "editcircle", username => $u->user, setcontentfilters => { 2 => $edited, 3 => $new } );
-    $success->( $err, "Edited content filters; those not mentioned should not be affected." );
+    $success->( "Edited content filters; those not mentioned should not be affected." );
     is( scalar keys %$res, 1, "Response contains only the newly added content filters." );
     is( scalar @{$res->{addedcontentfilters}}, 1, "Got back the newly-added content filter." );
 
@@ -404,7 +405,7 @@ note( "editcircle" );
     delete $contentfilters{1};
     delete $contentfilters{3};
     ( $res, $err ) = $do_request->( "editcircle", username => $u->user, deletecontentfilters => [ 1, 3 ] );
-    $success->( $err, "Deleted content filters." );
+    $success->( "Deleted content filters." );
     is( scalar keys %$res, 0, "No response expected." );
 
     ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includecontentfilters => 1 );
@@ -428,7 +429,7 @@ note( "editcircle" );
         username => "invalid_user",
         id => 2
     } ] );
-    $check_err->( $err, 203, "Tried to add an invalid user to a content filter." );
+    $check_err->( 203, "Tried to add an invalid user to a content filter." );
     ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includecontentfilters => 1 );
     ok( $res->{contentfilters}->[0]->{data} eq "", "No data for the content filter." );
 
@@ -438,7 +439,7 @@ note( "editcircle" );
         username => $watched->user,
         id => 2
     } ] );
-    $success->( $err, "Added a user to a content filter." );
+    $success->( "Added a user to a content filter." );
     is( scalar keys %$res, 0, "No response expected." );
 
     ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includecontentfilters => 1 );
@@ -450,7 +451,7 @@ note( "editcircle" );
         username => "invalid_user",
         id => 2
     } ] );
-    $check_err->( $err, 203, "Tried to remove an invalid user from a content filter." );
+    $check_err->( 203, "Tried to remove an invalid user from a content filter." );
     ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includecontentfilters => 1 );
     ok( $res->{contentfilters}->[0]->{data} ne "", "Some data in the content filter." );
 
@@ -460,7 +461,7 @@ note( "editcircle" );
         username => $watchedtrusted->user,
         id => 2
     } ] );
-    $success->( $err, "Tried to remove a user who was not in the content filter." );
+    $success->( "Tried to remove a user who was not in the content filter." );
     ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includecontentfilters => 1 );
     ok( $res->{contentfilters}->[0]->{data} ne "", "Some data in the content filter." );
 
@@ -469,7 +470,7 @@ note( "editcircle" );
         username => $watched->user,
         id => 2
     } ] );
-    $success->( $err, "Removed a user from a content filter." );
+    $success->( "Removed a user from a content filter." );
     is( scalar keys %$res, 0, "No response expected." );
 
     ( $res, $err ) = $do_request->( "getcircle", username => $u->user, includecontentfilters => 1 );
@@ -506,7 +507,7 @@ note( "post to community by various jour
         event      => "new test post to community",
         tz         => "guess",
     );
-    $success->( $err, "Entry posted successfully to community by personal journal." );
+    $success->( "Entry posted successfully to community by personal journal." );
 
 
     my $comm2 = temp_comm();
@@ -515,7 +516,7 @@ note( "post to community by various jour
         usejournal  => $comm->user,
         event       => "new test post to community by community2"
     );
-    $check_err->( $err, 300, "Communities cannot post entries." );
+    $check_err->( 300, "Communities cannot post entries." );
 
     ( $res, $err ) = $do_request->( "postevent",
         username    => $comm->user,
@@ -524,7 +525,7 @@ note( "post to community by various jour
         event       => "new test post to self by a community",
         tz          => "guess",
     );
-    $check_err->( $err, 300, "Communities cannot post entries, not even to themselves." );
+    $check_err->( 300, "Communities cannot post entries, not even to themselves." );
 
 
 
@@ -539,7 +540,7 @@ note( "post to community by various jour
         event       => "new test post to a community by an identity user",
         tz          => "guess",
     );
-    $check_err->( $err, 150, "OpenID users cannot post entries to communities with no OpenID posting prop." );
+    $check_err->( 150, "OpenID users cannot post entries to communities with no OpenID posting prop." );
 
 
     ( $res, $err ) = $do_request->( "postevent",
@@ -551,7 +552,7 @@ note( "post to community by various jour
 
         flags       => { importer_bypass => 1 },
     );
-    $success->( $err, "Always allow posting with the importer bypass." );
+    $success->( "Always allow posting with the importer bypass." );
 
 
     # allow all users to add and control tags (for convenience)
@@ -577,5 +578,151 @@ note( "post to community by various jour
         props       => { taglist => "testing" },
         tz          => "guess",
     );
-    $success->( $err, "OpenID users can post entries to communities with the appropriate prop." );
+    $success->( "OpenID users can post entries to communities with the appropriate prop." );
 }
+
+
+note( "checkforupdates" );
+{
+    
+    my $u = temp_user();
+
+    my $start = 0;
+    my $end = 15;
+
+    # make sure no one can use the protocol...
+    $LJ::CAP{$_}->{checkfriends} = 0
+        foreach( 0.. 15 );
+
+    ( $res, $err ) = $do_request->( "checkfriends" );
+    $check_err->( 504, "Use 'checkforupdates' instead" );
+
+
+    ( $res, $err ) = $do_request->( "checkforupdates" );
+    $check_err->( 200, "Needs arguments" );
+
+    ( $res, $err ) = $do_request->( "checkforupdates",
+        username => $u->user,
+        flags    => { noauth => 0 },
+    );
+    $check_err->( 101, "Have all arguments, but needs authorization" );
+
+    ( $res, $err ) = $do_request->( "checkforupdates",
+        username => $u->user,
+    );
+    $success->( "Not authorized to use checkforupdates" );
+    is_deeply( $res, {
+            interval => 36000,
+            new => 0
+    }, "Not authorized to use checkforupdates; no new entries, check back in an hour" );
+
+
+    # make sure everyone can use the protocol, and set interval to a known variable we can check against
+    # (not using $LJ::T_HAS_ALL_CAPS = 1, because that makes everyone readonly)
+    $LJ::CAP{$_}->{checkfriends} = 1
+        foreach( 0.. 15 );
+    $LJ::CAP{$_}->{checkfriends_interval} = 7
+        foreach( 0.. 15 );
+
+    ( $res, $err ) = $do_request->( "checkforupdates",
+        username => $u->user,
+    );
+    $success->( "Checkforupdates. We don't watch anyone, but that's okay" );
+    is( scalar %{ $u->watch_list }, 0, "Not watching anyone" );
+    is_deeply( $res, {
+            interval => 7,
+            new => 0,
+            lastupdate => "0000-00-00 00:00:00",
+    }, "Watching no one." );
+
+
+    # now we watch some people (who have no updates yet)
+    my $userinfilter = temp_user();
+    $u->add_edge( $userinfilter, watch => { nonotify => 1 } );
+    $u->create_content_filter( name => "filter" );
+    my $filter = $u->content_filters( name => "filter" );
+    $filter->add_row( userid => $userinfilter->userid );
+
+    my $usernotinfilter = temp_user();
+    $u->add_edge( $usernotinfilter, watch => { nonotify => 1 } );
+
+
+    # and go through the protocol again
+    ( $res, $err ) = $do_request->( "checkforupdates",
+        username => $u->user,
+    );
+    $success->( "Checkforupdates. No one has updated." );
+    is( scalar $u->watched_userids,2 );
+    is_deeply( $res, {
+            interval => 7,
+            new => 0,
+            lastupdate => "0000-00-00 00:00:00",
+    }, "No new entries." );
+
+
+    # and then let's see what happens when they get updates
+    $do_request->( "postevent", username => $userinfilter->user, event => "update", tz => "guess" );
+    sleep( 1 ); # pause so we have different time stamps (for checking against)
+    $do_request->( "postevent", username => $usernotinfilter->user, event => "update", tz => "guess" );
+
+    # use variables to make it easier to determine what I'm trying to check for
+    # In some tests, I will deliberately *not* use the variables
+    my $earlierupdate = $userinfilter->timeupdate;
+    my $laterupdate = $usernotinfilter->timeupdate;
+    ok( $earlierupdate < $laterupdate, "Timestamps need to be unequal for when we're testing stuff." );
+
+    # and go through the protocol again
+    ( $res, $err ) = $do_request->( "checkforupdates",
+        username => $u->user,
+    );
+    $success->( "Checkforupdates. Users have updated." );
+    is_deeply( $res, {
+            interval => 7,
+            new => 0,
+            lastupdate => LJ::mysql_time( $usernotinfilter->timeupdate ),
+    }, "No new entries." );
+
+
+    # and we also check a subset (filter)
+    ( $res, $err ) = $do_request->( "checkforupdates",
+        username => $u->user,
+        filter   => $filter->name,
+    );
+    $success->( "Checkforupdates of a subset of watched users." );
+    is_deeply( $res, {
+            interval => 7,
+            new => 0,
+            lastupdate => LJ::mysql_time( $userinfilter->timeupdate ),
+    }, "No new entries." );
+
+
+    # optional argument lastupdate
+    ( $res, $err ) = $do_request->( "checkforupdates",
+        username   => $u->user,
+        lastupdate => $earlierupdate
+    );
+    $check_err->( 203, "lastupdate argument needs to be in mysql_time format." );
+
+    ( $res, $err ) = $do_request->( "checkforupdates",
+        username   => $u->user,
+        lastupdate => LJ::mysql_time( $earlierupdate ),
+    );
+    $success->( "Checkforupdates since lastupdate. Have new updates" );
+    is_deeply( $res, {
+            interval => 7,
+            new => 1,
+            lastupdate => LJ::mysql_time( $laterupdate ),
+    }, "Have new entries." );
+
+    ( $res, $err ) = $do_request->( "checkforupdates",
+        username   => $u->user,
+        lastupdate => LJ::mysql_time( $laterupdate ),
+    );
+    $success->( "Checkforupdates since lastupdate. No new updates" );
+    is_deeply( $res, {
+            interval => 7,
+            new => 0,
+            lastupdate => LJ::mysql_time( $laterupdate ),
+    }, "No new entries." );
+
+}
--------------------------------------------------------------------------------

Post a comment in response:

This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

If you are unable to use this captcha for any reason, please contact us by email at support@dreamwidth.org