logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma

config_db_test.exs (17893B)


  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.ConfigDBTest do
  5. use Pleroma.DataCase, async: true
  6. import Pleroma.Factory
  7. alias Pleroma.ConfigDB
  8. test "get_by_params/1" do
  9. config = insert(:config)
  10. insert(:config)
  11. assert config == ConfigDB.get_by_params(%{group: config.group, key: config.key})
  12. end
  13. test "get_all_as_keyword/0" do
  14. saved = insert(:config)
  15. insert(:config, group: ":quack", key: ":level", value: :info)
  16. insert(:config, group: ":quack", key: ":meta", value: [:none])
  17. insert(:config,
  18. group: ":quack",
  19. key: ":webhook_url",
  20. value: "https://hooks.slack.com/services/KEY/some_val"
  21. )
  22. config = ConfigDB.get_all_as_keyword()
  23. assert config[:pleroma] == [
  24. {saved.key, saved.value}
  25. ]
  26. assert config[:quack][:level] == :info
  27. assert config[:quack][:meta] == [:none]
  28. assert config[:quack][:webhook_url] == "https://hooks.slack.com/services/KEY/some_val"
  29. end
  30. describe "update_or_create/1" do
  31. test "common" do
  32. config = insert(:config)
  33. key2 = :another_key
  34. params = [
  35. %{group: :pleroma, key: key2, value: "another_value"},
  36. %{group: :pleroma, key: config.key, value: [a: 1, b: 2, c: "new_value"]}
  37. ]
  38. assert Repo.all(ConfigDB) |> length() == 1
  39. Enum.each(params, &ConfigDB.update_or_create(&1))
  40. assert Repo.all(ConfigDB) |> length() == 2
  41. config1 = ConfigDB.get_by_params(%{group: config.group, key: config.key})
  42. config2 = ConfigDB.get_by_params(%{group: :pleroma, key: key2})
  43. assert config1.value == [a: 1, b: 2, c: "new_value"]
  44. assert config2.value == "another_value"
  45. end
  46. test "partial update" do
  47. config = insert(:config, value: [key1: "val1", key2: :val2])
  48. {:ok, config} =
  49. ConfigDB.update_or_create(%{
  50. group: config.group,
  51. key: config.key,
  52. value: [key1: :val1, key3: :val3]
  53. })
  54. updated = ConfigDB.get_by_params(%{group: config.group, key: config.key})
  55. assert config.value == updated.value
  56. assert updated.value[:key1] == :val1
  57. assert updated.value[:key2] == :val2
  58. assert updated.value[:key3] == :val3
  59. end
  60. test "deep merge" do
  61. config = insert(:config, value: [key1: "val1", key2: [k1: :v1, k2: "v2"]])
  62. {:ok, config} =
  63. ConfigDB.update_or_create(%{
  64. group: config.group,
  65. key: config.key,
  66. value: [key1: :val1, key2: [k2: :v2, k3: :v3], key3: :val3]
  67. })
  68. updated = ConfigDB.get_by_params(%{group: config.group, key: config.key})
  69. assert config.value == updated.value
  70. assert updated.value[:key1] == :val1
  71. assert updated.value[:key2] == [k1: :v1, k2: :v2, k3: :v3]
  72. assert updated.value[:key3] == :val3
  73. end
  74. test "only full update for some keys" do
  75. config1 = insert(:config, key: :ecto_repos, value: [repo: Pleroma.Repo])
  76. config2 = insert(:config, group: :cors_plug, key: :max_age, value: 18)
  77. {:ok, _config} =
  78. ConfigDB.update_or_create(%{
  79. group: config1.group,
  80. key: config1.key,
  81. value: [another_repo: [Pleroma.Repo]]
  82. })
  83. {:ok, _config} =
  84. ConfigDB.update_or_create(%{
  85. group: config2.group,
  86. key: config2.key,
  87. value: 777
  88. })
  89. updated1 = ConfigDB.get_by_params(%{group: config1.group, key: config1.key})
  90. updated2 = ConfigDB.get_by_params(%{group: config2.group, key: config2.key})
  91. assert updated1.value == [another_repo: [Pleroma.Repo]]
  92. assert updated2.value == 777
  93. end
  94. test "full update if value is not keyword" do
  95. config =
  96. insert(:config,
  97. group: ":tesla",
  98. key: ":adapter",
  99. value: Tesla.Adapter.Hackney
  100. )
  101. {:ok, _config} =
  102. ConfigDB.update_or_create(%{
  103. group: config.group,
  104. key: config.key,
  105. value: Tesla.Adapter.Httpc
  106. })
  107. updated = ConfigDB.get_by_params(%{group: config.group, key: config.key})
  108. assert updated.value == Tesla.Adapter.Httpc
  109. end
  110. test "only full update for some subkeys" do
  111. config1 =
  112. insert(:config,
  113. key: ":emoji",
  114. value: [groups: [a: 1, b: 2], key: [a: 1]]
  115. )
  116. config2 =
  117. insert(:config,
  118. key: ":assets",
  119. value: [mascots: [a: 1, b: 2], key: [a: 1]]
  120. )
  121. {:ok, _config} =
  122. ConfigDB.update_or_create(%{
  123. group: config1.group,
  124. key: config1.key,
  125. value: [groups: [c: 3, d: 4], key: [b: 2]]
  126. })
  127. {:ok, _config} =
  128. ConfigDB.update_or_create(%{
  129. group: config2.group,
  130. key: config2.key,
  131. value: [mascots: [c: 3, d: 4], key: [b: 2]]
  132. })
  133. updated1 = ConfigDB.get_by_params(%{group: config1.group, key: config1.key})
  134. updated2 = ConfigDB.get_by_params(%{group: config2.group, key: config2.key})
  135. assert updated1.value == [groups: [c: 3, d: 4], key: [a: 1, b: 2]]
  136. assert updated2.value == [mascots: [c: 3, d: 4], key: [a: 1, b: 2]]
  137. end
  138. end
  139. describe "delete/1" do
  140. test "error on deleting non existing setting" do
  141. {:error, error} = ConfigDB.delete(%{group: ":pleroma", key: ":key"})
  142. assert error =~ "Config with params %{group: \":pleroma\", key: \":key\"} not found"
  143. end
  144. test "full delete" do
  145. config = insert(:config)
  146. {:ok, deleted} = ConfigDB.delete(%{group: config.group, key: config.key})
  147. assert Ecto.get_meta(deleted, :state) == :deleted
  148. refute ConfigDB.get_by_params(%{group: config.group, key: config.key})
  149. end
  150. test "partial subkeys delete" do
  151. config = insert(:config, value: [groups: [a: 1, b: 2], key: [a: 1]])
  152. {:ok, deleted} =
  153. ConfigDB.delete(%{group: config.group, key: config.key, subkeys: [":groups"]})
  154. assert Ecto.get_meta(deleted, :state) == :loaded
  155. assert deleted.value == [key: [a: 1]]
  156. updated = ConfigDB.get_by_params(%{group: config.group, key: config.key})
  157. assert updated.value == deleted.value
  158. end
  159. test "full delete if remaining value after subkeys deletion is empty list" do
  160. config = insert(:config, value: [groups: [a: 1, b: 2]])
  161. {:ok, deleted} =
  162. ConfigDB.delete(%{group: config.group, key: config.key, subkeys: [":groups"]})
  163. assert Ecto.get_meta(deleted, :state) == :deleted
  164. refute ConfigDB.get_by_params(%{group: config.group, key: config.key})
  165. end
  166. end
  167. describe "to_elixir_types/1" do
  168. test "string" do
  169. assert ConfigDB.to_elixir_types("value as string") == "value as string"
  170. end
  171. test "boolean" do
  172. assert ConfigDB.to_elixir_types(false) == false
  173. end
  174. test "nil" do
  175. assert ConfigDB.to_elixir_types(nil) == nil
  176. end
  177. test "integer" do
  178. assert ConfigDB.to_elixir_types(150) == 150
  179. end
  180. test "atom" do
  181. assert ConfigDB.to_elixir_types(":atom") == :atom
  182. end
  183. test "ssl options" do
  184. assert ConfigDB.to_elixir_types([":tlsv1", ":tlsv1.1", ":tlsv1.2"]) == [
  185. :tlsv1,
  186. :"tlsv1.1",
  187. :"tlsv1.2"
  188. ]
  189. end
  190. test "pleroma module" do
  191. assert ConfigDB.to_elixir_types("Pleroma.Bookmark") == Pleroma.Bookmark
  192. end
  193. test "pleroma string" do
  194. assert ConfigDB.to_elixir_types("Pleroma") == "Pleroma"
  195. end
  196. test "phoenix module" do
  197. assert ConfigDB.to_elixir_types("Phoenix.Socket.V1.JSONSerializer") ==
  198. Phoenix.Socket.V1.JSONSerializer
  199. end
  200. test "tesla module" do
  201. assert ConfigDB.to_elixir_types("Tesla.Adapter.Hackney") == Tesla.Adapter.Hackney
  202. end
  203. test "ExSyslogger module" do
  204. assert ConfigDB.to_elixir_types("ExSyslogger") == ExSyslogger
  205. end
  206. test "Quack.Logger module" do
  207. assert ConfigDB.to_elixir_types("Quack.Logger") == Quack.Logger
  208. end
  209. test "Swoosh.Adapters modules" do
  210. assert ConfigDB.to_elixir_types("Swoosh.Adapters.SMTP") == Swoosh.Adapters.SMTP
  211. assert ConfigDB.to_elixir_types("Swoosh.Adapters.AmazonSES") == Swoosh.Adapters.AmazonSES
  212. end
  213. test "sigil" do
  214. assert ConfigDB.to_elixir_types("~r[comp[lL][aA][iI][nN]er]") == ~r/comp[lL][aA][iI][nN]er/
  215. end
  216. test "link sigil" do
  217. assert ConfigDB.to_elixir_types("~r/https:\/\/example.com/") == ~r/https:\/\/example.com/
  218. end
  219. test "link sigil with um modifiers" do
  220. assert ConfigDB.to_elixir_types("~r/https:\/\/example.com/um") ==
  221. ~r/https:\/\/example.com/um
  222. end
  223. test "link sigil with i modifier" do
  224. assert ConfigDB.to_elixir_types("~r/https:\/\/example.com/i") == ~r/https:\/\/example.com/i
  225. end
  226. test "link sigil with s modifier" do
  227. assert ConfigDB.to_elixir_types("~r/https:\/\/example.com/s") == ~r/https:\/\/example.com/s
  228. end
  229. test "raise if valid delimiter not found" do
  230. assert_raise ArgumentError, "valid delimiter for Regex expression not found", fn ->
  231. ConfigDB.to_elixir_types("~r/https://[]{}<>\"'()|example.com/s")
  232. end
  233. end
  234. test "2 child tuple" do
  235. assert ConfigDB.to_elixir_types(%{"tuple" => ["v1", ":v2"]}) == {"v1", :v2}
  236. end
  237. test "proxy tuple with localhost" do
  238. assert ConfigDB.to_elixir_types(%{
  239. "tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]
  240. }) == {:proxy_url, {:socks5, :localhost, 1234}}
  241. end
  242. test "proxy tuple with domain" do
  243. assert ConfigDB.to_elixir_types(%{
  244. "tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]
  245. }) == {:proxy_url, {:socks5, 'domain.com', 1234}}
  246. end
  247. test "proxy tuple with ip" do
  248. assert ConfigDB.to_elixir_types(%{
  249. "tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]
  250. }) == {:proxy_url, {:socks5, {127, 0, 0, 1}, 1234}}
  251. end
  252. test "tuple with n childs" do
  253. assert ConfigDB.to_elixir_types(%{
  254. "tuple" => [
  255. "v1",
  256. ":v2",
  257. "Pleroma.Bookmark",
  258. 150,
  259. false,
  260. "Phoenix.Socket.V1.JSONSerializer"
  261. ]
  262. }) == {"v1", :v2, Pleroma.Bookmark, 150, false, Phoenix.Socket.V1.JSONSerializer}
  263. end
  264. test "map with string key" do
  265. assert ConfigDB.to_elixir_types(%{"key" => "value"}) == %{"key" => "value"}
  266. end
  267. test "map with atom key" do
  268. assert ConfigDB.to_elixir_types(%{":key" => "value"}) == %{key: "value"}
  269. end
  270. test "list of strings" do
  271. assert ConfigDB.to_elixir_types(["v1", "v2", "v3"]) == ["v1", "v2", "v3"]
  272. end
  273. test "list of modules" do
  274. assert ConfigDB.to_elixir_types(["Pleroma.Repo", "Pleroma.Activity"]) == [
  275. Pleroma.Repo,
  276. Pleroma.Activity
  277. ]
  278. end
  279. test "list of atoms" do
  280. assert ConfigDB.to_elixir_types([":v1", ":v2", ":v3"]) == [:v1, :v2, :v3]
  281. end
  282. test "list of mixed values" do
  283. assert ConfigDB.to_elixir_types([
  284. "v1",
  285. ":v2",
  286. "Pleroma.Repo",
  287. "Phoenix.Socket.V1.JSONSerializer",
  288. 15,
  289. false
  290. ]) == [
  291. "v1",
  292. :v2,
  293. Pleroma.Repo,
  294. Phoenix.Socket.V1.JSONSerializer,
  295. 15,
  296. false
  297. ]
  298. end
  299. test "simple keyword" do
  300. assert ConfigDB.to_elixir_types([%{"tuple" => [":key", "value"]}]) == [key: "value"]
  301. end
  302. test "keyword" do
  303. assert ConfigDB.to_elixir_types([
  304. %{"tuple" => [":types", "Pleroma.PostgresTypes"]},
  305. %{"tuple" => [":telemetry_event", ["Pleroma.Repo.Instrumenter"]]},
  306. %{"tuple" => [":migration_lock", nil]},
  307. %{"tuple" => [":key1", 150]},
  308. %{"tuple" => [":key2", "string"]}
  309. ]) == [
  310. types: Pleroma.PostgresTypes,
  311. telemetry_event: [Pleroma.Repo.Instrumenter],
  312. migration_lock: nil,
  313. key1: 150,
  314. key2: "string"
  315. ]
  316. end
  317. test "trandformed keyword" do
  318. assert ConfigDB.to_elixir_types(a: 1, b: 2, c: "string") == [a: 1, b: 2, c: "string"]
  319. end
  320. test "complex keyword with nested mixed childs" do
  321. assert ConfigDB.to_elixir_types([
  322. %{"tuple" => [":uploader", "Pleroma.Uploaders.Local"]},
  323. %{"tuple" => [":filters", ["Pleroma.Upload.Filter.Dedupe"]]},
  324. %{"tuple" => [":link_name", true]},
  325. %{"tuple" => [":proxy_remote", false]},
  326. %{"tuple" => [":common_map", %{":key" => "value"}]},
  327. %{
  328. "tuple" => [
  329. ":proxy_opts",
  330. [
  331. %{"tuple" => [":redirect_on_failure", false]},
  332. %{"tuple" => [":max_body_length", 1_048_576]},
  333. %{
  334. "tuple" => [
  335. ":http",
  336. [
  337. %{"tuple" => [":follow_redirect", true]},
  338. %{"tuple" => [":pool", ":upload"]}
  339. ]
  340. ]
  341. }
  342. ]
  343. ]
  344. }
  345. ]) == [
  346. uploader: Pleroma.Uploaders.Local,
  347. filters: [Pleroma.Upload.Filter.Dedupe],
  348. link_name: true,
  349. proxy_remote: false,
  350. common_map: %{key: "value"},
  351. proxy_opts: [
  352. redirect_on_failure: false,
  353. max_body_length: 1_048_576,
  354. http: [
  355. follow_redirect: true,
  356. pool: :upload
  357. ]
  358. ]
  359. ]
  360. end
  361. test "common keyword" do
  362. assert ConfigDB.to_elixir_types([
  363. %{"tuple" => [":level", ":warn"]},
  364. %{"tuple" => [":meta", [":all"]]},
  365. %{"tuple" => [":path", ""]},
  366. %{"tuple" => [":val", nil]},
  367. %{"tuple" => [":webhook_url", "https://hooks.slack.com/services/YOUR-KEY-HERE"]}
  368. ]) == [
  369. level: :warn,
  370. meta: [:all],
  371. path: "",
  372. val: nil,
  373. webhook_url: "https://hooks.slack.com/services/YOUR-KEY-HERE"
  374. ]
  375. end
  376. test "complex keyword with sigil" do
  377. assert ConfigDB.to_elixir_types([
  378. %{"tuple" => [":federated_timeline_removal", []]},
  379. %{"tuple" => [":reject", ["~r/comp[lL][aA][iI][nN]er/"]]},
  380. %{"tuple" => [":replace", []]}
  381. ]) == [
  382. federated_timeline_removal: [],
  383. reject: [~r/comp[lL][aA][iI][nN]er/],
  384. replace: []
  385. ]
  386. end
  387. test "complex keyword with tuples with more than 2 values" do
  388. assert ConfigDB.to_elixir_types([
  389. %{
  390. "tuple" => [
  391. ":http",
  392. [
  393. %{
  394. "tuple" => [
  395. ":key1",
  396. [
  397. %{
  398. "tuple" => [
  399. ":_",
  400. [
  401. %{
  402. "tuple" => [
  403. "/api/v1/streaming",
  404. "Pleroma.Web.MastodonAPI.WebsocketHandler",
  405. []
  406. ]
  407. },
  408. %{
  409. "tuple" => [
  410. "/websocket",
  411. "Phoenix.Endpoint.CowboyWebSocket",
  412. %{
  413. "tuple" => [
  414. "Phoenix.Transports.WebSocket",
  415. %{
  416. "tuple" => [
  417. "Pleroma.Web.Endpoint",
  418. "Pleroma.Web.UserSocket",
  419. []
  420. ]
  421. }
  422. ]
  423. }
  424. ]
  425. },
  426. %{
  427. "tuple" => [
  428. ":_",
  429. "Phoenix.Endpoint.Cowboy2Handler",
  430. %{"tuple" => ["Pleroma.Web.Endpoint", []]}
  431. ]
  432. }
  433. ]
  434. ]
  435. }
  436. ]
  437. ]
  438. }
  439. ]
  440. ]
  441. }
  442. ]) == [
  443. http: [
  444. key1: [
  445. {:_,
  446. [
  447. {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
  448. {"/websocket", Phoenix.Endpoint.CowboyWebSocket,
  449. {Phoenix.Transports.WebSocket,
  450. {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, []}}},
  451. {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
  452. ]}
  453. ]
  454. ]
  455. ]
  456. end
  457. end
  458. end