1 defmodule Pleroma.LoadTesting.Fetcher do
3 alias Pleroma.Pagination
6 alias Pleroma.Web.ActivityPub.ActivityPub
7 alias Pleroma.Web.MastodonAPI.MastodonAPI
8 alias Pleroma.Web.MastodonAPI.StatusView
10 @spec run_benchmarks(User.t()) :: any()
11 def run_benchmarks(user) do
19 Benchee.Formatters.Console
23 defp fetch_user(user) do
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
31 formatters: formatters()
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)
47 defp render_views(user) do
48 render_timelines(user)
49 render_long_thread(user)
52 defp opts_for_home_timeline(user) do
54 "blocking_user" => user,
56 "muting_user" => user,
57 "type" => ["Create", "Announce"],
59 "with_muted" => "true"
63 defp fetch_home_timeline(user) do
64 opts = opts_for_home_timeline(user)
66 recipients = [user.ap_id | User.following(user)]
69 ActivityPub.fetch_activities(recipients, opts) |> Enum.reverse() |> List.last()
72 ActivityPub.fetch_activities(recipients, Map.put(opts, "max_id", first_page_last.id))
77 ActivityPub.fetch_activities(recipients, Map.put(opts, "max_id", second_page_last.id))
82 ActivityPub.fetch_activities(recipients, Map.put(opts, "max_id", third_page_last.id))
88 "home timeline" => fn opts -> ActivityPub.fetch_activities(recipients, opts) end
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")
106 formatters: formatters()
110 defp opts_for_direct_timeline(user) do
112 :visibility => "direct",
113 "blocking_user" => user,
117 "with_muted" => "true"
121 defp fetch_direct_timeline(user) do
122 recipients = [user.ap_id]
124 opts = opts_for_direct_timeline(user)
128 |> ActivityPub.fetch_activities_query(opts)
129 |> Pagination.fetch_paginated(opts)
132 opts2 = Map.put(opts, "max_id", first_page_last.id)
136 |> ActivityPub.fetch_activities_query(opts2)
137 |> Pagination.fetch_paginated(opts2)
140 opts3 = Map.put(opts, "max_id", second_page_last.id)
144 |> ActivityPub.fetch_activities_query(opts3)
145 |> Pagination.fetch_paginated(opts3)
148 opts4 = Map.put(opts, "max_id", third_page_last.id)
152 |> ActivityPub.fetch_activities_query(opts4)
153 |> Pagination.fetch_paginated(opts4)
158 "direct timeline" => fn opts ->
159 ActivityPub.fetch_activities_query(recipients, opts) |> Pagination.fetch_paginated(opts)
167 "5 page" => Map.put(opts4, "max_id", forth_page_last.id)
169 formatters: formatters()
173 defp opts_for_public_timeline(user) do
175 "type" => ["Create", "Announce"],
176 "local_only" => false,
177 "blocking_user" => user,
178 "muting_user" => user
182 defp opts_for_public_timeline(user, :local) do
184 "type" => ["Create", "Announce"],
185 "local_only" => true,
186 "blocking_user" => user,
187 "muting_user" => user
191 defp opts_for_public_timeline(user, :tag) do
193 "blocking_user" => user,
196 "muting_user" => user,
202 "with_muted" => "true"
206 defp fetch_public_timeline(user) do
207 opts = opts_for_public_timeline(user)
209 fetch_public_timeline(opts, "public timeline")
212 defp fetch_public_timeline(user, :local) do
213 opts = opts_for_public_timeline(user, :local)
215 fetch_public_timeline(opts, "public timeline only local")
218 defp fetch_public_timeline(user, :tag) do
219 opts = opts_for_public_timeline(user, :tag)
221 fetch_public_timeline(opts, "hashtag timeline")
224 defp fetch_public_timeline(user, :only_media) do
225 opts = opts_for_public_timeline(user) |> Map.put("only_media", "true")
227 fetch_public_timeline(opts, "public timeline only media")
230 defp fetch_public_timeline(opts, title) when is_binary(title) do
231 first_page_last = ActivityPub.fetch_public_activities(opts) |> List.last()
234 ActivityPub.fetch_public_activities(Map.put(opts, "max_id", first_page_last.id))
238 ActivityPub.fetch_public_activities(Map.put(opts, "max_id", second_page_last.id))
242 ActivityPub.fetch_public_activities(Map.put(opts, "max_id", third_page_last.id))
248 ActivityPub.fetch_public_activities(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)
258 formatters: formatters()
262 defp opts_for_notifications do
263 %{"count" => "20", "with_muted" => "true"}
266 defp fetch_notifications(user) do
267 opts = opts_for_notifications()
269 first_page_last = MastodonAPI.get_notifications(user, opts) |> List.last()
272 MastodonAPI.get_notifications(user, Map.put(opts, "max_id", first_page_last.id))
276 MastodonAPI.get_notifications(user, Map.put(opts, "max_id", second_page_last.id))
280 MastodonAPI.get_notifications(user, Map.put(opts, "max_id", third_page_last.id))
285 "Notifications" => fn opts ->
286 MastodonAPI.get_notifications(user, 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)
296 formatters: formatters()
300 defp fetch_favourites(user) do
301 first_page_last = ActivityPub.fetch_favourites(user) |> List.last()
304 ActivityPub.fetch_favourites(user, %{"max_id" => first_page_last.id}) |> List.last()
307 ActivityPub.fetch_favourites(user, %{"max_id" => second_page_last.id}) |> List.last()
310 ActivityPub.fetch_favourites(user, %{"max_id" => third_page_last.id}) |> List.last()
314 "Favourites" => fn opts ->
315 ActivityPub.fetch_favourites(user, opts)
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}
325 formatters: formatters()
329 defp opts_for_long_thread(user) do
331 "blocking_user" => user,
336 defp fetch_long_thread(user) do
337 %{public_thread: public, private_thread: private} =
338 Agent.get(:benchmark_state, fn state -> state end)
340 opts = opts_for_long_thread(user)
342 private_input = {private.data["context"], Map.put(opts, "exclude_id", private.id)}
344 public_input = {public.data["context"], Map.put(opts, "exclude_id", public.id)}
348 "fetch context" => fn {context, opts} ->
349 ActivityPub.fetch_activities_for_context(context, opts)
353 "Private long thread" => private_input,
354 "Public long thread" => public_input
356 formatters: formatters()
360 defp render_timelines(user) do
361 opts = opts_for_home_timeline(user)
363 recipients = [user.ap_id | User.following(user)]
365 home_activities = ActivityPub.fetch_activities(recipients, opts) |> Enum.reverse()
367 recipients = [user.ap_id]
369 opts = opts_for_direct_timeline(user)
373 |> ActivityPub.fetch_activities_query(opts)
374 |> Pagination.fetch_paginated(opts)
376 opts = opts_for_public_timeline(user)
378 public_activities = ActivityPub.fetch_public_activities(opts)
380 opts = opts_for_public_timeline(user, :tag)
382 tag_activities = ActivityPub.fetch_public_activities(opts)
384 opts = opts_for_notifications()
386 notifications = MastodonAPI.get_notifications(user, opts)
388 favourites = ActivityPub.fetch_favourites(user)
392 "Rendering home timeline" => fn ->
393 StatusView.render("index.json", %{
394 activities: home_activities,
399 "Rendering direct timeline" => fn ->
400 StatusView.render("index.json", %{
401 activities: direct_activities,
406 "Rendering public timeline" => fn ->
407 StatusView.render("index.json", %{
408 activities: public_activities,
413 "Rendering tag timeline" => fn ->
414 StatusView.render("index.json", %{
415 activities: tag_activities,
420 "Rendering notifications" => fn ->
421 Pleroma.Web.MastodonAPI.NotificationView.render("index.json", %{
422 notifications: notifications,
426 "Rendering favourites timeline" => fn ->
427 StatusView.render("index.json", %{
428 activities: favourites,
434 formatters: formatters()
438 defp render_long_thread(user) do
439 %{public_thread: public, private_thread: private} =
440 Agent.get(:benchmark_state, fn state -> state end)
443 public_activity = Activity.get_by_id_with_object(public.id)
444 private_activity = Activity.get_by_id_with_object(private.id)
448 "render" => fn opts ->
449 StatusView.render("show.json", opts)
453 "Public root" => Map.put(opts, :activity, public_activity),
454 "Private root" => Map.put(opts, :activity, private_activity)
456 formatters: formatters()
459 fetch_opts = opts_for_long_thread(user)
462 ActivityPub.fetch_activities_for_context(
463 public.data["context"],
464 Map.put(fetch_opts, "exclude_id", public.id)
468 ActivityPub.fetch_activities_for_context(
469 private.data["context"],
470 Map.put(fetch_opts, "exclude_id", private.id)
475 "render" => fn opts ->
476 StatusView.render("context.json", opts)
480 "Public context" => %{user: user, activity: public_activity, activities: public_context},
481 "Private context" => %{
483 activity: private_activity,
484 activities: private_context
487 formatters: formatters()
491 defp fetch_timelines_with_reply_filtering(user) do
492 public_params = opts_for_public_timeline(user)
496 "Public timeline without reply filtering" => fn ->
497 ActivityPub.fetch_public_activities(public_params)
499 "Public timeline with reply filtering - following" => fn ->
501 |> Map.put("reply_visibility", "following")
502 |> Map.put("reply_filtering_user", user)
503 |> ActivityPub.fetch_public_activities()
505 "Public timeline with reply filtering - self" => fn ->
507 |> Map.put("reply_visibility", "self")
508 |> Map.put("reply_filtering_user", user)
509 |> ActivityPub.fetch_public_activities()
512 formatters: formatters()
515 private_params = opts_for_home_timeline(user)
517 recipients = [user.ap_id | User.following(user)]
521 "Home timeline without reply filtering" => fn ->
522 ActivityPub.fetch_activities(recipients, private_params)
524 "Home timeline with reply filtering - following" => fn ->
527 |> Map.put("reply_filtering_user", user)
528 |> Map.put("reply_visibility", "following")
530 ActivityPub.fetch_activities(recipients, private_params)
532 "Home timeline with reply filtering - self" => fn ->
535 |> Map.put("reply_filtering_user", user)
536 |> Map.put("reply_visibility", "self")
538 ActivityPub.fetch_activities(recipients, private_params)
541 formatters: formatters()