096df92033165d87e19fc09f94628e2d0abfcbff
[akkoma] / test / config / config_db_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.ConfigDBTest do
6 use Pleroma.DataCase, async: true
7 import Pleroma.Factory
8 alias Pleroma.ConfigDB
9
10 test "get_by_key/1" do
11 config = insert(:config)
12 insert(:config)
13
14 assert config == ConfigDB.get_by_params(%{group: config.group, key: config.key})
15 end
16
17 test "create/1" do
18 {:ok, config} = ConfigDB.create(%{group: "pleroma", key: "some_key", value: "some_value"})
19 assert config == ConfigDB.get_by_params(%{group: "pleroma", key: "some_key"})
20 end
21
22 test "update/1" do
23 config = insert(:config)
24 {:ok, updated} = ConfigDB.update(config, %{value: "some_value"})
25 loaded = ConfigDB.get_by_params(%{group: config.group, key: config.key})
26 assert loaded == updated
27 end
28
29 describe "update_or_create/1" do
30 test "common" do
31 config = insert(:config)
32 key2 = "another_key"
33
34 params = [
35 %{group: "pleroma", key: key2, value: "another_value"},
36 %{group: config.group, key: config.key, value: "new_value"}
37 ]
38
39 assert Repo.all(ConfigDB) |> length() == 1
40
41 Enum.each(params, &ConfigDB.update_or_create(&1))
42
43 assert Repo.all(ConfigDB) |> length() == 2
44
45 config1 = ConfigDB.get_by_params(%{group: config.group, key: config.key})
46 config2 = ConfigDB.get_by_params(%{group: "pleroma", key: key2})
47
48 assert config1.value == ConfigDB.transform("new_value")
49 assert config2.value == ConfigDB.transform("another_value")
50 end
51
52 test "partial update" do
53 config = insert(:config, value: ConfigDB.to_binary(key1: "val1", key2: :val2))
54
55 {:ok, _config} =
56 ConfigDB.update_or_create(%{
57 group: config.group,
58 key: config.key,
59 value: [key1: :val1, key3: :val3]
60 })
61
62 updated = ConfigDB.get_by_params(%{group: config.group, key: config.key})
63
64 value = ConfigDB.from_binary(updated.value)
65 assert length(value) == 3
66 assert value[:key1] == :val1
67 assert value[:key2] == :val2
68 assert value[:key3] == :val3
69 end
70
71 test "deep merge" do
72 config = insert(:config, value: ConfigDB.to_binary(key1: "val1", key2: [k1: :v1, k2: "v2"]))
73
74 {:ok, config} =
75 ConfigDB.update_or_create(%{
76 group: config.group,
77 key: config.key,
78 value: [key1: :val1, key2: [k2: :v2, k3: :v3], key3: :val3]
79 })
80
81 updated = ConfigDB.get_by_params(%{group: config.group, key: config.key})
82
83 assert config.value == updated.value
84
85 value = ConfigDB.from_binary(updated.value)
86 assert value[:key1] == :val1
87 assert value[:key2] == [k1: :v1, k2: :v2, k3: :v3]
88 assert value[:key3] == :val3
89 end
90
91 test "only full update for some keys" do
92 config1 = insert(:config, key: ":ecto_repos", value: ConfigDB.to_binary(repo: Pleroma.Repo))
93
94 config2 =
95 insert(:config, group: ":cors_plug", key: ":max_age", value: ConfigDB.to_binary(18))
96
97 {:ok, _config} =
98 ConfigDB.update_or_create(%{
99 group: config1.group,
100 key: config1.key,
101 value: [another_repo: [Pleroma.Repo]]
102 })
103
104 {:ok, _config} =
105 ConfigDB.update_or_create(%{
106 group: config2.group,
107 key: config2.key,
108 value: 777
109 })
110
111 updated1 = ConfigDB.get_by_params(%{group: config1.group, key: config1.key})
112 updated2 = ConfigDB.get_by_params(%{group: config2.group, key: config2.key})
113
114 assert ConfigDB.from_binary(updated1.value) == [another_repo: [Pleroma.Repo]]
115 assert ConfigDB.from_binary(updated2.value) == 777
116 end
117
118 test "full update if value is not keyword" do
119 config =
120 insert(:config,
121 group: ":tesla",
122 key: ":adapter",
123 value: ConfigDB.to_binary(Tesla.Adapter.Hackney)
124 )
125
126 {:ok, _config} =
127 ConfigDB.update_or_create(%{
128 group: config.group,
129 key: config.key,
130 value: Tesla.Adapter.Httpc
131 })
132
133 updated = ConfigDB.get_by_params(%{group: config.group, key: config.key})
134
135 assert ConfigDB.from_binary(updated.value) == Tesla.Adapter.Httpc
136 end
137 end
138
139 test "delete/1" do
140 config = insert(:config)
141 {:ok, _} = ConfigDB.delete(%{key: config.key, group: config.group})
142 refute ConfigDB.get_by_params(%{key: config.key, group: config.group})
143 end
144
145 describe "transform/1" do
146 test "string" do
147 binary = ConfigDB.transform("value as string")
148 assert binary == :erlang.term_to_binary("value as string")
149 assert ConfigDB.from_binary(binary) == "value as string"
150 end
151
152 test "boolean" do
153 binary = ConfigDB.transform(false)
154 assert binary == :erlang.term_to_binary(false)
155 assert ConfigDB.from_binary(binary) == false
156 end
157
158 test "nil" do
159 binary = ConfigDB.transform(nil)
160 assert binary == :erlang.term_to_binary(nil)
161 assert ConfigDB.from_binary(binary) == nil
162 end
163
164 test "integer" do
165 binary = ConfigDB.transform(150)
166 assert binary == :erlang.term_to_binary(150)
167 assert ConfigDB.from_binary(binary) == 150
168 end
169
170 test "atom" do
171 binary = ConfigDB.transform(":atom")
172 assert binary == :erlang.term_to_binary(:atom)
173 assert ConfigDB.from_binary(binary) == :atom
174 end
175
176 test "ssl options" do
177 binary = ConfigDB.transform([":tlsv1", ":tlsv1.1", ":tlsv1.2"])
178 assert binary == :erlang.term_to_binary([:tlsv1, :"tlsv1.1", :"tlsv1.2"])
179 assert ConfigDB.from_binary(binary) == [:tlsv1, :"tlsv1.1", :"tlsv1.2"]
180 end
181
182 test "pleroma module" do
183 binary = ConfigDB.transform("Pleroma.Bookmark")
184 assert binary == :erlang.term_to_binary(Pleroma.Bookmark)
185 assert ConfigDB.from_binary(binary) == Pleroma.Bookmark
186 end
187
188 test "pleroma string" do
189 binary = ConfigDB.transform("Pleroma")
190 assert binary == :erlang.term_to_binary("Pleroma")
191 assert ConfigDB.from_binary(binary) == "Pleroma"
192 end
193
194 test "phoenix module" do
195 binary = ConfigDB.transform("Phoenix.Socket.V1.JSONSerializer")
196 assert binary == :erlang.term_to_binary(Phoenix.Socket.V1.JSONSerializer)
197 assert ConfigDB.from_binary(binary) == Phoenix.Socket.V1.JSONSerializer
198 end
199
200 test "tesla module" do
201 binary = ConfigDB.transform("Tesla.Adapter.Hackney")
202 assert binary == :erlang.term_to_binary(Tesla.Adapter.Hackney)
203 assert ConfigDB.from_binary(binary) == Tesla.Adapter.Hackney
204 end
205
206 test "ExSyslogger module" do
207 binary = ConfigDB.transform("ExSyslogger")
208 assert binary == :erlang.term_to_binary(ExSyslogger)
209 assert ConfigDB.from_binary(binary) == ExSyslogger
210 end
211
212 test "Quack.Logger module" do
213 binary = ConfigDB.transform("Quack.Logger")
214 assert binary == :erlang.term_to_binary(Quack.Logger)
215 assert ConfigDB.from_binary(binary) == Quack.Logger
216 end
217
218 test "sigil" do
219 binary = ConfigDB.transform("~r[comp[lL][aA][iI][nN]er]")
220 assert binary == :erlang.term_to_binary(~r/comp[lL][aA][iI][nN]er/)
221 assert ConfigDB.from_binary(binary) == ~r/comp[lL][aA][iI][nN]er/
222 end
223
224 test "link sigil" do
225 binary = ConfigDB.transform("~r/https:\/\/example.com/")
226 assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/)
227 assert ConfigDB.from_binary(binary) == ~r/https:\/\/example.com/
228 end
229
230 test "link sigil with um modifiers" do
231 binary = ConfigDB.transform("~r/https:\/\/example.com/um")
232 assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/um)
233 assert ConfigDB.from_binary(binary) == ~r/https:\/\/example.com/um
234 end
235
236 test "link sigil with i modifier" do
237 binary = ConfigDB.transform("~r/https:\/\/example.com/i")
238 assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/i)
239 assert ConfigDB.from_binary(binary) == ~r/https:\/\/example.com/i
240 end
241
242 test "link sigil with s modifier" do
243 binary = ConfigDB.transform("~r/https:\/\/example.com/s")
244 assert binary == :erlang.term_to_binary(~r/https:\/\/example.com/s)
245 assert ConfigDB.from_binary(binary) == ~r/https:\/\/example.com/s
246 end
247
248 test "raise if valid delimiter not found" do
249 assert_raise ArgumentError, "valid delimiter for Regex expression not found", fn ->
250 ConfigDB.transform("~r/https://[]{}<>\"'()|example.com/s")
251 end
252 end
253
254 test "2 child tuple" do
255 binary = ConfigDB.transform(%{"tuple" => ["v1", ":v2"]})
256 assert binary == :erlang.term_to_binary({"v1", :v2})
257 assert ConfigDB.from_binary(binary) == {"v1", :v2}
258 end
259
260 test "proxy tuple with localhost" do
261 binary =
262 ConfigDB.transform(%{
263 "tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]
264 })
265
266 assert binary == :erlang.term_to_binary({:proxy_url, {:socks5, :localhost, 1234}})
267 assert ConfigDB.from_binary(binary) == {:proxy_url, {:socks5, :localhost, 1234}}
268 end
269
270 test "proxy tuple with domain" do
271 binary =
272 ConfigDB.transform(%{
273 "tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]
274 })
275
276 assert binary == :erlang.term_to_binary({:proxy_url, {:socks5, 'domain.com', 1234}})
277 assert ConfigDB.from_binary(binary) == {:proxy_url, {:socks5, 'domain.com', 1234}}
278 end
279
280 test "proxy tuple with ip" do
281 binary =
282 ConfigDB.transform(%{
283 "tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]
284 })
285
286 assert binary == :erlang.term_to_binary({:proxy_url, {:socks5, {127, 0, 0, 1}, 1234}})
287 assert ConfigDB.from_binary(binary) == {:proxy_url, {:socks5, {127, 0, 0, 1}, 1234}}
288 end
289
290 test "tuple with n childs" do
291 binary =
292 ConfigDB.transform(%{
293 "tuple" => [
294 "v1",
295 ":v2",
296 "Pleroma.Bookmark",
297 150,
298 false,
299 "Phoenix.Socket.V1.JSONSerializer"
300 ]
301 })
302
303 assert binary ==
304 :erlang.term_to_binary(
305 {"v1", :v2, Pleroma.Bookmark, 150, false, Phoenix.Socket.V1.JSONSerializer}
306 )
307
308 assert ConfigDB.from_binary(binary) ==
309 {"v1", :v2, Pleroma.Bookmark, 150, false, Phoenix.Socket.V1.JSONSerializer}
310 end
311
312 test "tuple with dispatch key" do
313 binary = ConfigDB.transform(%{"tuple" => [":dispatch", ["{:_,
314 [
315 {\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
316 {\"/websocket\", Phoenix.Endpoint.CowboyWebSocket,
317 {Phoenix.Transports.WebSocket,
318 {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}},
319 {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
320 ]}"]]})
321
322 assert binary ==
323 :erlang.term_to_binary(
324 {:dispatch,
325 [
326 {:_,
327 [
328 {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
329 {"/websocket", Phoenix.Endpoint.CowboyWebSocket,
330 {Phoenix.Transports.WebSocket,
331 {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: "/websocket"]}}},
332 {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
333 ]}
334 ]}
335 )
336
337 assert ConfigDB.from_binary(binary) ==
338 {:dispatch,
339 [
340 {:_,
341 [
342 {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
343 {"/websocket", Phoenix.Endpoint.CowboyWebSocket,
344 {Phoenix.Transports.WebSocket,
345 {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: "/websocket"]}}},
346 {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
347 ]}
348 ]}
349 end
350
351 test "map with string key" do
352 binary = ConfigDB.transform(%{"key" => "value"})
353 assert binary == :erlang.term_to_binary(%{"key" => "value"})
354 assert ConfigDB.from_binary(binary) == %{"key" => "value"}
355 end
356
357 test "map with atom key" do
358 binary = ConfigDB.transform(%{":key" => "value"})
359 assert binary == :erlang.term_to_binary(%{key: "value"})
360 assert ConfigDB.from_binary(binary) == %{key: "value"}
361 end
362
363 test "list of strings" do
364 binary = ConfigDB.transform(["v1", "v2", "v3"])
365 assert binary == :erlang.term_to_binary(["v1", "v2", "v3"])
366 assert ConfigDB.from_binary(binary) == ["v1", "v2", "v3"]
367 end
368
369 test "list of modules" do
370 binary = ConfigDB.transform(["Pleroma.Repo", "Pleroma.Activity"])
371 assert binary == :erlang.term_to_binary([Pleroma.Repo, Pleroma.Activity])
372 assert ConfigDB.from_binary(binary) == [Pleroma.Repo, Pleroma.Activity]
373 end
374
375 test "list of atoms" do
376 binary = ConfigDB.transform([":v1", ":v2", ":v3"])
377 assert binary == :erlang.term_to_binary([:v1, :v2, :v3])
378 assert ConfigDB.from_binary(binary) == [:v1, :v2, :v3]
379 end
380
381 test "list of mixed values" do
382 binary =
383 ConfigDB.transform([
384 "v1",
385 ":v2",
386 "Pleroma.Repo",
387 "Phoenix.Socket.V1.JSONSerializer",
388 15,
389 false
390 ])
391
392 assert binary ==
393 :erlang.term_to_binary([
394 "v1",
395 :v2,
396 Pleroma.Repo,
397 Phoenix.Socket.V1.JSONSerializer,
398 15,
399 false
400 ])
401
402 assert ConfigDB.from_binary(binary) == [
403 "v1",
404 :v2,
405 Pleroma.Repo,
406 Phoenix.Socket.V1.JSONSerializer,
407 15,
408 false
409 ]
410 end
411
412 test "simple keyword" do
413 binary = ConfigDB.transform([%{"tuple" => [":key", "value"]}])
414 assert binary == :erlang.term_to_binary([{:key, "value"}])
415 assert ConfigDB.from_binary(binary) == [{:key, "value"}]
416 assert ConfigDB.from_binary(binary) == [key: "value"]
417 end
418
419 test "keyword with partial_chain key" do
420 binary =
421 ConfigDB.transform([%{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]}])
422
423 assert binary == :erlang.term_to_binary(partial_chain: &:hackney_connect.partial_chain/1)
424 assert ConfigDB.from_binary(binary) == [partial_chain: &:hackney_connect.partial_chain/1]
425 end
426
427 test "keyword" do
428 binary =
429 ConfigDB.transform([
430 %{"tuple" => [":types", "Pleroma.PostgresTypes"]},
431 %{"tuple" => [":telemetry_event", ["Pleroma.Repo.Instrumenter"]]},
432 %{"tuple" => [":migration_lock", nil]},
433 %{"tuple" => [":key1", 150]},
434 %{"tuple" => [":key2", "string"]}
435 ])
436
437 assert binary ==
438 :erlang.term_to_binary(
439 types: Pleroma.PostgresTypes,
440 telemetry_event: [Pleroma.Repo.Instrumenter],
441 migration_lock: nil,
442 key1: 150,
443 key2: "string"
444 )
445
446 assert ConfigDB.from_binary(binary) == [
447 types: Pleroma.PostgresTypes,
448 telemetry_event: [Pleroma.Repo.Instrumenter],
449 migration_lock: nil,
450 key1: 150,
451 key2: "string"
452 ]
453 end
454
455 test "complex keyword with nested mixed childs" do
456 binary =
457 ConfigDB.transform([
458 %{"tuple" => [":uploader", "Pleroma.Uploaders.Local"]},
459 %{"tuple" => [":filters", ["Pleroma.Upload.Filter.Dedupe"]]},
460 %{"tuple" => [":link_name", true]},
461 %{"tuple" => [":proxy_remote", false]},
462 %{"tuple" => [":common_map", %{":key" => "value"}]},
463 %{
464 "tuple" => [
465 ":proxy_opts",
466 [
467 %{"tuple" => [":redirect_on_failure", false]},
468 %{"tuple" => [":max_body_length", 1_048_576]},
469 %{
470 "tuple" => [
471 ":http",
472 [%{"tuple" => [":follow_redirect", true]}, %{"tuple" => [":pool", ":upload"]}]
473 ]
474 }
475 ]
476 ]
477 }
478 ])
479
480 assert binary ==
481 :erlang.term_to_binary(
482 uploader: Pleroma.Uploaders.Local,
483 filters: [Pleroma.Upload.Filter.Dedupe],
484 link_name: true,
485 proxy_remote: false,
486 common_map: %{key: "value"},
487 proxy_opts: [
488 redirect_on_failure: false,
489 max_body_length: 1_048_576,
490 http: [
491 follow_redirect: true,
492 pool: :upload
493 ]
494 ]
495 )
496
497 assert ConfigDB.from_binary(binary) ==
498 [
499 uploader: Pleroma.Uploaders.Local,
500 filters: [Pleroma.Upload.Filter.Dedupe],
501 link_name: true,
502 proxy_remote: false,
503 common_map: %{key: "value"},
504 proxy_opts: [
505 redirect_on_failure: false,
506 max_body_length: 1_048_576,
507 http: [
508 follow_redirect: true,
509 pool: :upload
510 ]
511 ]
512 ]
513 end
514
515 test "common keyword" do
516 binary =
517 ConfigDB.transform([
518 %{"tuple" => [":level", ":warn"]},
519 %{"tuple" => [":meta", [":all"]]},
520 %{"tuple" => [":path", ""]},
521 %{"tuple" => [":val", nil]},
522 %{"tuple" => [":webhook_url", "https://hooks.slack.com/services/YOUR-KEY-HERE"]}
523 ])
524
525 assert binary ==
526 :erlang.term_to_binary(
527 level: :warn,
528 meta: [:all],
529 path: "",
530 val: nil,
531 webhook_url: "https://hooks.slack.com/services/YOUR-KEY-HERE"
532 )
533
534 assert ConfigDB.from_binary(binary) == [
535 level: :warn,
536 meta: [:all],
537 path: "",
538 val: nil,
539 webhook_url: "https://hooks.slack.com/services/YOUR-KEY-HERE"
540 ]
541 end
542
543 test "complex keyword with sigil" do
544 binary =
545 ConfigDB.transform([
546 %{"tuple" => [":federated_timeline_removal", []]},
547 %{"tuple" => [":reject", ["~r/comp[lL][aA][iI][nN]er/"]]},
548 %{"tuple" => [":replace", []]}
549 ])
550
551 assert binary ==
552 :erlang.term_to_binary(
553 federated_timeline_removal: [],
554 reject: [~r/comp[lL][aA][iI][nN]er/],
555 replace: []
556 )
557
558 assert ConfigDB.from_binary(binary) ==
559 [federated_timeline_removal: [], reject: [~r/comp[lL][aA][iI][nN]er/], replace: []]
560 end
561
562 test "complex keyword with tuples with more than 2 values" do
563 binary =
564 ConfigDB.transform([
565 %{
566 "tuple" => [
567 ":http",
568 [
569 %{
570 "tuple" => [
571 ":key1",
572 [
573 %{
574 "tuple" => [
575 ":_",
576 [
577 %{
578 "tuple" => [
579 "/api/v1/streaming",
580 "Pleroma.Web.MastodonAPI.WebsocketHandler",
581 []
582 ]
583 },
584 %{
585 "tuple" => [
586 "/websocket",
587 "Phoenix.Endpoint.CowboyWebSocket",
588 %{
589 "tuple" => [
590 "Phoenix.Transports.WebSocket",
591 %{
592 "tuple" => [
593 "Pleroma.Web.Endpoint",
594 "Pleroma.Web.UserSocket",
595 []
596 ]
597 }
598 ]
599 }
600 ]
601 },
602 %{
603 "tuple" => [
604 ":_",
605 "Phoenix.Endpoint.Cowboy2Handler",
606 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
607 ]
608 }
609 ]
610 ]
611 }
612 ]
613 ]
614 }
615 ]
616 ]
617 }
618 ])
619
620 assert binary ==
621 :erlang.term_to_binary(
622 http: [
623 key1: [
624 _: [
625 {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
626 {"/websocket", Phoenix.Endpoint.CowboyWebSocket,
627 {Phoenix.Transports.WebSocket,
628 {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, []}}},
629 {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
630 ]
631 ]
632 ]
633 )
634
635 assert ConfigDB.from_binary(binary) == [
636 http: [
637 key1: [
638 {:_,
639 [
640 {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
641 {"/websocket", Phoenix.Endpoint.CowboyWebSocket,
642 {Phoenix.Transports.WebSocket,
643 {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, []}}},
644 {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
645 ]}
646 ]
647 ]
648 ]
649 end
650 end
651 end