From 293c23167ae9547da18e69e2efd8986ac12a9c38 Mon Sep 17 00:00:00 2001 From: noarkhh Date: Wed, 24 Apr 2024 17:53:32 +0200 Subject: [PATCH] Make tests pass, change get_transport --- lib/membrane_rtsp/rtsp.ex | 65 +++++----- lib/membrane_rtsp/session/logic.ex | 11 +- .../{transport => }/tcp_socket.ex | 9 +- lib/membrane_rtsp/transport/transport.ex | 51 -------- .../session/session_integration_test.exs | 7 +- .../session/session_logic_test.exs | 72 ++++++----- .../workflow_integration_test.exs | 119 ++++++++++-------- test/support/fake.ex | 33 ----- 8 files changed, 150 insertions(+), 217 deletions(-) rename lib/membrane_rtsp/{transport => }/tcp_socket.ex (91%) delete mode 100644 lib/membrane_rtsp/transport/transport.ex delete mode 100644 test/support/fake.ex diff --git a/lib/membrane_rtsp/rtsp.ex b/lib/membrane_rtsp/rtsp.ex index ba15bb5..fac6d85 100644 --- a/lib/membrane_rtsp/rtsp.ex +++ b/lib/membrane_rtsp/rtsp.ex @@ -6,7 +6,7 @@ defmodule Membrane.RTSP do alias Membrane.RTSP alias Membrane.RTSP.Logic.State - alias Membrane.RTSP.{Request, Response} + alias Membrane.RTSP.{Request, Response, TCPSocket} @type t() :: pid() @@ -22,21 +22,20 @@ defmodule Membrane.RTSP do * options - a keyword list that shall be passed when executing request over transport """ - @spec start_link(binary(), module() | URI.t(), Keyword.t()) :: GenServer.on_start() - def start_link(url, transport \\ Membrane.RTSP.Transport.TCPSocket, options \\ []) do - do_start(url, transport, options, &GenServer.start_link/2) + @spec start_link(binary() | URI.t(), Keyword.t()) :: GenServer.on_start() + def start_link(url, options \\ []) do + do_start(url, options, &GenServer.start_link/2) end - @spec start(binary(), module() | URI.t(), Keyword.t()) :: GenServer.on_start() - def start(url, transport \\ Membrane.RTSP.Transport.TCPSocket, options \\ []) do - do_start(url, transport, options, &GenServer.start/2) + @spec start(binary() | URI.t(), Keyword.t()) :: GenServer.on_start() + def start(url, options \\ []) do + do_start(url, options, &GenServer.start/2) end - defp do_start(url, transport, options, start_fun) do + defp do_start(url, options, start_fun) do case URI.parse(url) do %URI{host: host, scheme: "rtsp"} = url when is_binary(host) -> start_fun.(__MODULE__, %{ - transport: transport, url: %URI{url | port: url.port || @default_rtsp_port}, options: options }) @@ -47,7 +46,7 @@ defmodule Membrane.RTSP do end @impl true - def init(%{url: url, options: options, transport: transport_module}) do + def init(%{url: url, options: options}) do auth_type = case url do %URI{userinfo: nil} -> nil @@ -56,10 +55,9 @@ defmodule Membrane.RTSP do %URI{userinfo: info} when is_binary(info) -> :basic end - with {:ok, transport} <- transport_module.init(url, options) do + with {:ok, socket} <- TCPSocket.init(url, options) do state = %State{ - transport: transport, - transport_module: transport_module, + socket: socket, uri: url, execution_options: options, auth: auth_type @@ -81,8 +79,13 @@ defmodule Membrane.RTSP do end end - def handle_call(:get_transport, _from, %State{transport: transport} = state) do - {:reply, transport, state} + def handle_call( + {:get_socket_control, new_controlling_process}, + _from, + %State{socket: socket} = state + ) do + :ok = :gen_tcp.controlling_process(socket, new_controlling_process) + {:reply, socket, state} end def handle_call({:parse_response, raw_response}, _from, state) do @@ -108,16 +111,16 @@ defmodule Membrane.RTSP do end end - @impl true - # this might be a message for transport layer. Redirect - def handle_info(msg, %State{} = state) do - state.transport_module.handle_info(msg, state.transport) - |> translate(:transport, state) - end + # @impl true + # # this might be a message for transport layer. Redirect + # def handle_info(msg, %State{} = state) do + # TCPSocket.handle_info(msg, state.transport) + # |> translate(:transport, state) + # end @impl true def terminate(_reason, state) do - state.transport_module.close(state.transport) + TCPSocket.close(state.socket) end @spec request(pid(), binary(), RTSP.headers(), binary(), nil | binary()) :: Response.result() @@ -135,19 +138,19 @@ defmodule Membrane.RTSP do @spec close(pid()) :: :ok def close(session), do: GenServer.cast(session, :terminate) - defp translate({action, new_state}, key, state) do - {action, Map.put(state, key, new_state)} - end + # defp translate({action, new_state}, key, state) do + # {action, Map.put(state, key, new_state)} + # end - defp translate({action, reply, new_state}, key, state) do - {action, reply, Map.put(state, key, new_state)} - end + # defp translate({action, reply, new_state}, key, state) do + # {action, reply, Map.put(state, key, new_state)} + # end @type headers :: [{binary(), binary()}] - @spec get_transport(t()) :: any() - def get_transport(session) do - GenServer.call(session, :get_transport) + @spec get_socket_control(t(), pid()) :: :gen_tcp.socket() + def get_socket_control(session, new_controlling_process) do + GenServer.call(session, {:get_socket_control, new_controlling_process}) end @spec get_parameter_no_response(t(), headers(), binary()) :: :ok diff --git a/lib/membrane_rtsp/session/logic.ex b/lib/membrane_rtsp/session/logic.ex index a4f004b..d4b10c1 100644 --- a/lib/membrane_rtsp/session/logic.ex +++ b/lib/membrane_rtsp/session/logic.ex @@ -2,12 +2,12 @@ defmodule Membrane.RTSP.Logic do @moduledoc """ Logic for RTSP session """ - alias Membrane.RTSP.{Request, Response} + alias Membrane.RTSP.{Request, Response, TCPSocket} @user_agent "MembraneRTSP/#{Mix.Project.config()[:version]} (Membrane Framework RTSP Client)" defmodule State do @moduledoc "Struct representing the state of RTSP session" - @enforce_keys [:transport, :uri, :transport_module] + @enforce_keys [:socket, :uri] defstruct @enforce_keys ++ [ :session_id, @@ -24,7 +24,7 @@ defmodule Membrane.RTSP.Logic do @type auth_t() :: nil | :basic | {:digest, digest_opts()} @type t :: %__MODULE__{ - transport: any(), + socket: :gen_tcp.socket(), cseq: non_neg_integer(), uri: URI.t(), session_id: binary() | nil, @@ -41,8 +41,7 @@ defmodule Membrane.RTSP.Logic do def execute(request, state, get_response \\ true) do %State{ cseq: cseq, - transport: transport, - transport_module: transport_module, + socket: socket, uri: uri, session_id: session_id, execution_options: execution_options @@ -55,7 +54,7 @@ defmodule Membrane.RTSP.Logic do |> Request.with_header("User-Agent", @user_agent) |> apply_credentials(uri, state.auth) |> Request.stringify(uri) - |> transport_module.execute(transport, execution_options ++ [get_response: get_response]) + |> TCPSocket.execute(socket, execution_options ++ [get_response: get_response]) end @spec inject_session_header(Request.t(), binary()) :: Request.t() diff --git a/lib/membrane_rtsp/transport/tcp_socket.ex b/lib/membrane_rtsp/tcp_socket.ex similarity index 91% rename from lib/membrane_rtsp/transport/tcp_socket.ex rename to lib/membrane_rtsp/tcp_socket.ex index 641578c..cbd0f74 100644 --- a/lib/membrane_rtsp/transport/tcp_socket.ex +++ b/lib/membrane_rtsp/tcp_socket.ex @@ -1,4 +1,4 @@ -defmodule Membrane.RTSP.Transport.TCPSocket do +defmodule Membrane.RTSP.TCPSocket do @moduledoc """ This module implements the Transport behaviour and transmits requests over TCP Socket keeping connection until either session is closed or connection is @@ -8,13 +8,11 @@ defmodule Membrane.RTSP.Transport.TCPSocket do * timeout - time after request will be deemed missing and error shall be returned. """ - use Membrane.RTSP.Transport import Mockery.Macro @connection_timeout 1000 @response_timeout 5000 - @impl true def init(%URI{} = connection_info, options \\ []) do connection_timeout = options[:connection_timeout] || @connection_timeout @@ -34,7 +32,8 @@ defmodule Membrane.RTSP.Transport.TCPSocket do ) end - @impl true + @spec execute(binary(), :gen_tcp.socket(), Keyword.t()) :: + :ok | {:ok, binary()} | {:error, :closed | :timeout | :inet.posix()} def execute(request, socket, options) do case mockable(:gen_tcp).send(socket, request) do :ok -> if options[:get_response], do: recv(socket, options), else: :ok @@ -42,12 +41,10 @@ defmodule Membrane.RTSP.Transport.TCPSocket do end end - @impl true def handle_info({:tcp_closed, _socket}, state) do {:stop, :socket_closed, state} end - @impl true def close(_state), do: :ok defp recv(socket, options, length \\ 0, acc \\ <<>>) do diff --git a/lib/membrane_rtsp/transport/transport.ex b/lib/membrane_rtsp/transport/transport.ex deleted file mode 100644 index 37c8776..0000000 --- a/lib/membrane_rtsp/transport/transport.ex +++ /dev/null @@ -1,51 +0,0 @@ -defmodule Membrane.RTSP.Transport do - @moduledoc """ - Behaviour describing Transport Layer for Real Time Streaming Protocol - """ - - @doc """ - Callback for initialization of transport layer implementation. - - Upon successful initialization, the callback should return {:ok, state}. - Value of state can be anything, but it is recommended that it contains some information that identifies a transport layer instance. - """ - @callback init(url :: URI.t(), options :: Keyword.t()) :: - {:ok, any()} | {:error, any()} - - @doc """ - Callback for handling any transport-layer specific messages. Session will redirect any unknown messages to this callback. - - It is useful for eg. correctly handling :tcp_close message and similar. - """ - @callback handle_info(msg :: any(), state :: any()) :: - {action :: term(), state :: any()} - | {action :: term(), reply :: any(), state :: any()} - - @doc """ - Callback for executing requests with a given transport layer. - """ - @callback execute(request :: any(), state :: any(), options :: Keyword.t()) :: - :ok | {:ok, reply :: any()} | {:error, reason :: any()} - - @doc """ - Callback used for cleaning up the transport layer when the session is closed. - """ - @callback close(state :: any()) :: :ok - - @optional_callbacks handle_info: 2 - - defmacro __using__(_block) do - quote do - @behaviour Membrane.RTSP.Transport - - @impl Membrane.RTSP.Transport - def handle_info(_msg, _state), do: raise("handle_info/2 has not been implemented") - - defoverridable handle_info: 2 - end - end - - @spec new(module(), binary() | URI.t(), Keyword.t()) :: {:ok, any()} | {:error, any()} - @deprecated "Use Membrane.RTSP.init/3 instead. It is not recommended to manually initiate transport" - def new(module, url, options \\ []), do: module.init(url, options) -end diff --git a/test/membrane_rtsp/session/session_integration_test.exs b/test/membrane_rtsp/session/session_integration_test.exs index 6971ec3..2d152d3 100644 --- a/test/membrane_rtsp/session/session_integration_test.exs +++ b/test/membrane_rtsp/session/session_integration_test.exs @@ -4,19 +4,18 @@ defmodule Membrane.RTSP.IntegrationTest do alias Membrane.RTSP alias Membrane.RTSP.{Request, Response} - alias Membrane.RTSP.Transport.TCPSocket @uri "rtsp://wowzaec2demo.streamlock.net:554/vod/mp4:BigBuckBunny_115k.mov" describe "Session works in combination with" do @tag external: true test "real transport" do - integration_test(@uri, TCPSocket) + integration_test(@uri) end end - defp integration_test(uri, transport, options \\ []) do - {:ok, pid} = RTSP.start_link(uri, transport, options) + defp integration_test(uri, options \\ []) do + {:ok, pid} = RTSP.start_link(uri, options) request = %Request{ method: "DESCRIBE", diff --git a/test/membrane_rtsp/session/session_logic_test.exs b/test/membrane_rtsp/session/session_logic_test.exs index ce2cb70..8a1f305 100644 --- a/test/membrane_rtsp/session/session_logic_test.exs +++ b/test/membrane_rtsp/session/session_logic_test.exs @@ -2,21 +2,22 @@ defmodule Membrane.RTSP.SessionLogicTest do use ExUnit.Case use Bunch import Mockery - import Mockery.Assertions alias Membrane.RTSP alias Membrane.RTSP.Logic.State - alias Membrane.RTSP.Request - alias Membrane.RTSP.Transport.Fake + alias Membrane.RTSP.{Request, TCPSocket} + + @response_header "RTSP/1.0 200 OK\r\n" setup_all do - {:ok, transport} = Fake.init("fake_executor") + uri = "rtsp://localhost:5554/vod/mp4:name.mov" |> URI.parse() + mock(:gen_tcp, :connect, {:ok, nil}) + {:ok, socket} = TCPSocket.init(uri) state = %State{ - transport: transport, - transport_module: Fake, + socket: socket, cseq: 0, - uri: "rtsp://domain.net:554/vod/mp4:name.mov" |> URI.parse(), + uri: uri, session_id: "fake_session" } @@ -31,22 +32,26 @@ defmodule Membrane.RTSP.SessionLogicTest do resolved successfully\ """, %{state: state, request: request} do - mock(Fake, [proxy: 2], fn serialized_request, _options -> + mock(:gen_tcp, [send: 2], fn _socket, serialized_request -> assert String.contains?(serialized_request, "\r\nUser-Agent") + mock_response(serialized_request) end) assert {:reply, {:ok, _response}, next_state} = RTSP.handle_call({:execute, request}, nil, state) assert next_state == %State{state | cseq: state.cseq + 1} - assert_called(Fake, proxy: 2) end test "returns an error if response has different session", %{ state: state } do - resolver = fn _request -> {:error, :timeout} end - state = %State{state | execution_options: [resolver: resolver]} + mock(:gen_tcp, [send: 2], fn _socket, _request -> + {:error, :timeout} + end) + + # resolver = fn _request -> {:error, :timeout} end + # state = %State{state | execution_options: [resolver: resolver]} {:reply, {:error, :timeout}, ^state} = RTSP.handle_call({:execute, %Request{method: "OPTIONS"}}, nil, state) @@ -57,8 +62,9 @@ defmodule Membrane.RTSP.SessionLogicTest do session_id = "arbitrary_string" request = request |> Request.with_header("Session", session_id) - mock(Fake, [proxy: 2], fn serialized_request, _options -> + mock(:gen_tcp, [send: 2], fn _socket, serialized_request -> assert String.contains?(serialized_request, "\r\nSession: " <> session_id <> "\r\n") + mock_response(serialized_request) end) assert {:reply, {:ok, _response}, state} = RTSP.handle_call({:execute, request}, nil, state) @@ -67,16 +73,15 @@ defmodule Membrane.RTSP.SessionLogicTest do assert {:reply, {:ok, _response}, _state} = RTSP.handle_call({:execute, request}, nil, state) - - assert_called(Fake, proxy: 2) end test "add session_id header to request", %{request: request, state: state} do session_id = "arbitrary_string" state = %State{state | session_id: session_id} - mock(Fake, [proxy: 2], fn serialized_request, _options -> + mock(:gen_tcp, [send: 2], fn _socket, serialized_request -> assert String.contains?(serialized_request, "\r\nSession: " <> session_id <> "\r\n") + mock_response(serialized_request) end) assert {:reply, {:ok, _response}, _state} = @@ -90,74 +95,77 @@ defmodule Membrane.RTSP.SessionLogicTest do credentials = "login:password" encoded_credentials = credentials |> Base.encode64() - mock(Fake, [proxy: 2], fn serialized_request, _ref -> + mock(:gen_tcp, [send: 2], fn _socket, serialized_request -> assert String.contains?( serialized_request, "\r\nAuthorization: Basic #{encoded_credentials}\r\n" ) + + mock_response(serialized_request) end) - parsed_uri = URI.parse("rtsp://#{credentials}@domain.net:554/vod/mp4:name.mov") + parsed_uri = URI.parse("rtsp://#{credentials}@localhost:5554/vod/mp4:name.mov") state = %State{state | uri: parsed_uri, auth: :basic} assert {:reply, {:ok, _response}, _state} = RTSP.handle_call({:execute, request}, nil, state) - - assert_called(Fake, proxy: 2) end test "does not apply credentials to request if they were already present", %{state: state} do request = %Request{method: "OPTIONS", headers: [{"Authorization", "Basic data"}]} - mock(Fake, [proxy: 2], fn serialized_request, _ref -> + mock(:gen_tcp, [send: 2], fn _socket, serialized_request -> assert String.contains?( serialized_request, "\r\nAuthorization: Basic data\r\n" ) + + mock_response(serialized_request) end) - parsed_uri = URI.parse("rtsp://login:password@domain.net:554/vod/mp4:name.mov") + parsed_uri = URI.parse("rtsp://login:password@localhost:5554/vod/mp4:name.mov") state = %State{state | uri: parsed_uri} assert {:reply, {:ok, _response}, _state} = RTSP.handle_call({:execute, request}, nil, state) - - assert_called(Fake, proxy: 2) end end test "add digest information in the state", %{state: state, request: request} do - resolver = fn _request -> + mock(:gen_tcp, [send: 2], fn _socket, _request -> {:ok, "RTSP/1.0 200 OK\r\nWWW-Authenticate: Digest realm=\"realm\", nonce=\"nonce\"\r\n\r\n"} - end + end) - state = %State{state | execution_options: [resolver: resolver]} + # state = %State{state | execution_options: [resolver: resolver]} assert {:reply, {:ok, _response}, state} = RTSP.handle_call({:execute, request}, nil, state) assert state.auth == {:digest, %{nonce: "nonce", realm: "realm"}} - - assert_called(Fake, proxy: 2) end test "digest auth", %{state: state, request: request} do credentials = "login:password" - mock(Fake, [proxy: 2], fn serialized_request, _ref -> + mock(:gen_tcp, [send: 2], fn _socket, serialized_request -> assert String.contains?( serialized_request, - "\r\nAuthorization: Digest username=\"login\", realm=\"realm\", nonce=\"nonce\", uri=\"rtsp://domain.net:554/vod/mp4:name.mov\", response=\"13afc9c7a879e7fbd27bab70d472c4fc\"\r\n" + "\r\nAuthorization: Digest username=\"login\", realm=\"realm\", nonce=\"nonce\", uri=\"rtsp://localhost:5554/vod/mp4:name.mov\", response=\"0e19b16c4576c70fe6b4bf462f2a76b6\"\r\n" ) + + mock_response(serialized_request) end) - parsed_uri = URI.parse("rtsp://#{credentials}@domain.net:554/vod/mp4:name.mov") + parsed_uri = URI.parse("rtsp://#{credentials}@localhost:5554/vod/mp4:name.mov") digest_auth_options = {:digest, %{nonce: "nonce", realm: "realm"}} state = %State{state | uri: parsed_uri, auth: digest_auth_options} assert {:reply, {:ok, _response}, _state} = RTSP.handle_call({:execute, request}, nil, state) + end - assert_called(Fake, proxy: 2) + defp mock_response(request) do + [_line, rest] = String.split(request, "\r\n", parts: 2) + {:ok, @response_header <> rest} end end diff --git a/test/membrane_rtsp/workflow_integration_test.exs b/test/membrane_rtsp/workflow_integration_test.exs index cccf83e..c150fe3 100644 --- a/test/membrane_rtsp/workflow_integration_test.exs +++ b/test/membrane_rtsp/workflow_integration_test.exs @@ -3,25 +3,23 @@ defmodule Membrane.RTSP.WorkflowIntegrationTest do alias Membrane.RTSP alias Membrane.RTSP.Response - alias Membrane.RTSP.Transport.{Fake, TCPSocket} describe "RTSP workflow executes" do @tag external: true @tag timeout: 80 * 1000 test "over network" do - workflow( - "rtsp://wowzaec2demo.streamlock.net:554/vod/mp4:BigBuckBunny_115k.mov", - TCPSocket - ) + workflow("rtsp://wowzaec2demo.streamlock.net:554/vod/mp4:BigBuckBunny_115k.mov") end test "without internet" do - workflow("rtsp://domain.net:554/vod/mp4:mobvie.mov", Fake, resolver: &resolver/1) + url = "rtsp://localhost:554/vod/mp4:mobvie.mov" |> URI.parse() + spawn(fn -> mock_server_setup(url) end) + workflow(url) end end - defp workflow(url, transport, options \\ []) do - assert {:ok, session} = RTSP.start_link(url, transport, options) + defp workflow(url, options \\ []) do + assert {:ok, session} = RTSP.start_link(url, options) assert {:ok, %Response{status: 200}} = RTSP.describe(session) assert {:ok, %Response{status: 200}} = @@ -38,9 +36,24 @@ defmodule Membrane.RTSP.WorkflowIntegrationTest do assert {:ok, %Response{status: 200}} = RTSP.teardown(session) end - defp resolver(request) do - {_request, response} = List.keyfind(request_mappings(), request, 0) - response + defp mock_server_setup(%URI{port: port}) do + {:ok, listening_socket} = :gen_tcp.listen(port, active: false, mode: :binary) + {:ok, connected_socket} = :gen_tcp.accept(listening_socket) + mock_server_loop(connected_socket) + end + + defp mock_server_loop(socket) do + case :gen_tcp.recv(socket, 0, :infinity) do + {:ok, data} -> + {_request, response} = + List.keyfind(request_mappings(), data, 0) + + :gen_tcp.send(socket, response) + mock_server_loop(socket) + + {:error, :closed} -> + :ok + end end defp request_mappings do @@ -48,54 +61,52 @@ defmodule Membrane.RTSP.WorkflowIntegrationTest do [ {""" - DESCRIBE rtsp://domain.net:554/vod/mp4:mobvie.mov RTSP/1.0 + DESCRIBE rtsp://localhost:554/vod/mp4:mobvie.mov RTSP/1.0 User-Agent: #{user_agent} CSeq: 0\n """ |> format_rtsp_binary(), - {:ok, - """ - RTSP/1.0 200 OK - CSeq: 0 - Server: Wowza Streaming Engine 4.7.5.01 build21752\r\nCache-Control: no-cache - Expires: Tue, 12 Mar 2019 10:48:38 UTC - Content-Length: 587 - Content-Base: rtsp://domain.net:554/vod/mp4:mobvie.mov/ - Date: Tue, 12 Mar 2019 10:48:38 UTC - Content-Type: application/sdp - Session: 369279037;timeout=60 + """ + RTSP/1.0 200 OK + CSeq: 0 + Server: Wowza Streaming Engine 4.7.5.01 build21752 + Cache-Control: no-cache + Expires: Tue, 12 Mar 2019 10:48:38 UTC + Content-Length: 587 + Content-Base: rtsp://localhost:554/vod/mp4:mobvie.mov/ + Date: Tue, 12 Mar 2019 10:48:38 UTC + Content-Type: application/sdp + Session: 369279037;timeout=60 - v=0 - o=- 369279037 369279037 IN IP4 184.72.239.149\r\ns=BigBuckBunny_115k.mov - c=IN IP4 184.72.239.149 - t=0 0 - a=sdplang:en - a=range:npt=0- 596.48 - a=control:* - m=audio 0 RTP/AVP 96 - a=rtpmap:96 mpeg4-generic/12000/2 - a=fmtp:96 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=1490 - a=control:trackID=1 - m=video 0 RTP/AVP 97 - a=rtpmap:97 H264/90000 - a=fmtp:97 packetization-mode=1;profile-level-id=42C01E;sprop-parameter-sets=Z0LAHtkDxWhAAAADAEAAAAwDxYuS,aMuMsg== - a=cliprect:0,0,160,240 - a=framesize:97 240-160 - a=framerate:24.0 - a=control:trackID=2 - """}}, - {"SETUP rtsp://domain.net:554/vod/mp4:mobvie.mov/trackID=1 RTSP/1.0\r\nUser-Agent: #{user_agent}\r\nCSeq: 1\r\nSession: 369279037\r\nTransport: RTP/AVP;unicast;client_port=57614-57615\r\n\r\n", - {:ok, - "RTSP/1.0 200 OK\r\nCSeq: 1\r\nServer: Wowza Streaming Engine 4.7.5.01 build21752\r\nCache-Control: no-cache\r\nExpires: Tue, 12 Mar 2019 10:48:38 UTC\r\nTransport: RTP/AVP;unicast;client_port=57614-57615;source=184.72.239.149;server_port=16552-16553;ssrc=63D581FB\r\nDate: Tue, 12 Mar 2019 10:48:38 UTC\r\nSession: 369279037;timeout=60\r\n\r\n"}}, - {"SETUP rtsp://domain.net:554/vod/mp4:mobvie.mov/trackID=2 RTSP/1.0\r\nUser-Agent: #{user_agent}\r\nCSeq: 2\r\nSession: 369279037\r\nTransport: RTP/AVP;unicast;client_port=52614-52615\r\n\r\n", - {:ok, - "RTSP/1.0 200 OK\r\nCSeq: 2\r\nServer: Wowza Streaming Engine 4.7.5.01 build21752\r\nCache-Control: no-cache\r\nExpires: Tue, 12 Mar 2019 10:48:38 UTC\r\nTransport: RTP/AVP;unicast;client_port=52614-52615;source=184.72.239.149;server_port=16582-16583;ssrc=644708C0\r\nDate: Tue, 12 Mar 2019 10:48:38 UTC\r\nSession: 369279037;timeout=60\r\n\r\n"}}, - {"PLAY rtsp://domain.net:554/vod/mp4:mobvie.mov RTSP/1.0\r\nUser-Agent: #{user_agent}\r\nCSeq: 3\r\nSession: 369279037\r\n\r\n", - {:ok, - "RTSP/1.0 200 OK\r\nRTP-Info: url=rtsp://domain.net:554/vod/mp4:mobvie.mov/trackID=1;seq=1;rtptime=0,url=rtsp://domain.net:554/vod/mp4:mobvie.mov/trackID=2;seq=1;rtptime=0\r\nCSeq: 3\r\nServer: Wowza Streaming Engine 4.7.5.01 build21752\r\nCache-Control: no-cache\r\nRange: npt=0.0-\r\nSession: 369279037;timeout=60\r\n\r\n"}}, - {"TEARDOWN rtsp://domain.net:554/vod/mp4:mobvie.mov RTSP/1.0\r\nUser-Agent: #{user_agent}\r\nCSeq: 4\r\nSession: 369279037\r\n\r\n", - {:ok, - "RTSP/1.0 200 OK\r\nCSeq: 4\r\nServer: Wowza Streaming Engine 4.7.5.01 build21752\r\nCache-Control: no-cache\r\nSession: 369279037;timeout=60\r\n\r\n"}} + v=0 + o=- 369279037 369279037 IN IP4 184.72.239.149 + s=BigBuckBunny_115k.mov + c=IN IP4 184.72.239.149 + t=0 0 + a=sdplang:en + a=range:npt=0- 596.48 + a=control:* + m=audio 0 RTP/AVP 96 + a=rtpmap:96 mpeg4-generic/12000/2 + a=fmtp:96 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=1490 + a=control:trackID=1 + m=video 0 RTP/AVP 97 + a=rtpmap:97 H264/90000 + a=fmtp:97 packetization-mode=1;profile-level-id=42C01E;sprop-parameter-sets=Z0LAHtkDxWhAAAADAEAAAAwDxYuS,aMuMsg== + a=cliprect:0,0,160,240 + a=framesize:97 240-160 + a=framerate:24.0 + a=control:trackID=2 + """ + |> format_rtsp_binary()}, + {"SETUP rtsp://localhost:554/vod/mp4:mobvie.mov/trackID=1 RTSP/1.0\r\nUser-Agent: #{user_agent}\r\nCSeq: 1\r\nSession: 369279037\r\nTransport: RTP/AVP;unicast;client_port=57614-57615\r\n\r\n", + "RTSP/1.0 200 OK\r\nCSeq: 1\r\nServer: Wowza Streaming Engine 4.7.5.01 build21752\r\nCache-Control: no-cache\r\nExpires: Tue, 12 Mar 2019 10:48:38 UTC\r\nTransport: RTP/AVP;unicast;client_port=57614-57615;source=184.72.239.149;server_port=16552-16553;ssrc=63D581FB\r\nDate: Tue, 12 Mar 2019 10:48:38 UTC\r\nSession: 369279037;timeout=60\r\n\r\n"}, + {"SETUP rtsp://localhost:554/vod/mp4:mobvie.mov/trackID=2 RTSP/1.0\r\nUser-Agent: #{user_agent}\r\nCSeq: 2\r\nSession: 369279037\r\nTransport: RTP/AVP;unicast;client_port=52614-52615\r\n\r\n", + "RTSP/1.0 200 OK\r\nCSeq: 2\r\nServer: Wowza Streaming Engine 4.7.5.01 build21752\r\nCache-Control: no-cache\r\nExpires: Tue, 12 Mar 2019 10:48:38 UTC\r\nTransport: RTP/AVP;unicast;client_port=52614-52615;source=184.72.239.149;server_port=16582-16583;ssrc=644708C0\r\nDate: Tue, 12 Mar 2019 10:48:38 UTC\r\nSession: 369279037;timeout=60\r\n\r\n"}, + {"PLAY rtsp://localhost:554/vod/mp4:mobvie.mov RTSP/1.0\r\nUser-Agent: #{user_agent}\r\nCSeq: 3\r\nSession: 369279037\r\n\r\n", + "RTSP/1.0 200 OK\r\nRTP-Info: url=rtsp://localhost:554/vod/mp4:mobvie.mov/trackID=1;seq=1;rtptime=0,url=rtsp://localhost:554/vod/mp4:mobvie.mov/trackID=2;seq=1;rtptime=0\r\nCSeq: 3\r\nServer: Wowza Streaming Engine 4.7.5.01 build21752\r\nCache-Control: no-cache\r\nRange: npt=0.0-\r\nSession: 369279037;timeout=60\r\n\r\n"}, + {"TEARDOWN rtsp://localhost:554/vod/mp4:mobvie.mov RTSP/1.0\r\nUser-Agent: #{user_agent}\r\nCSeq: 4\r\nSession: 369279037\r\n\r\n", + "RTSP/1.0 200 OK\r\nCSeq: 4\r\nServer: Wowza Streaming Engine 4.7.5.01 build21752\r\nCache-Control: no-cache\r\nSession: 369279037;timeout=60\r\n\r\n"} ] end diff --git a/test/support/fake.ex b/test/support/fake.ex deleted file mode 100644 index 2e35559..0000000 --- a/test/support/fake.ex +++ /dev/null @@ -1,33 +0,0 @@ -defmodule Membrane.RTSP.Transport.Fake do - @moduledoc false - use Membrane.RTSP.Transport - import Mockery.Macro - @response "RTSP/1.0 200 OK\r\n" - - @impl true - def execute(request, ref, options \\ []) do - mockable(__MODULE__).proxy(request, ref) - options = Keyword.merge(ref, options) - resolver = Keyword.get(options, :resolver, &__MODULE__.default_resolver/1) - resolver.(request) - end - - @spec default_resolver(Membrane.RTSP.Request.t()) :: {:ok, binary()} - def default_resolver(request) do - [_line, rest] = String.split(request, "\r\n", parts: 2) - {:ok, @response <> rest} - end - - @impl true - def init(_url, options \\ []) do - {:ok, options} - end - - @impl true - def close(_ref) do - :ok - end - - @spec proxy(Membrane.RTSP.Request.t(), any()) :: nil - def proxy(_request, _ref), do: nil -end