[#1149] Merge remote-tracking branch 'remotes/upstream/develop' into 1149-oban-job...
[akkoma] / test / web / activity_pub / utils_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.ActivityPub.UtilsTest do
6 use Pleroma.DataCase
7 alias Pleroma.Activity
8 alias Pleroma.Object
9 alias Pleroma.Repo
10 alias Pleroma.User
11 alias Pleroma.Web.ActivityPub.ActivityPub
12 alias Pleroma.Web.ActivityPub.Utils
13 alias Pleroma.Web.CommonAPI
14
15 import Pleroma.Factory
16
17 describe "fetch the latest Follow" do
18 test "fetches the latest Follow activity" do
19 %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
20 follower = User.get_cached_by_ap_id(activity.data["actor"])
21 followed = User.get_cached_by_ap_id(activity.data["object"])
22
23 assert activity == Utils.fetch_latest_follow(follower, followed)
24 end
25 end
26
27 describe "fetch the latest Block" do
28 test "fetches the latest Block activity" do
29 blocker = insert(:user)
30 blocked = insert(:user)
31 {:ok, activity} = ActivityPub.block(blocker, blocked)
32
33 assert activity == Utils.fetch_latest_block(blocker, blocked)
34 end
35 end
36
37 describe "determine_explicit_mentions()" do
38 test "works with an object that has mentions" do
39 object = %{
40 "tag" => [
41 %{
42 "type" => "Mention",
43 "href" => "https://example.com/~alyssa",
44 "name" => "Alyssa P. Hacker"
45 }
46 ]
47 }
48
49 assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
50 end
51
52 test "works with an object that does not have mentions" do
53 object = %{
54 "tag" => [
55 %{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"}
56 ]
57 }
58
59 assert Utils.determine_explicit_mentions(object) == []
60 end
61
62 test "works with an object that has mentions and other tags" do
63 object = %{
64 "tag" => [
65 %{
66 "type" => "Mention",
67 "href" => "https://example.com/~alyssa",
68 "name" => "Alyssa P. Hacker"
69 },
70 %{"type" => "Hashtag", "href" => "https://example.com/tag/2hu", "name" => "2hu"}
71 ]
72 }
73
74 assert Utils.determine_explicit_mentions(object) == ["https://example.com/~alyssa"]
75 end
76
77 test "works with an object that has no tags" do
78 object = %{}
79
80 assert Utils.determine_explicit_mentions(object) == []
81 end
82
83 test "works with an object that has only IR tags" do
84 object = %{"tag" => ["2hu"]}
85
86 assert Utils.determine_explicit_mentions(object) == []
87 end
88 end
89
90 describe "make_like_data" do
91 setup do
92 user = insert(:user)
93 other_user = insert(:user)
94 third_user = insert(:user)
95 [user: user, other_user: other_user, third_user: third_user]
96 end
97
98 test "addresses actor's follower address if the activity is public", %{
99 user: user,
100 other_user: other_user,
101 third_user: third_user
102 } do
103 expected_to = Enum.sort([user.ap_id, other_user.follower_address])
104 expected_cc = Enum.sort(["https://www.w3.org/ns/activitystreams#Public", third_user.ap_id])
105
106 {:ok, activity} =
107 CommonAPI.post(user, %{
108 "status" =>
109 "hey @#{other_user.nickname}, @#{third_user.nickname} how about beering together this weekend?"
110 })
111
112 %{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil)
113 assert Enum.sort(to) == expected_to
114 assert Enum.sort(cc) == expected_cc
115 end
116
117 test "does not adress actor's follower address if the activity is not public", %{
118 user: user,
119 other_user: other_user,
120 third_user: third_user
121 } do
122 expected_to = Enum.sort([user.ap_id])
123 expected_cc = [third_user.ap_id]
124
125 {:ok, activity} =
126 CommonAPI.post(user, %{
127 "status" => "@#{other_user.nickname} @#{third_user.nickname} bought a new swimsuit!",
128 "visibility" => "private"
129 })
130
131 %{"to" => to, "cc" => cc} = Utils.make_like_data(other_user, activity, nil)
132 assert Enum.sort(to) == expected_to
133 assert Enum.sort(cc) == expected_cc
134 end
135 end
136
137 describe "fetch_ordered_collection" do
138 import Tesla.Mock
139
140 test "fetches the first OrderedCollectionPage when an OrderedCollection is encountered" do
141 mock(fn
142 %{method: :get, url: "http://mastodon.com/outbox"} ->
143 json(%{"type" => "OrderedCollection", "first" => "http://mastodon.com/outbox?page=true"})
144
145 %{method: :get, url: "http://mastodon.com/outbox?page=true"} ->
146 json(%{"type" => "OrderedCollectionPage", "orderedItems" => ["ok"]})
147 end)
148
149 assert Utils.fetch_ordered_collection("http://mastodon.com/outbox", 1) == ["ok"]
150 end
151
152 test "fetches several pages in the right order one after another, but only the specified amount" do
153 mock(fn
154 %{method: :get, url: "http://example.com/outbox"} ->
155 json(%{
156 "type" => "OrderedCollectionPage",
157 "orderedItems" => [0],
158 "next" => "http://example.com/outbox?page=1"
159 })
160
161 %{method: :get, url: "http://example.com/outbox?page=1"} ->
162 json(%{
163 "type" => "OrderedCollectionPage",
164 "orderedItems" => [1],
165 "next" => "http://example.com/outbox?page=2"
166 })
167
168 %{method: :get, url: "http://example.com/outbox?page=2"} ->
169 json(%{"type" => "OrderedCollectionPage", "orderedItems" => [2]})
170 end)
171
172 assert Utils.fetch_ordered_collection("http://example.com/outbox", 0) == [0]
173 assert Utils.fetch_ordered_collection("http://example.com/outbox", 1) == [0, 1]
174 end
175
176 test "returns an error if the url doesn't have an OrderedCollection/Page" do
177 mock(fn
178 %{method: :get, url: "http://example.com/not-an-outbox"} ->
179 json(%{"type" => "NotAnOutbox"})
180 end)
181
182 assert {:error, _} = Utils.fetch_ordered_collection("http://example.com/not-an-outbox", 1)
183 end
184
185 test "returns the what was collected if there are less pages than specified" do
186 mock(fn
187 %{method: :get, url: "http://example.com/outbox"} ->
188 json(%{
189 "type" => "OrderedCollectionPage",
190 "orderedItems" => [0],
191 "next" => "http://example.com/outbox?page=1"
192 })
193
194 %{method: :get, url: "http://example.com/outbox?page=1"} ->
195 json(%{"type" => "OrderedCollectionPage", "orderedItems" => [1]})
196 end)
197
198 assert Utils.fetch_ordered_collection("http://example.com/outbox", 5) == [0, 1]
199 end
200 end
201
202 test "make_json_ld_header/0" do
203 assert Utils.make_json_ld_header() == %{
204 "@context" => [
205 "https://www.w3.org/ns/activitystreams",
206 "http://localhost:4001/schemas/litepub-0.1.jsonld",
207 %{
208 "@language" => "und"
209 }
210 ]
211 }
212 end
213
214 describe "get_existing_votes" do
215 test "fetches existing votes" do
216 user = insert(:user)
217 other_user = insert(:user)
218
219 {:ok, activity} =
220 CommonAPI.post(user, %{
221 "status" => "How do I pronounce LaTeX?",
222 "poll" => %{
223 "options" => ["laytekh", "lahtekh", "latex"],
224 "expires_in" => 20,
225 "multiple" => true
226 }
227 })
228
229 object = Object.normalize(activity)
230 {:ok, votes, object} = CommonAPI.vote(other_user, object, [0, 1])
231 assert Enum.sort(Utils.get_existing_votes(other_user.ap_id, object)) == Enum.sort(votes)
232 end
233
234 test "fetches only Create activities" do
235 user = insert(:user)
236 other_user = insert(:user)
237
238 {:ok, activity} =
239 CommonAPI.post(user, %{
240 "status" => "Are we living in a society?",
241 "poll" => %{
242 "options" => ["yes", "no"],
243 "expires_in" => 20
244 }
245 })
246
247 object = Object.normalize(activity)
248 {:ok, [vote], object} = CommonAPI.vote(other_user, object, [0])
249 vote_object = Object.normalize(vote)
250 {:ok, _activity, _object} = ActivityPub.like(user, vote_object)
251 [fetched_vote] = Utils.get_existing_votes(other_user.ap_id, object)
252 assert fetched_vote.id == vote.id
253 end
254 end
255
256 describe "update_follow_state_for_all/2" do
257 test "updates the state of all Follow activities with the same actor and object" do
258 user = insert(:user, info: %{locked: true})
259 follower = insert(:user)
260
261 {:ok, follow_activity} = ActivityPub.follow(follower, user)
262 {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
263
264 data =
265 follow_activity_two.data
266 |> Map.put("state", "accept")
267
268 cng = Ecto.Changeset.change(follow_activity_two, data: data)
269
270 {:ok, follow_activity_two} = Repo.update(cng)
271
272 {:ok, follow_activity_two} =
273 Utils.update_follow_state_for_all(follow_activity_two, "accept")
274
275 assert Repo.get(Activity, follow_activity.id).data["state"] == "accept"
276 assert Repo.get(Activity, follow_activity_two.id).data["state"] == "accept"
277 end
278 end
279
280 describe "update_follow_state/2" do
281 test "updates the state of the given follow activity" do
282 user = insert(:user, info: %{locked: true})
283 follower = insert(:user)
284
285 {:ok, follow_activity} = ActivityPub.follow(follower, user)
286 {:ok, follow_activity_two} = ActivityPub.follow(follower, user)
287
288 data =
289 follow_activity_two.data
290 |> Map.put("state", "accept")
291
292 cng = Ecto.Changeset.change(follow_activity_two, data: data)
293
294 {:ok, follow_activity_two} = Repo.update(cng)
295
296 {:ok, follow_activity_two} = Utils.update_follow_state(follow_activity_two, "reject")
297
298 assert Repo.get(Activity, follow_activity.id).data["state"] == "pending"
299 assert Repo.get(Activity, follow_activity_two.id).data["state"] == "reject"
300 end
301 end
302 end