X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=test%2Fweb%2Factivity_pub%2Factivity_pub_test.exs;fp=test%2Fweb%2Factivity_pub%2Factivity_pub_test.exs;h=68bfb3858f7a89f2199da7f47bbf638353cf17b7;hb=627e5a0a4992cc19fc65a7e93a09c470c8e2bf33;hp=bc9fcc75df0427670f525f7482632913bc292108;hpb=d6ab701a14f7c9fb4d59953648c425e04725fc62;p=akkoma diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index bc9fcc75d..68bfb3858 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -1,12 +1,70 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.Web.ActivityPub.ActivityPubTest do use Pleroma.DataCase + alias Pleroma.Activity + alias Pleroma.Builders.ActivityBuilder + alias Pleroma.Instances + alias Pleroma.Object + alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.CommonAPI - alias Pleroma.{Activity, Object, User} - alias Pleroma.Builders.ActivityBuilder import Pleroma.Factory + import Tesla.Mock + import Mock + + setup do + mock(fn env -> apply(HttpRequestMock, :request, [env]) end) + :ok + end + + describe "fetching restricted by visibility" do + test "it restricts by the appropriate visibility" do + user = insert(:user) + + {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"}) + + {:ok, direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"}) + + {:ok, unlisted_activity} = + CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"}) + + {:ok, private_activity} = + CommonAPI.post(user, %{"status" => ".", "visibility" => "private"}) + + activities = + ActivityPub.fetch_activities([], %{:visibility => "direct", "actor_id" => user.ap_id}) + + assert activities == [direct_activity] + + activities = + ActivityPub.fetch_activities([], %{:visibility => "unlisted", "actor_id" => user.ap_id}) + + assert activities == [unlisted_activity] + + activities = + ActivityPub.fetch_activities([], %{:visibility => "private", "actor_id" => user.ap_id}) + + assert activities == [private_activity] + + activities = + ActivityPub.fetch_activities([], %{:visibility => "public", "actor_id" => user.ap_id}) + + assert activities == [public_activity] + + activities = + ActivityPub.fetch_activities([], %{ + :visibility => ~w[private public], + "actor_id" => user.ap_id + }) + + assert activities == [public_activity, private_activity] + end + end describe "building a user from his ap id" do test "it returns a user" do @@ -18,14 +76,71 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert user.info.ap_enabled assert user.follower_address == "http://mastodon.example.org/users/admin/followers" end + + test "it fetches the appropriate tag-restricted posts" do + user = insert(:user) + + {:ok, status_one} = CommonAPI.post(user, %{"status" => ". #test"}) + {:ok, status_two} = CommonAPI.post(user, %{"status" => ". #essais"}) + {:ok, status_three} = CommonAPI.post(user, %{"status" => ". #test #reject"}) + + fetch_one = ActivityPub.fetch_activities([], %{"tag" => "test"}) + fetch_two = ActivityPub.fetch_activities([], %{"tag" => ["test", "essais"]}) + + fetch_three = + ActivityPub.fetch_activities([], %{ + "tag" => ["test", "essais"], + "tag_reject" => ["reject"] + }) + + fetch_four = + ActivityPub.fetch_activities([], %{ + "tag" => ["test"], + "tag_all" => ["test", "reject"] + }) + + assert fetch_one == [status_one, status_three] + assert fetch_two == [status_one, status_two, status_three] + assert fetch_three == [status_one, status_two] + assert fetch_four == [status_three] + end end describe "insertion" do + test "drops activities beyond a certain limit" do + limit = Pleroma.Config.get([:instance, :remote_limit]) + + random_text = + :crypto.strong_rand_bytes(limit + 1) + |> Base.encode64() + |> binary_part(0, limit + 1) + + data = %{ + "ok" => true, + "object" => %{ + "content" => random_text + } + } + + assert {:error, {:remote_limit_error, _}} = ActivityPub.insert(data) + end + + test "doesn't drop activities with content being null" do + data = %{ + "ok" => true, + "object" => %{ + "content" => nil + } + } + + assert {:ok, _} = ActivityPub.insert(data) + end + test "returns the activity if one with the same id is already in" do activity = insert(:note_activity) {:ok, new_activity} = ActivityPub.insert(activity.data) - assert activity == new_activity + assert activity.id == new_activity.id end test "inserts a given map into the activity database, giving it an id if it has none." do @@ -102,7 +217,59 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert activity.data["to"] == ["user1", "user2"] assert activity.actor == user.ap_id - assert activity.recipients == ["user1", "user2"] + assert activity.recipients == ["user1", "user2", user.ap_id] + end + + test "increases user note count only for public activities" do + user = insert(:user) + + {:ok, _} = + CommonAPI.post(User.get_by_id(user.id), %{"status" => "1", "visibility" => "public"}) + + {:ok, _} = + CommonAPI.post(User.get_by_id(user.id), %{"status" => "2", "visibility" => "unlisted"}) + + {:ok, _} = + CommonAPI.post(User.get_by_id(user.id), %{"status" => "2", "visibility" => "private"}) + + {:ok, _} = + CommonAPI.post(User.get_by_id(user.id), %{"status" => "3", "visibility" => "direct"}) + + user = User.get_by_id(user.id) + assert user.info.note_count == 2 + end + + test "increases replies count" do + user = insert(:user) + user2 = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{"status" => "1", "visibility" => "public"}) + ap_id = activity.data["id"] + reply_data = %{"status" => "1", "in_reply_to_status_id" => activity.id} + + # public + {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "public")) + assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert data["object"]["repliesCount"] == 1 + assert object.data["repliesCount"] == 1 + + # unlisted + {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "unlisted")) + assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert data["object"]["repliesCount"] == 2 + assert object.data["repliesCount"] == 2 + + # private + {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "private")) + assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert data["object"]["repliesCount"] == 2 + assert object.data["repliesCount"] == 2 + + # direct + {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "direct")) + assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert data["object"]["repliesCount"] == 2 + assert object.data["repliesCount"] == 2 end end @@ -142,7 +309,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do booster = insert(:user) {:ok, user} = User.block(user, %{ap_id: activity_one.data["actor"]}) - activities = ActivityPub.fetch_activities([], %{"blocking_user" => user}) + activities = + ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true}) assert Enum.member?(activities, activity_two) assert Enum.member?(activities, activity_three) @@ -150,7 +318,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do {:ok, user} = User.unblock(user, %{ap_id: activity_one.data["actor"]}) - activities = ActivityPub.fetch_activities([], %{"blocking_user" => user}) + activities = + ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true}) assert Enum.member?(activities, activity_two) assert Enum.member?(activities, activity_three) @@ -158,17 +327,76 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do {:ok, user} = User.block(user, %{ap_id: activity_three.data["actor"]}) {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster) - %Activity{} = boost_activity = Activity.get_create_activity_by_object_ap_id(id) - activity_three = Repo.get(Activity, activity_three.id) + %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id) + activity_three = Activity.get_by_id(activity_three.id) + + activities = + ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true}) + + assert Enum.member?(activities, activity_two) + refute Enum.member?(activities, activity_three) + refute Enum.member?(activities, boost_activity) + assert Enum.member?(activities, activity_one) + + activities = + ActivityPub.fetch_activities([], %{"blocking_user" => nil, "skip_preload" => true}) + + assert Enum.member?(activities, activity_two) + assert Enum.member?(activities, activity_three) + assert Enum.member?(activities, boost_activity) + assert Enum.member?(activities, activity_one) + end + + test "doesn't return muted activities" do + activity_one = insert(:note_activity) + activity_two = insert(:note_activity) + activity_three = insert(:note_activity) + user = insert(:user) + booster = insert(:user) + {:ok, user} = User.mute(user, %User{ap_id: activity_one.data["actor"]}) + + activities = + ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true}) + + assert Enum.member?(activities, activity_two) + assert Enum.member?(activities, activity_three) + refute Enum.member?(activities, activity_one) + + # Calling with 'with_muted' will deliver muted activities, too. + activities = + ActivityPub.fetch_activities([], %{ + "muting_user" => user, + "with_muted" => true, + "skip_preload" => true + }) + + assert Enum.member?(activities, activity_two) + assert Enum.member?(activities, activity_three) + assert Enum.member?(activities, activity_one) + + {:ok, user} = User.unmute(user, %User{ap_id: activity_one.data["actor"]}) + + activities = + ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true}) + + assert Enum.member?(activities, activity_two) + assert Enum.member?(activities, activity_three) + assert Enum.member?(activities, activity_one) + + {:ok, user} = User.mute(user, %User{ap_id: activity_three.data["actor"]}) + {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster) + %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id) + activity_three = Activity.get_by_id(activity_three.id) - activities = ActivityPub.fetch_activities([], %{"blocking_user" => user}) + activities = + ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true}) assert Enum.member?(activities, activity_two) refute Enum.member?(activities, activity_three) refute Enum.member?(activities, boost_activity) assert Enum.member?(activities, activity_one) - activities = ActivityPub.fetch_activities([], %{"blocking_user" => nil}) + activities = ActivityPub.fetch_activities([], %{"muting_user" => nil, "skip_preload" => true}) assert Enum.member?(activities, activity_two) assert Enum.member?(activities, activity_three) @@ -176,11 +404,35 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert Enum.member?(activities, activity_one) end + test "does include announces on request" do + activity_three = insert(:note_activity) + user = insert(:user) + booster = insert(:user) + + {:ok, user} = User.follow(user, booster) + + {:ok, announce, _object} = CommonAPI.repeat(activity_three.id, booster) + + [announce_activity] = ActivityPub.fetch_activities([user.ap_id | user.following]) + + assert announce_activity.id == announce.id + end + + test "excludes reblogs on request" do + user = insert(:user) + {:ok, expected_activity} = ActivityBuilder.insert(%{"type" => "Create"}, %{:user => user}) + {:ok, _} = ActivityBuilder.insert(%{"type" => "Announce"}, %{:user => user}) + + [activity] = ActivityPub.fetch_user_activities(user, nil, %{"exclude_reblogs" => "true"}) + + assert activity == expected_activity + end + describe "public fetch activities" do test "doesn't retrieve unlisted activities" do user = insert(:user) - {:ok, unlisted_activity} = + {:ok, _unlisted_activity} = CommonAPI.post(user, %{"status" => "yeah", "visibility" => "unlisted"}) {:ok, listed_activity} = CommonAPI.post(user, %{"status" => "yeah"}) @@ -237,6 +489,33 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert length(activities) == 20 assert last == last_expected end + + test "doesn't return reblogs for users for whom reblogs have been muted" do + activity = insert(:note_activity) + user = insert(:user) + booster = insert(:user) + {:ok, user} = CommonAPI.hide_reblogs(user, booster) + + {:ok, activity, _} = CommonAPI.repeat(activity.id, booster) + + activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) + + refute Enum.any?(activities, fn %{id: id} -> id == activity.id end) + end + + test "returns reblogs for users for whom reblogs have not been muted" do + activity = insert(:note_activity) + user = insert(:user) + booster = insert(:user) + {:ok, user} = CommonAPI.hide_reblogs(user, booster) + {:ok, user} = CommonAPI.show_reblogs(user, booster) + + {:ok, activity, _} = CommonAPI.repeat(activity.id, booster) + + activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) + + assert Enum.any?(activities, fn %{id: id} -> id == activity.id end) + end end describe "like an object" do @@ -262,7 +541,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert like_activity == same_like_activity assert object.data["likes"] == [user.ap_id] - [note_activity] = Activity.all_by_object_ap_id(object.data["id"]) + [note_activity] = Activity.get_all_create_by_object_ap_id(object.data["id"]) assert note_activity.data["object"]["like_count"] == 1 {:ok, _like_activity, object} = ActivityPub.like(user_two, object) @@ -286,7 +565,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do {:ok, _, _, object} = ActivityPub.unlike(user, object) assert object.data["like_count"] == 0 - assert Repo.get(Activity, like_activity.id) == nil + assert Activity.get_by_id(like_activity.id) == nil end end @@ -337,7 +616,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert unannounce_activity.data["actor"] == user.ap_id assert unannounce_activity.data["context"] == announce_activity.data["context"] - assert Repo.get(Activity, announce_activity.id) == nil + assert Activity.get_by_id(announce_activity.id) == nil end end @@ -372,6 +651,43 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do end end + describe "fetching an object" do + test "it fetches an object" do + {:ok, object} = + ActivityPub.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367") + + assert activity = Activity.get_create_by_object_ap_id(object.data["id"]) + assert activity.data["id"] + + {:ok, object_again} = + ActivityPub.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367") + + assert [attachment] = object.data["attachment"] + assert is_list(attachment["url"]) + + assert object == object_again + end + + test "it works with objects only available via Ostatus" do + {:ok, object} = ActivityPub.fetch_object_from_id("https://shitposter.club/notice/2827873") + assert activity = Activity.get_create_by_object_ap_id(object.data["id"]) + assert activity.data["id"] + + {:ok, object_again} = + ActivityPub.fetch_object_from_id("https://shitposter.club/notice/2827873") + + assert object == object_again + end + + test "it correctly stitches up conversations between ostatus and ap" do + last = "https://mstdn.io/users/mayuutann/statuses/99568293732299394" + {:ok, object} = ActivityPub.fetch_object_from_id(last) + + object = Object.get_by_ap_id(object.data["inReplyTo"]) + assert object + end + end + describe "following / unfollowing" do test "creates a follow activity" do follower = insert(:user) @@ -439,9 +755,88 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do assert delete.data["actor"] == note.data["actor"] assert delete.data["object"] == note.data["object"]["id"] - assert Repo.get(Activity, delete.id) != nil + assert Activity.get_by_id(delete.id) != nil - assert Repo.get(Object, object.id) == nil + assert Repo.get(Object, object.id).data["type"] == "Tombstone" + end + + test "decrements user note count only for public activities" do + user = insert(:user, info: %{note_count: 10}) + + {:ok, a1} = + CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "public"}) + + {:ok, a2} = + CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "unlisted"}) + + {:ok, a3} = + CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "private"}) + + {:ok, a4} = + CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "direct"}) + + {:ok, _} = a1.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete() + {:ok, _} = a2.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete() + {:ok, _} = a3.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete() + {:ok, _} = a4.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete() + + user = User.get_by_id(user.id) + assert user.info.note_count == 10 + end + + test "it creates a delete activity and checks that it is also sent to users mentioned by the deleted object" do + user = insert(:user) + note = insert(:note_activity) + + {:ok, object} = + Object.get_by_ap_id(note.data["object"]["id"]) + |> Object.change(%{ + data: %{ + "actor" => note.data["object"]["actor"], + "id" => note.data["object"]["id"], + "to" => [user.ap_id], + "type" => "Note" + } + }) + |> Object.update_and_set_cache() + + {:ok, delete} = ActivityPub.delete(object) + + assert user.ap_id in delete.data["to"] + end + + test "decreases reply count" do + user = insert(:user) + user2 = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{"status" => "1", "visibility" => "public"}) + reply_data = %{"status" => "1", "in_reply_to_status_id" => activity.id} + ap_id = activity.data["id"] + + {:ok, public_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "public")) + {:ok, unlisted_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "unlisted")) + {:ok, private_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "private")) + {:ok, direct_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "direct")) + + _ = CommonAPI.delete(direct_reply.id, user2) + assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert data["object"]["repliesCount"] == 2 + assert object.data["repliesCount"] == 2 + + _ = CommonAPI.delete(private_reply.id, user2) + assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert data["object"]["repliesCount"] == 2 + assert object.data["repliesCount"] == 2 + + _ = CommonAPI.delete(public_reply.id, user2) + assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert data["object"]["repliesCount"] == 1 + assert object.data["repliesCount"] == 1 + + _ = CommonAPI.delete(unlisted_reply.id, user2) + assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) + assert data["object"]["repliesCount"] == 0 + assert object.data["repliesCount"] == 0 end end @@ -479,10 +874,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do "in_reply_to_status_id" => private_activity_2.id }) - assert user1.following == [user3.ap_id <> "/followers", user1.ap_id] - activities = ActivityPub.fetch_activities([user1.ap_id | user1.following]) + private_activity_1 = Activity.get_by_ap_id_with_object(private_activity_1.data["id"]) assert [public_activity, private_activity_1, private_activity_3] == activities assert length(activities) == 3 @@ -514,6 +908,177 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do end end + test "it can fetch peertube videos" do + {:ok, object} = + ActivityPub.fetch_object_from_id( + "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3" + ) + + assert object + end + + test "returned pinned statuses" do + Pleroma.Config.put([:instance, :max_pinned_statuses], 3) + user = insert(:user) + + {:ok, activity_one} = CommonAPI.post(user, %{"status" => "HI!!!"}) + {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"}) + {:ok, activity_three} = CommonAPI.post(user, %{"status" => "HI!!!"}) + + CommonAPI.pin(activity_one.id, user) + user = refresh_record(user) + + CommonAPI.pin(activity_two.id, user) + user = refresh_record(user) + + CommonAPI.pin(activity_three.id, user) + user = refresh_record(user) + + activities = ActivityPub.fetch_user_activities(user, nil, %{"pinned" => "true"}) + + assert 3 = length(activities) + end + + test "it can create a Flag activity" do + reporter = insert(:user) + target_account = insert(:user) + {:ok, activity} = CommonAPI.post(target_account, %{"status" => "foobar"}) + context = Utils.generate_context_id() + content = "foobar" + + reporter_ap_id = reporter.ap_id + target_ap_id = target_account.ap_id + activity_ap_id = activity.data["id"] + + assert {:ok, activity} = + ActivityPub.flag(%{ + actor: reporter, + context: context, + account: target_account, + statuses: [activity], + content: content + }) + + assert %Activity{ + actor: ^reporter_ap_id, + data: %{ + "type" => "Flag", + "content" => ^content, + "context" => ^context, + "object" => [^target_ap_id, ^activity_ap_id] + } + } = activity + end + + describe "publish_one/1" do + test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is not specified", + Instances, + [:passthrough], + [] do + actor = insert(:user) + inbox = "http://200.site/users/nick1/inbox" + + assert {:ok, _} = ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1}) + + assert called(Instances.set_reachable(inbox)) + end + + test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is set", + Instances, + [:passthrough], + [] do + actor = insert(:user) + inbox = "http://200.site/users/nick1/inbox" + + assert {:ok, _} = + ActivityPub.publish_one(%{ + inbox: inbox, + json: "{}", + actor: actor, + id: 1, + unreachable_since: NaiveDateTime.utc_now() + }) + + assert called(Instances.set_reachable(inbox)) + end + + test_with_mock "does NOT call `Instances.set_reachable` on successful federation if `unreachable_since` is nil", + Instances, + [:passthrough], + [] do + actor = insert(:user) + inbox = "http://200.site/users/nick1/inbox" + + assert {:ok, _} = + ActivityPub.publish_one(%{ + inbox: inbox, + json: "{}", + actor: actor, + id: 1, + unreachable_since: nil + }) + + refute called(Instances.set_reachable(inbox)) + end + + test_with_mock "calls `Instances.set_unreachable` on target inbox on non-2xx HTTP response code", + Instances, + [:passthrough], + [] do + actor = insert(:user) + inbox = "http://404.site/users/nick1/inbox" + + assert {:error, _} = + ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1}) + + assert called(Instances.set_unreachable(inbox)) + end + + test_with_mock "it calls `Instances.set_unreachable` on target inbox on request error of any kind", + Instances, + [:passthrough], + [] do + actor = insert(:user) + inbox = "http://connrefused.site/users/nick1/inbox" + + assert {:error, _} = + ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1}) + + assert called(Instances.set_unreachable(inbox)) + end + + test_with_mock "does NOT call `Instances.set_unreachable` if target is reachable", + Instances, + [:passthrough], + [] do + actor = insert(:user) + inbox = "http://200.site/users/nick1/inbox" + + assert {:ok, _} = ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1}) + + refute called(Instances.set_unreachable(inbox)) + end + + test_with_mock "does NOT call `Instances.set_unreachable` if target instance has non-nil `unreachable_since`", + Instances, + [:passthrough], + [] do + actor = insert(:user) + inbox = "http://connrefused.site/users/nick1/inbox" + + assert {:error, _} = + ActivityPub.publish_one(%{ + inbox: inbox, + json: "{}", + actor: actor, + id: 1, + unreachable_since: NaiveDateTime.utc_now() + }) + + refute called(Instances.set_unreachable(inbox)) + end + end + def data_uri do File.read!("test/fixtures/avatar_data_uri") end