publisher_test.exs (11641B)
- # Pleroma: A lightweight social networking server
- # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
- # SPDX-License-Identifier: AGPL-3.0-only
- defmodule Pleroma.Web.ActivityPub.PublisherTest do
- use Pleroma.Web.ConnCase
- import ExUnit.CaptureLog
- import Pleroma.Factory
- import Tesla.Mock
- import Mock
- alias Pleroma.Activity
- alias Pleroma.Instances
- alias Pleroma.Object
- alias Pleroma.Web.ActivityPub.Publisher
- alias Pleroma.Web.CommonAPI
- @as_public "https://www.w3.org/ns/activitystreams#Public"
- setup do
- mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
- :ok
- end
- setup_all do: clear_config([:instance, :federating], true)
- describe "gather_webfinger_links/1" do
- test "it returns links" do
- user = insert(:user)
- expected_links = [
- %{"href" => user.ap_id, "rel" => "self", "type" => "application/activity+json"},
- %{
- "href" => user.ap_id,
- "rel" => "self",
- "type" => "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
- },
- %{
- "rel" => "http://ostatus.org/schema/1.0/subscribe",
- "template" => "#{Pleroma.Web.base_url()}/ostatus_subscribe?acct={uri}"
- }
- ]
- assert expected_links == Publisher.gather_webfinger_links(user)
- end
- end
- describe "determine_inbox/2" do
- test "it returns sharedInbox for messages involving as:Public in to" do
- user = insert(:user, %{shared_inbox: "http://example.com/inbox"})
- activity = %Activity{
- data: %{"to" => [@as_public], "cc" => [user.follower_address]}
- }
- assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
- end
- test "it returns sharedInbox for messages involving as:Public in cc" do
- user = insert(:user, %{shared_inbox: "http://example.com/inbox"})
- activity = %Activity{
- data: %{"cc" => [@as_public], "to" => [user.follower_address]}
- }
- assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
- end
- test "it returns sharedInbox for messages involving multiple recipients in to" do
- user = insert(:user, %{shared_inbox: "http://example.com/inbox"})
- user_two = insert(:user)
- user_three = insert(:user)
- activity = %Activity{
- data: %{"cc" => [], "to" => [user.ap_id, user_two.ap_id, user_three.ap_id]}
- }
- assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
- end
- test "it returns sharedInbox for messages involving multiple recipients in cc" do
- user = insert(:user, %{shared_inbox: "http://example.com/inbox"})
- user_two = insert(:user)
- user_three = insert(:user)
- activity = %Activity{
- data: %{"to" => [], "cc" => [user.ap_id, user_two.ap_id, user_three.ap_id]}
- }
- assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
- end
- test "it returns sharedInbox for messages involving multiple recipients in total" do
- user =
- insert(:user, %{
- shared_inbox: "http://example.com/inbox",
- inbox: "http://example.com/personal-inbox"
- })
- user_two = insert(:user)
- activity = %Activity{
- data: %{"to" => [user_two.ap_id], "cc" => [user.ap_id]}
- }
- assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
- end
- test "it returns inbox for messages involving single recipients in total" do
- user =
- insert(:user, %{
- shared_inbox: "http://example.com/inbox",
- inbox: "http://example.com/personal-inbox"
- })
- activity = %Activity{
- data: %{"to" => [user.ap_id], "cc" => []}
- }
- assert Publisher.determine_inbox(activity, user) == "http://example.com/personal-inbox"
- end
- end
- describe "publish_one/1" do
- test "publish to url with with different ports" do
- inbox80 = "http://42.site/users/nick1/inbox"
- inbox42 = "http://42.site:42/users/nick1/inbox"
- mock(fn
- %{method: :post, url: "http://42.site:42/users/nick1/inbox"} ->
- {:ok, %Tesla.Env{status: 200, body: "port 42"}}
- %{method: :post, url: "http://42.site/users/nick1/inbox"} ->
- {:ok, %Tesla.Env{status: 200, body: "port 80"}}
- end)
- actor = insert(:user)
- assert {:ok, %{body: "port 42"}} =
- Publisher.publish_one(%{
- inbox: inbox42,
- json: "{}",
- actor: actor,
- id: 1,
- unreachable_since: true
- })
- assert {:ok, %{body: "port 80"}} =
- Publisher.publish_one(%{
- inbox: inbox80,
- json: "{}",
- actor: actor,
- id: 1,
- unreachable_since: true
- })
- end
- 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, _} = Publisher.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, _} =
- Publisher.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, _} =
- Publisher.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, _} = Publisher.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 capture_log(fn ->
- assert {:error, _} =
- Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
- end) =~ "connrefused"
- 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, _} = Publisher.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 capture_log(fn ->
- assert {:error, _} =
- Publisher.publish_one(%{
- inbox: inbox,
- json: "{}",
- actor: actor,
- id: 1,
- unreachable_since: NaiveDateTime.utc_now()
- })
- end) =~ "connrefused"
- refute called(Instances.set_unreachable(inbox))
- end
- end
- describe "publish/2" do
- test_with_mock "publishes an activity with BCC to all relevant peers.",
- Pleroma.Web.Federator.Publisher,
- [:passthrough],
- [] do
- follower =
- insert(:user, %{
- local: false,
- inbox: "https://domain.com/users/nick1/inbox",
- ap_enabled: true
- })
- actor = insert(:user, follower_address: follower.ap_id)
- user = insert(:user)
- {:ok, _follower_one} = Pleroma.User.follow(follower, actor)
- actor = refresh_record(actor)
- note_activity =
- insert(:note_activity,
- recipients: [follower.ap_id],
- data_attrs: %{"bcc" => [user.ap_id]}
- )
- res = Publisher.publish(actor, note_activity)
- assert res == :ok
- assert called(
- Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
- inbox: "https://domain.com/users/nick1/inbox",
- actor_id: actor.id,
- id: note_activity.data["id"]
- })
- )
- end
- test_with_mock "publishes a delete activity to peers who signed fetch requests to the create acitvity/object.",
- Pleroma.Web.Federator.Publisher,
- [:passthrough],
- [] do
- fetcher =
- insert(:user,
- local: false,
- inbox: "https://domain.com/users/nick1/inbox",
- ap_enabled: true
- )
- another_fetcher =
- insert(:user,
- local: false,
- inbox: "https://domain2.com/users/nick1/inbox",
- ap_enabled: true
- )
- actor = insert(:user)
- note_activity = insert(:note_activity, user: actor)
- object = Object.normalize(note_activity)
- activity_path = String.trim_leading(note_activity.data["id"], Pleroma.Web.Endpoint.url())
- object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url())
- build_conn()
- |> put_req_header("accept", "application/activity+json")
- |> assign(:user, fetcher)
- |> get(object_path)
- |> json_response(200)
- build_conn()
- |> put_req_header("accept", "application/activity+json")
- |> assign(:user, another_fetcher)
- |> get(activity_path)
- |> json_response(200)
- {:ok, delete} = CommonAPI.delete(note_activity.id, actor)
- res = Publisher.publish(actor, delete)
- assert res == :ok
- assert called(
- Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
- inbox: "https://domain.com/users/nick1/inbox",
- actor_id: actor.id,
- id: delete.data["id"]
- })
- )
- assert called(
- Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
- inbox: "https://domain2.com/users/nick1/inbox",
- actor_id: actor.id,
- id: delete.data["id"]
- })
- )
- end
- end
- end