Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

305 lines
10KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.UserSearchTest do
  5. alias Pleroma.Repo
  6. alias Pleroma.User
  7. use Pleroma.DataCase
  8. import Pleroma.Factory
  9. setup_all do
  10. Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
  11. :ok
  12. end
  13. describe "User.search" do
  14. test "accepts limit parameter" do
  15. Enum.each(0..4, &insert(:user, %{nickname: "john#{&1}"}))
  16. assert length(User.search("john", limit: 3)) == 3
  17. assert length(User.search("john")) == 5
  18. end
  19. test "accepts offset parameter" do
  20. Enum.each(0..4, &insert(:user, %{nickname: "john#{&1}"}))
  21. assert length(User.search("john", limit: 3)) == 3
  22. assert length(User.search("john", limit: 3, offset: 3)) == 2
  23. end
  24. test "finds a user by full or partial nickname" do
  25. user = insert(:user, %{nickname: "john"})
  26. Enum.each(["john", "jo", "j"], fn query ->
  27. assert user ==
  28. User.search(query)
  29. |> List.first()
  30. |> Map.put(:search_rank, nil)
  31. |> Map.put(:search_type, nil)
  32. end)
  33. end
  34. test "finds a user by full or partial name" do
  35. user = insert(:user, %{name: "John Doe"})
  36. Enum.each(["John Doe", "JOHN", "doe", "j d", "j", "d"], fn query ->
  37. assert user ==
  38. User.search(query)
  39. |> List.first()
  40. |> Map.put(:search_rank, nil)
  41. |> Map.put(:search_type, nil)
  42. end)
  43. end
  44. test "finds users, preferring nickname matches over name matches" do
  45. u1 = insert(:user, %{name: "lain", nickname: "nick1"})
  46. u2 = insert(:user, %{nickname: "lain", name: "nick1"})
  47. assert [u2.id, u1.id] == Enum.map(User.search("lain"), & &1.id)
  48. end
  49. test "finds users, considering density of matched tokens" do
  50. u1 = insert(:user, %{name: "Bar Bar plus Word Word"})
  51. u2 = insert(:user, %{name: "Word Word Bar Bar Bar"})
  52. assert [u2.id, u1.id] == Enum.map(User.search("bar word"), & &1.id)
  53. end
  54. test "finds users, ranking by similarity" do
  55. u1 = insert(:user, %{name: "lain"})
  56. _u2 = insert(:user, %{name: "ean"})
  57. u3 = insert(:user, %{name: "ebn", nickname: "lain@mastodon.social"})
  58. u4 = insert(:user, %{nickname: "lain@pleroma.soykaf.com"})
  59. assert [u4.id, u3.id, u1.id] == Enum.map(User.search("lain@ple", for_user: u1), & &1.id)
  60. end
  61. test "finds users, handling misspelled requests" do
  62. u1 = insert(:user, %{name: "lain"})
  63. assert [u1.id] == Enum.map(User.search("laiin"), & &1.id)
  64. end
  65. test "finds users, boosting ranks of friends and followers" do
  66. u1 = insert(:user)
  67. u2 = insert(:user, %{name: "Doe"})
  68. follower = insert(:user, %{name: "Doe"})
  69. friend = insert(:user, %{name: "Doe"})
  70. {:ok, follower} = User.follow(follower, u1)
  71. {:ok, u1} = User.follow(u1, friend)
  72. assert [friend.id, follower.id, u2.id] --
  73. Enum.map(User.search("doe", resolve: false, for_user: u1), & &1.id) == []
  74. end
  75. test "finds followers of user by partial name" do
  76. u1 = insert(:user)
  77. u2 = insert(:user, %{name: "Jimi"})
  78. follower_jimi = insert(:user, %{name: "Jimi Hendrix"})
  79. follower_lizz = insert(:user, %{name: "Lizz Wright"})
  80. friend = insert(:user, %{name: "Jimi"})
  81. {:ok, follower_jimi} = User.follow(follower_jimi, u1)
  82. {:ok, _follower_lizz} = User.follow(follower_lizz, u2)
  83. {:ok, u1} = User.follow(u1, friend)
  84. assert Enum.map(User.search("jimi", following: true, for_user: u1), & &1.id) == [
  85. follower_jimi.id
  86. ]
  87. assert User.search("lizz", following: true, for_user: u1) == []
  88. end
  89. test "find local and remote users for authenticated users" do
  90. u1 = insert(:user, %{name: "lain"})
  91. u2 = insert(:user, %{name: "ebn", nickname: "lain@mastodon.social", local: false})
  92. u3 = insert(:user, %{nickname: "lain@pleroma.soykaf.com", local: false})
  93. results =
  94. "lain"
  95. |> User.search(for_user: u1)
  96. |> Enum.map(& &1.id)
  97. |> Enum.sort()
  98. assert [u1.id, u2.id, u3.id] == results
  99. end
  100. test "find only local users for unauthenticated users" do
  101. %{id: id} = insert(:user, %{name: "lain"})
  102. insert(:user, %{name: "ebn", nickname: "lain@mastodon.social", local: false})
  103. insert(:user, %{nickname: "lain@pleroma.soykaf.com", local: false})
  104. assert [%{id: ^id}] = User.search("lain")
  105. end
  106. test "find only local users for authenticated users when `limit_to_local_content` is `:all`" do
  107. Pleroma.Config.put([:instance, :limit_to_local_content], :all)
  108. %{id: id} = insert(:user, %{name: "lain"})
  109. insert(:user, %{name: "ebn", nickname: "lain@mastodon.social", local: false})
  110. insert(:user, %{nickname: "lain@pleroma.soykaf.com", local: false})
  111. assert [%{id: ^id}] = User.search("lain")
  112. Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
  113. end
  114. test "find all users for unauthenticated users when `limit_to_local_content` is `false`" do
  115. Pleroma.Config.put([:instance, :limit_to_local_content], false)
  116. u1 = insert(:user, %{name: "lain"})
  117. u2 = insert(:user, %{name: "ebn", nickname: "lain@mastodon.social", local: false})
  118. u3 = insert(:user, %{nickname: "lain@pleroma.soykaf.com", local: false})
  119. results =
  120. "lain"
  121. |> User.search()
  122. |> Enum.map(& &1.id)
  123. |> Enum.sort()
  124. assert [u1.id, u2.id, u3.id] == results
  125. Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
  126. end
  127. test "finds a user whose name is nil" do
  128. _user = insert(:user, %{name: "notamatch", nickname: "testuser@pleroma.amplifie.red"})
  129. user_two = insert(:user, %{name: nil, nickname: "lain@pleroma.soykaf.com"})
  130. assert user_two ==
  131. User.search("lain@pleroma.soykaf.com")
  132. |> List.first()
  133. |> Map.put(:search_rank, nil)
  134. |> Map.put(:search_type, nil)
  135. end
  136. test "does not yield false-positive matches" do
  137. insert(:user, %{name: "John Doe"})
  138. Enum.each(["mary", "a", ""], fn query ->
  139. assert [] == User.search(query)
  140. end)
  141. end
  142. test "works with URIs" do
  143. user = insert(:user)
  144. results =
  145. User.search("http://mastodon.example.org/users/admin", resolve: true, for_user: user)
  146. result = results |> List.first()
  147. user = User.get_cached_by_ap_id("http://mastodon.example.org/users/admin")
  148. assert length(results) == 1
  149. assert user == result |> Map.put(:search_rank, nil) |> Map.put(:search_type, nil)
  150. end
  151. test "excludes a blocked users from search result" do
  152. user = insert(:user, %{nickname: "Bill"})
  153. [blocked_user | users] = Enum.map(0..3, &insert(:user, %{nickname: "john#{&1}"}))
  154. blocked_user2 =
  155. insert(
  156. :user,
  157. %{nickname: "john awful", ap_id: "https://awful-and-rude-instance.com/user/bully"}
  158. )
  159. User.block_domain(user, "awful-and-rude-instance.com")
  160. User.block(user, blocked_user)
  161. account_ids = User.search("john", for_user: refresh_record(user)) |> collect_ids
  162. assert account_ids == collect_ids(users)
  163. refute Enum.member?(account_ids, blocked_user.id)
  164. refute Enum.member?(account_ids, blocked_user2.id)
  165. assert length(account_ids) == 3
  166. end
  167. test "local user has the same search_rank as for users with the same nickname, but another domain" do
  168. user = insert(:user)
  169. insert(:user, nickname: "lain@mastodon.social")
  170. insert(:user, nickname: "lain")
  171. insert(:user, nickname: "lain@pleroma.social")
  172. assert User.search("lain@localhost", resolve: true, for_user: user)
  173. |> Enum.each(fn u -> u.search_rank == 0.5 end)
  174. end
  175. test "localhost is the part of the domain" do
  176. user = insert(:user)
  177. insert(:user, nickname: "another@somedomain")
  178. insert(:user, nickname: "lain")
  179. insert(:user, nickname: "lain@examplelocalhost")
  180. result = User.search("lain@examplelocalhost", resolve: true, for_user: user)
  181. assert Enum.each(result, fn u -> u.search_rank == 0.5 end)
  182. assert length(result) == 2
  183. end
  184. test "local user search with users" do
  185. user = insert(:user)
  186. local_user = insert(:user, nickname: "lain")
  187. insert(:user, nickname: "another@localhost.com")
  188. insert(:user, nickname: "localhost@localhost.com")
  189. [result] = User.search("lain@localhost", resolve: true, for_user: user)
  190. assert Map.put(result, :search_rank, nil) |> Map.put(:search_type, nil) == local_user
  191. end
  192. test "works with idna domains" do
  193. user = insert(:user, nickname: "lain@" <> to_string(:idna.encode("zetsubou.みんな")))
  194. results = User.search("lain@zetsubou.みんな", resolve: false, for_user: user)
  195. result = List.first(results)
  196. assert user == result |> Map.put(:search_rank, nil) |> Map.put(:search_type, nil)
  197. end
  198. test "works with idna domains converted input" do
  199. user = insert(:user, nickname: "lain@" <> to_string(:idna.encode("zetsubou.みんな")))
  200. results =
  201. User.search("lain@zetsubou." <> to_string(:idna.encode("zetsubou.みんな")),
  202. resolve: false,
  203. for_user: user
  204. )
  205. result = List.first(results)
  206. assert user == result |> Map.put(:search_rank, nil) |> Map.put(:search_type, nil)
  207. end
  208. test "works with idna domains and bad chars in domain" do
  209. user = insert(:user, nickname: "lain@" <> to_string(:idna.encode("zetsubou.みんな")))
  210. results =
  211. User.search("lain@zetsubou!@#$%^&*()+,-/:;<=>?[]'_{}|~`.みんな",
  212. resolve: false,
  213. for_user: user
  214. )
  215. result = List.first(results)
  216. assert user == result |> Map.put(:search_rank, nil) |> Map.put(:search_type, nil)
  217. end
  218. test "works with idna domains and query as link" do
  219. user = insert(:user, nickname: "lain@" <> to_string(:idna.encode("zetsubou.みんな")))
  220. results =
  221. User.search("https://zetsubou.みんな/users/lain",
  222. resolve: false,
  223. for_user: user
  224. )
  225. result = List.first(results)
  226. assert user == result |> Map.put(:search_rank, nil) |> Map.put(:search_type, nil)
  227. end
  228. end
  229. end