mourningdove/t/esn-journalnewcomment.t
2026-05-24 01:03:05 +00:00

411 lines
13 KiB
Perl

# 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;