Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 1 addition & 14 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
CACHEGRIND=qcachegrind
REBAR3=$(shell which rebar3)
ifeq ($(REBAR3),)
REBAR3=./bin/rebar3
Expand All @@ -22,22 +21,10 @@ eunit:
@echo "Running rebar3 eunit..."
@$(REBAR3) do eunit -cv, cover -v

profile:
@echo "Profiling..."
@$(REBAR3) as test compile
@erl +K true \
-noshell \
-pa _build/test/lib/*/ebin \
-pa _build/test/lib/*/test \
-eval 'buoy_profile:fprofx()' \
-eval 'init:stop()'
@_build/test/lib/fprofx/erlgrindx -p fprofx.analysis
@$(CACHEGRIND) fprofx.cgrind

test: xref eunit dialyzer

xref:
@echo "Running rebar3 xref..."
@$(REBAR3) xref

.PHONY: clean compile dialyzer eunit profile test xref
.PHONY: clean compile dialyzer eunit test xref
11 changes: 2 additions & 9 deletions rebar.config
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{deps, [
{foil, "0.1.4"},
{shackle, "0.7.1"},
{foil, "0.1.6"},
{shackle, "0.7.3"},
{telemetry, "1.4.2"}
]}.

Expand Down Expand Up @@ -35,13 +35,6 @@
warn_unused_import,
warn_unused_vars
]}
]},
{test, [
{deps, [
{cowboy, "2.12.0"},
{fprofx,
{git, "https://github.com/lpgauth/fprofx.git", {branch, "otp_19"}}}
]}
]}
]}.

Expand Down
18 changes: 9 additions & 9 deletions rebar.lock
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
{"1.2.0",
[{<<"foil">>,{pkg,<<"foil">>,<<"0.1.4">>},0},
{<<"knot">>,{pkg,<<"knot">>,<<"0.1.0">>},1},
[{<<"foil">>,{pkg,<<"foil">>,<<"0.1.6">>},0},
{<<"knot">>,{pkg,<<"knot">>,<<"0.1.2">>},1},
{<<"metal">>,{pkg,<<"metal">>,<<"0.1.2">>},1},
{<<"shackle">>,{pkg,<<"shackle">>,<<"0.7.1">>},0},
{<<"shackle">>,{pkg,<<"shackle">>,<<"0.7.3">>},0},
{<<"telemetry">>,{pkg,<<"telemetry">>,<<"1.4.2">>},0}]}.
[
{pkg_hash,[
{<<"foil">>, <<"1B786A2CC3E81496F98F799DF23AA24065253A94032AB79E5D60AED5423850AE">>},
{<<"knot">>, <<"62CACC2CD9E2D50373EAFAC7C26A4286EF22C4590CBBF42FC81B4B0F497CC87D">>},
{<<"foil">>, <<"31A9048E8EC6E8AC951ED3C4E4EB8F549465920C70F19E92CD9FC8A6867E7253">>},
{<<"knot">>, <<"3B6C07CD24831D62752D879F031BCEDCFADB343738679EB1774A029D0A8B7D48">>},
{<<"metal">>, <<"7501F14B075380F829498C4CE605643D6C7F0C55F60EBFCFBF694C33A558DF98">>},
{<<"shackle">>, <<"0516B5890BFAC7153D10FABD8D73AB735685E84B6C22D0A8306567142741E63A">>},
{<<"shackle">>, <<"DEDE0777BC297B212DE3DBE4377B391DA991FC011B4D5201960A5C4F11E83B2C">>},
{<<"telemetry">>, <<"A0CB522801DFFB1C49FE6E30561BADFFC7B6D0E180DB1300DF759FAA22062855">>}]},
{pkg_hash_ext,[
{<<"foil">>, <<"4B0C51432A13740E5D74289C19A584A02B1BA02558AA9002665900EC61260E1B">>},
{<<"knot">>, <<"5659015314767F69BD95D88B0AEDF6A65DCBEF3E9AFE49172D0429B18DB89584">>},
{<<"foil">>, <<"8D34B12D712FFB30AD9E192F57885ABB1A61510CD3D9F6AA44470510A50B979E">>},
{<<"knot">>, <<"42CB91A8024A8857D70A61B33E83D31370D5EB48681B366AE1203CB7C7CCFB38">>},
{<<"metal">>, <<"CAC84E5CF2875B56E68874F3F0B3D598AF3EC30397EC2151D5C81C408961E6E4">>},
{<<"shackle">>, <<"A9E14E3E253369F133226163C22854A20A5BC22DDCE5C61C87A51E587E5E67C8">>},
{<<"shackle">>, <<"056944FEEB85ED0F3E1B7505FBC7174CDE0788993A19E9ADA85137A23CA56349">>},
{<<"telemetry">>, <<"928F6495066506077862C0D1646609EED891A4326BEE3126BA54B60AF61FEBB1">>}]}
].
151 changes: 113 additions & 38 deletions test/buoy_http_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -5,49 +5,124 @@
stop/0
]).

-export([
init/2
]).
-define(PORT, 8080).

