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