diff --git a/.circleci/config.yml b/.circleci/config.yml index 534de67..2008c48 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,7 +16,7 @@ jobs: executor: machine_executor_amd64 steps: - checkout - - run: docker compose -f docker-compose-integration.yaml run test + - run: docker compose -f docker-compose-test.yaml up test --exit-code-from test - codecov/upload workflows: diff --git a/README.md b/README.md index d70e85a..488fe30 100644 --- a/README.md +++ b/README.md @@ -35,14 +35,14 @@ config :jellyfish_server_sdk, secure?: true ``` -Alternatively, the connection options can be provided when creating a `Jellyfish.Client` or starting `Jellyfish.Notifier`: +Alternatively, the connection options can be provided when creating a `Jellyfish.Client` or starting `Jellyfish.WSNotifier`: ```elixir client = Jellyfish.Client.new(server_address: "localhost:5002", server_api_token: "your-jellyfish-token") {:ok, notifier} = - Jellyfish.Notifier.start( + Jellyfish.WSNotifier.start( server_address: "localhost:5002", server_api_token: "your-jellyfish-token" ) @@ -54,8 +54,8 @@ Make API calls to Jellyfish and receive server events: ```elixir # start process responsible for receiving events -{:ok, notifier} = Jellyfish.Notifier.start() -:ok = Jellyfish.Notifier.subscribe_server_notifications(notifier) +{:ok, notifier} = Jellyfish.WSNotifier.start() +:ok = Jellyfish.WSNotifier.subscribe_server_notifications(notifier) # create HTTP client instance client = Jellyfish.Client.new() diff --git a/config/integration_test.exs b/config/integration_test.exs deleted file mode 100644 index 0492dc5..0000000 --- a/config/integration_test.exs +++ /dev/null @@ -1,7 +0,0 @@ -import Config - -config :jellyfish_server_sdk, - server_address: "jellyfish:5002", - server_api_token: "development", - divo: "docker-compose-integration.yaml", - divo_wait: [dwell: 1_500, max_tries: 50] diff --git a/config/test.exs b/config/test.exs index 1024d01..16882d2 100644 --- a/config/test.exs +++ b/config/test.exs @@ -1,7 +1,6 @@ import Config config :jellyfish_server_sdk, - server_address: "localhost:5002", + server_address: "jellyfish:5002", server_api_token: "development", - divo: "docker-compose-dev.yaml", - divo_wait: [dwell: 1_500, max_tries: 50] + webhook_address: "test" diff --git a/config/test_local.exs b/config/test_local.exs new file mode 100644 index 0000000..58f9b3d --- /dev/null +++ b/config/test_local.exs @@ -0,0 +1,6 @@ +import Config + +config :jellyfish_server_sdk, + server_address: "127.0.0.1:5002", + server_api_token: "development", + webhook_address: "127.0.0.1" diff --git a/docker-compose-integration.yaml b/docker-compose-test.yaml similarity index 75% rename from docker-compose-integration.yaml rename to docker-compose-test.yaml index 80009f5..1c87ad7 100644 --- a/docker-compose-integration.yaml +++ b/docker-compose-test.yaml @@ -4,12 +4,10 @@ services: test: image: hexpm/elixir:1.14.4-erlang-25.3.2-alpine-3.16.5 command: sh -c "cd app/ && apk add git && mix local.hex --force && mix local.rebar --force && mix deps.get && mix coveralls.json --warnings-as-errors" - environment: - - MIX_ENV=integration_test volumes: - .:/app - networks: - - network + ports: + - "4000:4000" depends_on: jellyfish: condition: service_healthy @@ -20,9 +18,3 @@ services: service: jellyfish environment: - JF_HOST=jellyfish:5002 - networks: - - network - -networks: - network: - driver: bridge diff --git a/examples/server_socket.exs b/examples/server_socket.exs index e3e4b55..2ff3361 100644 --- a/examples/server_socket.exs +++ b/examples/server_socket.exs @@ -9,10 +9,10 @@ server_address = "localhost:5002" server_api_token = "development" {:ok, notifier} = - Jellyfish.Notifier.start(server_address: server_address, server_api_token: server_api_token) + Jellyfish.WSNotifier.start(server_address: server_address, server_api_token: server_api_token) -{:ok, _rooms} = Jellyfish.Notifier.subscribe_server_notifications(notifier, :all) -:ok = Jellyfish.Notifier.subscribe_metrics(notifier) +{:ok, _rooms} = Jellyfish.WSNotifier.subscribe_server_notifications(notifier, :all) +:ok = Jellyfish.WSNotifier.subscribe_metrics(notifier) receive_notification = fn receive_notification -> receive do diff --git a/lib/jellyfish/room.ex b/lib/jellyfish/room.ex index aaba150..5602215 100644 --- a/lib/jellyfish/room.ex +++ b/lib/jellyfish/room.ex @@ -121,7 +121,8 @@ defmodule Jellyfish.Room do "/room", %{ "maxPeers" => Keyword.get(opts, :max_peers), - "videoCodec" => Keyword.get(opts, :video_codec) + "videoCodec" => Keyword.get(opts, :video_codec), + "webhookUrl" => Keyword.get(opts, :webhook_url) } ), {:ok, data} <- Map.fetch(body, "data"), diff --git a/lib/jellyfish/webhook_notifier.ex b/lib/jellyfish/webhook_notifier.ex new file mode 100644 index 0000000..6e0ee78 --- /dev/null +++ b/lib/jellyfish/webhook_notifier.ex @@ -0,0 +1,34 @@ +defmodule Jellyfish.WebhookNotifier do + @moduledoc """ + Module defining a function allowing decoding received webhook notification from jellyfish to notification structs. + """ + + alias Jellyfish.{Notification, ServerMessage} + + @doc """ + Decodes received webhook to notification structs. + + ``` + iex> %{ + ...> "notification" => <<18, 76, 10, 36, 102, 98, 102, 52, 49, 57, 48, 99, 45, 53, 99, 55, 54, 45, 52, + ...> 49, 53, 99, 45, 56, 57, 51, 57, 45, 53, 50, 99, 54, 101, 100, 50, 48, 56, 54, + ...> 56, 98, 18, 36, 99, 55, 50, 51, 54, 53, 56, 55, 45, 53, 100, 102, 56, 45, 52, + ...> 98, 52, 49, 45, 98, 54, 101, 52, 45, 50, 54, 56, 101, 55, 49, 49, 51, 51, 101, + ...> 101, 50>> + ...> } |> Jellyfish.WebhookNotifier.receive() + %Jellyfish.Notification.PeerConnected{ + room_id: "fbf4190c-5c76-415c-8939-52c6ed20868b", + peer_id: "c7236587-5df8-4b41-b6e4-268e71133ee2" + } + ``` + """ + @spec receive(term()) :: struct() + def receive(json) do + %ServerMessage{content: {_type, notification}} = + json + |> Map.get("notification") + |> ServerMessage.decode() + + Notification.to_notification(notification) + end +end diff --git a/lib/jellyfish/notifier.ex b/lib/jellyfish/ws_notifier.ex similarity index 96% rename from lib/jellyfish/notifier.ex rename to lib/jellyfish/ws_notifier.ex index 191b8e2..ed29861 100644 --- a/lib/jellyfish/notifier.ex +++ b/lib/jellyfish/ws_notifier.ex @@ -1,4 +1,4 @@ -defmodule Jellyfish.Notifier do +defmodule Jellyfish.WSNotifier do @moduledoc """ Module defining a process responsible for establishing WebSocket connection and receiving events from Jellyfish server. @@ -7,13 +7,13 @@ defmodule Jellyfish.Notifier do ``` # Start the Notifier - iex> {:ok, notifier} = Jellyfish.Notifier.start() + iex> {:ok, notifier} = Jellyfish.WSNotifier.start() {:ok, #PID<0.301.0>} ``` ``` # Subscribe current process to server notifications. - iex> :ok = Jellyfish.Notifier.subscribe_server_notifications(notifier) + iex> :ok = Jellyfish.WSNotifier.subscribe_server_notifications(notifier) # here add a room and a peer using functions from `Jellyfish.Room` module # you should receive a notification after the peer established connection @@ -28,7 +28,7 @@ defmodule Jellyfish.Notifier do When starting the Notifier, you can provide the name under which the process will be registered. ``` - iex> {:ok, notifier} = Jellyfish.Notifier.start_link(name: Jellyfish.Notifier) + iex> {:ok, notifier} = Jellyfish.WSNotifier.start_link(name: Jellyfish.WSNotifier) ``` """ diff --git a/mix.exs b/mix.exs index b516049..c65ec14 100644 --- a/mix.exs +++ b/mix.exs @@ -33,7 +33,8 @@ defmodule Membrane.Template.Mixfile do "coveralls.detail": :test, "coveralls.post": :test, "coveralls.html": :test, - "coveralls.json": :test + "coveralls.json": :test, + "test.local": :test ] ] end @@ -44,7 +45,7 @@ defmodule Membrane.Template.Mixfile do ] end - defp elixirc_paths(env) when env in [:test, :integration_test], do: ["lib", "test/support"] + defp elixirc_paths(env) when env in [:test, :test_local], do: ["lib", "test/support"] defp elixirc_paths(_env), do: ["lib"] defp deps do @@ -58,14 +59,16 @@ defmodule Membrane.Template.Mixfile do # protobuf deps {:protobuf, "~> 0.12.0"}, - # Tests - {:divo, "~> 1.3.1", only: [:test]}, # Docs, credo, test coverage, dialyzer {:ex_doc, ">= 0.0.0", only: :dev, runtime: false}, {:dialyxir, ">= 0.0.0", only: :dev, runtime: false}, {:credo, ">= 0.0.0", only: :dev, runtime: false}, - {:excoveralls, ">= 0.0.0", only: [:test, :integration_test], runtime: false} + {:excoveralls, ">= 0.0.0", only: [:test, :test_local], runtime: false}, + + # Test deps + {:plug_cowboy, "~> 2.5", only: [:test, :test_local]}, + {:phoenix_pubsub, "~> 2.1", only: [:test, :test_local]} ] end @@ -112,10 +115,62 @@ defmodule Membrane.Template.Mixfile do def aliases do [ - integration_test: [ - "cmd docker compose -f docker-compose-integration.yaml pull", - "cmd docker compose -f docker-compose-integration.yaml run test" - ] + test: &test_in_docker/1, + "test.local": ["cmd MIX_ENV=test_local mix test --without_docker"] ] end + + defp test_in_docker(opts) do + cond do + List.last(opts) == "--without_docker" -> + IO.puts("Running tests locally (it requires setting up jellyfish without docker) ...") + + Mix.Task.run("test") + + System.find_executable("docker") -> + IO.puts("Running tests using Docker. To run tests without Docker call \"mix test.local\"") + + docker_compose_prefix = ["docker", "compose", "-f", "docker-compose-test.yaml"] + + stream_command(docker_compose_prefix ++ ["pull"]) + + stream_command( + docker_compose_prefix ++ ["up", "--remove-orphans", "test", "--exit-code-from", "test"] + ) + + stream_command(docker_compose_prefix ++ ["down"]) + + true -> + IO.puts("Running tests inside docker container ...") + + Mix.Task.run("test") + end + end + + defp stream_command(cmd) do + port = + Port.open({:spawn, Enum.join(cmd, " ")}, [ + {:line, 1024}, + :use_stdio, + :stderr_to_stdout, + :exit_status + ]) + + receive_and_print(port) + end + + defp receive_and_print(port) do + receive do + {^port, {:data, {:eol, line}}} -> + IO.puts(line) + receive_and_print(port) + + {^port, {:data, data}} -> + IO.puts(data) + receive_and_print(port) + + {^port, {:exit_status, exit_status}} -> + IO.puts("Docker command exited with status code: #{exit_status}") + end + end end diff --git a/mix.lock b/mix.lock index 5652275..b30cae7 100644 --- a/mix.lock +++ b/mix.lock @@ -1,9 +1,11 @@ %{ "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"}, "castore": {:hex, :castore, "1.0.3", "7130ba6d24c8424014194676d608cb989f62ef8039efd50ff4b3f33286d06db8", [:mix], [], "hexpm", "680ab01ef5d15b161ed6a95449fac5c6b8f60055677a8e79acf01b27baa4390b"}, + "cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"}, + "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, + "cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"}, "credo": {:hex, :credo, "1.7.0", "6119bee47272e85995598ee04f2ebbed3e947678dee048d10b5feca139435f75", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "6839fcf63d1f0d1c0f450abc8564a57c43d644077ab96f2934563e68b8a769d7"}, "dialyxir": {:hex, :dialyxir, "1.4.1", "a22ed1e7bd3a3e3f197b68d806ef66acb61ee8f57b3ac85fc5d57354c5482a93", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "84b795d6d7796297cca5a3118444b80c7d94f7ce247d49886e7c291e1ae49801"}, - "divo": {:hex, :divo, "1.3.2", "3a5ce880a1fe930ea804361d1b57b5144129e79e1c856623d923a6fab6d539a1", [:mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:patiently, "~> 0.2", [hex: :patiently, repo: "hexpm", optional: false]}], "hexpm", "4bd035510838959709db2cacd28edd2eda7948d0e7f1b0dfa810a134c913a88a"}, "earmark_parser": {:hex, :earmark_parser, "1.4.35", "437773ca9384edf69830e26e9e7b2e0d22d2596c4a6b17094a3b29f01ea65bb8", [:mix], [], "hexpm", "8652ba3cb85608d0d7aa2d21b45c6fad4ddc9a1f9a1f1b30ca3a246f0acc33f6"}, "elixir_uuid": {:hex, :elixir_uuid, "1.2.1", "dce506597acb7e6b0daeaff52ff6a9043f5919a4c3315abb4143f0b00378c097", [:mix], [], "hexpm", "f7eba2ea6c3555cea09706492716b0d87397b88946e6380898c2889d68585752"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, @@ -18,8 +20,13 @@ "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, "mint": {:hex, :mint, "1.5.1", "8db5239e56738552d85af398798c80648db0e90f343c8469f6c6d8898944fb6f", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "4a63e1e76a7c3956abd2c72f370a0d0aecddc3976dea5c27eccbecfa5e7d5b1e"}, "nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"}, - "patiently": {:hex, :patiently, "0.2.0", "67eb139591e10c4b363ae0198e832552f191c58894731efd3bf124ec4722267a", [:mix], [], "hexpm", "c08cc5edc27def565647a9b55a0bea8025a5f81a4472e57692f28f2292c44c94"}, + "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, + "plug": {:hex, :plug, "1.15.1", "b7efd81c1a1286f13efb3f769de343236bd8b7d23b4a9f40d3002fc39ad8f74c", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "459497bd94d041d98d948054ec6c0b76feacd28eec38b219ca04c0de13c79d30"}, + "plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"}, + "plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"}, "protobuf": {:hex, :protobuf, "0.12.0", "58c0dfea5f929b96b5aa54ec02b7130688f09d2de5ddc521d696eec2a015b223", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "75fa6cbf262062073dd51be44dd0ab940500e18386a6c4e87d5819a58964dc45"}, + "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, + "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, "tesla": {:hex, :tesla, "1.7.0", "a62dda2f80d4f8a925eb7b8c5b78c461e0eb996672719fe1a63b26321a5f8b4e", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "2e64f01ebfdb026209b47bc651a0e65203fcff4ae79c11efb73c4852b00dc313"}, "websockex": {:hex, :websockex, "0.4.3", "92b7905769c79c6480c02daacaca2ddd49de936d912976a4d3c923723b647bf0", [:mix], [], "hexpm", "95f2e7072b85a3a4cc385602d42115b73ce0b74a9121d0d6dbbf557645ac53e4"}, } diff --git a/test/jellyfish/notifier_test.exs b/test/jellyfish/notifier_test.exs index 73d458b..926a6ab 100644 --- a/test/jellyfish/notifier_test.exs +++ b/test/jellyfish/notifier_test.exs @@ -1,7 +1,7 @@ defmodule Jellyfish.NotifierTest do use ExUnit.Case - - alias Jellyfish.{Client, Notifier, Peer, Room} + doctest Jellyfish.WebhookNotifier + alias Jellyfish.{Client, Peer, Room, WSNotifier} alias Jellyfish.PeerMessage alias Jellyfish.PeerMessage.AuthRequest @@ -16,45 +16,88 @@ defmodule Jellyfish.NotifierTest do alias Jellyfish.MetricsReport alias Jellyfish.WS + alias Phoenix.PubSub @peer_opts %Peer.WebRTC{} @max_peers 10 @video_codec :vp8 + @webhook_port 4000 + @webhook_host Application.compile_env!(:jellyfish_server_sdk, :webhook_address) + @webhook_address "http://#{@webhook_host}:#{@webhook_port}/" + @pubsub Jellyfish.PubSub + + setup_all do + children = [ + {Plug.Cowboy, + plug: WebHookPlug, scheme: :http, options: [port: @webhook_port, ip: {0, 0, 0, 0}]}, + {Phoenix.PubSub, name: Jellyfish.PubSub} + ] + + {:ok, _pid} = + Supervisor.start_link(children, + strategy: :one_for_one + ) + + :ok + end + + setup do + :ok = PubSub.subscribe(@pubsub, "webhook") + + on_exit(fn -> + :ok = PubSub.unsubscribe(@pubsub, "webhook") + end) + end describe "connecting to the server and subcribing for events" do - test "when credentials are valid" do - assert {:ok, pid} = Notifier.start_link() + test "when credentials are valid", %{} do + assert {:ok, pid} = WSNotifier.start_link() assert is_pid(pid) end - test "when token is invalid" do - assert {:error, :invalid_token} = Notifier.start_link(server_api_token: "invalid_token") + test "when token is invalid", %{} do + assert {:error, :invalid_token} = + WSNotifier.start_link(server_api_token: "invalid_token") end end describe "receiving notifications" do setup do - {:ok, notifier} = Notifier.start_link() - :ok = Notifier.subscribe_server_notifications(notifier) + {:ok, notifier} = WSNotifier.start_link() + :ok = WSNotifier.subscribe_server_notifications(notifier) %{client: Client.new()} end - test "when room gets created and then deleted", %{client: client} do + test "when room gets created and then deleted", %{ + client: client + } do {:ok, %Jellyfish.Room{id: room_id}, _jellyfish_address} = - Room.create(client, max_peers: @max_peers, video_codec: @video_codec) + Room.create(client, + max_peers: @max_peers, + video_codec: @video_codec, + webhook_url: @webhook_address + ) assert_receive {:jellyfish, %RoomCreated{room_id: ^room_id}} + assert_receive {:webhook, %RoomCreated{room_id: ^room_id}}, 2_500 :ok = Room.delete(client, room_id) assert_receive {:jellyfish, %RoomDeleted{room_id: ^room_id}} + assert_receive {:webhook, %RoomDeleted{room_id: ^room_id}}, 2_500 end - test "when peer connects and then disconnects", %{client: client} do + test "when peer connects and then disconnects", %{ + client: client + } do {:ok, %Jellyfish.Room{id: room_id}, jellyfish_address} = - Room.create(client, max_peers: @max_peers, video_codec: @video_codec) + Room.create(client, + max_peers: @max_peers, + video_codec: @video_codec, + webhook_url: @webhook_address + ) {:ok, %Jellyfish.Peer{id: peer_id}, peer_token} = Room.add_peer(client, room_id, @peer_opts) @@ -65,25 +108,30 @@ defmodule Jellyfish.NotifierTest do :ok = WS.send_frame(peer_ws, auth_request) assert_receive {:jellyfish, %PeerConnected{peer_id: ^peer_id, room_id: ^room_id}} + assert_receive {:webhook, %PeerConnected{peer_id: ^peer_id, room_id: ^room_id}}, 2_500 :ok = Room.delete_peer(client, room_id, peer_id) - assert_receive {:jellyfish, %PeerDisconnected{peer_id: ^peer_id, room_id: ^room_id}} + assert_receive {:jellyfish, %PeerDisconnected{peer_id: ^peer_id, room_id: ^room_id}}, 1_000 + assert_receive {:webhook, %PeerDisconnected{peer_id: ^peer_id, room_id: ^room_id}}, 2_500 end end describe "receiving metrics" do setup do - {:ok, notifier} = Notifier.start_link() - :ok = Notifier.subscribe_server_notifications(notifier) - :ok = Notifier.subscribe_metrics(notifier) + {:ok, notifier} = WSNotifier.start_link() + :ok = WSNotifier.subscribe_server_notifications(notifier) + :ok = WSNotifier.subscribe_metrics(notifier) %{client: Client.new()} end test "with one peer", %{client: client} do {:ok, %Jellyfish.Room{id: room_id}, jellyfish_address} = - Room.create(client, max_peers: @max_peers) + Room.create(client, + max_peers: @max_peers, + webhook_url: @webhook_address + ) {:ok, %Jellyfish.Peer{id: peer_id}, peer_token} = Room.add_peer(client, room_id, @peer_opts) @@ -93,6 +141,7 @@ defmodule Jellyfish.NotifierTest do :ok = WS.send_frame(peer_ws, auth_request) assert_receive {:jellyfish, %PeerConnected{peer_id: ^peer_id, room_id: ^room_id}} + assert_receive {:webhook, %PeerConnected{peer_id: ^peer_id, room_id: ^room_id}}, 2_500 assert_receive {:jellyfish, %MetricsReport{metrics: metrics}} when metrics != %{}, 1500 end diff --git a/test/jellyfish/room_test.exs b/test/jellyfish/room_test.exs index 4e3f6f2..a7eae78 100644 --- a/test/jellyfish/room_test.exs +++ b/test/jellyfish/room_test.exs @@ -59,6 +59,7 @@ defmodule Jellyfish.RoomTest do } = room server_address = Application.fetch_env!(:jellyfish_server_sdk, :server_address) + assert ^server_address = jellyfish_address end @@ -80,16 +81,17 @@ defmodule Jellyfish.RoomTest do } = room server_address = Application.fetch_env!(:jellyfish_server_sdk, :server_address) + assert ^server_address = jellyfish_address end test "when request is invalid, max peers", %{client: client} do - assert {:error, "Request failed: maxPeers must be a number"} = + assert {:error, "Request failed: Expected maxPeers to be a number, got: abc"} = Room.create(client, max_peers: @invalid_max_peers) end test "when request is invalid, video codec", %{client: client} do - assert {:error, "Request failed: videoCodec must be 'h264' or 'vp8'"} = + assert {:error, "Request failed: Expected videoCodec to be 'h264' or 'vp8', got: opus"} = Room.create(client, video_codec: @invalid_video_codec) end end diff --git a/test/support/webhook_plug.ex b/test/support/webhook_plug.ex new file mode 100644 index 0000000..b45f898 --- /dev/null +++ b/test/support/webhook_plug.ex @@ -0,0 +1,25 @@ +defmodule WebHookPlug do + @moduledoc false + import Plug.Conn + alias Jellyfish.WebhookNotifier + alias Phoenix.PubSub + + @pubsub Jellyfish.PubSub + + def init(opts) do + opts + end + + def call(conn, _opts) do + {:ok, body, conn} = Plug.Conn.read_body(conn, []) + notification = Jason.decode!(body) + + notification = WebhookNotifier.receive(notification) + + :ok = PubSub.broadcast(@pubsub, "webhook", {:webhook, notification}) + + conn + |> put_resp_content_type("text/plain") + |> send_resp(200, "OK") + end +end diff --git a/test/test_helper.exs b/test/test_helper.exs index 0bffcaa..6a0af57 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,5 +1 @@ -if Mix.env() != :integration_test do - Divo.Suite.start(services: [:jellyfish]) -end - ExUnit.start(capture_log: true)