added prepare html for RichMedia.Parser
[akkoma] / test / web / activity_pub / publisher_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.ActivityPub.PublisherTest do
6 use Pleroma.DataCase
7
8 import ExUnit.CaptureLog
9 import Pleroma.Factory
10 import Tesla.Mock
11 import Mock
12
13 alias Pleroma.Activity
14 alias Pleroma.Instances
15 alias Pleroma.Web.ActivityPub.Publisher
16
17 @as_public "https://www.w3.org/ns/activitystreams#Public"
18
19 setup do
20 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
21 :ok
22 end
23
24 describe "determine_inbox/2" do
25 test "it returns sharedInbox for messages involving as:Public in to" do
26 user =
27 insert(:user, %{
28 info: %{source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}}
29 })
30
31 activity = %Activity{
32 data: %{"to" => [@as_public], "cc" => [user.follower_address]}
33 }
34
35 assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
36 end
37
38 test "it returns sharedInbox for messages involving as:Public in cc" do
39 user =
40 insert(:user, %{
41 info: %{source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}}
42 })
43
44 activity = %Activity{
45 data: %{"cc" => [@as_public], "to" => [user.follower_address]}
46 }
47
48 assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
49 end
50
51 test "it returns sharedInbox for messages involving multiple recipients in to" do
52 user =
53 insert(:user, %{
54 info: %{source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}}
55 })
56
57 user_two = insert(:user)
58 user_three = insert(:user)
59
60 activity = %Activity{
61 data: %{"cc" => [], "to" => [user.ap_id, user_two.ap_id, user_three.ap_id]}
62 }
63
64 assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
65 end
66
67 test "it returns sharedInbox for messages involving multiple recipients in cc" do
68 user =
69 insert(:user, %{
70 info: %{source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}}
71 })
72
73 user_two = insert(:user)
74 user_three = insert(:user)
75
76 activity = %Activity{
77 data: %{"to" => [], "cc" => [user.ap_id, user_two.ap_id, user_three.ap_id]}
78 }
79
80 assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
81 end
82
83 test "it returns sharedInbox for messages involving multiple recipients in total" do
84 user =
85 insert(:user, %{
86 info: %{
87 source_data: %{
88 "inbox" => "http://example.com/personal-inbox",
89 "endpoints" => %{"sharedInbox" => "http://example.com/inbox"}
90 }
91 }
92 })
93
94 user_two = insert(:user)
95
96 activity = %Activity{
97 data: %{"to" => [user_two.ap_id], "cc" => [user.ap_id]}
98 }
99
100 assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
101 end
102
103 test "it returns inbox for messages involving single recipients in total" do
104 user =
105 insert(:user, %{
106 info: %{
107 source_data: %{
108 "inbox" => "http://example.com/personal-inbox",
109 "endpoints" => %{"sharedInbox" => "http://example.com/inbox"}
110 }
111 }
112 })
113
114 activity = %Activity{
115 data: %{"to" => [user.ap_id], "cc" => []}
116 }
117
118 assert Publisher.determine_inbox(activity, user) == "http://example.com/personal-inbox"
119 end
120 end
121
122 describe "publish_one/1" do
123 test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is not specified",
124 Instances,
125 [:passthrough],
126 [] do
127 actor = insert(:user)
128 inbox = "http://200.site/users/nick1/inbox"
129
130 assert {:ok, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
131
132 assert called(Instances.set_reachable(inbox))
133 end
134
135 test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is set",
136 Instances,
137 [:passthrough],
138 [] do
139 actor = insert(:user)
140 inbox = "http://200.site/users/nick1/inbox"
141
142 assert {:ok, _} =
143 Publisher.publish_one(%{
144 inbox: inbox,
145 json: "{}",
146 actor: actor,
147 id: 1,
148 unreachable_since: NaiveDateTime.utc_now()
149 })
150
151 assert called(Instances.set_reachable(inbox))
152 end
153
154 test_with_mock "does NOT call `Instances.set_reachable` on successful federation if `unreachable_since` is nil",
155 Instances,
156 [:passthrough],
157 [] do
158 actor = insert(:user)
159 inbox = "http://200.site/users/nick1/inbox"
160
161 assert {:ok, _} =
162 Publisher.publish_one(%{
163 inbox: inbox,
164 json: "{}",
165 actor: actor,
166 id: 1,
167 unreachable_since: nil
168 })
169
170 refute called(Instances.set_reachable(inbox))
171 end
172
173 test_with_mock "calls `Instances.set_unreachable` on target inbox on non-2xx HTTP response code",
174 Instances,
175 [:passthrough],
176 [] do
177 actor = insert(:user)
178 inbox = "http://404.site/users/nick1/inbox"
179
180 assert {:error, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
181
182 assert called(Instances.set_unreachable(inbox))
183 end
184
185 test_with_mock "it calls `Instances.set_unreachable` on target inbox on request error of any kind",
186 Instances,
187 [:passthrough],
188 [] do
189 actor = insert(:user)
190 inbox = "http://connrefused.site/users/nick1/inbox"
191
192 assert capture_log(fn ->
193 assert {:error, _} =
194 Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
195 end) =~ "connrefused"
196
197 assert called(Instances.set_unreachable(inbox))
198 end
199
200 test_with_mock "does NOT call `Instances.set_unreachable` if target is reachable",
201 Instances,
202 [:passthrough],
203 [] do
204 actor = insert(:user)
205 inbox = "http://200.site/users/nick1/inbox"
206
207 assert {:ok, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
208
209 refute called(Instances.set_unreachable(inbox))
210 end
211
212 test_with_mock "does NOT call `Instances.set_unreachable` if target instance has non-nil `unreachable_since`",
213 Instances,
214 [:passthrough],
215 [] do
216 actor = insert(:user)
217 inbox = "http://connrefused.site/users/nick1/inbox"
218
219 assert capture_log(fn ->
220 assert {:error, _} =
221 Publisher.publish_one(%{
222 inbox: inbox,
223 json: "{}",
224 actor: actor,
225 id: 1,
226 unreachable_since: NaiveDateTime.utc_now()
227 })
228 end) =~ "connrefused"
229
230 refute called(Instances.set_unreachable(inbox))
231 end
232 end
233
234 describe "publish/2" do
235 test_with_mock "publishes an activity with BCC to all relevant peers.",
236 Pleroma.Web.Federator.Publisher,
237 [:passthrough],
238 [] do
239 follower =
240 insert(:user,
241 local: false,
242 info: %{
243 ap_enabled: true,
244 source_data: %{"inbox" => "https://domain.com/users/nick1/inbox"}
245 }
246 )
247
248 actor = insert(:user, follower_address: follower.ap_id)
249 user = insert(:user)
250
251 {:ok, _follower_one} = Pleroma.User.follow(follower, actor)
252 actor = refresh_record(actor)
253
254 note_activity =
255 insert(:note_activity,
256 recipients: [follower.ap_id],
257 data_attrs: %{"bcc" => [user.ap_id]}
258 )
259
260 res = Publisher.publish(actor, note_activity)
261 assert res == :ok
262
263 assert called(
264 Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
265 inbox: "https://domain.com/users/nick1/inbox",
266 actor: actor,
267 id: note_activity.data["id"]
268 })
269 )
270 end
271 end
272 end