%% public
start() ->
application:ensure_all_started(cowboy),
Dispatch = cowboy_router:compile([{'_', [
{"/:test", ?MODULE, []}]}]),
{ok, _} = cowboy:start_clear(?MODULE, [{port, 8080}], #{
env => #{dispatch => Dispatch},
max_keepalive => infinity,
request_timeout => infinity
}).
Self = self(),
Pid = spawn(fun () -> init(Self) end),
receive
{Pid, started} ->
{ok, Pid}
after 5000 ->
{error, timeout}
end.

stop() ->
cowboy:stop_listener(?MODULE).

%% cowboy callbacks
init(Req, State) ->
case cowboy_req:binding(test, Req) of
<<"1">> ->
reply(200, <<"Hello world!">>, Req, State);
<<"2">> ->
Body = [<<"Hello world!">> || _ <- lists:seq(1, 1000)],
reply(200, Body, Req, State);
<<"3">> ->
{ok, Body, Req2} = cowboy_req:read_body(Req),
reply(200, Body, Req2, State);
<<"4">> ->
Req2 = cowboy_req:stream_reply(200, Req),
ok = cowboy_req:stream_body("Hello", nofin, Req2),
ok = cowboy_req:stream_body(" world!", fin, Req2),
{ok, Req2, State};
<<"5">> ->
Verb = cowboy_req:method(Req),
reply(200, Verb, Req, State)
case whereis(?MODULE) of
undefined ->
ok;
Pid ->
exit(Pid, kill),
ok
end.

%% private
reply(StatusCode, Body, Req, State) ->
Req2 = cowboy_req:reply(StatusCode, #{
<<"Content-Type">> => <<"text/plain">>,
<<"Connection">> => <<"Keep-Alive">>
}, Body, Req),
{ok, Req2, State}.
init(Parent) ->
register(?MODULE, self()),
{ok, LSocket} = gen_tcp:listen(?PORT, [
binary,
{active, false},
{backlog, 128},
{packet, http_bin},
{reuseaddr, true}
]),
Parent ! {self(), started},
accept(LSocket).

accept(LSocket) ->
{ok, Socket} = gen_tcp:accept(LSocket),
Pid = spawn_link(fun () ->
receive go -> connection(Socket) end
end),
ok = gen_tcp:controlling_process(Socket, Pid),
Pid ! go,
accept(LSocket).

connection(Socket) ->
case gen_tcp:recv(Socket, 0) of
{ok, {http_request, Method, {abs_path, Path}, _Version}} ->
ContentLength = headers(Socket, 0),
Body = body(Socket, ContentLength),
respond(Socket, Method, Path, Body),
connection(Socket);
{ok, _} ->
gen_tcp:close(Socket);
{error, _} ->
gen_tcp:close(Socket)
end.

headers(Socket, ContentLength) ->
case gen_tcp:recv(Socket, 0) of
{ok, {http_header, _, 'Content-Length', _, Value}} ->
headers(Socket, binary_to_integer(Value));
{ok, {http_header, _, _, _, _}} ->
headers(Socket, ContentLength);
{ok, http_eoh} ->
ContentLength
end.

body(_Socket, 0) ->
<<>>;
body(Socket, ContentLength) ->
ok = inet:setopts(Socket, [{packet, raw}]),
{ok, Body} = gen_tcp:recv(Socket, ContentLength),
ok = inet:setopts(Socket, [{packet, http_bin}]),
Body.

respond(Socket, Method, <<"/1">>, _Body) ->
reply(Socket, Method, <<"Hello world!">>);
respond(Socket, Method, <<"/2">>, _Body) ->
reply(Socket, Method, binary:copy(<<"Hello world!">>, 1000));
respond(Socket, Method, <<"/3">>, Body) ->
reply(Socket, Method, Body);
respond(Socket, Method, <<"/4">>, _Body) ->
chunked_reply(Socket, Method, [<<"Hello">>, <<" world!">>]);
respond(Socket, Method, <<"/5">>, _Body) ->
reply(Socket, Method, method(Method)).

method(Method) when is_atom(Method) ->
atom_to_binary(Method, utf8);
method(Method) when is_binary(Method) ->
Method.

reply(Socket, Method, Body) ->
Headers = [
<<"HTTP/1.1 200 OK\r\n">>,
<<"Connection: Keep-Alive\r\n">>,
<<"Content-Type: text/plain\r\n">>,
<<"Content-Length: ">>, integer_to_binary(iolist_size(Body)),
<<"\r\n\r\n">>
],
case Method of
'HEAD' ->
ok = gen_tcp:send(Socket, Headers);
_ ->
ok = gen_tcp:send(Socket, [Headers, Body])
end.

chunked_reply(Socket, Method, Chunks) ->
Headers = [
<<"HTTP/1.1 200 OK\r\n">>,
<<"Connection: Keep-Alive\r\n">>,
<<"Content-Type: text/plain\r\n">>,
<<"Transfer-Encoding: chunked\r\n\r\n">>
],
case Method of
'HEAD' ->
ok = gen_tcp:send(Socket, Headers);
_ ->
Encoded = [[integer_to_binary(byte_size(Chunk), 16), <<"\r\n">>,
Chunk, <<"\r\n">>] || Chunk <- Chunks],
ok = gen_tcp:send(Socket, [Headers, Encoded, <<"0\r\n\r\n">>])
end.
55 changes: 0 additions & 55 deletions test/buoy_profile.erl

This file was deleted.