File 7082-inets-add-httpc_SUITE-remote_socket_close_parallel.patch of Package erlang
From 2e8c18646a001ea75fb3d15ddf3419105d7568d9 Mon Sep 17 00:00:00 2001
From: Jakub Witczak <kuba@erlang.org>
Date: Thu, 6 Apr 2023 17:54:41 +0200
Subject: [PATCH 2/4] inets: add httpc_SUITE:remote_socket_close_parallel
- add test case for reproducing ERIERL-937
---
lib/inets/test/httpc_SUITE.erl | 86 +++++++++++++++++++++++++++++++++-
1 file changed, 84 insertions(+), 2 deletions(-)
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index b9ccbff3ec..f89b06fddd 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -76,6 +76,7 @@ groups() ->
{sim_http, [], only_simulated() ++ server_closing_connection() ++
[process_leak_on_keepalive]},
{http_internal, [], real_requests_esi()},
+ {http_internal_minimum_bytes, [], [remote_socket_close_parallel]},
{http_unix_socket, [], simulated_unix_socket()},
{https, [], real_requests()},
{sim_https, [], only_simulated()},
@@ -353,7 +354,8 @@ init_per_testcase(persistent_connection, Config) ->
{max_keep_alive_length, 3}], persistent),
Config;
-init_per_testcase(wait_for_whole_response, Config) ->
+init_per_testcase(Case, Config) when Case == wait_for_whole_response;
+ Case == remote_socket_close_parallel ->
ct:timetrap({seconds, 60*3}),
Config;
init_per_testcase(Case, Config) when Case == post;
@@ -1905,7 +1907,81 @@ request_options(Config) when is_list(Config) ->
[{socket_opts,[{ipfamily, inet6}]}]),
{error,{failed_connect,_ }} = httpc:request(get, Request, [], []).
-
+%%-------------------------------------------------------------------------
+remote_socket_close_parallel() ->
+ [{doc,
+ "Verify remote socket closure (related tickets: OTP-18509, OTP-18545,"
+ "ERIERL-937). Transferred data size needs to be significant, so that "
+ "socket is closed, in the middle of a transfer."
+ "Note: test case is require good network and CPU - due to that "
+ " it is not included in all()."}].
+remote_socket_close_parallel(Config0) when is_list(Config0) ->
+ ClientNumber = 200,
+ Config = [{iterations, 10} | Config0],
+ ClientPids =
+ [spawn(?MODULE, connect, [self(), [{client_id, Id} | Config]]) ||
+ Id <- lists:seq(1, ClientNumber)],
+ ct:log("Started ~p clients: ~w", [ClientNumber, ClientPids]),
+ Receive = fun(S) ->
+ receive
+ ok ->
+ ct:log("++ Client finished (~p)", [S]),
+ ok;
+ Other ->
+ ct:fail(Other)
+ end
+ end,
+ [ok = Receive(S) || S <- lists:seq(1, ClientNumber)],
+ ok.
+
+connect(From, Config) ->
+ From ! loop(?config(iterations, Config),
+ io_lib:format("C~p|", [?config(client_id, Config)]),
+ Config).
+
+loop(0, Acc, _Config) ->
+ ct:log("~n~s|", [Acc]),
+ ok;
+loop(Cnt, Acc, Config) ->
+ case request(Config) of
+ {ok, {{_,200,"OK"}, _, _}} ->
+ case process_info(self(), message_queue_len) of
+ {message_queue_len,0} ->
+ loop(Cnt-1, Acc ++ ".", Config);
+ _ ->
+ %% queue is expected to be empty
+ queue_check(),
+ ct:pal("~n~s|", [Acc ++ "x"]),
+ fail
+ end;
+ {ok, NotOk} ->
+ ct:pal("200 OK was not received~n~p", [NotOk]),
+ fail;
+ Error ->
+ ct:pal("Error: ~p",[Error]),
+ fail
+ end.
+
+queue_check() ->
+ receive
+ {http, {ReqId, {_Result, _Head, Data}}} when is_binary(Data) ->
+ ct:pal("Unexpected data received: ~p ",
+ [ReqId]),
+ queue_check();
+ X ->
+ ct:pal("Caught unexpected something else: ~p",[X]),
+ queue_check()
+ after 5000 ->
+ done
+ end.
+
+request(Config) ->
+ Request = {url(group_name(Config), "/httpc_SUITE/foo", Config), []},
+ httpc:request(get, Request, [],[{sync,true}, {body_format,binary}]).
+
+foo(SID, _Env, _Input) ->
+ EightyMillionBits = 80000000, %% ~10MB transferred
+ mod_esi:deliver(SID, [<<0:EightyMillionBits>>]).
%%--------------------------------------------------------------------
%% Internal Functions ------------------------------------------------
@@ -2002,7 +2080,8 @@ url(https, End, Config) ->
{ok,Host} = inet:gethostname(),
?TLS_URL_START ++ Host ++ ":" ++ integer_to_list(Port) ++ End;
url(Group, End, Config) when Group == sim_http;
- Group == http_internal ->
+ Group == http_internal;
+ Group == http_internal_minimum_bytes ->
url(http, End, Config);
url(sim_https, End, Config) ->
url(https, End, Config).
@@ -2094,6 +2173,9 @@ server_config(http_ipv6, Config) ->
server_config(http_internal, Config) ->
server_config(http, Config) ++
[{erl_script_alias, {"", [httpc_SUITE]}}];
+server_config(http_internal_minimum_bytes, Config) ->
+ server_config(http_internal, Config) ++
+ [{minimum_bytes_per_second, 100}];
server_config(https, Config) ->
[{socket_type, {essl, ssl_config(Config)}} | server_config(http, Config)];
server_config(sim_https, Config) ->
--
2.35.3