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