X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=test%2Fpleroma%2Fweb%2Factivity_pub%2Fside_effects_test.exs;h=ee664bb8f42b4db90d57a36905dc0583a3da462f;hb=b7e8ce235073ab45db24dfc6c27bc6998b43a200;hp=297fc0b84d1b2a8bea04b36618bd280856fac93c;hpb=cbce88007672dc810cb345bb9872a009cbdc93d8;p=akkoma diff --git a/test/pleroma/web/activity_pub/side_effects_test.exs b/test/pleroma/web/activity_pub/side_effects_test.exs index 297fc0b84..ee664bb8f 100644 --- a/test/pleroma/web/activity_pub/side_effects_test.exs +++ b/test/pleroma/web/activity_pub/side_effects_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors +# Copyright © 2017-2021 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.SideEffectsTest do @@ -7,8 +7,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do use Pleroma.DataCase alias Pleroma.Activity - alias Pleroma.Chat - alias Pleroma.Chat.MessageReference alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo @@ -17,26 +15,62 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Builder alias Pleroma.Web.ActivityPub.SideEffects + alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.CommonAPI - import ExUnit.CaptureLog import Mock import Pleroma.Factory + describe "handle" do + test "it queues a fetch of instance information" do + author = insert(:user, local: false, ap_id: "https://wowee.example.com/users/1") + recipient = insert(:user, local: true) + + {:ok, note_data, _meta} = + Builder.note(%Pleroma.Web.CommonAPI.ActivityDraft{ + user: author, + to: [recipient.ap_id], + mentions: [recipient], + content_html: "hey", + extra: %{"id" => "https://wowee.example.com/notes/1"} + }) + + {:ok, create_activity_data, _meta} = + Builder.create(author, note_data["id"], [recipient.ap_id]) + + {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) + + {:ok, _create_activity, _meta} = + SideEffects.handle(create_activity, local: false, object_data: note_data) + + assert_enqueued( + worker: Pleroma.Workers.NodeInfoFetcherWorker, + args: %{"op" => "process", "source_url" => "https://wowee.example.com/users/1"} + ) + end + end + describe "handle_after_transaction" do test "it streams out notifications and streams" do author = insert(:user, local: true) recipient = insert(:user, local: true) - {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") + {:ok, note_data, _meta} = + Builder.note(%Pleroma.Web.CommonAPI.ActivityDraft{ + user: author, + to: [recipient.ap_id], + mentions: [recipient], + content_html: "hey", + extra: %{"id" => Utils.generate_object_id()} + }) {:ok, create_activity_data, _meta} = - Builder.create(author, chat_message_data["id"], [recipient.ap_id]) + Builder.create(author, note_data["id"], [recipient.ap_id]) {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) {:ok, _create_activity, meta} = - SideEffects.handle(create_activity, local: false, object_data: chat_message_data) + SideEffects.handle(create_activity, local: false, object_data: note_data) assert [notification] = meta[:notifications] @@ -59,7 +93,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do SideEffects.handle_after_transaction(meta) assert called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification)) - assert called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_)) assert called(Pleroma.Web.Push.send(notification)) end end @@ -89,6 +122,16 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do assert User.blocks?(user, blocked) end + test "it updates following relationship", %{user: user, blocked: blocked, block: block} do + {:ok, _, _} = SideEffects.handle(block) + + refute Pleroma.FollowingRelationship.get(user, blocked) + assert User.get_follow_state(user, blocked) == nil + assert User.get_follow_state(blocked, user) == nil + assert User.get_follow_state(user, blocked, nil) == nil + assert User.get_follow_state(blocked, user, nil) == nil + end + test "it blocks but does not unfollow if the relevant setting is set", %{ user: user, blocked: blocked, @@ -109,7 +152,10 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do describe "update users" do setup do user = insert(:user, local: false) - {:ok, update_data, []} = Builder.update(user, %{"id" => user.ap_id, "name" => "new name!"}) + + {:ok, update_data, []} = + Builder.update(user, %{"id" => user.ap_id, "type" => "Person", "name" => "new name!"}) + {:ok, update, _meta} = ActivityPub.persist(update_data, local: true) %{user: user, update_data: update_data, update: update} @@ -131,112 +177,295 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do end end - describe "delete objects" do + describe "update notes" do setup do + make_time = fn -> + Pleroma.Web.ActivityPub.Utils.make_date() + end + user = insert(:user) - other_user = insert(:user) + note = insert(:note, user: user, data: %{"published" => make_time.()}) + _note_activity = insert(:note_activity, note: note) - {:ok, op} = CommonAPI.post(other_user, %{status: "big oof"}) - {:ok, post} = CommonAPI.post(user, %{status: "hey", in_reply_to_id: op}) - {:ok, favorite} = CommonAPI.favorite(user, post.id) - object = Object.normalize(post) - {:ok, delete_data, _meta} = Builder.delete(user, object.data["id"]) - {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id) - {:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true) - {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true) + updated_note = + note.data + |> Map.put("summary", "edited summary") + |> Map.put("content", "edited content") + |> Map.put("updated", make_time.()) + + {:ok, update_data, []} = Builder.update(user, updated_note) + {:ok, update, _meta} = ActivityPub.persist(update_data, local: true) %{ user: user, - delete: delete, - post: post, - object: object, - delete_user: delete_user, - op: op, - favorite: favorite + note: note, + object_id: note.id, + update_data: update_data, + update: update, + updated_note: updated_note } end - test "it handles object deletions", %{ - delete: delete, - post: post, - object: object, + test "it updates the note", %{ + object_id: object_id, + update: update, + updated_note: updated_note + } do + {:ok, _, _} = SideEffects.handle(update, object_data: updated_note) + updated_time = updated_note["updated"] + + new_note = Pleroma.Object.get_by_id(object_id) + + assert %{ + "summary" => "edited summary", + "content" => "edited content", + "updated" => ^updated_time + } = new_note.data + end + + test "it rejects updates with no updated attribute in object", %{ + object_id: object_id, + update: update, + updated_note: updated_note + } do + old_note = Pleroma.Object.get_by_id(object_id) + updated_note = Map.drop(updated_note, ["updated"]) + {:ok, _, _} = SideEffects.handle(update, object_data: updated_note) + new_note = Pleroma.Object.get_by_id(object_id) + assert old_note.data == new_note.data + end + + test "it rejects updates with updated attribute older than what we have in the original object", + %{ + object_id: object_id, + update: update, + updated_note: updated_note + } do + old_note = Pleroma.Object.get_by_id(object_id) + {:ok, creation_time, _} = DateTime.from_iso8601(old_note.data["published"]) + + updated_note = + Map.put(updated_note, "updated", DateTime.to_iso8601(DateTime.add(creation_time, -10))) + + {:ok, _, _} = SideEffects.handle(update, object_data: updated_note) + new_note = Pleroma.Object.get_by_id(object_id) + assert old_note.data == new_note.data + end + + test "it rejects updates with updated attribute older than the last Update", %{ + object_id: object_id, + update: update, + updated_note: updated_note + } do + old_note = Pleroma.Object.get_by_id(object_id) + {:ok, creation_time, _} = DateTime.from_iso8601(old_note.data["published"]) + + updated_note = + Map.put(updated_note, "updated", DateTime.to_iso8601(DateTime.add(creation_time, +10))) + + {:ok, _, _} = SideEffects.handle(update, object_data: updated_note) + + old_note = Pleroma.Object.get_by_id(object_id) + {:ok, update_time, _} = DateTime.from_iso8601(old_note.data["updated"]) + + updated_note = + Map.put(updated_note, "updated", DateTime.to_iso8601(DateTime.add(update_time, -5))) + + {:ok, _, _} = SideEffects.handle(update, object_data: updated_note) + + new_note = Pleroma.Object.get_by_id(object_id) + assert old_note.data == new_note.data + end + + test "it updates using object_data", %{ + object_id: object_id, + update: update, + updated_note: updated_note + } do + updated_note = Map.put(updated_note, "summary", "mew mew") + {:ok, _, _} = SideEffects.handle(update, object_data: updated_note) + new_note = Pleroma.Object.get_by_id(object_id) + assert %{"summary" => "mew mew", "content" => "edited content"} = new_note.data + end + + test "it records the original note in formerRepresentations", %{ + note: note, + object_id: object_id, + update: update, + updated_note: updated_note + } do + {:ok, _, _} = SideEffects.handle(update, object_data: updated_note) + %{data: new_note} = Pleroma.Object.get_by_id(object_id) + assert %{"summary" => "edited summary", "content" => "edited content"} = new_note + + assert [Map.drop(note.data, ["id", "formerRepresentations"])] == + new_note["formerRepresentations"]["orderedItems"] + + assert new_note["formerRepresentations"]["totalItems"] == 1 + end + + test "it puts the original note at the front of formerRepresentations", %{ user: user, - op: op, - favorite: favorite + note: note, + object_id: object_id, + update: update, + updated_note: updated_note } do - with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough], - stream_out: fn _ -> nil end, - stream_out_participations: fn _, _ -> nil end do - {:ok, delete, _} = SideEffects.handle(delete) - user = User.get_cached_by_ap_id(object.data["actor"]) - - assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete)) - assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user)) - end + {:ok, _, _} = SideEffects.handle(update, object_data: updated_note) + %{data: first_edit} = Pleroma.Object.get_by_id(object_id) + + second_updated_note = + note.data + |> Map.put("summary", "edited summary 2") + |> Map.put("content", "edited content 2") + |> Map.put( + "updated", + first_edit["updated"] + |> DateTime.from_iso8601() + |> elem(1) + |> DateTime.add(10) + |> DateTime.to_iso8601() + ) + + {:ok, second_update_data, []} = Builder.update(user, second_updated_note) + {:ok, update, _meta} = ActivityPub.persist(second_update_data, local: true) + {:ok, _, _} = SideEffects.handle(update, object_data: second_updated_note) + %{data: new_note} = Pleroma.Object.get_by_id(object_id) + assert %{"summary" => "edited summary 2", "content" => "edited content 2"} = new_note + + original_version = Map.drop(note.data, ["id", "formerRepresentations"]) + first_edit = Map.drop(first_edit, ["id", "formerRepresentations"]) + + assert [first_edit, original_version] == + new_note["formerRepresentations"]["orderedItems"] + + assert new_note["formerRepresentations"]["totalItems"] == 2 + end + + test "it does not prepend to formerRepresentations if no actual changes are made", %{ + note: note, + object_id: object_id, + update: update, + updated_note: updated_note + } do + {:ok, _, _} = SideEffects.handle(update, object_data: updated_note) + %{data: first_edit} = Pleroma.Object.get_by_id(object_id) - object = Object.get_by_id(object.id) - assert object.data["type"] == "Tombstone" - refute Activity.get_by_id(post.id) - refute Activity.get_by_id(favorite.id) + updated_note = + updated_note + |> Map.put( + "updated", + first_edit["updated"] + |> DateTime.from_iso8601() + |> elem(1) + |> DateTime.add(10) + |> DateTime.to_iso8601() + ) - user = User.get_by_id(user.id) - assert user.note_count == 0 + {:ok, _, _} = SideEffects.handle(update, object_data: updated_note) + %{data: new_note} = Pleroma.Object.get_by_id(object_id) + assert %{"summary" => "edited summary", "content" => "edited content"} = new_note + + original_version = Map.drop(note.data, ["id", "formerRepresentations"]) - object = Object.normalize(op.data["object"], false) + assert [original_version] == + new_note["formerRepresentations"]["orderedItems"] - assert object.data["repliesCount"] == 0 + assert new_note["formerRepresentations"]["totalItems"] == 1 + end + end + + describe "update questions" do + setup do + user = insert(:user) + + question = + insert(:question, + user: user, + data: %{"published" => Pleroma.Web.ActivityPub.Utils.make_date()} + ) + + %{user: user, data: question.data, id: question.id} end - test "it handles object deletions when the object itself has been pruned", %{ - delete: delete, - post: post, - object: object, + test "allows updating choice count without generating edit history", %{ user: user, - op: op + data: data, + id: id } do - with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough], - stream_out: fn _ -> nil end, - stream_out_participations: fn _, _ -> nil end do - {:ok, delete, _} = SideEffects.handle(delete) - user = User.get_cached_by_ap_id(object.data["actor"]) - - assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete)) - assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user)) - end + new_choices = + data["oneOf"] + |> Enum.map(fn choice -> put_in(choice, ["replies", "totalItems"], 5) end) - object = Object.get_by_id(object.id) - assert object.data["type"] == "Tombstone" - refute Activity.get_by_id(post.id) + updated_question = + data + |> Map.put("oneOf", new_choices) + |> Map.put("updated", Pleroma.Web.ActivityPub.Utils.make_date()) - user = User.get_by_id(user.id) - assert user.note_count == 0 + {:ok, update_data, []} = Builder.update(user, updated_question) + {:ok, update, _meta} = ActivityPub.persist(update_data, local: true) - object = Object.normalize(op.data["object"], false) + {:ok, _, _} = SideEffects.handle(update, object_data: updated_question) - assert object.data["repliesCount"] == 0 + %{data: new_question} = Pleroma.Object.get_by_id(id) + + assert [%{"replies" => %{"totalItems" => 5}}, %{"replies" => %{"totalItems" => 5}}] = + new_question["oneOf"] + + refute Map.has_key?(new_question, "formerRepresentations") end - test "it handles user deletions", %{delete_user: delete, user: user} do - {:ok, _delete, _} = SideEffects.handle(delete) - ObanHelpers.perform_all() + test "allows updating choice count without updated field", %{ + user: user, + data: data, + id: id + } do + new_choices = + data["oneOf"] + |> Enum.map(fn choice -> put_in(choice, ["replies", "totalItems"], 5) end) + + updated_question = + data + |> Map.put("oneOf", new_choices) + + {:ok, update_data, []} = Builder.update(user, updated_question) + {:ok, update, _meta} = ActivityPub.persist(update_data, local: true) + + {:ok, _, _} = SideEffects.handle(update, object_data: updated_question) + + %{data: new_question} = Pleroma.Object.get_by_id(id) - assert User.get_cached_by_ap_id(user.ap_id).deactivated + assert [%{"replies" => %{"totalItems" => 5}}, %{"replies" => %{"totalItems" => 5}}] = + new_question["oneOf"] + + refute Map.has_key?(new_question, "formerRepresentations") end - test "it logs issues with objects deletion", %{ - delete: delete, - object: object + test "allows updating choice count with updated field same as the creation date", %{ + user: user, + data: data, + id: id } do - {:ok, object} = - object - |> Object.change(%{data: Map.delete(object.data, "actor")}) - |> Repo.update() + new_choices = + data["oneOf"] + |> Enum.map(fn choice -> put_in(choice, ["replies", "totalItems"], 5) end) + + updated_question = + data + |> Map.put("oneOf", new_choices) + |> Map.put("updated", data["published"]) + + {:ok, update_data, []} = Builder.update(user, updated_question) + {:ok, update, _meta} = ActivityPub.persist(update_data, local: true) + + {:ok, _, _} = SideEffects.handle(update, object_data: updated_question) - Object.invalid_object_cache(object) + %{data: new_question} = Pleroma.Object.get_by_id(id) - assert capture_log(fn -> - {:error, :no_object_actor} = SideEffects.handle(delete) - end) =~ "object doesn't have an actor" + assert [%{"replies" => %{"totalItems" => 5}}, %{"replies" => %{"totalItems" => 5}}] = + new_question["oneOf"] + + refute Map.has_key?(new_question, "formerRepresentations") end end @@ -258,7 +487,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do object = Object.get_by_ap_id(emoji_react.data["object"]) assert object.data["reaction_count"] == 1 - assert ["👌", [user.ap_id]] in object.data["reactions"] + assert ["👌", [user.ap_id], nil] in object.data["reactions"] end test "creates a notification", %{emoji_react: emoji_react, poster: poster} do @@ -267,22 +496,38 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do end end + describe "Question objects" do + setup do + user = insert(:user) + question = build(:question, user: user) + question_activity = build(:question_activity, question: question) + activity_data = Map.put(question_activity.data, "object", question.data["id"]) + meta = [object_data: question.data, local: false] + + {:ok, activity, meta} = ActivityPub.persist(activity_data, meta) + + %{activity: activity, meta: meta} + end + + test "enqueues the poll end", %{activity: activity, meta: meta} do + {:ok, activity, meta} = SideEffects.handle(activity, meta) + + assert_enqueued( + worker: Pleroma.Workers.PollWorker, + args: %{op: "poll_end", activity_id: activity.id}, + scheduled_at: NaiveDateTime.from_iso8601!(meta[:object_data]["closed"]) + ) + end + end + describe "delete users with confirmation pending" do setup do - user = insert(:user, confirmation_pending: true) + user = insert(:user, is_confirmed: false) {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id) {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true) {:ok, delete: delete_user, user: user} end - test "when activation is not required", %{delete: delete, user: user} do - clear_config([:instance, :account_activation_required], false) - {:ok, _, _} = SideEffects.handle(delete) - ObanHelpers.perform_all() - - assert User.get_cached_by_id(user.id).deactivated - end - test "when activation is required", %{delete: delete, user: user} do clear_config([:instance, :account_activation_required], true) {:ok, _, _} = SideEffects.handle(delete) @@ -420,147 +665,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do end end - describe "creation of ChatMessages" do - test "notifies the recipient" do - author = insert(:user, local: false) - recipient = insert(:user, local: true) - - {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") - - {:ok, create_activity_data, _meta} = - Builder.create(author, chat_message_data["id"], [recipient.ap_id]) - - {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) - - {:ok, _create_activity, _meta} = - SideEffects.handle(create_activity, local: false, object_data: chat_message_data) - - assert Repo.get_by(Notification, user_id: recipient.id, activity_id: create_activity.id) - end - - test "it streams the created ChatMessage" do - author = insert(:user, local: true) - recipient = insert(:user, local: true) - - {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") - - {:ok, create_activity_data, _meta} = - Builder.create(author, chat_message_data["id"], [recipient.ap_id]) - - {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) - - {:ok, _create_activity, meta} = - SideEffects.handle(create_activity, local: false, object_data: chat_message_data) - - assert [_, _] = meta[:streamables] - end - - test "it creates a Chat and MessageReferences for the local users and bumps the unread count, except for the author" do - author = insert(:user, local: true) - recipient = insert(:user, local: true) - - {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") - - {:ok, create_activity_data, _meta} = - Builder.create(author, chat_message_data["id"], [recipient.ap_id]) - - {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) - - with_mocks([ - { - Pleroma.Web.Streamer, - [], - [ - stream: fn _, _ -> nil end - ] - }, - { - Pleroma.Web.Push, - [], - [ - send: fn _ -> nil end - ] - } - ]) do - {:ok, _create_activity, meta} = - SideEffects.handle(create_activity, local: false, object_data: chat_message_data) - - # The notification gets created - assert [notification] = meta[:notifications] - assert notification.activity_id == create_activity.id - - # But it is not sent out - refute called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification)) - refute called(Pleroma.Web.Push.send(notification)) - - # Same for the user chat stream - assert [{topics, _}, _] = meta[:streamables] - assert topics == ["user", "user:pleroma_chat"] - refute called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_)) - - chat = Chat.get(author.id, recipient.ap_id) - - [cm_ref] = MessageReference.for_chat_query(chat) |> Repo.all() - - assert cm_ref.object.data["content"] == "hey" - assert cm_ref.unread == false - - chat = Chat.get(recipient.id, author.ap_id) - - [cm_ref] = MessageReference.for_chat_query(chat) |> Repo.all() - - assert cm_ref.object.data["content"] == "hey" - assert cm_ref.unread == true - end - end - - test "it creates a Chat for the local users and bumps the unread count" do - author = insert(:user, local: false) - recipient = insert(:user, local: true) - - {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") - - {:ok, create_activity_data, _meta} = - Builder.create(author, chat_message_data["id"], [recipient.ap_id]) - - {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) - - {:ok, _create_activity, _meta} = - SideEffects.handle(create_activity, local: false, object_data: chat_message_data) - - # An object is created - assert Object.get_by_ap_id(chat_message_data["id"]) - - # The remote user won't get a chat - chat = Chat.get(author.id, recipient.ap_id) - refute chat - - # The local user will get a chat - chat = Chat.get(recipient.id, author.ap_id) - assert chat - - author = insert(:user, local: true) - recipient = insert(:user, local: true) - - {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") - - {:ok, create_activity_data, _meta} = - Builder.create(author, chat_message_data["id"], [recipient.ap_id]) - - {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) - - {:ok, _create_activity, _meta} = - SideEffects.handle(create_activity, local: false, object_data: chat_message_data) - - # Both users are local and get the chat - chat = Chat.get(author.id, recipient.ap_id) - assert chat - - chat = Chat.get(recipient.id, author.ap_id) - assert chat - end - end - describe "announce objects" do setup do poster = insert(:user) @@ -636,4 +740,74 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do end end end + + describe "removing a follower" do + setup do + user = insert(:user) + followed = insert(:user) + + {:ok, _, _, follow_activity} = CommonAPI.follow(user, followed) + + {:ok, reject_data, []} = Builder.reject(followed, follow_activity) + {:ok, reject, _meta} = ActivityPub.persist(reject_data, local: true) + + %{user: user, followed: followed, reject: reject} + end + + test "", %{user: user, followed: followed, reject: reject} do + assert User.following?(user, followed) + assert Pleroma.FollowingRelationship.get(user, followed) + + {:ok, _, _} = SideEffects.handle(reject) + + refute User.following?(user, followed) + refute Pleroma.FollowingRelationship.get(user, followed) + assert User.get_follow_state(user, followed) == nil + assert User.get_follow_state(user, followed, nil) == nil + end + end + + describe "removing a follower from remote" do + setup do + user = insert(:user) + followed = insert(:user, local: false) + + # Mock a local-to-remote follow + {:ok, follow_data, []} = Builder.follow(user, followed) + + follow_data = + follow_data + |> Map.put("state", "accept") + + {:ok, follow, _meta} = ActivityPub.persist(follow_data, local: true) + {:ok, _, _} = SideEffects.handle(follow) + + # Mock a remote-to-local accept + {:ok, accept_data, _} = Builder.accept(followed, follow) + {:ok, accept, _} = ActivityPub.persist(accept_data, local: false) + {:ok, _, _} = SideEffects.handle(accept) + + # Mock a remote-to-local reject + {:ok, reject_data, []} = Builder.reject(followed, follow) + {:ok, reject, _meta} = ActivityPub.persist(reject_data, local: false) + + %{user: user, followed: followed, reject: reject} + end + + test "", %{user: user, followed: followed, reject: reject} do + assert User.following?(user, followed) + assert Pleroma.FollowingRelationship.get(user, followed) + + {:ok, _, _} = SideEffects.handle(reject) + + refute User.following?(user, followed) + refute Pleroma.FollowingRelationship.get(user, followed) + + assert Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(user, followed).data["state"] == + "reject" + + assert User.get_follow_state(user, followed) == nil + assert User.get_follow_state(user, followed, nil) == nil + end + end end