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)
46 defp render_views(user) do
47 render_timelines(user)
48 render_long_thread(user)
51 defp opts_for_home_timeline(user) do
53 "blocking_user" => user,
55 "muting_user" => user,
56 "type" => ["Create", "Announce"],
58 "with_muted" => "true"
62 defp fetch_home_timeline(user) do
63 opts = opts_for_home_timeline(user)
65 recipients = [user.ap_id | User.following(user)]
68 ActivityPub.fetch_activities(recipients, opts) |> Enum.reverse() |> List.last()
71 ActivityPub.fetch_activities(recipients, Map.put(opts, "max_id", first_page_last.id))
76 ActivityPub.fetch_activities(recipients, Map.put(opts, "max_id", second_page_last.id))
81 ActivityPub.fetch_activities(recipients, Map.put(opts, "max_id", third_page_last.id))
87 "home timeline" => fn opts -> ActivityPub.fetch_activities(recipients, opts) end
91 "2 page" => Map.put(opts, "max_id", first_page_last.id),
92 "3 page" => Map.put(opts, "max_id", second_page_last.id),
93 "4 page" => Map.put(opts, "max_id", third_page_last.id),
94 "5 page" => Map.put(opts, "max_id", forth_page_last.id),
95 "1 page only media" => Map.put(opts, "only_media", "true"),
96 "2 page only media" =>
97 Map.put(opts, "max_id", first_page_last.id) |> Map.put("only_media", "true"),
98 "3 page only media" =>
99 Map.put(opts, "max_id", second_page_last.id) |> Map.put("only_media", "true"),
100 "4 page only media" =>
101 Map.put(opts, "max_id", third_page_last.id) |> Map.put("only_media", "true"),
102 "5 page only media" =>
103 Map.put(opts, "max_id", forth_page_last.id) |> Map.put("only_media", "true")
105 formatters: formatters()
109 defp opts_for_direct_timeline(user) do
111 :visibility => "direct",
112 "blocking_user" => user,
116 "with_muted" => "true"
120 defp fetch_direct_timeline(user) do
121 recipients = [user.ap_id]
123 opts = opts_for_direct_timeline(user)
127 |> ActivityPub.fetch_activities_query(opts)
128 |> Pagination.fetch_paginated(opts)
131 opts2 = Map.put(opts, "max_id", first_page_last.id)
135 |> ActivityPub.fetch_activities_query(opts2)
136 |> Pagination.fetch_paginated(opts2)
139 opts3 = Map.put(opts, "max_id", second_page_last.id)
143 |> ActivityPub.fetch_activities_query(opts3)
144 |> Pagination.fetch_paginated(opts3)
147 opts4 = Map.put(opts, "max_id", third_page_last.id)
151 |> ActivityPub.fetch_activities_query(opts4)
152 |> Pagination.fetch_paginated(opts4)
157 "direct timeline" => fn opts ->
158 ActivityPub.fetch_activities_query(recipients, opts) |> Pagination.fetch_paginated(opts)
166 "5 page" => Map.put(opts4, "max_id", forth_page_last.id)
168 formatters: formatters()
172 defp opts_for_public_timeline(user) do
174 "type" => ["Create", "Announce"],
175 "local_only" => false,
176 "blocking_user" => user,
177 "muting_user" => user
181 defp opts_for_public_timeline(user, :local) do
183 "type" => ["Create", "Announce"],
184 "local_only" => true,
185 "blocking_user" => user,
186 "muting_user" => user
190 defp opts_for_public_timeline(user, :tag) do
192 "blocking_user" => user,
195 "muting_user" => user,
201 "with_muted" => "true"
205 defp fetch_public_timeline(user) do
206 opts = opts_for_public_timeline(user)
208 fetch_public_timeline(opts, "public timeline")
211 defp fetch_public_timeline(user, :local) do
212 opts = opts_for_public_timeline(user, :local)
214 fetch_public_timeline(opts, "public timeline only local")
217 defp fetch_public_timeline(user, :tag) do
218 opts = opts_for_public_timeline(user, :tag)
220 fetch_public_timeline(opts, "hashtag timeline")
223 defp fetch_public_timeline(user, :only_media) do
224 opts = opts_for_public_timeline(user) |> Map.put("only_media", "true")
226 fetch_public_timeline(opts, "public timeline only media")
229 defp fetch_public_timeline(opts, title) when is_binary(title) do
230 first_page_last = ActivityPub.fetch_public_activities(opts) |> List.last()
233 ActivityPub.fetch_public_activities(Map.put(opts, "max_id", first_page_last.id))
237 ActivityPub.fetch_public_activities(Map.put(opts, "max_id", second_page_last.id))
241 ActivityPub.fetch_public_activities(Map.put(opts, "max_id", third_page_last.id))
247 ActivityPub.fetch_public_activities(opts)
252 "2 page" => Map.put(opts, "max_id", first_page_last.id),
253 "3 page" => Map.put(opts, "max_id", second_page_last.id),
254 "4 page" => Map.put(opts, "max_id", third_page_last.id),
255 "5 page" => Map.put(opts, "max_id", forth_page_last.id)
257 formatters: formatters()
261 defp opts_for_notifications do
262 %{"count" => "20", "with_muted" => "true"}
265 defp fetch_notifications(user) do
266 opts = opts_for_notifications()
268 first_page_last = MastodonAPI.get_notifications(user, opts) |> List.last()
271 MastodonAPI.get_notifications(user, Map.put(opts, "max_id", first_page_last.id))
275 MastodonAPI.get_notifications(user, Map.put(opts, "max_id", second_page_last.id))
279 MastodonAPI.get_notifications(user, Map.put(opts, "max_id", third_page_last.id))
284 "Notifications" => fn opts ->
285 MastodonAPI.get_notifications(user, opts)
290 "2 page" => Map.put(opts, "max_id", first_page_last.id),
291 "3 page" => Map.put(opts, "max_id", second_page_last.id),
292 "4 page" => Map.put(opts, "max_id", third_page_last.id),
293 "5 page" => Map.put(opts, "max_id", forth_page_last.id)
295 formatters: formatters()
299 defp fetch_favourites(user) do
300 first_page_last = ActivityPub.fetch_favourites(user) |> List.last()
303 ActivityPub.fetch_favourites(user, %{"max_id" => first_page_last.id}) |> List.last()
306 ActivityPub.fetch_favourites(user, %{"max_id" => second_page_last.id}) |> List.last()
309 ActivityPub.fetch_favourites(user, %{"max_id" => third_page_last.id}) |> List.last()
313 "Favourites" => fn opts ->
314 ActivityPub.fetch_favourites(user, opts)
319 "2 page" => %{"max_id" => first_page_last.id},
320 "3 page" => %{"max_id" => second_page_last.id},
321 "4 page" => %{"max_id" => third_page_last.id},
322 "5 page" => %{"max_id" => forth_page_last.id}
324 formatters: formatters()
328 defp opts_for_long_thread(user) do
330 "blocking_user" => user,
335 defp fetch_long_thread(user) do
336 %{public_thread: public, private_thread: private} =
337 Agent.get(:benchmark_state, fn state -> state end)
339 opts = opts_for_long_thread(user)
341 private_input = {private.data["context"], Map.put(opts, "exclude_id", private.id)}
343 public_input = {public.data["context"], Map.put(opts, "exclude_id", public.id)}
347 "fetch context" => fn {context, opts} ->
348 ActivityPub.fetch_activities_for_context(context, opts)
352 "Private long thread" => private_input,
353 "Public long thread" => public_input
355 formatters: formatters()
359 defp render_timelines(user) do
360 opts = opts_for_home_timeline(user)
362 recipients = [user.ap_id | User.following(user)]
364 home_activities = ActivityPub.fetch_activities(recipients, opts) |> Enum.reverse()
366 recipients = [user.ap_id]
368 opts = opts_for_direct_timeline(user)
372 |> ActivityPub.fetch_activities_query(opts)
373 |> Pagination.fetch_paginated(opts)
375 opts = opts_for_public_timeline(user)
377 public_activities = ActivityPub.fetch_public_activities(opts)
379 opts = opts_for_public_timeline(user, :tag)
381 tag_activities = ActivityPub.fetch_public_activities(opts)
383 opts = opts_for_notifications()
385 notifications = MastodonAPI.get_notifications(user, opts)
387 favourites = ActivityPub.fetch_favourites(user)
389 output_relationships =
390 !!Pleroma.Config.get([:extensions, :output_relationships_in_statuses_by_default])
394 "Rendering home timeline" => fn ->
395 StatusView.render("index.json", %{
396 activities: home_activities,
399 skip_relationships: !output_relationships
402 "Rendering direct timeline" => fn ->
403 StatusView.render("index.json", %{
404 activities: direct_activities,
407 skip_relationships: !output_relationships
410 "Rendering public timeline" => fn ->
411 StatusView.render("index.json", %{
412 activities: public_activities,
415 skip_relationships: !output_relationships
418 "Rendering tag timeline" => fn ->
419 StatusView.render("index.json", %{
420 activities: tag_activities,
423 skip_relationships: !output_relationships
426 "Rendering notifications" => fn ->
427 Pleroma.Web.MastodonAPI.NotificationView.render("index.json", %{
428 notifications: notifications,
430 skip_relationships: !output_relationships
433 "Rendering favourites timeline" => fn ->
434 StatusView.render("index.json", %{
435 activities: favourites,
438 skip_relationships: !output_relationships
442 formatters: formatters()
446 defp render_long_thread(user) do
447 %{public_thread: public, private_thread: private} =
448 Agent.get(:benchmark_state, fn state -> state end)
451 public_activity = Activity.get_by_id_with_object(public.id)
452 private_activity = Activity.get_by_id_with_object(private.id)
456 "render" => fn opts ->
457 StatusView.render("show.json", opts)
461 "Public root" => Map.put(opts, :activity, public_activity),
462 "Private root" => Map.put(opts, :activity, private_activity)
464 formatters: formatters()
467 fetch_opts = opts_for_long_thread(user)
470 ActivityPub.fetch_activities_for_context(
471 public.data["context"],
472 Map.put(fetch_opts, "exclude_id", public.id)
476 ActivityPub.fetch_activities_for_context(
477 private.data["context"],
478 Map.put(fetch_opts, "exclude_id", private.id)
483 "render" => fn opts ->
484 StatusView.render("context.json", opts)
488 "Public context" => %{user: user, activity: public_activity, activities: public_context},
489 "Private context" => %{
491 activity: private_activity,
492 activities: private_context
495 formatters: formatters()