aboutsummaryrefslogblamecommitdiffstats
path: root/test/ws_SUITE.erl
blob: 2310b31b72c5e653b3b547a559c674a58be39042 (plain) (tree)













































































































































                                                                                                             
                                                              
































                                                                 
%% Copyright (c) 2015, Loïc Hoguin <[email protected]>
%%
%% Permission to use, copy, modify, and/or distribute this software for any
%% purpose with or without fee is hereby granted, provided that the above
%% copyright notice and this permission notice appear in all copies.
%%
%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

-module(ws_SUITE).
-compile(export_all).

-import(ct_helper, [config/2]).

%% ct.

all() ->
	[{group, autobahn}].

groups() ->
	[{autobahn, [], [autobahn_fuzzingserver]}].

init_per_group(autobahn, Config) ->
	%% Some systems have it named pip2.
	Out = os:cmd("pip show autobahntestsuite ; pip2 show autobahntestsuite"),
	case string:str(Out, "autobahntestsuite") of
		0 ->
			ct:print("Skipping the autobahn group because the "
				"Autobahn Test Suite is not installed.~nTo install it, "
				"please follow the instructions on this page:~n~n    "
				"http://autobahn.ws/testsuite/installation.html"),
			{skip, "Autobahn Test Suite not installed."};
		_ ->
			Config
	end.

end_per_group(_, _) ->
	oK.

%% Tests.

autobahn_fuzzingserver(Config) ->
	Self = self(),
	spawn_link(fun() -> start_port(Config, Self) end),
	receive autobahn_ready -> ok end,
	N = get_case_count(),
	run_cases(0, N),
	Report = config(priv_dir, Config) ++ "reports/clients/index.html",
	ct:log("<h2><a href=\"~s\">Full report</a></h2>~n", [Report]),
	ct:print("Autobahn Test Suite report: file://~s~n", [Report]),
	log_output(),
	terminate(),
	{ok, HTML} = file:read_file(Report),
	case length(binary:matches(HTML, <<"case_failed">>)) > 2 of
		true -> error(failed);
		false -> ok
	end.

start_port(Config, Pid) ->
	Port = open_port({spawn, "wstest -m fuzzingserver -s " ++ config(data_dir, Config) ++ "server.json"},
		[{line, 10000}, {cd, config(priv_dir, Config)}, binary]),
	receive_preamble(Port, Pid),
	receive_infinity(Port).

receive_preamble(Port, Pid) ->
	receive
		{Port, {data, {eol, Line = <<"Ok, will run", _/bits>>}}} ->
			Pid ! autobahn_ready,
			io:format(user, "~s~n", [Line]);
		{Port, {data, {eol, Line}}} ->
			io:format(user, "~s~n", [Line]),
			receive_preamble(Port, Pid)
	after 5000 ->
		terminate(),
		error(timeout)
	end.

receive_infinity(Port) ->
	receive
		{Port, {data, {eol, <<"Updating reports", _/bits>>}}} ->
			receive_infinity(Port);
		{Port, {data, {eol, Line}}} ->
			io:format(user, "~s~n", [Line]),
			receive_infinity(Port)
	end.

get_case_count() ->
	{Pid, Ref} = connect("/getCaseCount"),
	receive
		{gun_ws, Pid, {text, N}} ->
			close(Pid, Ref),
			binary_to_integer(N);
		Msg ->
			ct:print("Unexpected message ~p", [Msg]),
			terminate(),
			error(failed)
	end.

run_cases(Total, Total) ->
	ok;
run_cases(N, Total) ->
	{Pid, Ref} = connect(["/runCase?case=", integer_to_binary(N + 1), "&agent=Gun"]),
	loop(Pid, Ref),
	update_reports(),
	run_cases(N + 1, Total).

loop(Pid, Ref) ->
	receive
		{gun_ws, Pid, close} ->
			gun:ws_send(Pid, close),
			loop(Pid, Ref);
		{gun_ws, Pid, {close, Code, _}} ->
			gun:ws_send(Pid, {close, Code, <<>>}),
			loop(Pid, Ref);
		{gun_ws, Pid, Frame} ->
			gun:ws_send(Pid, Frame),
			loop(Pid, Ref);
		{'DOWN', Ref, process, Pid, normal} ->
			close(Pid, Ref);
		Msg ->
			ct:print("Unexpected message ~p", [Msg]),
			close(Pid, Ref)
	end.

update_reports() ->
	{Pid, Ref} = connect("/updateReports?agent=Gun"),
	receive
		{gun_ws, Pid, close} ->
			close(Pid, Ref)
	after 5000 ->
		error(failed)
	end.

log_output() ->
	ok.

connect(Path) ->
	{ok, Pid} = gun:open("127.0.0.1", 33080, #{retry=>0}),
	Ref = monitor(process, Pid),
	gun:ws_upgrade(Pid, Path, [], #{compress => true}),
	receive
		{gun_ws_upgrade, Pid, ok} ->
			ok;
		Msg ->
			ct:print("Unexpected message ~p", [Msg]),
			terminate(),
			error(failed)
	end,
	{Pid, Ref}.

close(Pid, Ref) ->
	demonitor(Ref),
	gun:close(Pid),
	flush(Pid).

flush(Pid) ->
	receive
		{gun_ws, Pid, _} ->
			flush(Pid);
		{gun_ws_upgrade, Pid, _} ->
			flush(Pid);
		{'DOWN', _, process, Pid, _} ->
			flush(Pid)
	after 0 ->
		ok
	end.

terminate() ->
	Res = os:cmd("killall wstest"),
	io:format(user, "~s", [Res]),
	ok.