# t/esn-journalnewcomment.t # # Test notifications for new journal comments. # # This code was forked from the LiveJournal project owned and operated # by Live Journal, Inc. The code has been modified and expanded by # Dreamwidth Studios, LLC. These files were originally licensed under # the terms of the license supplied by Live Journal, Inc, which can # currently be found at: # # http://code.livejournal.org/trac/livejournal/browser/trunk/LICENSE-LiveJournal.txt # # In accordance with the original license, this code and all its # modifications are provided under the GNU General Public License. # A copy of that license can be found in the LICENSE file included as # part of this distribution. use strict; use warnings; use Test::More tests => 50; BEGIN { $LJ::_T_CONFIG = 1; require "$ENV{LJHOME}/cgi-bin/ljlib.pl"; } use LJ::Protocol; use LJ::Event; use LJ::Talk; use LJ::Test qw(memcache_stress temp_user); use FindBin qw($Bin); # we want to test eight major cases here, matching and not matching for # four types of subscriptions, all of subscr etypeid = JournalNewComment # # jid sarg1 sarg2 meaning # S1: n 0 0 all new comments in journal 'n' (subject to security) # S2: n ditemid 0 all new comments on post (n,ditemid) # S3: n ditemid jtalkid all new comments UNDER comment n/jtalkid (in ditemid) # S4: 0 0 0 all new comments from any journal you watch # -- NOTE: This test is disabled unless JournalNewComment allows it # we also want to test for matching and not matching cases for JournalNewComment::TopLevel # a subclass of JournalNewComment my %got_email = (); # userid -> received email local $LJ::_T_EMAIL_NOTIFICATION = sub { my ( $u, $body ) = @_; $got_email{ $u->userid }++; return 1; }; my $proc_events = sub { %got_email = (); LJ::Event->process_fired_events; }; my $got_notified = sub { my $u = shift; $proc_events->(); return $got_email{ $u->{userid} }; }; # testing case S1 above: test_esn_flow( sub { my ( $u1, $u2 ) = @_; my $email; my $comment; my $othercomment; # clear subs $_->delete foreach $u1->subscriptions; $_->delete foreach $u2->subscriptions; # subscribe $u1 to all posts on $u2 my $subsc = $u1->subscribe( event => "JournalNewComment", method => "Email", journal => $u2, ); ok( $subsc, "made S1 subscription" ); # post an entry in $u2 my $u2e1 = eval { $u2->t_post_fake_entry }; ok( $u2e1, "made a post" ); is( $@, "", "no errors" ); # $u1 leave a comment on $u2 $comment = $u2e1->t_enter_comment; ok( $comment, "left a comment" ); # make sure we got notification $email = $got_notified->($u1); ok( $email, "got the email" ); # S1 failing case: # post an entry on $u1, where nobody's subscribed my $u1e1 = eval { $u1->t_post_fake_entry }; ok( $u1e1, "did a post" ); # post a comment on it $comment = $u1e1->t_enter_comment; ok( $comment, "left comment" ); # make sure we didn't get notification $email = $got_notified->($u1); ok( !$email, "got no email" ); # S1 failing case, posting to u2, due to security my $u2e2f = eval { $u2->t_post_fake_entry( security => "friends" ) }; ok( $u2e2f, "did a post" ); is( $u2e2f->security, "usemask", "is actually friends only" ); # post a comment on it $comment = $u2e2f->t_enter_comment; ok( $comment, "got jtalkid" ); # make sure we didn't get notification $email = $got_notified->($u1); ok( !$email, "got no email, due to security (u2 doesn't trust u1)" ); ok( $subsc->delete, "Deleted subscription" ); ###### S2: # subscribe $u1 to all comments on u2e1 $subsc = $u1->subscribe( event => "JournalNewComment", method => "Email", journal => $u2, arg1 => $u2e1->ditemid, ); ok( $subsc, "made S2 subscription" ); # post a comment on u2e1 $comment = $u2e1->t_enter_comment; ok( $comment, "got jtalkid" ); $email = $got_notified->($u1); ok( $email, "Got comment notification" ); # post another entry on u2 my $u2e3 = eval { $u2->t_post_fake_entry }; ok( $u2e3, "did a post" ); # post a comment that $subsc won't match $comment = $u2e3->t_enter_comment( u => $u2 ); ok( $comment, "Posted comment" ); $email = $got_notified->($u1); ok( !$email, "didn't get comment notification on unrelated post" ); # entry gets locked $u2e1->{security} = "friends"; ok( $u2e1, "first entry locked" ); # u2 comments on their own entry $othercomment = $u2e1->t_enter_comment; ok( $othercomment, "comment added to locked entry" ); # u1 can't see and doesn't get notified $email = $got_notified->($u1); ok( !$email, "didn't get comment notification on locked post" ); $u2e1->{security} = "public"; $subsc->delete; ######## S3 (watching a thread) # make sure we can track threads $LJ::CAP{$_}->{track_thread} = 1 foreach ( 0 .. 15 ); # subscribe to replies to a thread $subsc = $u1->subscribe( event => "JournalNewComment", method => "Email", journal => $u2, arg1 => $u2e3->ditemid, arg2 => $comment->jtalkid, ); ok( $subsc, "Subscribed" ); # post a reply to the comment from the earlier test my $reply = $comment->t_reply( u => $u2 ); ok( $reply, "Got reply" ); $proc_events->(); $email = $got_email{ $u1->{userid} }; ok( $email, "Got notified" ); $email = $got_email{ $u2->{userid} }; ok( !$email, "Unsubscribed watcher not notified" ); # post a new comment on this entry, make sure not notified my $comment2 = $u2e3->t_enter_comment; ok( $comment2, "Posted comment" ); $email = $got_notified->($u1); ok( !$email, "didn't get notified" ); # post a reply to a different thread and make sure not notified my $reply2 = $comment2->t_reply; ok( $reply2, "Posted reply" ); $email = $got_notified->($u1); ok( !$email, "didn't get notified" ); $LJ::CAP{$_}->{track_thread} = 0 foreach ( 0 .. 15 ); $subsc->delete; if ( ( LJ::Event::JournalNewComment->zero_journalid_subs_means // "" ) eq "friends" ) { ####### S4 (watching new comments on all friends' journals) $subsc = $u1->subscribe( event => "JournalNewComment", method => "Email", ); ok( $subsc, "made S4 wildcard subscription" ); my $u2e4 = eval { $u2->t_post_fake_entry }; ok( $u2e4, "Got entry" ); for my $pass ( 1 .. 2 ) { my $u2c1 = eval { $u2e4->t_enter_comment }; ok( $u2c1, "Posted comment" ); $proc_events->(); if ( $pass == 1 ) { $email = $got_email{ $u1->{userid} }; ok( $email, "Got wildcard notification" ); $email = $got_email{ $u2->{userid} }; ok( !$email, "Non-subscribed user did not get notification" ); # remove the friend $u1->remove_edge( $u2, watch => { nonotify => 1 } ); } elsif ( $pass == 2 ) { $email = $got_email{ $u1->{userid} }; ok( !$email, "didn't get wildcard notification" ); # add the friend back $u1->add_edge( $u2, watch => { nonotify => 1 } ); # make u1 watch u2 } } # leave some comment on u1, make sure no notification received my $u1e2 = eval { $u1->t_post_fake_entry }; ok( $u1e2, "Posted entry" ); my $u1c1 = eval { $u1e2->t_enter_comment }; ok( $u1c1, "Got comment" ); $email = $got_notified->($u1); ok( !$email, "Did not receive notification" ); $subsc->delete; } # LJ::Event::JournalNewComment::TopLevel my $u2e5 = eval { $u2->t_post_fake_entry }; # subscribe to replies to a thread $subsc = $u1->subscribe( event => "JournalNewComment::TopLevel", method => "Email", journal => $u2, arg1 => $u2e5->ditemid, ); ok( $subsc, "Subscribed" ); # post a top-level comment $comment = $u2e5->t_enter_comment; ok( $comment, "Posted comment" ); $proc_events->(); $email = $got_email{ $u1->{userid} }; ok( $email, "Got notified" ); $email = $got_email{ $u2->{userid} }; ok( !$email, "Unsubscribed watcher not notified" ); # reply to a comment on this entry, make sure we're not notified $reply = $comment->t_reply; ok( $reply, "Posted reply" ); $email = $got_notified->($u1); ok( !$email, "didn't get notified" ); $subsc->delete; my $u2e6 = eval { $u2->t_post_fake_entry }; $subsc = $u1->subscribe( event => "JournalNewComment", method => "Email", journal => $u2, arg1 => $u2e6->ditemid, ); my $subsc2 = $u1->subscribe( event => "JournalNewComment::TopLevel", method => "Email", journal => $u2, arg1 => $u2e6->ditemid, ); ok( $subsc2, "Subscribed to new top-level comments on this journal" ); $comment = $u2e6->t_enter_comment( u => $u2 ); ok( $comment, "Posted comment" ); $proc_events->(); is( $got_email{ $u1->userid }, 1, "No duplicate emails" ); $subsc->delete; $subsc2->delete; } ); ######## Unscreen notification tests (issue #3487) # When a screened comment is unscreened, users who couldn't see it # while screened should be notified. Users who could already see it # (journal owner, entry poster) should NOT get a duplicate. test_esn_flow( sub { my ( $u1, $u2 ) = @_; my $u3 = temp_user(); # clear subs $_->delete foreach $u1->subscriptions; $_->delete foreach $u2->subscriptions; # u1 subscribes to all comments on u2's journal my $subsc = $u1->subscribe( event => "JournalNewComment", method => "Email", journal => $u2, ); ok( $subsc, "Unscreen: u1 subscribed to u2's journal comments" ); # u2 posts an entry my $entry = eval { $u2->t_post_fake_entry }; ok( $entry, "Unscreen: u2 posted entry" ); # u3 posts a top-level comment (active) my $comment = $entry->t_enter_comment( u => $u3 ); ok( $comment, "Unscreen: u3 posted comment" ); # u1 should be notified of the active comment my $email = $got_notified->($u1); ok( $email, "Unscreen: u1 notified of active comment" ); # u3 posts a SCREENED reply to the first comment my $screened_reply = $comment->t_reply( u => $u3, state => 'S' ); ok( $screened_reply, "Unscreen: u3 posted screened reply" ); # u1 should NOT be notified (can't see screened comments) $email = $got_notified->($u1); ok( !$email, "Unscreen: u1 not notified of screened reply" ); # unscreen the reply LJ::Talk::unscreen_comment( $u2, $entry->jitemid, $screened_reply->jtalkid ); # u1 SHOULD now be notified $email = $got_notified->($u1); ok( $email, "Unscreen: u1 notified after reply unscreened" ); $subsc->delete; # Now test that journal owner doesn't get duplicate notifications my $subsc_owner = $u2->subscribe( event => "JournalNewComment", method => "Email", journal => $u2, ); ok( $subsc_owner, "Unscreen: u2 subscribed to own journal comments" ); # post a screened comment on the entry my $screened2 = $entry->t_enter_comment( u => $u3, state => 'S' ); ok( $screened2, "Unscreen: u3 posted another screened comment" ); # u2 (journal owner) SHOULD be notified of screened comment $proc_events->(); ok( $got_email{ $u2->userid }, "Unscreen: journal owner notified of screened comment" ); # unscreen it LJ::Talk::unscreen_comment( $u2, $entry->jitemid, $screened2->jtalkid ); # u2 should NOT get a duplicate notification $proc_events->(); ok( !$got_email{ $u2->userid }, "Unscreen: journal owner not notified again after unscreen" ); $subsc_owner->delete; } ); sub test_esn_flow { my $cv = shift; my $u1 = temp_user(); my $u2 = temp_user(); $u1->add_edge( $u2, watch => { nonotify => 1 } ); # make u1 watch u2 $cv->( $u1, $u2 ); } 1;