logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://hacktivis.me/git/pleroma.git

users.ex (4481B)


  1. defmodule Pleroma.LoadTesting.Users do
  2. @moduledoc """
  3. Module for generating users with friends.
  4. """
  5. import Ecto.Query
  6. import Pleroma.LoadTesting.Helper, only: [to_sec: 1]
  7. alias Pleroma.Repo
  8. alias Pleroma.User
  9. alias Pleroma.User.Query
  10. @defaults [
  11. users: 20_000,
  12. friends: 100
  13. ]
  14. @max_concurrency 10
  15. @spec generate(keyword()) :: User.t()
  16. def generate(opts \\ []) do
  17. opts = Keyword.merge(@defaults, opts)
  18. generate_users(opts[:users])
  19. main_user =
  20. Repo.one(from(u in User, where: u.local == true, order_by: fragment("RANDOM()"), limit: 1))
  21. make_friends(main_user, opts[:friends])
  22. User.get_by_id(main_user.id)
  23. end
  24. def generate_users(max) do
  25. IO.puts("Starting generating #{max} users...")
  26. {time, users} =
  27. :timer.tc(fn ->
  28. Task.async_stream(
  29. 1..max,
  30. &generate_user(&1),
  31. max_concurrency: @max_concurrency,
  32. timeout: 30_000
  33. )
  34. |> Enum.to_list()
  35. end)
  36. IO.puts("Generating users took #{to_sec(time)} sec.\n")
  37. users
  38. end
  39. defp generate_user(i) do
  40. remote = Enum.random([true, false])
  41. %User{
  42. name: "Test ใƒ†ใ‚นใƒˆ User #{i}",
  43. email: "user#{i}@example.com",
  44. nickname: "nick#{i}",
  45. password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("test"),
  46. bio: "Tester Number #{i}",
  47. local: !remote
  48. }
  49. |> user_urls()
  50. |> Repo.insert!()
  51. end
  52. defp user_urls(%{local: true} = user) do
  53. urls = %{
  54. ap_id: User.ap_id(user),
  55. follower_address: User.ap_followers(user),
  56. following_address: User.ap_following(user)
  57. }
  58. Map.merge(user, urls)
  59. end
  60. defp user_urls(%{local: false} = user) do
  61. base_domain = Enum.random(["domain1.com", "domain2.com", "domain3.com"])
  62. ap_id = "https://#{base_domain}/users/#{user.nickname}"
  63. urls = %{
  64. ap_id: ap_id,
  65. follower_address: ap_id <> "/followers",
  66. following_address: ap_id <> "/following"
  67. }
  68. Map.merge(user, urls)
  69. end
  70. def make_friends(main_user, max) when is_integer(max) do
  71. IO.puts("Starting making friends for #{max} users...")
  72. {time, _} =
  73. :timer.tc(fn ->
  74. number_of_users =
  75. (max / 2)
  76. |> Kernel.trunc()
  77. main_user
  78. |> get_users(%{limit: number_of_users, local: :local})
  79. |> run_stream(main_user)
  80. main_user
  81. |> get_users(%{limit: number_of_users, local: :external})
  82. |> run_stream(main_user)
  83. end)
  84. IO.puts("Making friends took #{to_sec(time)} sec.\n")
  85. end
  86. def make_friends(%User{} = main_user, %User{} = user) do
  87. {:ok, _, _} = User.follow(main_user, user)
  88. {:ok, _, _} = User.follow(user, main_user)
  89. end
  90. @spec get_users(User.t(), keyword()) :: [User.t()]
  91. def get_users(user, opts) do
  92. criteria = %{limit: opts[:limit]}
  93. criteria =
  94. if opts[:local] do
  95. Map.put(criteria, opts[:local], true)
  96. else
  97. criteria
  98. end
  99. criteria =
  100. if opts[:friends?] do
  101. Map.put(criteria, :friends, user)
  102. else
  103. criteria
  104. end
  105. query =
  106. criteria
  107. |> Query.build()
  108. |> random_without_user(user)
  109. query =
  110. if opts[:friends?] == false do
  111. friends_ids =
  112. %{friends: user}
  113. |> Query.build()
  114. |> Repo.all()
  115. |> Enum.map(& &1.id)
  116. from(u in query, where: u.id not in ^friends_ids)
  117. else
  118. query
  119. end
  120. Repo.all(query)
  121. end
  122. defp random_without_user(query, user) do
  123. from(u in query,
  124. where: u.id != ^user.id,
  125. order_by: fragment("RANDOM()")
  126. )
  127. end
  128. defp run_stream(users, main_user) do
  129. Task.async_stream(users, &make_friends(main_user, &1),
  130. max_concurrency: @max_concurrency,
  131. timeout: 30_000
  132. )
  133. |> Stream.run()
  134. end
  135. @spec prepare_users(User.t(), keyword()) :: map()
  136. def prepare_users(user, opts) do
  137. friends_limit = opts[:friends_used]
  138. non_friends_limit = opts[:non_friends_used]
  139. %{
  140. user: user,
  141. friends_local: fetch_users(user, friends_limit, :local, true),
  142. friends_remote: fetch_users(user, friends_limit, :external, true),
  143. non_friends_local: fetch_users(user, non_friends_limit, :local, false),
  144. non_friends_remote: fetch_users(user, non_friends_limit, :external, false)
  145. }
  146. end
  147. defp fetch_users(user, limit, local, friends?) do
  148. user
  149. |> get_users(limit: limit, local: local, friends?: friends?)
  150. |> Enum.shuffle()
  151. end
  152. end