X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=test%2Fnotification_test.exs;h=b4eb7fd0f78b4e9c0ce909ffb58dea2a77048b7c;hb=36049f08efadb5f6f727753ecc1f7be6a5b4e3d8;hp=31c0d2c64848f258748786722d8c14e35ca6fac9;hpb=89fbed88212657e3dcd4bbcb2c0718b07802037f;p=akkoma diff --git a/test/notification_test.exs b/test/notification_test.exs index 31c0d2c64..b4eb7fd0f 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -4,12 +4,16 @@ defmodule Pleroma.NotificationTest do use Pleroma.DataCase - alias Pleroma.Web.TwitterAPI.TwitterAPI - alias Pleroma.Web.CommonAPI - alias Pleroma.{User, Notification} - alias Pleroma.Web.ActivityPub.Transmogrifier + import Pleroma.Factory + alias Pleroma.Notification + alias Pleroma.User + alias Pleroma.Web.ActivityPub.Transmogrifier + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.Streamer + alias Pleroma.Web.TwitterAPI.TwitterAPI + describe "create_notifications" do test "notifies someone when they are directly addressed" do user = insert(:user) @@ -28,23 +32,190 @@ defmodule Pleroma.NotificationTest do assert notification.activity_id == activity.id assert other_notification.activity_id == activity.id end + + test "it creates a notification for subscribed users" do + user = insert(:user) + subscriber = insert(:user) + + User.subscribe(subscriber, user) + + {:ok, status} = TwitterAPI.create_status(user, %{"status" => "Akariiiin"}) + {:ok, [notification]} = Notification.create_notifications(status) + + assert notification.user_id == subscriber.id + end end describe "create_notification" do - test "it doesn't create a notification for user if the user blocks the activity author" do + setup do + GenServer.start(Streamer, %{}, name: Streamer) + + on_exit(fn -> + if pid = Process.whereis(Streamer) do + Process.exit(pid, :kill) + end + end) + end + + test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do + user = insert(:user) + task = Task.async(fn -> assert_receive {:text, _}, 4_000 end) + task_user_notification = Task.async(fn -> assert_receive {:text, _}, 4_000 end) + Streamer.add_socket("user", %{transport_pid: task.pid, assigns: %{user: user}}) + + Streamer.add_socket( + "user:notification", + %{transport_pid: task_user_notification.pid, assigns: %{user: user}} + ) + + activity = insert(:note_activity) + + notify = Notification.create_notification(activity, user) + assert notify.user_id == user.id + Task.await(task) + Task.await(task_user_notification) + end + + test "it creates a notification for user if the user blocks the activity author" do activity = insert(:note_activity) - author = User.get_by_ap_id(activity.data["actor"]) + author = User.get_cached_by_ap_id(activity.data["actor"]) user = insert(:user) {:ok, user} = User.block(user, author) - assert nil == Notification.create_notification(activity, user) + assert Notification.create_notification(activity, user) + end + + test "it creates a notificatin for the user if the user mutes the activity author" do + muter = insert(:user) + muted = insert(:user) + {:ok, _} = User.mute(muter, muted) + muter = Repo.get(User, muter.id) + {:ok, activity} = CommonAPI.post(muted, %{"status" => "Hi @#{muter.nickname}"}) + + assert Notification.create_notification(activity, muter) + end + + test "notification created if user is muted without notifications" do + muter = insert(:user) + muted = insert(:user) + + {:ok, muter} = User.mute(muter, muted, false) + + {:ok, activity} = CommonAPI.post(muted, %{"status" => "Hi @#{muter.nickname}"}) + + assert Notification.create_notification(activity, muter) + end + + test "it creates a notification for an activity from a muted thread" do + muter = insert(:user) + other_user = insert(:user) + {:ok, activity} = CommonAPI.post(muter, %{"status" => "hey"}) + CommonAPI.add_mute(muter, activity) + + {:ok, activity} = + CommonAPI.post(other_user, %{ + "status" => "Hi @#{muter.nickname}", + "in_reply_to_status_id" => activity.id + }) + + assert Notification.create_notification(activity, muter) + end + + test "it disables notifications from followers" do + follower = insert(:user) + followed = insert(:user, info: %{notification_settings: %{"followers" => false}}) + User.follow(follower, followed) + {:ok, activity} = CommonAPI.post(follower, %{"status" => "hey @#{followed.nickname}"}) + refute Notification.create_notification(activity, followed) + end + + test "it disables notifications from non-followers" do + follower = insert(:user) + followed = insert(:user, info: %{notification_settings: %{"non_followers" => false}}) + {:ok, activity} = CommonAPI.post(follower, %{"status" => "hey @#{followed.nickname}"}) + refute Notification.create_notification(activity, followed) + end + + test "it disables notifications from people the user follows" do + follower = insert(:user, info: %{notification_settings: %{"follows" => false}}) + followed = insert(:user) + User.follow(follower, followed) + follower = Repo.get(User, follower.id) + {:ok, activity} = CommonAPI.post(followed, %{"status" => "hey @#{follower.nickname}"}) + refute Notification.create_notification(activity, follower) + end + + test "it disables notifications from people the user does not follow" do + follower = insert(:user, info: %{notification_settings: %{"non_follows" => false}}) + followed = insert(:user) + {:ok, activity} = CommonAPI.post(followed, %{"status" => "hey @#{follower.nickname}"}) + refute Notification.create_notification(activity, follower) end test "it doesn't create a notification for user if he is the activity author" do activity = insert(:note_activity) - author = User.get_by_ap_id(activity.data["actor"]) + author = User.get_cached_by_ap_id(activity.data["actor"]) + + refute Notification.create_notification(activity, author) + end + + test "it doesn't create a notification for follow-unfollow-follow chains" do + user = insert(:user) + followed_user = insert(:user) + {:ok, _, _, activity} = TwitterAPI.follow(user, %{"user_id" => followed_user.id}) + Notification.create_notification(activity, followed_user) + TwitterAPI.unfollow(user, %{"user_id" => followed_user.id}) + {:ok, _, _, activity_dupe} = TwitterAPI.follow(user, %{"user_id" => followed_user.id}) + refute Notification.create_notification(activity_dupe, followed_user) + end + + test "it doesn't create a notification for like-unlike-like chains" do + user = insert(:user) + liked_user = insert(:user) + {:ok, status} = TwitterAPI.create_status(liked_user, %{"status" => "Yui is best yuru"}) + {:ok, fav_status} = TwitterAPI.fav(user, status.id) + Notification.create_notification(fav_status, liked_user) + TwitterAPI.unfav(user, status.id) + {:ok, dupe} = TwitterAPI.fav(user, status.id) + refute Notification.create_notification(dupe, liked_user) + end + + test "it doesn't create a notification for repeat-unrepeat-repeat chains" do + user = insert(:user) + retweeted_user = insert(:user) + + {:ok, status} = + TwitterAPI.create_status(retweeted_user, %{ + "status" => "Send dupe notifications to the shadow realm" + }) + + {:ok, retweeted_activity} = TwitterAPI.repeat(user, status.id) + Notification.create_notification(retweeted_activity, retweeted_user) + TwitterAPI.unrepeat(user, status.id) + {:ok, dupe} = TwitterAPI.repeat(user, status.id) + refute Notification.create_notification(dupe, retweeted_user) + end - assert nil == Notification.create_notification(activity, author) + test "it doesn't create duplicate notifications for follow+subscribed users" do + user = insert(:user) + subscriber = insert(:user) + + {:ok, _, _, _} = TwitterAPI.follow(subscriber, %{"user_id" => user.id}) + User.subscribe(subscriber, user) + {:ok, status} = TwitterAPI.create_status(user, %{"status" => "Akariiiin"}) + {:ok, [_notif]} = Notification.create_notifications(status) + end + + test "it doesn't create subscription notifications if the recipient cannot see the status" do + user = insert(:user) + subscriber = insert(:user) + + User.subscribe(subscriber, user) + + {:ok, status} = + TwitterAPI.create_status(user, %{"status" => "inwisible", "visibility" => "direct"}) + + assert {:ok, []} == Notification.create_notifications(status) end end @@ -161,6 +332,51 @@ defmodule Pleroma.NotificationTest do end end + describe "for_user_since/2" do + defp days_ago(days) do + NaiveDateTime.add( + NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second), + -days * 60 * 60 * 24, + :second + ) + end + + test "Returns recent notifications" do + user1 = insert(:user) + user2 = insert(:user) + + Enum.each(0..10, fn i -> + {:ok, _activity} = + CommonAPI.post(user1, %{ + "status" => "hey ##{i} @#{user2.nickname}!" + }) + end) + + {old, new} = Enum.split(Notification.for_user(user2), 5) + + Enum.each(old, fn notification -> + notification + |> cast(%{updated_at: days_ago(10)}, [:updated_at]) + |> Pleroma.Repo.update!() + end) + + recent_notifications_ids = + user2 + |> Notification.for_user_since( + NaiveDateTime.add(NaiveDateTime.utc_now(), -5 * 86_400, :second) + ) + |> Enum.map(& &1.id) + + Enum.each(old, fn %{id: id} -> + refute id in recent_notifications_ids + end) + + Enum.each(new, fn %{id: id} -> + assert id in recent_notifications_ids + end) + end + end + describe "notification target determination" do test "it sends notifications to addressed users in new messages" do user = insert(:user) @@ -262,7 +478,7 @@ defmodule Pleroma.NotificationTest do {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"}) - assert length(Notification.for_user(user)) == 0 + assert Enum.empty?(Notification.for_user(user)) {:ok, _, _} = CommonAPI.favorite(activity.id, other_user) @@ -270,7 +486,7 @@ defmodule Pleroma.NotificationTest do {:ok, _} = CommonAPI.delete(activity.id, user) - assert length(Notification.for_user(user)) == 0 + assert Enum.empty?(Notification.for_user(user)) end test "liking an activity results in 1 notification, then 0 if the activity is unliked" do @@ -279,7 +495,7 @@ defmodule Pleroma.NotificationTest do {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"}) - assert length(Notification.for_user(user)) == 0 + assert Enum.empty?(Notification.for_user(user)) {:ok, _, _} = CommonAPI.favorite(activity.id, other_user) @@ -287,7 +503,7 @@ defmodule Pleroma.NotificationTest do {:ok, _, _, _} = CommonAPI.unfavorite(activity.id, other_user) - assert length(Notification.for_user(user)) == 0 + assert Enum.empty?(Notification.for_user(user)) end test "repeating an activity results in 1 notification, then 0 if the activity is deleted" do @@ -296,7 +512,7 @@ defmodule Pleroma.NotificationTest do {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"}) - assert length(Notification.for_user(user)) == 0 + assert Enum.empty?(Notification.for_user(user)) {:ok, _, _} = CommonAPI.repeat(activity.id, other_user) @@ -304,7 +520,7 @@ defmodule Pleroma.NotificationTest do {:ok, _} = CommonAPI.delete(activity.id, user) - assert length(Notification.for_user(user)) == 0 + assert Enum.empty?(Notification.for_user(user)) end test "repeating an activity results in 1 notification, then 0 if the activity is unrepeated" do @@ -313,7 +529,7 @@ defmodule Pleroma.NotificationTest do {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"}) - assert length(Notification.for_user(user)) == 0 + assert Enum.empty?(Notification.for_user(user)) {:ok, _, _} = CommonAPI.repeat(activity.id, other_user) @@ -321,7 +537,7 @@ defmodule Pleroma.NotificationTest do {:ok, _, _} = CommonAPI.unrepeat(activity.id, other_user) - assert length(Notification.for_user(user)) == 0 + assert Enum.empty?(Notification.for_user(user)) end test "liking an activity which is already deleted does not generate a notification" do @@ -330,15 +546,15 @@ defmodule Pleroma.NotificationTest do {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"}) - assert length(Notification.for_user(user)) == 0 + assert Enum.empty?(Notification.for_user(user)) {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user) - assert length(Notification.for_user(user)) == 0 + assert Enum.empty?(Notification.for_user(user)) {:error, _} = CommonAPI.favorite(activity.id, other_user) - assert length(Notification.for_user(user)) == 0 + assert Enum.empty?(Notification.for_user(user)) end test "repeating an activity which is already deleted does not generate a notification" do @@ -347,15 +563,15 @@ defmodule Pleroma.NotificationTest do {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"}) - assert length(Notification.for_user(user)) == 0 + assert Enum.empty?(Notification.for_user(user)) {:ok, _deletion_activity} = CommonAPI.delete(activity.id, user) - assert length(Notification.for_user(user)) == 0 + assert Enum.empty?(Notification.for_user(user)) {:error, _} = CommonAPI.repeat(activity.id, other_user) - assert length(Notification.for_user(user)) == 0 + assert Enum.empty?(Notification.for_user(user)) end test "replying to a deleted post without tagging does not generate a notification" do @@ -371,7 +587,101 @@ defmodule Pleroma.NotificationTest do "in_reply_to_status_id" => activity.id }) - assert length(Notification.for_user(user)) == 0 + assert Enum.empty?(Notification.for_user(user)) + end + end + + describe "for_user" do + test "it returns notifications for muted user without notifications" do + user = insert(:user) + muted = insert(:user) + {:ok, user} = User.mute(user, muted, false) + + {:ok, _activity} = TwitterAPI.create_status(muted, %{"status" => "hey @#{user.nickname}"}) + + assert length(Notification.for_user(user)) == 1 + end + + test "it doesn't return notifications for muted user with notifications" do + user = insert(:user) + muted = insert(:user) + {:ok, user} = User.mute(user, muted) + + {:ok, _activity} = TwitterAPI.create_status(muted, %{"status" => "hey @#{user.nickname}"}) + + assert Notification.for_user(user) == [] + end + + test "it doesn't return notifications for blocked user" do + user = insert(:user) + blocked = insert(:user) + {:ok, user} = User.block(user, blocked) + + {:ok, _activity} = TwitterAPI.create_status(blocked, %{"status" => "hey @#{user.nickname}"}) + + assert Notification.for_user(user) == [] + end + + test "it doesn't return notificatitons for blocked domain" do + user = insert(:user) + blocked = insert(:user, ap_id: "http://some-domain.com") + {:ok, user} = User.block_domain(user, "some-domain.com") + + {:ok, _activity} = TwitterAPI.create_status(blocked, %{"status" => "hey @#{user.nickname}"}) + + assert Notification.for_user(user) == [] + end + + test "it doesn't return notifications for muted thread" do + user = insert(:user) + another_user = insert(:user) + + {:ok, activity} = + TwitterAPI.create_status(another_user, %{"status" => "hey @#{user.nickname}"}) + + {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"]) + assert Notification.for_user(user) == [] + end + + test "it returns notifications for muted user with notifications and with_muted parameter" do + user = insert(:user) + muted = insert(:user) + {:ok, user} = User.mute(user, muted) + + {:ok, _activity} = TwitterAPI.create_status(muted, %{"status" => "hey @#{user.nickname}"}) + + assert length(Notification.for_user(user, %{with_muted: true})) == 1 + end + + test "it returns notifications for blocked user and with_muted parameter" do + user = insert(:user) + blocked = insert(:user) + {:ok, user} = User.block(user, blocked) + + {:ok, _activity} = TwitterAPI.create_status(blocked, %{"status" => "hey @#{user.nickname}"}) + + assert length(Notification.for_user(user, %{with_muted: true})) == 1 + end + + test "it returns notificatitons for blocked domain and with_muted parameter" do + user = insert(:user) + blocked = insert(:user, ap_id: "http://some-domain.com") + {:ok, user} = User.block_domain(user, "some-domain.com") + + {:ok, _activity} = TwitterAPI.create_status(blocked, %{"status" => "hey @#{user.nickname}"}) + + assert length(Notification.for_user(user, %{with_muted: true})) == 1 + end + + test "it returns notifications for muted thread with_muted parameter" do + user = insert(:user) + another_user = insert(:user) + + {:ok, activity} = + TwitterAPI.create_status(another_user, %{"status" => "hey @#{user.nickname}"}) + + {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"]) + assert length(Notification.for_user(user, %{with_muted: true})) == 1 end end end