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