Add `account_activation_required` to /api/v1/instance
[akkoma] / benchmarks / load_testing / fetcher.ex
1 defmodule Pleroma.LoadTesting.Fetcher do
2 alias Pleroma.Activity
3 alias Pleroma.Pagination
4 alias Pleroma.Repo
5 alias Pleroma.User
6 alias Pleroma.Web.ActivityPub.ActivityPub
7 alias Pleroma.Web.MastodonAPI.MastodonAPI
8 alias Pleroma.Web.MastodonAPI.StatusView
9
10 @spec run_benchmarks(User.t()) :: any()
11 def run_benchmarks(user) do
12 fetch_user(user)
13 fetch_timelines(user)
14 render_views(user)
15 end
16
17 defp formatters do
18 [
19 Benchee.Formatters.Console
20 ]
21 end
22
23 defp fetch_user(user) do
24 Benchee.run(
25 %{
26 "By id" => fn -> Repo.get_by(User, id: user.id) end,
27 "By ap_id" => fn -> Repo.get_by(User, ap_id: user.ap_id) end,
28 "By email" => fn -> Repo.get_by(User, email: user.email) end,
29 "By nickname" => fn -> Repo.get_by(User, nickname: user.nickname) end
30 },
31 formatters: formatters()
32 )
33 end
34
35 defp fetch_timelines(user) do
36 fetch_home_timeline(user)
37 fetch_direct_timeline(user)
38 fetch_public_timeline(user)
39 fetch_public_timeline(user, :local)
40 fetch_public_timeline(user, :tag)
41 fetch_notifications(user)
42 fetch_favourites(user)
43 fetch_long_thread(user)
44 fetch_timelines_with_reply_filtering(user)
45 end
46
47 defp render_views(user) do
48 render_timelines(user)
49 render_long_thread(user)
50 end
51
52 defp opts_for_home_timeline(user) do
53 %{
54 "blocking_user" => user,
55 "count" => "20",
56 "muting_user" => user,
57 "type" => ["Create", "Announce"],
58 "user" => user,
59 "with_muted" => "true"
60 }
61 end
62
63 defp fetch_home_timeline(user) do
64 opts = opts_for_home_timeline(user)
65
66 recipients = [user.ap_id | User.following(user)]
67
68 first_page_last =
69 ActivityPub.fetch_activities(recipients, opts) |> Enum.reverse() |> List.last()
70
71 second_page_last =
72 ActivityPub.fetch_activities(recipients, Map.put(opts, "max_id", first_page_last.id))
73 |> Enum.reverse()
74 |> List.last()
75
76 third_page_last =
77 ActivityPub.fetch_activities(recipients, Map.put(opts, "max_id", second_page_last.id))
78 |> Enum.reverse()
79 |> List.last()
80
81 forth_page_last =
82 ActivityPub.fetch_activities(recipients, Map.put(opts, "max_id", third_page_last.id))
83 |> Enum.reverse()
84 |> List.last()
85
86 Benchee.run(
87 %{
88 "home timeline" => fn opts -> ActivityPub.fetch_activities(recipients, opts) end
89 },
90 inputs: %{
91 "1 page" => opts,
92 "2 page" => Map.put(opts, "max_id", first_page_last.id),
93 "3 page" => Map.put(opts, "max_id", second_page_last.id),
94 "4 page" => Map.put(opts, "max_id", third_page_last.id),
95 "5 page" => Map.put(opts, "max_id", forth_page_last.id),
96 "1 page only media" => Map.put(opts, "only_media", "true"),
97 "2 page only media" =>
98 Map.put(opts, "max_id", first_page_last.id) |> Map.put("only_media", "true"),
99 "3 page only media" =>
100 Map.put(opts, "max_id", second_page_last.id) |> Map.put("only_media", "true"),
101 "4 page only media" =>
102 Map.put(opts, "max_id", third_page_last.id) |> Map.put("only_media", "true"),
103 "5 page only media" =>
104 Map.put(opts, "max_id", forth_page_last.id) |> Map.put("only_media", "true")
105 },
106 formatters: formatters()
107 )
108 end
109
110 defp opts_for_direct_timeline(user) do
111 %{
112 :visibility => "direct",
113 "blocking_user" => user,
114 "count" => "20",
115 "type" => "Create",
116 "user" => user,
117 "with_muted" => "true"
118 }
119 end
120
121 defp fetch_direct_timeline(user) do
122 recipients = [user.ap_id]
123
124 opts = opts_for_direct_timeline(user)
125
126 first_page_last =
127 recipients
128 |> ActivityPub.fetch_activities_query(opts)
129 |> Pagination.fetch_paginated(opts)
130 |> List.last()
131
132 opts2 = Map.put(opts, "max_id", first_page_last.id)
133
134 second_page_last =
135 recipients
136 |> ActivityPub.fetch_activities_query(opts2)
137 |> Pagination.fetch_paginated(opts2)
138 |> List.last()
139
140 opts3 = Map.put(opts, "max_id", second_page_last.id)
141
142 third_page_last =
143 recipients
144 |> ActivityPub.fetch_activities_query(opts3)
145 |> Pagination.fetch_paginated(opts3)
146 |> List.last()
147
148 opts4 = Map.put(opts, "max_id", third_page_last.id)
149
150 forth_page_last =
151 recipients
152 |> ActivityPub.fetch_activities_query(opts4)
153 |> Pagination.fetch_paginated(opts4)
154 |> List.last()
155
156 Benchee.run(
157 %{
158 "direct timeline" => fn opts ->
159 ActivityPub.fetch_activities_query(recipients, opts) |> Pagination.fetch_paginated(opts)
160 end
161 },
162 inputs: %{
163 "1 page" => opts,
164 "2 page" => opts2,
165 "3 page" => opts3,
166 "4 page" => opts4,
167 "5 page" => Map.put(opts4, "max_id", forth_page_last.id)
168 },
169 formatters: formatters()
170 )
171 end
172
173 defp opts_for_public_timeline(user) do
174 %{
175 "type" => ["Create", "Announce"],
176 "local_only" => false,
177 "blocking_user" => user,
178 "muting_user" => user
179 }
180 end
181
182 defp opts_for_public_timeline(user, :local) do
183 %{
184 "type" => ["Create", "Announce"],
185 "local_only" => true,
186 "blocking_user" => user,
187 "muting_user" => user
188 }
189 end
190
191 defp opts_for_public_timeline(user, :tag) do
192 %{
193 "blocking_user" => user,
194 "count" => "20",
195 "local_only" => nil,
196 "muting_user" => user,
197 "tag" => ["tag"],
198 "tag_all" => [],
199 "tag_reject" => [],
200 "type" => "Create",
201 "user" => user,
202 "with_muted" => "true"
203 }
204 end
205
206 defp fetch_public_timeline(user) do
207 opts = opts_for_public_timeline(user)
208
209 fetch_public_timeline(opts, "public timeline")
210 end
211
212 defp fetch_public_timeline(user, :local) do
213 opts = opts_for_public_timeline(user, :local)
214
215 fetch_public_timeline(opts, "public timeline only local")
216 end
217
218 defp fetch_public_timeline(user, :tag) do
219 opts = opts_for_public_timeline(user, :tag)
220
221 fetch_public_timeline(opts, "hashtag timeline")
222 end
223
224 defp fetch_public_timeline(user, :only_media) do
225 opts = opts_for_public_timeline(user) |> Map.put("only_media", "true")
226
227 fetch_public_timeline(opts, "public timeline only media")
228 end
229
230 defp fetch_public_timeline(opts, title) when is_binary(title) do
231 first_page_last = ActivityPub.fetch_public_activities(opts) |> List.last()
232
233 second_page_last =
234 ActivityPub.fetch_public_activities(Map.put(opts, "max_id", first_page_last.id))
235 |> List.last()
236
237 third_page_last =
238 ActivityPub.fetch_public_activities(Map.put(opts, "max_id", second_page_last.id))
239 |> List.last()
240
241 forth_page_last =
242 ActivityPub.fetch_public_activities(Map.put(opts, "max_id", third_page_last.id))
243 |> List.last()
244
245 Benchee.run(
246 %{
247 title => fn opts ->
248 ActivityPub.fetch_public_activities(opts)
249 end
250 },
251 inputs: %{
252 "1 page" => opts,
253 "2 page" => Map.put(opts, "max_id", first_page_last.id),
254 "3 page" => Map.put(opts, "max_id", second_page_last.id),
255 "4 page" => Map.put(opts, "max_id", third_page_last.id),
256 "5 page" => Map.put(opts, "max_id", forth_page_last.id)
257 },
258 formatters: formatters()
259 )
260 end
261
262 defp opts_for_notifications do
263 %{"count" => "20", "with_muted" => "true"}
264 end
265
266 defp fetch_notifications(user) do
267 opts = opts_for_notifications()
268
269 first_page_last = MastodonAPI.get_notifications(user, opts) |> List.last()
270
271 second_page_last =
272 MastodonAPI.get_notifications(user, Map.put(opts, "max_id", first_page_last.id))
273 |> List.last()
274
275 third_page_last =
276 MastodonAPI.get_notifications(user, Map.put(opts, "max_id", second_page_last.id))
277 |> List.last()
278
279 forth_page_last =
280 MastodonAPI.get_notifications(user, Map.put(opts, "max_id", third_page_last.id))
281 |> List.last()
282
283 Benchee.run(
284 %{
285 "Notifications" => fn opts ->
286 MastodonAPI.get_notifications(user, opts)
287 end
288 },
289 inputs: %{
290 "1 page" => opts,
291 "2 page" => Map.put(opts, "max_id", first_page_last.id),
292 "3 page" => Map.put(opts, "max_id", second_page_last.id),
293 "4 page" => Map.put(opts, "max_id", third_page_last.id),
294 "5 page" => Map.put(opts, "max_id", forth_page_last.id)
295 },
296 formatters: formatters()
297 )
298 end
299
300 defp fetch_favourites(user) do
301 first_page_last = ActivityPub.fetch_favourites(user) |> List.last()
302
303 second_page_last =
304 ActivityPub.fetch_favourites(user, %{"max_id" => first_page_last.id}) |> List.last()
305
306 third_page_last =
307 ActivityPub.fetch_favourites(user, %{"max_id" => second_page_last.id}) |> List.last()
308
309 forth_page_last =
310 ActivityPub.fetch_favourites(user, %{"max_id" => third_page_last.id}) |> List.last()
311
312 Benchee.run(
313 %{
314 "Favourites" => fn opts ->
315 ActivityPub.fetch_favourites(user, opts)
316 end
317 },
318 inputs: %{
319 "1 page" => %{},
320 "2 page" => %{"max_id" => first_page_last.id},
321 "3 page" => %{"max_id" => second_page_last.id},
322 "4 page" => %{"max_id" => third_page_last.id},
323 "5 page" => %{"max_id" => forth_page_last.id}
324 },
325 formatters: formatters()
326 )
327 end
328
329 defp opts_for_long_thread(user) do
330 %{
331 "blocking_user" => user,
332 "user" => user
333 }
334 end
335
336 defp fetch_long_thread(user) do
337 %{public_thread: public, private_thread: private} =
338 Agent.get(:benchmark_state, fn state -> state end)
339
340 opts = opts_for_long_thread(user)
341
342 private_input = {private.data["context"], Map.put(opts, "exclude_id", private.id)}
343
344 public_input = {public.data["context"], Map.put(opts, "exclude_id", public.id)}
345
346 Benchee.run(
347 %{
348 "fetch context" => fn {context, opts} ->
349 ActivityPub.fetch_activities_for_context(context, opts)
350 end
351 },
352 inputs: %{
353 "Private long thread" => private_input,
354 "Public long thread" => public_input
355 },
356 formatters: formatters()
357 )
358 end
359
360 defp render_timelines(user) do
361 opts = opts_for_home_timeline(user)
362
363 recipients = [user.ap_id | User.following(user)]
364
365 home_activities = ActivityPub.fetch_activities(recipients, opts) |> Enum.reverse()
366
367 recipients = [user.ap_id]
368
369 opts = opts_for_direct_timeline(user)
370
371 direct_activities =
372 recipients
373 |> ActivityPub.fetch_activities_query(opts)
374 |> Pagination.fetch_paginated(opts)
375
376 opts = opts_for_public_timeline(user)
377
378 public_activities = ActivityPub.fetch_public_activities(opts)
379
380 opts = opts_for_public_timeline(user, :tag)
381
382 tag_activities = ActivityPub.fetch_public_activities(opts)
383
384 opts = opts_for_notifications()
385
386 notifications = MastodonAPI.get_notifications(user, opts)
387
388 favourites = ActivityPub.fetch_favourites(user)
389
390 Benchee.run(
391 %{
392 "Rendering home timeline" => fn ->
393 StatusView.render("index.json", %{
394 activities: home_activities,
395 for: user,
396 as: :activity
397 })
398 end,
399 "Rendering direct timeline" => fn ->
400 StatusView.render("index.json", %{
401 activities: direct_activities,
402 for: user,
403 as: :activity
404 })
405 end,
406 "Rendering public timeline" => fn ->
407 StatusView.render("index.json", %{
408 activities: public_activities,
409 for: user,
410 as: :activity
411 })
412 end,
413 "Rendering tag timeline" => fn ->
414 StatusView.render("index.json", %{
415 activities: tag_activities,
416 for: user,
417 as: :activity
418 })
419 end,
420 "Rendering notifications" => fn ->
421 Pleroma.Web.MastodonAPI.NotificationView.render("index.json", %{
422 notifications: notifications,
423 for: user
424 })
425 end,
426 "Rendering favourites timeline" => fn ->
427 StatusView.render("index.json", %{
428 activities: favourites,
429 for: user,
430 as: :activity
431 })
432 end
433 },
434 formatters: formatters()
435 )
436 end
437
438 defp render_long_thread(user) do
439 %{public_thread: public, private_thread: private} =
440 Agent.get(:benchmark_state, fn state -> state end)
441
442 opts = %{for: user}
443 public_activity = Activity.get_by_id_with_object(public.id)
444 private_activity = Activity.get_by_id_with_object(private.id)
445
446 Benchee.run(
447 %{
448 "render" => fn opts ->
449 StatusView.render("show.json", opts)
450 end
451 },
452 inputs: %{
453 "Public root" => Map.put(opts, :activity, public_activity),
454 "Private root" => Map.put(opts, :activity, private_activity)
455 },
456 formatters: formatters()
457 )
458
459 fetch_opts = opts_for_long_thread(user)
460
461 public_context =
462 ActivityPub.fetch_activities_for_context(
463 public.data["context"],
464 Map.put(fetch_opts, "exclude_id", public.id)
465 )
466
467 private_context =
468 ActivityPub.fetch_activities_for_context(
469 private.data["context"],
470 Map.put(fetch_opts, "exclude_id", private.id)
471 )
472
473 Benchee.run(
474 %{
475 "render" => fn opts ->
476 StatusView.render("context.json", opts)
477 end
478 },
479 inputs: %{
480 "Public context" => %{user: user, activity: public_activity, activities: public_context},
481 "Private context" => %{
482 user: user,
483 activity: private_activity,
484 activities: private_context
485 }
486 },
487 formatters: formatters()
488 )
489 end
490
491 defp fetch_timelines_with_reply_filtering(user) do
492 public_params = opts_for_public_timeline(user)
493
494 Benchee.run(
495 %{
496 "Public timeline without reply filtering" => fn ->
497 ActivityPub.fetch_public_activities(public_params)
498 end,
499 "Public timeline with reply filtering - following" => fn ->
500 public_params
501 |> Map.put("reply_visibility", "following")
502 |> Map.put("reply_filtering_user", user)
503 |> ActivityPub.fetch_public_activities()
504 end,
505 "Public timeline with reply filtering - self" => fn ->
506 public_params
507 |> Map.put("reply_visibility", "self")
508 |> Map.put("reply_filtering_user", user)
509 |> ActivityPub.fetch_public_activities()
510 end
511 },
512 formatters: formatters()
513 )
514
515 private_params = opts_for_home_timeline(user)
516
517 recipients = [user.ap_id | User.following(user)]
518
519 Benchee.run(
520 %{
521 "Home timeline without reply filtering" => fn ->
522 ActivityPub.fetch_activities(recipients, private_params)
523 end,
524 "Home timeline with reply filtering - following" => fn ->
525 private_params =
526 private_params
527 |> Map.put("reply_filtering_user", user)
528 |> Map.put("reply_visibility", "following")
529
530 ActivityPub.fetch_activities(recipients, private_params)
531 end,
532 "Home timeline with reply filtering - self" => fn ->
533 private_params =
534 private_params
535 |> Map.put("reply_filtering_user", user)
536 |> Map.put("reply_visibility", "self")
537
538 ActivityPub.fetch_activities(recipients, private_params)
539 end
540 },
541 formatters: formatters()
542 )
543 end
544 end