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)
390 output_relationships =
391 !!Pleroma.Config.get([:extensions, :output_relationships_in_statuses_by_default])
395 "Rendering home timeline" => fn ->
396 StatusView.render("index.json", %{
397 activities: home_activities,
400 skip_relationships: !output_relationships
403 "Rendering direct timeline" => fn ->
404 StatusView.render("index.json", %{
405 activities: direct_activities,
408 skip_relationships: !output_relationships
411 "Rendering public timeline" => fn ->
412 StatusView.render("index.json", %{
413 activities: public_activities,
416 skip_relationships: !output_relationships
419 "Rendering tag timeline" => fn ->
420 StatusView.render("index.json", %{
421 activities: tag_activities,
424 skip_relationships: !output_relationships
427 "Rendering notifications" => fn ->
428 Pleroma.Web.MastodonAPI.NotificationView.render("index.json", %{
429 notifications: notifications,
431 skip_relationships: !output_relationships
434 "Rendering favourites timeline" => fn ->
435 StatusView.render("index.json", %{
436 activities: favourites,
439 skip_relationships: !output_relationships
443 formatters: formatters()
447 defp render_long_thread(user) do
448 %{public_thread: public, private_thread: private} =
449 Agent.get(:benchmark_state, fn state -> state end)
452 public_activity = Activity.get_by_id_with_object(public.id)
453 private_activity = Activity.get_by_id_with_object(private.id)
457 "render" => fn opts ->
458 StatusView.render("show.json", opts)
462 "Public root" => Map.put(opts, :activity, public_activity),
463 "Private root" => Map.put(opts, :activity, private_activity)
465 formatters: formatters()
468 fetch_opts = opts_for_long_thread(user)
471 ActivityPub.fetch_activities_for_context(
472 public.data["context"],
473 Map.put(fetch_opts, "exclude_id", public.id)
477 ActivityPub.fetch_activities_for_context(
478 private.data["context"],
479 Map.put(fetch_opts, "exclude_id", private.id)
484 "render" => fn opts ->
485 StatusView.render("context.json", opts)
489 "Public context" => %{user: user, activity: public_activity, activities: public_context},
490 "Private context" => %{
492 activity: private_activity,
493 activities: private_context
496 formatters: formatters()
500 defp fetch_timelines_with_reply_filtering(user) do
501 public_params = opts_for_public_timeline(user)
505 "Public timeline without reply filtering" => fn ->
506 ActivityPub.fetch_public_activities(public_params)
508 "Public timeline with reply filtering - following" => fn ->
510 |> Map.put("reply_visibility", "following")
511 |> Map.put("reply_filtering_user", user)
512 |> ActivityPub.fetch_public_activities()
514 "Public timeline with reply filtering - self" => fn ->
516 |> Map.put("reply_visibility", "self")
517 |> Map.put("reply_filtering_user", user)
518 |> ActivityPub.fetch_public_activities()
521 formatters: formatters()
524 private_params = opts_for_home_timeline(user)
526 recipients = [user.ap_id | User.following(user)]
530 "Home timeline without reply filtering" => fn ->
531 ActivityPub.fetch_activities(recipients, private_params)
533 "Home timeline with reply filtering - following" => fn ->
536 |> Map.put("reply_filtering_user", user)
537 |> Map.put("reply_visibility", "following")
539 ActivityPub.fetch_activities(recipients, private_params)
541 "Home timeline with reply filtering - self" => fn ->
544 |> Map.put("reply_filtering_user", user)
545 |> Map.put("reply_visibility", "self")
547 ActivityPub.fetch_activities(recipients, private_params)
550 formatters: formatters()