Add tests
[akkoma] / test / web / mastodon_api / mastodon_api_controller_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.MastodonAPI.MastodonAPIControllerTest do
6 use Pleroma.Web.ConnCase
7
8 alias Ecto.Changeset
9 alias Pleroma.Config
10 alias Pleroma.Notification
11 alias Pleroma.Repo
12 alias Pleroma.Tests.ObanHelpers
13 alias Pleroma.User
14 alias Pleroma.Web.CommonAPI
15
16 import Pleroma.Factory
17 import Swoosh.TestAssertions
18 import Tesla.Mock
19
20 setup do
21 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
22 :ok
23 end
24
25 clear_config([:instance, :public])
26 clear_config([:rich_media, :enabled])
27
28 test "getting a list of mutes", %{conn: conn} do
29 user = insert(:user)
30 other_user = insert(:user)
31
32 {:ok, user} = User.mute(user, other_user)
33
34 conn =
35 conn
36 |> assign(:user, user)
37 |> get("/api/v1/mutes")
38
39 other_user_id = to_string(other_user.id)
40 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
41 end
42
43 test "getting a list of blocks", %{conn: conn} do
44 user = insert(:user)
45 other_user = insert(:user)
46
47 {:ok, user} = User.block(user, other_user)
48
49 conn =
50 conn
51 |> assign(:user, user)
52 |> get("/api/v1/blocks")
53
54 other_user_id = to_string(other_user.id)
55 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
56 end
57
58 test "unimplemented follow_requests, blocks, domain blocks" do
59 user = insert(:user)
60
61 ["blocks", "domain_blocks", "follow_requests"]
62 |> Enum.each(fn endpoint ->
63 conn =
64 build_conn()
65 |> assign(:user, user)
66 |> get("/api/v1/#{endpoint}")
67
68 assert [] = json_response(conn, 200)
69 end)
70 end
71
72 test "returns the favorites of a user", %{conn: conn} do
73 user = insert(:user)
74 other_user = insert(:user)
75
76 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
77 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
78
79 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
80
81 first_conn =
82 conn
83 |> assign(:user, user)
84 |> get("/api/v1/favourites")
85
86 assert [status] = json_response(first_conn, 200)
87 assert status["id"] == to_string(activity.id)
88
89 assert [{"link", _link_header}] =
90 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
91
92 # Honours query params
93 {:ok, second_activity} =
94 CommonAPI.post(other_user, %{
95 "status" =>
96 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
97 })
98
99 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
100
101 last_like = status["id"]
102
103 second_conn =
104 conn
105 |> assign(:user, user)
106 |> get("/api/v1/favourites?since_id=#{last_like}")
107
108 assert [second_status] = json_response(second_conn, 200)
109 assert second_status["id"] == to_string(second_activity.id)
110
111 third_conn =
112 conn
113 |> assign(:user, user)
114 |> get("/api/v1/favourites?limit=0")
115
116 assert [] = json_response(third_conn, 200)
117 end
118
119 test "get instance information", %{conn: conn} do
120 conn = get(conn, "/api/v1/instance")
121 assert result = json_response(conn, 200)
122
123 email = Config.get([:instance, :email])
124 # Note: not checking for "max_toot_chars" since it's optional
125 assert %{
126 "uri" => _,
127 "title" => _,
128 "description" => _,
129 "version" => _,
130 "email" => from_config_email,
131 "urls" => %{
132 "streaming_api" => _
133 },
134 "stats" => _,
135 "thumbnail" => _,
136 "languages" => _,
137 "registrations" => _,
138 "poll_limits" => _
139 } = result
140
141 assert email == from_config_email
142 end
143
144 test "get instance stats", %{conn: conn} do
145 user = insert(:user, %{local: true})
146
147 user2 = insert(:user, %{local: true})
148 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
149
150 insert(:user, %{local: false, nickname: "u@peer1.com"})
151 insert(:user, %{local: false, nickname: "u@peer2.com"})
152
153 {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"})
154
155 # Stats should count users with missing or nil `info.deactivated` value
156
157 {:ok, _user} =
158 user.id
159 |> User.get_cached_by_id()
160 |> User.update_info(&Changeset.change(&1, %{deactivated: nil}))
161
162 Pleroma.Stats.force_update()
163
164 conn = get(conn, "/api/v1/instance")
165
166 assert result = json_response(conn, 200)
167
168 stats = result["stats"]
169
170 assert stats
171 assert stats["user_count"] == 1
172 assert stats["status_count"] == 1
173 assert stats["domain_count"] == 2
174 end
175
176 test "get peers", %{conn: conn} do
177 insert(:user, %{local: false, nickname: "u@peer1.com"})
178 insert(:user, %{local: false, nickname: "u@peer2.com"})
179
180 Pleroma.Stats.force_update()
181
182 conn = get(conn, "/api/v1/instance/peers")
183
184 assert result = json_response(conn, 200)
185
186 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
187 end
188
189 test "put settings", %{conn: conn} do
190 user = insert(:user)
191
192 conn =
193 conn
194 |> assign(:user, user)
195 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
196
197 assert _result = json_response(conn, 200)
198
199 user = User.get_cached_by_ap_id(user.ap_id)
200 assert user.info.settings == %{"programming" => "socks"}
201 end
202
203 describe "link headers" do
204 test "preserves parameters in link headers", %{conn: conn} do
205 user = insert(:user)
206 other_user = insert(:user)
207
208 {:ok, activity1} =
209 CommonAPI.post(other_user, %{
210 "status" => "hi @#{user.nickname}",
211 "visibility" => "public"
212 })
213
214 {:ok, activity2} =
215 CommonAPI.post(other_user, %{
216 "status" => "hi @#{user.nickname}",
217 "visibility" => "public"
218 })
219
220 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
221 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
222
223 conn =
224 conn
225 |> assign(:user, user)
226 |> get("/api/v1/notifications", %{media_only: true})
227
228 assert [link_header] = get_resp_header(conn, "link")
229 assert link_header =~ ~r/media_only=true/
230 assert link_header =~ ~r/min_id=#{notification2.id}/
231 assert link_header =~ ~r/max_id=#{notification1.id}/
232 end
233 end
234
235 describe "custom emoji" do
236 test "with tags", %{conn: conn} do
237 [emoji | _body] =
238 conn
239 |> get("/api/v1/custom_emojis")
240 |> json_response(200)
241
242 assert Map.has_key?(emoji, "shortcode")
243 assert Map.has_key?(emoji, "static_url")
244 assert Map.has_key?(emoji, "tags")
245 assert is_list(emoji["tags"])
246 assert Map.has_key?(emoji, "category")
247 assert Map.has_key?(emoji, "url")
248 assert Map.has_key?(emoji, "visible_in_picker")
249 end
250 end
251
252 describe "index/2 redirections" do
253 setup %{conn: conn} do
254 session_opts = [
255 store: :cookie,
256 key: "_test",
257 signing_salt: "cooldude"
258 ]
259
260 conn =
261 conn
262 |> Plug.Session.call(Plug.Session.init(session_opts))
263 |> fetch_session()
264
265 test_path = "/web/statuses/test"
266 %{conn: conn, path: test_path}
267 end
268
269 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
270 conn = get(conn, path)
271
272 assert conn.status == 302
273 assert redirected_to(conn) == "/web/login"
274 end
275
276 test "redirects not logged-in users to the login page on private instances", %{
277 conn: conn,
278 path: path
279 } do
280 Config.put([:instance, :public], false)
281
282 conn = get(conn, path)
283
284 assert conn.status == 302
285 assert redirected_to(conn) == "/web/login"
286 end
287
288 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
289 token = insert(:oauth_token)
290
291 conn =
292 conn
293 |> assign(:user, token.user)
294 |> put_session(:oauth_token, token.token)
295 |> get(path)
296
297 assert conn.status == 200
298 end
299
300 test "saves referer path to session", %{conn: conn, path: path} do
301 conn = get(conn, path)
302 return_to = Plug.Conn.get_session(conn, :return_to)
303
304 assert return_to == path
305 end
306
307 test "redirects to the saved path after log in", %{conn: conn, path: path} do
308 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
309 auth = insert(:oauth_authorization, app: app)
310
311 conn =
312 conn
313 |> put_session(:return_to, path)
314 |> get("/web/login", %{code: auth.token})
315
316 assert conn.status == 302
317 assert redirected_to(conn) == path
318 end
319
320 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
321 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
322 auth = insert(:oauth_authorization, app: app)
323
324 conn = get(conn, "/web/login", %{code: auth.token})
325
326 assert conn.status == 302
327 assert redirected_to(conn) == "/web/getting-started"
328 end
329 end
330
331 describe "POST /auth/password, with valid parameters" do
332 setup %{conn: conn} do
333 user = insert(:user)
334 conn = post(conn, "/auth/password?email=#{user.email}")
335 %{conn: conn, user: user}
336 end
337
338 test "it returns 204", %{conn: conn} do
339 assert json_response(conn, :no_content)
340 end
341
342 test "it creates a PasswordResetToken record for user", %{user: user} do
343 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
344 assert token_record
345 end
346
347 test "it sends an email to user", %{user: user} do
348 ObanHelpers.perform_all()
349 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
350
351 email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
352 notify_email = Config.get([:instance, :notify_email])
353 instance_name = Config.get([:instance, :name])
354
355 assert_email_sent(
356 from: {instance_name, notify_email},
357 to: {user.name, user.email},
358 html_body: email.html_body
359 )
360 end
361 end
362
363 describe "POST /auth/password, with invalid parameters" do
364 setup do
365 user = insert(:user)
366 {:ok, user: user}
367 end
368
369 test "it returns 404 when user is not found", %{conn: conn, user: user} do
370 conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
371 assert conn.status == 404
372 assert conn.resp_body == ""
373 end
374
375 test "it returns 400 when user is not local", %{conn: conn, user: user} do
376 {:ok, user} = Repo.update(Changeset.change(user, local: false))
377 conn = post(conn, "/auth/password?email=#{user.email}")
378 assert conn.status == 400
379 assert conn.resp_body == ""
380 end
381 end
382
383 describe "DELETE /auth/sign_out" do
384 test "redirect to root page", %{conn: conn} do
385 user = insert(:user)
386
387 conn =
388 conn
389 |> assign(:user, user)
390 |> delete("/auth/sign_out")
391
392 assert conn.status == 302
393 assert redirected_to(conn) == "/"
394 end
395 end
396
397 describe "empty_array, stubs for mastodon api" do
398 test "GET /api/v1/accounts/:id/identity_proofs", %{conn: conn} do
399 user = insert(:user)
400
401 res =
402 conn
403 |> assign(:user, user)
404 |> get("/api/v1/accounts/#{user.id}/identity_proofs")
405 |> json_response(200)
406
407 assert res == []
408 end
409
410 test "GET /api/v1/endorsements", %{conn: conn} do
411 user = insert(:user)
412
413 res =
414 conn
415 |> assign(:user, user)
416 |> get("/api/v1/endorsements")
417 |> json_response(200)
418
419 assert res == []
420 end
421
422 test "GET /api/v1/trends", %{conn: conn} do
423 user = insert(:user)
424
425 res =
426 conn
427 |> assign(:user, user)
428 |> get("/api/v1/trends")
429 |> json_response(200)
430
431 assert res == []
432 end
433 end
434 end