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, :with_blocks)
40 fetch_public_timeline(user, :local)
41 fetch_public_timeline(user, :tag)
42 fetch_notifications(user)
43 fetch_favourites(user)
44 fetch_long_thread(user)
45 fetch_timelines_with_reply_filtering(user)
48 defp render_views(user) do
49 render_timelines(user)
50 render_long_thread(user)
53 defp opts_for_home_timeline(user) do
55 "blocking_user" => user,
57 "muting_user" => user,
58 "type" => ["Create", "Announce"],
60 "with_muted" => "true"
64 defp fetch_home_timeline(user) do
65 opts = opts_for_home_timeline(user)
67 recipients = [user.ap_id | User.following(user)]
70 ActivityPub.fetch_activities(recipients, opts) |> Enum.reverse() |> List.last()
73 ActivityPub.fetch_activities(recipients, Map.put(opts, "max_id", first_page_last.id))
78 ActivityPub.fetch_activities(recipients, Map.put(opts, "max_id", second_page_last.id))
83 ActivityPub.fetch_activities(recipients, Map.put(opts, "max_id", third_page_last.id))
89 "home timeline" => fn opts -> ActivityPub.fetch_activities(recipients, opts) end
93 "2 page" => Map.put(opts, "max_id", first_page_last.id),
94 "3 page" => Map.put(opts, "max_id", second_page_last.id),
95 "4 page" => Map.put(opts, "max_id", third_page_last.id),
96 "5 page" => Map.put(opts, "max_id", forth_page_last.id),
97 "1 page only media" => Map.put(opts, "only_media", "true"),
98 "2 page only media" =>
99 Map.put(opts, "max_id", first_page_last.id) |> Map.put("only_media", "true"),
100 "3 page only media" =>
101 Map.put(opts, "max_id", second_page_last.id) |> Map.put("only_media", "true"),
102 "4 page only media" =>
103 Map.put(opts, "max_id", third_page_last.id) |> Map.put("only_media", "true"),
104 "5 page only media" =>
105 Map.put(opts, "max_id", forth_page_last.id) |> Map.put("only_media", "true")
107 formatters: formatters()
111 defp opts_for_direct_timeline(user) do
113 :visibility => "direct",
114 "blocking_user" => user,
118 "with_muted" => "true"
122 defp fetch_direct_timeline(user) do
123 recipients = [user.ap_id]
125 opts = opts_for_direct_timeline(user)
129 |> ActivityPub.fetch_activities_query(opts)
130 |> Pagination.fetch_paginated(opts)
133 opts2 = Map.put(opts, "max_id", first_page_last.id)
137 |> ActivityPub.fetch_activities_query(opts2)
138 |> Pagination.fetch_paginated(opts2)
141 opts3 = Map.put(opts, "max_id", second_page_last.id)
145 |> ActivityPub.fetch_activities_query(opts3)
146 |> Pagination.fetch_paginated(opts3)
149 opts4 = Map.put(opts, "max_id", third_page_last.id)
153 |> ActivityPub.fetch_activities_query(opts4)
154 |> Pagination.fetch_paginated(opts4)
159 "direct timeline" => fn opts ->
160 ActivityPub.fetch_activities_query(recipients, opts) |> Pagination.fetch_paginated(opts)
168 "5 page" => Map.put(opts4, "max_id", forth_page_last.id)
170 formatters: formatters()
174 defp opts_for_public_timeline(user) do
176 "type" => ["Create", "Announce"],
177 "local_only" => false,
178 "blocking_user" => user,
179 "muting_user" => user
183 defp opts_for_public_timeline(user, :local) do
185 "type" => ["Create", "Announce"],
186 "local_only" => true,
187 "blocking_user" => user,
188 "muting_user" => user
192 defp opts_for_public_timeline(user, :tag) do
194 "blocking_user" => user,
197 "muting_user" => user,
203 "with_muted" => "true"
207 defp fetch_public_timeline(user) do
208 opts = opts_for_public_timeline(user)
210 fetch_public_timeline(opts, "public timeline")
213 defp fetch_public_timeline(user, :local) do
214 opts = opts_for_public_timeline(user, :local)
216 fetch_public_timeline(opts, "public timeline only local")
219 defp fetch_public_timeline(user, :tag) do
220 opts = opts_for_public_timeline(user, :tag)
222 fetch_public_timeline(opts, "hashtag timeline")
225 defp fetch_public_timeline(user, :only_media) do
226 opts = opts_for_public_timeline(user) |> Map.put("only_media", "true")
228 fetch_public_timeline(opts, "public timeline only media")
231 defp fetch_public_timeline(user, :with_blocks) do
232 opts = opts_for_public_timeline(user)
234 remote_non_friends = Agent.get(:non_friends_remote, & &1)
237 "public timeline without blocks" => fn ->
238 ActivityPub.fetch_public_activities(opts)
242 Enum.each(remote_non_friends, fn non_friend ->
243 {:ok, _} = User.block(user, non_friend)
246 user = User.get_by_id(user.id)
248 opts = Map.put(opts, "blocking_user", user)
252 "public timeline with user block" => fn ->
253 ActivityPub.fetch_public_activities(opts)
259 Enum.reduce(remote_non_friends, [], fn non_friend, domains ->
260 {:ok, _user} = User.unblock(user, non_friend)
261 %{host: host} = URI.parse(non_friend.ap_id)
265 domains = Enum.uniq(domains)
267 Enum.each(domains, fn domain ->
268 {:ok, _} = User.block_domain(user, domain)
271 user = User.get_by_id(user.id)
272 opts = Map.put(opts, "blocking_user", user)
276 "public timeline with domain block" => fn opts ->
277 ActivityPub.fetch_public_activities(opts)
283 defp fetch_public_timeline(opts, title) when is_binary(title) do
284 first_page_last = ActivityPub.fetch_public_activities(opts) |> List.last()
287 ActivityPub.fetch_public_activities(Map.put(opts, "max_id", first_page_last.id))
291 ActivityPub.fetch_public_activities(Map.put(opts, "max_id", second_page_last.id))
295 ActivityPub.fetch_public_activities(Map.put(opts, "max_id", third_page_last.id))
301 ActivityPub.fetch_public_activities(opts)
306 "2 page" => Map.put(opts, "max_id", first_page_last.id),
307 "3 page" => Map.put(opts, "max_id", second_page_last.id),
308 "4 page" => Map.put(opts, "max_id", third_page_last.id),
309 "5 page" => Map.put(opts, "max_id", forth_page_last.id)
311 formatters: formatters()
315 defp opts_for_notifications do
316 %{"count" => "20", "with_muted" => "true"}
319 defp fetch_notifications(user) do
320 opts = opts_for_notifications()
322 first_page_last = MastodonAPI.get_notifications(user, opts) |> List.last()
325 MastodonAPI.get_notifications(user, Map.put(opts, "max_id", first_page_last.id))
329 MastodonAPI.get_notifications(user, Map.put(opts, "max_id", second_page_last.id))
333 MastodonAPI.get_notifications(user, Map.put(opts, "max_id", third_page_last.id))
338 "Notifications" => fn opts ->
339 MastodonAPI.get_notifications(user, opts)
344 "2 page" => Map.put(opts, "max_id", first_page_last.id),
345 "3 page" => Map.put(opts, "max_id", second_page_last.id),
346 "4 page" => Map.put(opts, "max_id", third_page_last.id),
347 "5 page" => Map.put(opts, "max_id", forth_page_last.id)
349 formatters: formatters()
353 defp fetch_favourites(user) do
354 first_page_last = ActivityPub.fetch_favourites(user) |> List.last()
357 ActivityPub.fetch_favourites(user, %{"max_id" => first_page_last.id}) |> List.last()
360 ActivityPub.fetch_favourites(user, %{"max_id" => second_page_last.id}) |> List.last()
363 ActivityPub.fetch_favourites(user, %{"max_id" => third_page_last.id}) |> List.last()
367 "Favourites" => fn opts ->
368 ActivityPub.fetch_favourites(user, opts)
373 "2 page" => %{"max_id" => first_page_last.id},
374 "3 page" => %{"max_id" => second_page_last.id},
375 "4 page" => %{"max_id" => third_page_last.id},
376 "5 page" => %{"max_id" => forth_page_last.id}
378 formatters: formatters()
382 defp opts_for_long_thread(user) do
384 "blocking_user" => user,
389 defp fetch_long_thread(user) do
390 %{public_thread: public, private_thread: private} =
391 Agent.get(:benchmark_state, fn state -> state end)
393 opts = opts_for_long_thread(user)
395 private_input = {private.data["context"], Map.put(opts, "exclude_id", private.id)}
397 public_input = {public.data["context"], Map.put(opts, "exclude_id", public.id)}
401 "fetch context" => fn {context, opts} ->
402 ActivityPub.fetch_activities_for_context(context, opts)
406 "Private long thread" => private_input,
407 "Public long thread" => public_input
409 formatters: formatters()
413 defp render_timelines(user) do
414 opts = opts_for_home_timeline(user)
416 recipients = [user.ap_id | User.following(user)]
418 home_activities = ActivityPub.fetch_activities(recipients, opts) |> Enum.reverse()
420 recipients = [user.ap_id]
422 opts = opts_for_direct_timeline(user)
426 |> ActivityPub.fetch_activities_query(opts)
427 |> Pagination.fetch_paginated(opts)
429 opts = opts_for_public_timeline(user)
431 public_activities = ActivityPub.fetch_public_activities(opts)
433 opts = opts_for_public_timeline(user, :tag)
435 tag_activities = ActivityPub.fetch_public_activities(opts)
437 opts = opts_for_notifications()
439 notifications = MastodonAPI.get_notifications(user, opts)
441 favourites = ActivityPub.fetch_favourites(user)
445 "Rendering home timeline" => fn ->
446 StatusView.render("index.json", %{
447 activities: home_activities,
452 "Rendering direct timeline" => fn ->
453 StatusView.render("index.json", %{
454 activities: direct_activities,
459 "Rendering public timeline" => fn ->
460 StatusView.render("index.json", %{
461 activities: public_activities,
466 "Rendering tag timeline" => fn ->
467 StatusView.render("index.json", %{
468 activities: tag_activities,
473 "Rendering notifications" => fn ->
474 Pleroma.Web.MastodonAPI.NotificationView.render("index.json", %{
475 notifications: notifications,
479 "Rendering favourites timeline" => fn ->
480 StatusView.render("index.json", %{
481 activities: favourites,
487 formatters: formatters()
491 defp render_long_thread(user) do
492 %{public_thread: public, private_thread: private} =
493 Agent.get(:benchmark_state, fn state -> state end)
496 public_activity = Activity.get_by_id_with_object(public.id)
497 private_activity = Activity.get_by_id_with_object(private.id)
501 "render" => fn opts ->
502 StatusView.render("show.json", opts)
506 "Public root" => Map.put(opts, :activity, public_activity),
507 "Private root" => Map.put(opts, :activity, private_activity)
509 formatters: formatters()
512 fetch_opts = opts_for_long_thread(user)
515 ActivityPub.fetch_activities_for_context(
516 public.data["context"],
517 Map.put(fetch_opts, "exclude_id", public.id)
521 ActivityPub.fetch_activities_for_context(
522 private.data["context"],
523 Map.put(fetch_opts, "exclude_id", private.id)
528 "render" => fn opts ->
529 StatusView.render("context.json", opts)
533 "Public context" => %{user: user, activity: public_activity, activities: public_context},
534 "Private context" => %{
536 activity: private_activity,
537 activities: private_context
540 formatters: formatters()
544 defp fetch_timelines_with_reply_filtering(user) do
545 public_params = opts_for_public_timeline(user)
549 "Public timeline without reply filtering" => fn ->
550 ActivityPub.fetch_public_activities(public_params)
552 "Public timeline with reply filtering - following" => fn ->
554 |> Map.put("reply_visibility", "following")
555 |> Map.put("reply_filtering_user", user)
556 |> ActivityPub.fetch_public_activities()
558 "Public timeline with reply filtering - self" => fn ->
560 |> Map.put("reply_visibility", "self")
561 |> Map.put("reply_filtering_user", user)
562 |> ActivityPub.fetch_public_activities()
565 formatters: formatters()
568 private_params = opts_for_home_timeline(user)
570 recipients = [user.ap_id | User.following(user)]
574 "Home timeline without reply filtering" => fn ->
575 ActivityPub.fetch_activities(recipients, private_params)
577 "Home timeline with reply filtering - following" => fn ->
580 |> Map.put("reply_filtering_user", user)
581 |> Map.put("reply_visibility", "following")
583 ActivityPub.fetch_activities(recipients, private_params)
585 "Home timeline with reply filtering - self" => fn ->
588 |> Map.put("reply_filtering_user", user)
589 |> Map.put("reply_visibility", "self")
591 ActivityPub.fetch_activities(recipients, private_params)
594 formatters: formatters()