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