forked from AkkomaGang/akkoma
Merge branch 'tests/activity_pub_publisher' into 'develop'
tests for Pleroma.Web.ActivityPub.Publisher See merge request pleroma/pleroma!1473
This commit is contained in:
commit
dd96be5c8b
7 changed files with 197 additions and 130 deletions
|
@ -586,12 +586,23 @@ def get_followers_query(user, page) do
|
||||||
@spec get_followers_query(User.t()) :: Ecto.Query.t()
|
@spec get_followers_query(User.t()) :: Ecto.Query.t()
|
||||||
def get_followers_query(user), do: get_followers_query(user, nil)
|
def get_followers_query(user), do: get_followers_query(user, nil)
|
||||||
|
|
||||||
|
@spec get_followers(User.t(), pos_integer()) :: {:ok, list(User.t())}
|
||||||
def get_followers(user, page \\ nil) do
|
def get_followers(user, page \\ nil) do
|
||||||
q = get_followers_query(user, page)
|
q = get_followers_query(user, page)
|
||||||
|
|
||||||
{:ok, Repo.all(q)}
|
{:ok, Repo.all(q)}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec get_external_followers(User.t(), pos_integer()) :: {:ok, list(User.t())}
|
||||||
|
def get_external_followers(user, page \\ nil) do
|
||||||
|
q =
|
||||||
|
user
|
||||||
|
|> get_followers_query(page)
|
||||||
|
|> User.Query.build(%{external: true})
|
||||||
|
|
||||||
|
{:ok, Repo.all(q)}
|
||||||
|
end
|
||||||
|
|
||||||
def get_followers_ids(user, page \\ nil) do
|
def get_followers_ids(user, page \\ nil) do
|
||||||
q = get_followers_query(user, page)
|
q = get_followers_query(user, page)
|
||||||
|
|
||||||
|
|
|
@ -97,13 +97,13 @@ defp should_federate?(inbox, public) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec recipients(User.t(), Activity.t()) :: list(User.t()) | []
|
||||||
defp recipients(actor, activity) do
|
defp recipients(actor, activity) do
|
||||||
followers =
|
{:ok, followers} =
|
||||||
if actor.follower_address in activity.recipients do
|
if actor.follower_address in activity.recipients do
|
||||||
{:ok, followers} = User.get_followers(actor)
|
User.get_external_followers(actor)
|
||||||
Enum.filter(followers, &(!&1.local))
|
|
||||||
else
|
else
|
||||||
[]
|
{:ok, []}
|
||||||
end
|
end
|
||||||
|
|
||||||
Pleroma.Web.Salmon.remote_users(actor, activity) ++ followers
|
Pleroma.Web.Salmon.remote_users(actor, activity) ++ followers
|
||||||
|
|
|
@ -8,14 +8,14 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
||||||
|
@public "https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
|
||||||
|
@spec is_public?(Object.t() | Activity.t() | map()) :: boolean()
|
||||||
def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false
|
def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false
|
||||||
def is_public?(%Object{data: data}), do: is_public?(data)
|
def is_public?(%Object{data: data}), do: is_public?(data)
|
||||||
def is_public?(%Activity{data: data}), do: is_public?(data)
|
def is_public?(%Activity{data: data}), do: is_public?(data)
|
||||||
def is_public?(%{"directMessage" => true}), do: false
|
def is_public?(%{"directMessage" => true}), do: false
|
||||||
|
def is_public?(data), do: @public in (data["to"] ++ (data["cc"] || []))
|
||||||
def is_public?(data) do
|
|
||||||
"https://www.w3.org/ns/activitystreams#Public" in (data["to"] ++ (data["cc"] || []))
|
|
||||||
end
|
|
||||||
|
|
||||||
def is_private?(activity) do
|
def is_private?(activity) do
|
||||||
with false <- is_public?(activity),
|
with false <- is_public?(activity),
|
||||||
|
@ -69,15 +69,14 @@ def entire_thread_visible_for_user?(%Activity{} = activity, %User{} = user) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_visibility(object) do
|
def get_visibility(object) do
|
||||||
public = "https://www.w3.org/ns/activitystreams#Public"
|
|
||||||
to = object.data["to"] || []
|
to = object.data["to"] || []
|
||||||
cc = object.data["cc"] || []
|
cc = object.data["cc"] || []
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
public in to ->
|
@public in to ->
|
||||||
"public"
|
"public"
|
||||||
|
|
||||||
public in cc ->
|
@public in cc ->
|
||||||
"unlisted"
|
"unlisted"
|
||||||
|
|
||||||
# this should use the sql for the object's activity
|
# this should use the sql for the object's activity
|
||||||
|
|
|
@ -118,17 +118,20 @@ def direct_note_activity_factory do
|
||||||
def note_activity_factory(attrs \\ %{}) do
|
def note_activity_factory(attrs \\ %{}) do
|
||||||
user = attrs[:user] || insert(:user)
|
user = attrs[:user] || insert(:user)
|
||||||
note = attrs[:note] || insert(:note, user: user)
|
note = attrs[:note] || insert(:note, user: user)
|
||||||
attrs = Map.drop(attrs, [:user, :note])
|
data_attrs = attrs[:data_attrs] || %{}
|
||||||
|
attrs = Map.drop(attrs, [:user, :note, :data_attrs])
|
||||||
|
|
||||||
data = %{
|
data =
|
||||||
"id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
|
%{
|
||||||
"type" => "Create",
|
"id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
|
||||||
"actor" => note.data["actor"],
|
"type" => "Create",
|
||||||
"to" => note.data["to"],
|
"actor" => note.data["actor"],
|
||||||
"object" => note.data["id"],
|
"to" => note.data["to"],
|
||||||
"published" => DateTime.utc_now() |> DateTime.to_iso8601(),
|
"object" => note.data["id"],
|
||||||
"context" => note.data["context"]
|
"published" => DateTime.utc_now() |> DateTime.to_iso8601(),
|
||||||
}
|
"context" => note.data["context"]
|
||||||
|
}
|
||||||
|
|> Map.merge(data_attrs)
|
||||||
|
|
||||||
%Pleroma.Activity{
|
%Pleroma.Activity{
|
||||||
data: data,
|
data: data,
|
||||||
|
|
|
@ -6,11 +6,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
|
||||||
use Pleroma.DataCase
|
use Pleroma.DataCase
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Builders.ActivityBuilder
|
alias Pleroma.Builders.ActivityBuilder
|
||||||
alias Pleroma.Instances
|
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.ActivityPub.Publisher
|
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
|
|
||||||
|
@ -1083,113 +1081,6 @@ test "it can create a Flag activity" do
|
||||||
} = activity
|
} = activity
|
||||||
end
|
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, _} = 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 {:error, _} = Publisher.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, _} = 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 {:error, _} =
|
|
||||||
Publisher.publish_one(%{
|
|
||||||
inbox: inbox,
|
|
||||||
json: "{}",
|
|
||||||
actor: actor,
|
|
||||||
id: 1,
|
|
||||||
unreachable_since: NaiveDateTime.utc_now()
|
|
||||||
})
|
|
||||||
|
|
||||||
refute called(Instances.set_unreachable(inbox))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test "fetch_activities/2 returns activities addressed to a list " do
|
test "fetch_activities/2 returns activities addressed to a list " do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
member = insert(:user)
|
member = insert(:user)
|
||||||
|
|
|
@ -6,12 +6,20 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
|
||||||
use Pleroma.DataCase
|
use Pleroma.DataCase
|
||||||
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
import Tesla.Mock
|
||||||
|
import Mock
|
||||||
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Instances
|
||||||
alias Pleroma.Web.ActivityPub.Publisher
|
alias Pleroma.Web.ActivityPub.Publisher
|
||||||
|
|
||||||
@as_public "https://www.w3.org/ns/activitystreams#Public"
|
@as_public "https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
|
||||||
|
setup do
|
||||||
|
mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
describe "determine_inbox/2" do
|
describe "determine_inbox/2" do
|
||||||
test "it returns sharedInbox for messages involving as:Public in to" do
|
test "it returns sharedInbox for messages involving as:Public in to" do
|
||||||
user =
|
user =
|
||||||
|
@ -109,4 +117,150 @@ test "it returns inbox for messages involving single recipients in total" do
|
||||||
assert Publisher.determine_inbox(activity, user) == "http://example.com/personal-inbox"
|
assert Publisher.determine_inbox(activity, user) == "http://example.com/personal-inbox"
|
||||||
end
|
end
|
||||||
end
|
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, _} = 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 {:error, _} = Publisher.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, _} = 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 {:error, _} =
|
||||||
|
Publisher.publish_one(%{
|
||||||
|
inbox: inbox,
|
||||||
|
json: "{}",
|
||||||
|
actor: actor,
|
||||||
|
id: 1,
|
||||||
|
unreachable_since: NaiveDateTime.utc_now()
|
||||||
|
})
|
||||||
|
|
||||||
|
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,
|
||||||
|
info: %{
|
||||||
|
ap_enabled: true,
|
||||||
|
source_data: %{"inbox" => "https://domain.com/users/nick1/inbox"}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
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: actor,
|
||||||
|
id: note_activity.data["id"]
|
||||||
|
})
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,6 +22,15 @@ defmodule Pleroma.Web.FederatorTest do
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "Publisher.perform" do
|
||||||
|
test "call `perform` with unknown task" do
|
||||||
|
assert {
|
||||||
|
:error,
|
||||||
|
"Don't know what to do with this"
|
||||||
|
} = Pleroma.Web.Federator.Publisher.perform("test", :ok, :ok)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "Publish an activity" do
|
describe "Publish an activity" do
|
||||||
setup do
|
setup do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
Loading…
Reference in a new issue