From 154024758dde99bc95a4f3c5d4c2fdbd40948f17 Mon Sep 17 00:00:00 2001 From: Henry Popp Date: Mon, 2 Jul 2018 23:46:22 -0500 Subject: [PATCH 1/3] feat: `:params` option for requests --- CHANGELOG.md | 3 +++ lib/kadabra.ex | 18 +++++++++++++++--- mix.exs | 2 +- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6de241..f3a775b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## v0.5.0 +- Request parameter encoding with new `:params` option + ## v0.4.2 - Fixed `{:closed, pid}` task race condition during connection cleanup - Everything is supervised under `Kadabra.Application` again, instead of diff --git a/lib/kadabra.ex b/lib/kadabra.ex index a296b29..92791d6 100644 --- a/lib/kadabra.ex +++ b/lib/kadabra.ex @@ -195,16 +195,17 @@ defmodule Kadabra do ## Examples iex> {:ok, pid} = Kadabra.open('https://http2.golang.org') - iex> Kadabra.head(pid, "/reqinfo") + iex> Kadabra.get(pid, "/reqinfo", params: [something: 123]) :ok iex> response = receive do ...> {:end_stream, response} -> response ...> end - iex> {response.id, response.status, response.body} - {1, 200, ""} + iex> {response.id, response.status} + {1, 200} """ @spec get(pid, String.t(), Keyword.t()) :: no_return def get(pid, path, opts \\ []) do + path = encode_params(path, opts) request(pid, [{:headers, headers("GET", path)} | opts]) end @@ -224,6 +225,7 @@ defmodule Kadabra do """ @spec head(pid, String.t(), Keyword.t()) :: no_return def head(pid, path, opts \\ []) do + path = encode_params(path, opts) request(pid, [{:headers, headers("HEAD", path)} | opts]) end @@ -243,6 +245,7 @@ defmodule Kadabra do """ @spec post(pid, String.t(), Keyword.t()) :: no_return def post(pid, path, opts \\ []) do + path = encode_params(path, opts) request(pid, [{:headers, headers("POST", path)} | opts]) end @@ -264,6 +267,7 @@ defmodule Kadabra do """ @spec put(pid, String.t(), Keyword.t()) :: no_return def put(pid, path, opts \\ []) do + path = encode_params(path, opts) request(pid, [{:headers, headers("PUT", path)} | opts]) end @@ -283,9 +287,17 @@ defmodule Kadabra do """ @spec delete(pid, String.t(), Keyword.t()) :: no_return def delete(pid, path, opts \\ []) do + path = encode_params(path, opts) request(pid, [{:headers, headers("DELETE", path)} | opts]) end + defp encode_params(path, opts) do + case Keyword.get(opts, :params) do + nil -> path + params -> "#{path}?#{URI.encode_query(params)}" + end + end + defp headers(method, path) do [ {":method", method}, diff --git a/mix.exs b/mix.exs index ef37d98..8300296 100644 --- a/mix.exs +++ b/mix.exs @@ -1,7 +1,7 @@ defmodule Kadabra.Mixfile do use Mix.Project - @version "0.4.2" + @version "0.5.0" def project do [ From f0cafd3f37065662c748ff52872eb8848d735945 Mon Sep 17 00:00:00 2001 From: Henry Popp Date: Sat, 1 Dec 2018 12:44:47 -0600 Subject: [PATCH 2/3] feat: synchronous requests TODO: - Handle push promises correctly - %Kadabra.Error{} structs, etc --- lib/application.ex | 27 +++++ lib/connection/flow_control.ex | 2 +- lib/connection/processor.ex | 8 +- lib/connection_pool.ex | 5 +- lib/kadabra.ex | 141 +++++++++++----------- lib/stream.ex | 13 ++- test/connection_test.exs | 11 +- test/kadabra_test.exs | 207 ++++++++++++++------------------- test/request_test.exs | 6 +- test/stream_test.exs | 6 +- 10 files changed, 224 insertions(+), 202 deletions(-) diff --git a/lib/application.ex b/lib/application.ex index 2ba4ef5..8842390 100644 --- a/lib/application.ex +++ b/lib/application.ex @@ -4,6 +4,8 @@ defmodule Kadabra.Application do use Application import Supervisor.Spec + alias Kadabra.ConnectionPool + def start(_type, _args) do children = [ supervisor(Registry, [:unique, Registry.Kadabra]), @@ -12,4 +14,29 @@ defmodule Kadabra.Application do Supervisor.start_link(children, strategy: :one_for_one, name: :kadabra) end + + def route_request(pid, request) when is_pid(pid) do + ConnectionPool.request(pid, request) + end + + def route_request(uri, request) do + pid = + case open(uri, name: via_tuple(uri)) do + {:ok, pid} -> pid + {:error, {{:already_started, pid}, _}} -> pid + end + + ConnectionPool.request(pid, request) + end + + defp via_tuple(%{scheme: scheme, host: host, port: port}) do + {:via, Registry, {Registry.Kadabra, {scheme, host, port}}} + end + + def open(uri, opts) do + spec_opts = [id: :erlang.make_ref(), restart: :transient] + spec = worker(Kadabra.ConnectionPool, [uri, self(), opts], spec_opts) + + Supervisor.start_child(:kadabra, spec) + end end diff --git a/lib/connection/flow_control.ex b/lib/connection/flow_control.ex index 6b8816c..7891278 100644 --- a/lib/connection/flow_control.ex +++ b/lib/connection/flow_control.ex @@ -75,7 +75,7 @@ defmodule Kadabra.Connection.FlowControl do max_frame_size: max_frame } = flow - stream = Stream.new(config, stream_id, window, max_frame) + stream = Stream.new(config, stream_id, window, max_frame, request) case Stream.start_link(stream) do {:ok, pid} -> diff --git a/lib/connection/processor.ex b/lib/connection/processor.ex index 64c88ca..68c2922 100644 --- a/lib/connection/processor.ex +++ b/lib/connection/processor.ex @@ -81,8 +81,10 @@ defmodule Kadabra.Connection.Processor do end def process(%RstStream{stream_id: stream_id} = frame, state) do - pid = StreamSet.pid_for(state.flow_control.stream_set, stream_id) - Stream.call_recv(pid, frame) + case StreamSet.pid_for(state.flow_control.stream_set, stream_id) do + nil -> nil + pid -> Stream.call_recv(pid, frame) + end {:ok, state} end @@ -150,7 +152,7 @@ defmodule Kadabra.Connection.Processor do max_frame_size: max_frame } = flow_control - stream = Stream.new(config, stream_id, window, max_frame) + stream = Stream.new(config, stream_id, window, max_frame, nil) case Stream.start_link(stream) do {:ok, pid} -> diff --git a/lib/connection_pool.ex b/lib/connection_pool.ex index a67353d..898ccc9 100644 --- a/lib/connection_pool.ex +++ b/lib/connection_pool.ex @@ -21,7 +21,10 @@ defmodule Kadabra.ConnectionPool do opts: opts } - GenServer.start_link(__MODULE__, config) + case opts[:name] do + nil -> GenServer.start_link(__MODULE__, config) + name -> GenServer.start_link(__MODULE__, config, name: name) + end end def request(pid, requests) when is_list(requests) do diff --git a/lib/kadabra.ex b/lib/kadabra.ex index 0466483..8981a07 100644 --- a/lib/kadabra.ex +++ b/lib/kadabra.ex @@ -168,7 +168,9 @@ defmodule Kadabra do ...> {":method", "PUT"}, ...> {":path", path}, ...> ] - iex> Kadabra.request(pid, headers: headers, body: body) + iex> me = self() + iex> resp = & send(me, {:end_stream, &1}) + iex> Kadabra.request(pid, headers: headers, body: body, on_response: resp) iex> response = receive do ...> {:end_stream, %Kadabra.Stream.Response{} = response} -> response ...> after 5_000 -> :timed_out @@ -185,9 +187,30 @@ defmodule Kadabra do ConnectionPool.request(pid, requests) end - def request(pid, opts) when is_list(opts) do - request = Request.new(opts) - ConnectionPool.request(pid, request) + def request(uri, opts) when is_list(opts) do + timeout = Keyword.get(opts, :timeout, 5_000) + sync? = not Keyword.has_key?(opts, :on_response) + + request = + opts + |> Request.new() + |> put_sync_response(sync?) + + case opts[:to] do + nil -> Kadabra.Application.route_request(uri, request) + pid -> Kadabra.Application.route_request(pid, request) + end + + if sync? do + receive do + {:end_stream, response} -> response + {:push_promise, response} -> response + after + timeout -> :timeout + end + else + :ok + end end @doc ~S""" @@ -195,19 +218,16 @@ defmodule Kadabra do ## Examples - iex> {:ok, pid} = Kadabra.open('https://http2.golang.org') - iex> Kadabra.get(pid, "/reqinfo", params: [something: 123]) - :ok - iex> response = receive do - ...> {:end_stream, response} -> response - ...> end - iex> {response.id, response.status} - {1, 200} + iex> response = Kadabra.get("https://http2.golang.org/reqinfo", + ...> params: [something: 123]) + iex> response.status + 200 """ - @spec get(pid, String.t(), Keyword.t()) :: no_return - def get(pid, path, opts \\ []) do - path = encode_params(path, opts) - request(pid, [{:headers, headers("GET", path)} | opts]) + @spec get(String.t(), Keyword.t()) :: no_return + def get(uri, opts \\ []) do + uri = URI.parse(uri) + path = encode_params(uri.path, opts) + request(uri, [{:headers, headers("GET", path)} | opts]) end @doc ~S""" @@ -215,19 +235,15 @@ defmodule Kadabra do ## Examples - iex> {:ok, pid} = Kadabra.open('https://http2.golang.org') - iex> Kadabra.head(pid, "/") - :ok - iex> response = receive do - ...> {:end_stream, response} -> response - ...> end - iex> {response.id, response.status, response.body} - {1, 200, ""} + iex> response = Kadabra.head("https://http2.golang.org") + iex> {response.status, response.body} + {200, ""} """ - @spec head(pid, String.t(), Keyword.t()) :: no_return - def head(pid, path, opts \\ []) do - path = encode_params(path, opts) - request(pid, [{:headers, headers("HEAD", path)} | opts]) + @spec head(String.t(), Keyword.t()) :: no_return + def head(uri, opts \\ []) do + uri = URI.parse(uri) + path = encode_params(uri.path, opts) + request(uri, [{:headers, headers("HEAD", path)} | opts]) end @doc ~S""" @@ -235,19 +251,15 @@ defmodule Kadabra do ## Examples - iex> {:ok, pid} = Kadabra.open('https://http2.golang.org') - iex> Kadabra.post(pid, "/", body: "test=123") - :ok - iex> response = receive do - ...> {:end_stream, response} -> response - ...> end - iex> {response.id, response.status} - {1, 200} + iex> response = Kadabra.post("https://http2.golang.org/", body: "test=123") + iex> response.status + 200 """ - @spec post(pid, String.t(), Keyword.t()) :: no_return - def post(pid, path, opts \\ []) do - path = encode_params(path, opts) - request(pid, [{:headers, headers("POST", path)} | opts]) + @spec post(String.t(), Keyword.t()) :: no_return + def post(uri, opts \\ []) do + uri = URI.parse(uri) + path = encode_params(uri.path, opts) + request(uri, [{:headers, headers("POST", path)} | opts]) end @doc ~S""" @@ -255,21 +267,15 @@ defmodule Kadabra do ## Examples - iex> {:ok, pid} = Kadabra.open('https://http2.golang.org') - iex> Kadabra.put(pid, "/crc32", body: "test") - :ok - iex> stream = receive do - ...> {:end_stream, stream} -> stream - ...> end - iex> stream.status - 200 - iex> stream.body - "bytes=4, CRC32=d87f7e0c" + iex> response = Kadabra.put("https://http2.golang.org/crc32", body: "test") + iex> {response.status, response.body} + {200, "bytes=4, CRC32=d87f7e0c"} """ - @spec put(pid, String.t(), Keyword.t()) :: no_return - def put(pid, path, opts \\ []) do - path = encode_params(path, opts) - request(pid, [{:headers, headers("PUT", path)} | opts]) + @spec put(String.t(), Keyword.t()) :: no_return + def put(uri, opts \\ []) do + uri = URI.parse(uri) + path = encode_params(uri.path, opts) + request(uri, [{:headers, headers("PUT", path)} | opts]) end @doc ~S""" @@ -277,21 +283,26 @@ defmodule Kadabra do ## Examples - iex> {:ok, pid} = Kadabra.open('https://http2.golang.org') - iex> Kadabra.delete(pid, "/") - :ok - iex> stream = receive do - ...> {:end_stream, stream} -> stream - ...> end - iex> stream.status + iex> response = Kadabra.delete("https://http2.golang.org/") + iex> response.status 200 """ - @spec delete(pid, String.t(), Keyword.t()) :: no_return - def delete(pid, path, opts \\ []) do - path = encode_params(path, opts) - request(pid, [{:headers, headers("DELETE", path)} | opts]) + @spec delete(String.t(), Keyword.t()) :: no_return + def delete(uri, opts \\ []) do + uri = URI.parse(uri) + path = encode_params(uri.path, opts) + request(uri, [{:headers, headers("DELETE", path)} | opts]) end + defp put_sync_response(request, true) do + pid = self() + Map.put(request, :on_response, &send(pid, {:end_stream, &1})) + end + + defp put_sync_response(request, false), do: request + + defp encode_params(nil, opts), do: encode_params("/", opts) + defp encode_params(path, opts) do case Keyword.get(opts, :params) do nil -> path diff --git a/lib/stream.ex b/lib/stream.ex index bc5cb92..a567e8f 100644 --- a/lib/stream.ex +++ b/lib/stream.ex @@ -11,7 +11,7 @@ defmodule Kadabra.Stream do flow: nil, uri: nil, headers: [], - on_response: nil + request: nil require Logger @@ -46,7 +46,7 @@ defmodule Kadabra.Stream do # @reserved_local :reserved_local @reserved_remote :reserved_remote - def new(config, stream_id, initial_window_size, max_frame_size) do + def new(config, stream_id, initial_window_size, max_frame_size, request) do flow_opts = [ window: initial_window_size, max_frame_size: max_frame_size @@ -60,7 +60,8 @@ defmodule Kadabra.Stream do encoder: config.encoder, decoder: config.decoder, connection: self(), - flow: Stream.FlowControl.new(flow_opts) + flow: Stream.FlowControl.new(flow_opts), + request: request } end @@ -185,8 +186,10 @@ defmodule Kadabra.Stream do def handle_event(:enter, _old, @closed, stream) do response = Response.new(stream.id, stream.headers, stream.body) - Tasks.run(stream.on_response, response) - send(stream.client, {:end_stream, response}) + + if stream.request do + Tasks.run(stream.request.on_response, response) + end {:stop, {:shutdown, {:finished, stream.id}}} end diff --git a/test/connection_test.exs b/test/connection_test.exs index 30bf975..13bb9b2 100644 --- a/test/connection_test.exs +++ b/test/connection_test.exs @@ -8,8 +8,15 @@ defmodule Kadabra.ConnectionTest do ref = Process.monitor(pid) # Open two streams that send the time every second - Kadabra.get(pid, "/clockstream", on_response: & &1) - Kadabra.get(pid, "/clockstream", on_response: & &1) + Kadabra.get("https://http2.golang.org/clockstream", + on_response: & &1, + to: pid + ) + + Kadabra.get("https://http2.golang.org/clockstream", + on_response: & &1, + to: pid + ) conn_pid = :sys.get_state(pid).connection socket_pid = :sys.get_state(conn_pid).config.socket diff --git a/test/kadabra_test.exs b/test/kadabra_test.exs index 7d6f9e6..3a63dbd 100644 --- a/test/kadabra_test.exs +++ b/test/kadabra_test.exs @@ -8,18 +8,9 @@ defmodule KadabraTest do @golang_uri "https://http2.golang.org" - setup do - pid = - @golang_uri - |> Kadabra.open() - |> elem(1) - - [conn: pid] - end - describe "open/2" do @tag :golang - test "sets port if specified", _context do + test "sets port if specified" do opts = [port: 443] {:ok, pid} = Kadabra.open(@golang_uri, opts) @@ -31,17 +22,23 @@ defmodule KadabraTest do end end + def send_msg do + p = self() + fn response -> send(p, {:end_stream, response}) end + end + describe "request/2" do @tag :golang - test "can take a list of requests", context do + test "can take a list of requests" do headers = [ {":method", "GET"}, {":path", "/"} ] - request = Kadabra.Request.new(headers: headers) + {:ok, pid} = Kadabra.open("https://http2.golang.org") + request = Kadabra.Request.new(headers: headers, on_response: send_msg()) - Kadabra.request(context[:conn], [request, request]) + Kadabra.request(pid, [request, request]) for x <- [1, 3] do assert_receive {:end_stream, %Stream.Response{id: ^x}}, 5_000 @@ -49,23 +46,24 @@ defmodule KadabraTest do end @tag :golang - test "can take a single request", context do + test "can take a single request" do headers = [ {":method", "GET"}, {":path", "/"} ] - request = Kadabra.Request.new(headers: headers) + {:ok, pid} = Kadabra.open("https://http2.golang.org") + request = Kadabra.Request.new(headers: headers, on_response: send_msg()) - Kadabra.request(context[:conn], request) + Kadabra.request(pid, request) assert_receive {:end_stream, %Stream.Response{id: 1}}, 5_000 end end describe "close/1" do - test "sends close message and stops supervisor", context do - pid = context[:conn] + test "sends close message and stops supervisor" do + {:ok, pid} = Kadabra.open("https://http2.golang.org") ref = Process.monitor(pid) Kadabra.close(pid) @@ -76,171 +74,138 @@ defmodule KadabraTest do describe "GET" do @tag :golang - test "can take an options keyword list", context do + test "can take an options keyword list" do headers = [ {":method", "GET"}, {":path", "/"} ] - Kadabra.request(context[:conn], headers: headers, on_response: & &1) + {:ok, pid} = Kadabra.open("https://http2.golang.org") - assert_receive {:end_stream, %Stream.Response{id: 1}}, 5_000 + response = Kadabra.request(pid, headers: headers) + assert response.id == 1 + assert response.body + assert response.headers end @tag :golang - test "https://http2.golang.org/reqinfo", context do - Kadabra.get(context[:conn], "/reqinfo") + test "https://http2.golang.org/reqinfo" do + uri = "https://http2.golang.org/reqinfo" + response = Kadabra.get(uri) - receive do - {:end_stream, response} -> - assert response.id == 1 - assert response.status == 200 - after - 5_000 -> - flunk("No stream response received.") - end + assert response.status == 200 end @tag :golang - test "https://http2.golang.org/reqinfo a lot", context do + test "https://http2.golang.org/reqinfo a lot" do count = 5_000 for _x <- 1..count do - Kadabra.get(context[:conn], "/reqinfo") + pid = self() + + Kadabra.get("https://http2.golang.org/reqinfo", + on_response: fn response -> + send(pid, {:end_stream, response}) + end + ) end is_odd = fn x -> rem(x, 2) == 1 end streams = 1..(2 * count) |> Enum.filter(&is_odd.(&1)) - for x <- streams do - assert_receive {:end_stream, %Stream.Response{id: ^x}}, 30_000 + for _x <- streams do + assert_receive {:end_stream, %Stream.Response{}}, 30_000 end end @tag :golang - test "https://http2.golang.org/redirect", context do - Kadabra.get(context[:conn], "/redirect") + test "https://http2.golang.org/redirect" do + uri = "https://http2.golang.org/redirect" + response = Kadabra.get(uri) expected_body = "Found.\n\n" - expected_status = 302 - - receive do - {:end_stream, response} -> - assert response.id == 1 - assert response.status == expected_status - assert response.body == expected_body - after - 5_000 -> - flunk("No stream response received.") - end - end - @tag :golang - test "https://http2.golang.org/file/gopher.png", context do - Kadabra.get(context[:conn], "/file/gopher.png") - - receive do - {:end_stream, response} -> - assert response.id == 1 - assert response.status == 200 - assert byte_size(response.body) == 17_668 - after - 5_000 -> - flunk("No stream response received.") - end + assert response.status == 302 + assert response.body == expected_body end @tag :golang - test "https://http2.golang.org/file/go.src.tar.gz", context do - Kadabra.get(context[:conn], "/file/go.src.tar.gz") + test "https://http2.golang.org/file/gopher.png" do + response = Kadabra.get("https://http2.golang.org/file/gopher.png") - receive do - {:end_stream, response} -> - assert response.id == 1 - assert response.status == 200 - assert byte_size(response.body) == 10_921_353 - - other -> - flunk("Unexpected response: #{inspect(other)}") - after - 45_000 -> - flunk("No stream response received.") - end + assert response.status == 200 + assert byte_size(response.body) == 17_668 end @tag :golang - test "https://http2.golang.org/serverpush", context do - Kadabra.get(context[:conn], "/serverpush") - - receive do - {:push_promise, response} -> - assert response.id == 2 - refute response.status - assert Stream.Response.get_header(response.headers, ":path") - after - 5_000 -> - flunk("No push promise received.") - end + test "https://http2.golang.org/file/go.src.tar.gz" do + response = + Kadabra.get("https://http2.golang.org/file/go.src.tar.gz", + timeout: 45_000 + ) + + assert response.status == 200 + assert byte_size(response.body) == 10_921_353 end + + # @tag :golang + # test "https://http2.golang.org/serverpush" do + # response = + # Kadabra.get("https://http2.golang.org/serverpush") + # |> IO.inspect() + + # refute response.status + # assert rem(response.id, 2) == 0 + # assert Stream.Response.get_header(response.headers, ":path") + # end end describe "PUT" do @tag :golang - test "https://http2.golong.org/ECHO", context do + test "https://http2.golong.org/ECHO" do payload = String.duplicate("test", 10) - Kadabra.put(context[:conn], "/ECHO", body: payload) + + resp = + Kadabra.put("https://http2.golang.org/ECHO", + body: payload, + timeout: 15_000 + ) expected_body = String.upcase(payload) - receive do - {:end_stream, response} -> - assert response.id == 1 - assert response.status == 200 - assert response.body == expected_body - after - 15_000 -> - flunk("No stream response received.") - end + assert resp.status == 200 + assert resp.body == expected_body end @tag :golang - test "https://http2.golong.org/ECHO with large payload", context do + test "https://http2.golong.org/ECHO with large payload" do payload = String.duplicate("test", 1_000_000) - Kadabra.put(context[:conn], "/ECHO", body: payload) + opts = [body: payload, timeout: 45_000] - expected_body = String.upcase(payload) + case Kadabra.put("https://http2.golang.org/ECHO", opts) do + :timeout -> + flunk("No stream response received.") - receive do - {:end_stream, response} -> - assert response.id == 1 + response -> assert response.status == 200 - assert response.body == expected_body - after - 45_000 -> - flunk("No stream response received.") + assert response.body == String.upcase(payload) end end @tag :golang - test "https://http2.golong.org/crc32", context do + test "https://http2.golong.org/crc32" do payload = "test" - Kadabra.put(context[:conn], "/crc32", body: payload) + + response = Kadabra.put("https://http2.golang.org/crc32", body: payload) expected_body = "bytes=4, CRC32=d87f7e0c" - receive do - {:end_stream, response} -> - assert response.id == 1 - assert response.status == 200 - assert response.body == expected_body - after - 5_000 -> - flunk("No stream response received.") - end + assert response.status == 200 + assert response.body == expected_body end end - test "socket close message closes connection", _context do + test "socket close message closes connection" do pid = @golang_uri |> Kadabra.open() diff --git a/test/request_test.exs b/test/request_test.exs index 3f8ae66..4eded4e 100644 --- a/test/request_test.exs +++ b/test/request_test.exs @@ -8,7 +8,11 @@ defmodule Kadabra.RequestTest do on_resp = fn _resp -> send(pid, :done) end {:ok, pid} = Kadabra.open(uri) - Kadabra.get(pid, "/reqinfo", on_response: on_resp) + + Kadabra.request("https://http2.golang.org/reqinfo", + on_response: on_resp, + to: pid + ) receive do :done -> :ok diff --git a/test/stream_test.exs b/test/stream_test.exs index 8853ef8..55c392c 100644 --- a/test/stream_test.exs +++ b/test/stream_test.exs @@ -6,7 +6,7 @@ defmodule Kadabra.StreamTest do describe "recv/3" do test "keeps state on unknown stream" do - stream = Stream.new(%Config{}, nil, nil, 1) + stream = Stream.new(%Config{}, nil, nil, 1, nil) # Individual streams shouldn't get pings ping = Frame.Ping.new() @@ -14,7 +14,7 @@ defmodule Kadabra.StreamTest do end test "closes stream on RST_STREAM" do - stream = Stream.new(%Config{}, nil, nil, 1) + stream = Stream.new(%Config{}, nil, nil, 1, nil) rst = Frame.RstStream.new(1) reply = [{:reply, self(), :ok}] @@ -24,7 +24,7 @@ defmodule Kadabra.StreamTest do end test "closes stream on DATA with END_STREAM in hc_local state" do - stream = Stream.new(%Config{}, nil, nil, 1) + stream = Stream.new(%Config{}, nil, nil, 1, nil) data = %Frame.Data{stream_id: 1, data: "test", end_stream: true} assert {:next_state, :closed, _stream} = From 37c8eb8c3d2e7c0195ae938a258c592c8d335b35 Mon Sep 17 00:00:00 2001 From: Henry Popp Date: Sat, 1 Dec 2018 12:54:05 -0600 Subject: [PATCH 3/3] refactor: Kadabra.Error -> Kadabra.Connection.Error --- lib/connection/egress.ex | 3 ++- lib/{ => connection}/error.ex | 20 ++++++++++---------- lib/connection/processor.ex | 3 +-- lib/connection/settings.ex | 10 +++++----- lib/frame/goaway.ex | 3 ++- lib/frame/rst_stream.ex | 3 ++- test/connection/error_test.exs | 4 ++++ test/error_test.exs | 4 ---- 8 files changed, 26 insertions(+), 24 deletions(-) rename lib/{ => connection}/error.ex (86%) create mode 100644 test/connection/error_test.exs delete mode 100644 test/error_test.exs diff --git a/lib/connection/egress.ex b/lib/connection/egress.ex index 770188e..f745a3d 100644 --- a/lib/connection/egress.ex +++ b/lib/connection/egress.ex @@ -1,7 +1,8 @@ defmodule Kadabra.Connection.Egress do @moduledoc false - alias Kadabra.{Encodable, Error, Frame, Socket} + alias Kadabra.{Encodable, Frame, Socket} + alias Kadabra.Connection.Error alias Kadabra.Frame.{ Goaway, diff --git a/lib/error.ex b/lib/connection/error.ex similarity index 86% rename from lib/error.ex rename to lib/connection/error.ex index 93e2169..83fee37 100644 --- a/lib/error.ex +++ b/lib/connection/error.ex @@ -1,4 +1,4 @@ -defmodule Kadabra.Error do +defmodule Kadabra.Connection.Error do @moduledoc false @type error :: @@ -26,7 +26,7 @@ defmodule Kadabra.Error do ## Examples - iex> Kadabra.Error.no_error + iex> Kadabra.Connection.Error.no_error <<0, 0, 0, 0>> """ @spec no_error :: <<_::32>> @@ -40,7 +40,7 @@ defmodule Kadabra.Error do ## Examples - iex> Kadabra.Error.protocol_error + iex> Kadabra.Connection.Error.protocol_error <<0, 0, 0, 1>> """ @spec protocol_error :: <<_::32>> @@ -53,7 +53,7 @@ defmodule Kadabra.Error do ## Examples - iex> Kadabra.Error.flow_control_error + iex> Kadabra.Connection.Error.flow_control_error <<0, 0, 0, 3>> """ @spec flow_control_error :: <<_::32>> @@ -64,7 +64,7 @@ defmodule Kadabra.Error do ## Examples - iex> Kadabra.Error.frame_size_error + iex> Kadabra.Connection.Error.frame_size_error <<0, 0, 0, 6>> """ @spec frame_size_error :: <<_::32>> @@ -75,7 +75,7 @@ defmodule Kadabra.Error do ## Examples - iex> Kadabra.Error.compression_error + iex> Kadabra.Connection.Error.compression_error <<0, 0, 0, 9>> """ @spec compression_error :: <<_::32>> @@ -86,9 +86,9 @@ defmodule Kadabra.Error do ## Examples - iex> Kadabra.Error.parse(0x1) + iex> Kadabra.Connection.Error.parse(0x1) :PROTOCOL_ERROR - iex> Kadabra.Error.parse(0xfff) + iex> Kadabra.Connection.Error.parse(0xfff) 0xfff """ @spec parse(integer) :: error | integer @@ -113,9 +113,9 @@ defmodule Kadabra.Error do ## Examples - iex> Kadabra.Error.code(:PROTOCOL_ERROR) + iex> Kadabra.Connection.Error.code(:PROTOCOL_ERROR) 0x1 - iex> Kadabra.Error.code(:NOT_AN_ERROR) + iex> Kadabra.Connection.Error.code(:NOT_AN_ERROR) :NOT_AN_ERROR """ @spec code(error) :: integer diff --git a/lib/connection/processor.ex b/lib/connection/processor.ex index 68c2922..b086ede 100644 --- a/lib/connection/processor.ex +++ b/lib/connection/processor.ex @@ -5,14 +5,13 @@ defmodule Kadabra.Connection.Processor do alias Kadabra.{ Connection, - Error, Frame, Hpack, Stream, StreamSet } - alias Kadabra.Connection.{Egress, FlowControl} + alias Kadabra.Connection.{Egress, Error, FlowControl} alias Kadabra.Frame.{ Continuation, diff --git a/lib/connection/settings.ex b/lib/connection/settings.ex index b0c7e42..bca96a0 100644 --- a/lib/connection/settings.ex +++ b/lib/connection/settings.ex @@ -12,7 +12,7 @@ defmodule Kadabra.Connection.Settings do max_frame_size: @default_max_frame_size, max_header_list_size: nil - alias Kadabra.Error + alias Kadabra.Connection.Error @type t :: %__MODULE__{ header_table_size: non_neg_integer, @@ -54,23 +54,23 @@ defmodule Kadabra.Connection.Settings do iex> Kadabra.Connection.Settings.put(s, enable_push, 1) {:ok, %Kadabra.Connection.Settings{enable_push: true}} iex> Kadabra.Connection.Settings.put(s, enable_push, :bad) - {:error, Kadabra.Error.protocol_error, s} + {:error, Kadabra.Connection.Error.protocol_error, s} iex> s = %Kadabra.Connection.Settings{} iex> init_window_size = 0x4 iex> Kadabra.Connection.Settings.put(s, init_window_size, 70_000) {:ok, %Kadabra.Connection.Settings{initial_window_size: 70_000}} iex> Kadabra.Connection.Settings.put(s, init_window_size, 5_000_000_000) - {:error, Kadabra.Error.flow_control_error, s} + {:error, Kadabra.Connection.Error.flow_control_error, s} iex> s = %Kadabra.Connection.Settings{} iex> max_frame_size = 0x5 iex> Kadabra.Connection.Settings.put(s, max_frame_size, 20_000) {:ok, %Kadabra.Connection.Settings{max_frame_size: 20_000}} iex> Kadabra.Connection.Settings.put(s, max_frame_size, 20_000_000) - {:error, Kadabra.Error.protocol_error, s} + {:error, Kadabra.Connection.Error.protocol_error, s} iex> Kadabra.Connection.Settings.put(s, max_frame_size, 2_000) - {:error, Kadabra.Error.protocol_error, s} + {:error, Kadabra.Connection.Error.protocol_error, s} """ @spec put(t, non_neg_integer, term) :: {:ok, t} | {:error, binary, t} def put(settings, @table_header_size, value) do diff --git a/lib/frame/goaway.ex b/lib/frame/goaway.ex index e94afbd..5489b60 100644 --- a/lib/frame/goaway.ex +++ b/lib/frame/goaway.ex @@ -3,7 +3,8 @@ defmodule Kadabra.Frame.Goaway do defstruct last_stream_id: nil, error_code: nil, debug_data: <<>> - alias Kadabra.{Error, Frame} + alias Kadabra.Connection.Error + alias Kadabra.Frame @type t :: %__MODULE__{ debug_data: bitstring, diff --git a/lib/frame/rst_stream.ex b/lib/frame/rst_stream.ex index cf9abe9..2ef597e 100644 --- a/lib/frame/rst_stream.ex +++ b/lib/frame/rst_stream.ex @@ -3,7 +3,8 @@ defmodule Kadabra.Frame.RstStream do defstruct [:stream_id, :error_code] - alias Kadabra.{Error, Frame} + alias Kadabra.Connection.Error + alias Kadabra.Frame @type t :: %__MODULE__{ error_code: <<_::32>>, diff --git a/test/connection/error_test.exs b/test/connection/error_test.exs new file mode 100644 index 0000000..49568c2 --- /dev/null +++ b/test/connection/error_test.exs @@ -0,0 +1,4 @@ +defmodule Kadabra.Connection.ErrorTest do + use ExUnit.Case + doctest Kadabra.Connection.Error +end diff --git a/test/error_test.exs b/test/error_test.exs deleted file mode 100644 index 2ec6b20..0000000 --- a/test/error_test.exs +++ /dev/null @@ -1,4 +0,0 @@ -defmodule Kadabra.ErrorTest do - use ExUnit.Case - doctest Kadabra.Error -end