diff options
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | erlang.mk | 72 | ||||
-rw-r--r-- | test/ranch_concuerror.erl | 80 | ||||
-rw-r--r-- | test/ranch_erlang_transport.erl | 174 |
4 files changed, 329 insertions, 2 deletions
@@ -20,6 +20,11 @@ TEST_DEPS = $(if $(CI_ERLANG_MK),ci.erlang.mk) ct_helper stampede dep_ct_helper = git https://github.com/ninenines/ct_helper master dep_stampede = git https://github.com/juhlig/stampede 0.5.0 +# Concuerror tests. + +# CONCUERROR_OPTS = -v 7 -k +CONCUERROR_TESTS = ranch_concuerror:start_stop ranch_concuerror:info + # CI configuration. dep_ci.erlang.mk = git https://github.com/ninenines/ci.erlang.mk master @@ -17,7 +17,7 @@ ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) export ERLANG_MK_FILENAME -ERLANG_MK_VERSION = 89f2eca +ERLANG_MK_VERSION = 2020.03.05-18-g4ad50cd ERLANG_MK_WITHOUT = # Make 3.81 and 3.82 are deprecated. @@ -4834,7 +4834,7 @@ define dep_autopatch_rebar.erl Write("\npre-app::\n\t@$$\(MAKE) --no-print-directory -f c_src/Makefile.erlang.mk\n"), PortSpecWrite(io_lib:format("ERL_CFLAGS ?= -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), - PortSpecWrite(io_lib:format("ERL_LDFLAGS ?= -L \\"~s\\" -lerl_interface -lei\n", + PortSpecWrite(io_lib:format("ERL_LDFLAGS ?= -L \\"~s\\" -lei\n", [code:lib_dir(erl_interface, lib)])), [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], FilterEnv = fun(Env) -> @@ -6541,6 +6541,74 @@ help:: endif +# Copyright (c) 2020, Loïc Hoguin <[email protected]> +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifdef CONCUERROR_TESTS + +.PHONY: concuerror distclean-concuerror + +# Configuration + +CONCUERROR_LOGS_DIR ?= $(CURDIR)/logs +CONCUERROR_OPTS ?= + +# Core targets. + +check:: concuerror + +ifndef KEEP_LOGS +distclean:: distclean-concuerror +endif + +# Plugin-specific targets. + +$(ERLANG_MK_TMP)/Concuerror/bin/concuerror: | $(ERLANG_MK_TMP) + $(verbose) git clone https://github.com/parapluu/Concuerror $(ERLANG_MK_TMP)/Concuerror + $(verbose) make -C $(ERLANG_MK_TMP)/Concuerror + +$(CONCUERROR_LOGS_DIR): + $(verbose) mkdir -p $(CONCUERROR_LOGS_DIR) + +define concuerror_html_report +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<title>Concuerror HTML report</title> +</head> +<body> +<h1>Concuerror HTML report</h1> +<p>Generated on $(concuerror_date)</p> +<ul> +$(foreach t,$(concuerror_targets),<li><a href="$(t).txt">$(t)</a></li>) +</ul> +</body> +</html> +endef + +concuerror: $(addprefix concuerror-,$(subst :,-,$(CONCUERROR_TESTS))) + $(eval concuerror_date := $(shell date)) + $(eval concuerror_targets := $^) + $(verbose) $(call core_render,concuerror_html_report,$(CONCUERROR_LOGS_DIR)/concuerror.html) + +define concuerror_target +.PHONY: concuerror-$1-$2 + +concuerror-$1-$2: test-build | $(ERLANG_MK_TMP)/Concuerror/bin/concuerror $(CONCUERROR_LOGS_DIR) + $(ERLANG_MK_TMP)/Concuerror/bin/concuerror \ + --pa $(CURDIR)/ebin --pa $(TEST_DIR) \ + -o $(CONCUERROR_LOGS_DIR)/concuerror-$1-$2.txt \ + $$(CONCUERROR_OPTS) -m $1 -t $2 +endef + +$(foreach test,$(CONCUERROR_TESTS),$(eval $(call concuerror_target,$(firstword $(subst :, ,$(test))),$(lastword $(subst :, ,$(test)))))) + +distclean-concuerror: + $(gen_verbose) rm -rf $(CONCUERROR_LOGS_DIR) + +endif + # Copyright (c) 2013-2016, Loïc Hoguin <[email protected]> # This file is part of erlang.mk and subject to the terms of the ISC License. diff --git a/test/ranch_concuerror.erl b/test/ranch_concuerror.erl new file mode 100644 index 0000000..0347fce --- /dev/null +++ b/test/ranch_concuerror.erl @@ -0,0 +1,80 @@ +%% Copyright (c) 2020, 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(ranch_concuerror). +-compile(export_all). +-compile(nowarn_export_all). + +-concuerror_options([ + {after_timeout, 5000}, + {treat_as_normal, [ + killed, %% Acceptors are killed on shutdown. + shutdown %% This is a normal exit reason in OTP. + ]} +]). + +%% Convenience functions. + +do_start() -> + {ok, SupPid} = ranch_app:start(temporary, []), + SupPid. + +do_stop(SupPid) -> + exit(SupPid, shutdown), + %% We make sure that SupPid terminated before the test ends, + %% because otherwise the shutdown will not be ordered and + %% can produce error exit reasons. + receive after infinity -> ok end. + +%% Tests. + +start_stop() -> + %% Start a listener then stop it. + SupPid = do_start(), + {ok, _} = ranch:start_listener(?FUNCTION_NAME, + ranch_erlang_transport, #{ + num_acceptors => 1 + }, + echo_protocol, []), + ok = ranch:stop_listener(?FUNCTION_NAME), + do_stop(SupPid). + +%% @todo This takes a huge amount of time. +%start_stop_twice() -> +% %% Start a listener then stop it. Then start and stop it again. +% SupPid = do_start(), +% {ok, _} = ranch:start_listener(?FUNCTION_NAME, +% ranch_erlang_transport, #{ +% num_acceptors => 1 +% }, +% echo_protocol, []), +% ok = ranch:stop_listener(?FUNCTION_NAME), +% {ok, _} = ranch:start_listener(?FUNCTION_NAME, +% ranch_erlang_transport, #{ +% num_acceptors => 1 +% }, +% echo_protocol, []), +% ok = ranch:stop_listener(?FUNCTION_NAME), +% do_stop(SupPid). + +info() -> + %% Ensure we can call ranch:info/1 after starting a listener. + SupPid = do_start(), + {ok, _} = ranch:start_listener(?FUNCTION_NAME, + ranch_erlang_transport, #{ + num_acceptors => 1 + }, + echo_protocol, []), + #{} = ranch:info(?FUNCTION_NAME), + do_stop(SupPid). diff --git a/test/ranch_erlang_transport.erl b/test/ranch_erlang_transport.erl new file mode 100644 index 0000000..914d91a --- /dev/null +++ b/test/ranch_erlang_transport.erl @@ -0,0 +1,174 @@ +%% Copyright (c) 2020, 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(ranch_erlang_transport). +-behaviour(ranch_transport). + +-export([name/0]). +-export([secure/0]). +-export([messages/0]). +-export([listen/1]). +-export([accept/2]). +-export([handshake/2]). +-export([handshake/3]). +-export([handshake_continue/2]). +-export([handshake_continue/3]). +-export([handshake_cancel/1]). +-export([connect/3]). +-export([connect/4]). +-export([recv/3]). +-export([recv_proxy_header/2]). +-export([send/2]). +-export([sendfile/2]). +-export([sendfile/4]). +-export([sendfile/5]). +-export([setopts/2]). +-export([getopts/2]). +-export([getstat/1]). +-export([getstat/2]). +-export([controlling_process/2]). +-export([peername/1]). +-export([sockname/1]). +-export([shutdown/2]). +-export([close/1]). +-export([cleanup/1]). + +-type opts() :: []. +-export_type([opts/0]). + +-spec name() -> erlang. +name() -> erlang. + +-spec secure() -> boolean(). +secure() -> + false. + +-spec messages() -> {erlang, erlang_closed, erlang_error, erlang_passive}. +messages() -> {erlang, erlang_closed, erlang_error, erlang_passive}. + +-spec listen(ranch:transport_opts(opts())) -> {ok, reference()}. +listen(_TransOpts) -> + {ok, make_ref()}. + +-spec accept(reference(), timeout()) -> {ok, reference()}. +accept(_LSocket, _Timeout) -> + receive after infinity -> {ok, make_ref()} end. + +-spec handshake(reference(), timeout()) -> {ok, reference()}. +handshake(CSocket, Timeout) -> + handshake(CSocket, [], Timeout). + +-spec handshake(reference(), opts(), timeout()) -> {ok, reference()}. +handshake(CSocket, _, _) -> + {ok, CSocket}. + +-spec handshake_continue(reference(), timeout()) -> no_return(). +handshake_continue(CSocket, Timeout) -> + handshake_continue(CSocket, [], Timeout). + +-spec handshake_continue(reference(), opts(), timeout()) -> no_return(). +handshake_continue(_, _, _) -> + error(not_supported). + +-spec handshake_cancel(reference()) -> no_return(). +handshake_cancel(_) -> + error(not_supported). + +-spec connect(inet:ip_address() | inet:hostname(), + inet:port_number(), any()) + -> {ok, reference()}. +connect(_Host, Port, _Opts) when is_integer(Port) -> + {ok, make_ref()}. + +-spec connect(inet:ip_address() | inet:hostname(), + inet:port_number(), any(), timeout()) + -> {ok, reference()}. +connect(_Host, Port, _Opts, _Timeout) when is_integer(Port) -> + {ok, make_ref()}. + +-spec recv(reference(), non_neg_integer(), timeout()) + -> {ok, any()} | {error, closed | atom()}. +recv(_Socket, _Length, _Timeout) -> + {ok, <<>>}. + +-spec recv_proxy_header(reference(), timeout()) -> no_return(). +recv_proxy_header(_Socket, _Timeout) -> + error(not_supported). + +-spec send(reference(), iodata()) -> ok | {error, atom()}. +send(_Socket, _Packet) -> + ok. + +-spec sendfile(reference(), file:name_all() | file:fd()) + -> no_return(). +sendfile(Socket, Filename) -> + sendfile(Socket, Filename, 0, 0, []). + +-spec sendfile(reference(), file:name_all() | file:fd(), non_neg_integer(), + non_neg_integer()) + -> no_return(). +sendfile(Socket, File, Offset, Bytes) -> + sendfile(Socket, File, Offset, Bytes, []). + +-spec sendfile(reference(), file:name_all() | file:fd(), non_neg_integer(), + non_neg_integer(), [{chunk_size, non_neg_integer()}]) + -> no_return(). +sendfile(_Socket, Filename, _Offset, _Bytes, _Opts) + when is_list(Filename) orelse is_atom(Filename) + orelse is_binary(Filename) -> + error(not_supported). + +-spec setopts(reference(), list()) -> ok. +setopts(_Socket, _Opts) -> + ok. + +-spec getopts(reference(), [atom()]) -> {ok, list()} | {error, atom()}. +getopts(_Socket, _Opts) -> + {ok, []}. + +-spec getstat(reference()) -> {ok, list()} | {error, atom()}. +getstat(_Socket) -> + {ok, []}. + +-spec getstat(reference(), [atom()]) -> {ok, list()} | {error, atom()}. +getstat(_Socket, _OptionNames) -> + {ok, []}. + +-spec controlling_process(reference(), pid()) + -> ok | {error, closed | not_owner | atom()}. +controlling_process(_Socket, _Pid) -> + ok. + +-spec peername(reference()) + -> {ok, {inet:ip_address(), inet:port_number()} | {local, binary()}} | {error, atom()}. +peername(_Socket) -> + {ok, {{127, 0, 0, 1}, 12701}}. + +-spec sockname(reference()) + -> {ok, {inet:ip_address(), inet:port_number()} | {local, binary()}} | {error, atom()}. +sockname(_Socket) -> + {ok, {{127, 0, 0, 1}, 12710}}. + +-spec shutdown(reference(), read | write | read_write) + -> ok | {error, atom()}. +shutdown(_Socket, _How) -> + ok. + +-spec close(reference()) -> ok. +close(_Socket) -> + ok. + +-spec cleanup(ranch:transport_opts(opts())) -> ok. +cleanup(_) -> + ok. |