From 6aa87d58b756ef65650ee793ad4ece8add7b70fb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?=
Date: Tue, 2 Oct 2012 18:44:03 +0200
Subject: erts, heart: Ensure erl_crash.dump is written
When a crash dump is about to be written and we have
heartbeat enabled on a system. We need time to write it
before heart explicitly kills the beam.
---
lib/kernel/src/heart.erl | 3 +++
1 file changed, 3 insertions(+)
(limited to 'lib')
diff --git a/lib/kernel/src/heart.erl b/lib/kernel/src/heart.erl
index 28452a377e..de287bfa43 100644
--- a/lib/kernel/src/heart.erl
+++ b/lib/kernel/src/heart.erl
@@ -42,6 +42,7 @@
-define(CLEAR_CMD, 5).
-define(GET_CMD, 6).
-define(HEART_CMD, 7).
+-define(PREPARING_CRASH, 8). % Used in beam vm
-define(TIMEOUT, 5000).
-define(CYCLE_TIMEOUT, 10000).
@@ -130,6 +131,8 @@ start_portprogram() ->
Port when is_port(Port) ->
case wait_ack(Port) of
ok ->
+ %% register port so the vm can find it if need be
+ register(heart_port, Port),
{ok, Port};
{error, Reason} ->
report_problem({{port_problem, Reason},
--
cgit v1.2.3
From a725c75107cea0ba72efdf18c9b135974b6c4339 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?=
Date: Thu, 11 Oct 2012 15:38:23 +0200
Subject: test: Refactor away ?line macros in heart_SUITE
---
lib/kernel/test/heart_SUITE.erl | 249 ++++++++++++++++++++--------------------
1 file changed, 122 insertions(+), 127 deletions(-)
(limited to 'lib')
diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl
index 233e438dc9..943de48f6a 100644
--- a/lib/kernel/test/heart_SUITE.erl
+++ b/lib/kernel/test/heart_SUITE.erl
@@ -38,15 +38,15 @@ init_per_testcase(_Func, Config) ->
end_per_testcase(_Func, Config) ->
Nodes = nodes(),
lists:foreach(fun(X) ->
- NNam = list_to_atom(hd(string:tokens(atom_to_list(X),"@"))),
- case NNam of
- heart_test ->
- ?t:format(1, "WARNING: Killed ~p~n", [X]),
- rpc:cast(X, erlang, halt, []);
- _ ->
- ok
- end
- end, Nodes),
+ NNam = list_to_atom(hd(string:tokens(atom_to_list(X),"@"))),
+ case NNam of
+ heart_test ->
+ ?t:format(1, "WARNING: Killed ~p~n", [X]),
+ rpc:cast(X, erlang, halt, []);
+ _ ->
+ ok
+ end
+ end, Nodes),
Dog=?config(watchdog, Config),
test_server:timetrap_cancel(Dog).
@@ -82,15 +82,15 @@ end_per_suite(Config) when is_list(Config) ->
start_check(Type, Name) ->
Args = case ?t:os_type() of
- {win32,_} -> "-heart -env HEART_COMMAND no_reboot";
- _ -> "-heart"
- end,
+ {win32,_} -> "-heart -env HEART_COMMAND no_reboot";
+ _ -> "-heart"
+ end,
{ok, Node} = case Type of
- loose ->
- loose_node:start(Name, Args, ?DEFAULT_TIMEOUT_SECS);
- _ ->
- ?t:start_node(Name, Type, [{args, Args}])
- end,
+ loose ->
+ loose_node:start(Name, Args, ?DEFAULT_TIMEOUT_SECS);
+ _ ->
+ ?t:start_node(Name, Type, [{args, Args}])
+ end,
erlang:monitor_node(Node, true),
case rpc:call(Node, erlang, whereis, [heart]) of
Pid when is_pid(Pid) ->
@@ -103,21 +103,19 @@ start_check(Type, Name) ->
start(doc) -> [];
start(suite) -> {req, [{time, 10}]};
start(Config) when is_list(Config) ->
- ?line {ok, Node} = start_check(slave, heart_test),
- ?line rpc:call(Node, init, reboot, []),
+ {ok, Node} = start_check(slave, heart_test),
+ rpc:call(Node, init, reboot, []),
receive
- {nodedown, Node} ->
- ok
- after 2000 ->
- test_server:fail(node_not_closed)
+ {nodedown, Node} -> ok
+ after 2000 -> test_server:fail(node_not_closed)
end,
test_server:sleep(5000),
- ?line case net_adm:ping(Node) of
- pang ->
- ok;
- _ ->
- test_server:fail(node_rebooted)
- end,
+ case net_adm:ping(Node) of
+ pang ->
+ ok;
+ _ ->
+ test_server:fail(node_rebooted)
+ end,
test_server:stop_node(Node).
%% Also test fixed bug in R1B (it was not possible to
@@ -134,8 +132,8 @@ restart(suite) ->
{skip, "Only run on unix and win32"}
end;
restart(Config) when is_list(Config) ->
- ?line {ok, Node} = start_check(loose, heart_test),
- ?line rpc:call(Node, init, restart, []),
+ {ok, Node} = start_check(loose, heart_test),
+ rpc:call(Node, init, restart, []),
receive
{nodedown, Node} ->
ok
@@ -144,20 +142,20 @@ restart(Config) when is_list(Config) ->
end,
test_server:sleep(5000),
- ?line case net_adm:ping(Node) of
- pong ->
- erlang:monitor_node(Node, true),
- ?line rpc:call(Node, init, stop, []),
- receive
- {nodedown, Node} ->
- ok
- after 2000 ->
- test_server:fail(node_not_closed2)
- end,
- ok;
- _ ->
- test_server:fail(node_not_restarted)
- end,
+ case net_adm:ping(Node) of
+ pong ->
+ erlang:monitor_node(Node, true),
+ rpc:call(Node, init, stop, []),
+ receive
+ {nodedown, Node} ->
+ ok
+ after 2000 ->
+ test_server:fail(node_not_closed2)
+ end,
+ ok;
+ _ ->
+ test_server:fail(node_not_restarted)
+ end,
loose_node:stop(Node).
reboot(doc) -> [];
@@ -165,10 +163,10 @@ reboot(suite) -> {req, [{time, 10}]};
reboot(Config) when is_list(Config) ->
{ok, Node} = start_check(slave, heart_test),
- ?line ok = rpc:call(Node, heart, set_cmd,
+ ok = rpc:call(Node, heart, set_cmd,
[atom_to_list(lib:progname()) ++
" -noshell -heart " ++ name(Node) ++ "&"]),
- ?line rpc:call(Node, init, reboot, []),
+ rpc:call(Node, init, reboot, []),
receive
{nodedown, Node} ->
ok
@@ -176,44 +174,44 @@ reboot(Config) when is_list(Config) ->
test_server:fail(node_not_closed)
end,
test_server:sleep(5000),
- ?line case net_adm:ping(Node) of
- pong ->
- erlang:monitor_node(Node, true),
- ?line rpc:call(Node, init, reboot, []),
- receive
- {nodedown, Node} ->
- ok
- after 2000 ->
- test_server:fail(node_not_closed2)
- end,
- ok;
- _ ->
- test_server:fail(node_not_rebooted)
- end,
+ case net_adm:ping(Node) of
+ pong ->
+ erlang:monitor_node(Node, true),
+ rpc:call(Node, init, reboot, []),
+ receive
+ {nodedown, Node} ->
+ ok
+ after 2000 ->
+ test_server:fail(node_not_closed2)
+ end,
+ ok;
+ _ ->
+ test_server:fail(node_not_rebooted)
+ end,
ok.
%% Only tests bad command, correct behaviour is tested in reboot/1.
set_cmd(suite) -> [];
set_cmd(Config) when is_list(Config) ->
- ?line {ok, Node} = start_check(slave, heart_test),
+ {ok, Node} = start_check(slave, heart_test),
Cmd = wrong_atom,
- ?line {error, {bad_cmd, Cmd}} = rpc:call(Node, heart, set_cmd, [Cmd]),
+ {error, {bad_cmd, Cmd}} = rpc:call(Node, heart, set_cmd, [Cmd]),
Cmd1 = lists:duplicate(2047, $a),
- ?line {error, {bad_cmd, Cmd1}} = rpc:call(Node, heart, set_cmd, [Cmd1]),
+ {error, {bad_cmd, Cmd1}} = rpc:call(Node, heart, set_cmd, [Cmd1]),
Cmd2 = lists:duplicate(28, $a),
- ?line ok = rpc:call(Node, heart, set_cmd, [Cmd2]),
+ ok = rpc:call(Node, heart, set_cmd, [Cmd2]),
Cmd3 = lists:duplicate(2000, $a),
- ?line ok = rpc:call(Node, heart, set_cmd, [Cmd3]),
+ ok = rpc:call(Node, heart, set_cmd, [Cmd3]),
stop_node(Node),
ok.
clear_cmd(suite) -> {req,[{time,15}]};
clear_cmd(Config) when is_list(Config) ->
- ?line {ok, Node} = start_check(slave, heart_test),
- ?line ok = rpc:call(Node, heart, set_cmd,
+ {ok, Node} = start_check(slave, heart_test),
+ ok = rpc:call(Node, heart, set_cmd,
[atom_to_list(lib:progname()) ++
" -noshell -heart " ++ name(Node) ++ "&"]),
- ?line rpc:call(Node, init, reboot, []),
+ rpc:call(Node, init, reboot, []),
receive
{nodedown, Node} ->
ok
@@ -221,16 +219,16 @@ clear_cmd(Config) when is_list(Config) ->
test_server:fail(node_not_closed)
end,
test_server:sleep(5000),
- ?line case net_adm:ping(Node) of
- pong ->
- erlang:monitor_node(Node, true);
- _ ->
- test_server:fail(node_not_rebooted)
- end,
- ?line ok = rpc:call(Node, heart, set_cmd,
+ case net_adm:ping(Node) of
+ pong ->
+ erlang:monitor_node(Node, true);
+ _ ->
+ test_server:fail(node_not_rebooted)
+ end,
+ ok = rpc:call(Node, heart, set_cmd,
["erl -noshell -heart " ++ name(Node) ++ "&"]),
- ?line ok = rpc:call(Node, heart, clear_cmd, []),
- ?line rpc:call(Node, init, reboot, []),
+ ok = rpc:call(Node, heart, clear_cmd, []),
+ rpc:call(Node, init, reboot, []),
receive
{nodedown, Node} ->
ok
@@ -238,20 +236,20 @@ clear_cmd(Config) when is_list(Config) ->
test_server:fail(node_not_closed)
end,
test_server:sleep(5000),
- ?line case net_adm:ping(Node) of
- pang ->
- ok;
- _ ->
- test_server:fail(node_rebooted)
- end,
+ case net_adm:ping(Node) of
+ pang ->
+ ok;
+ _ ->
+ test_server:fail(node_rebooted)
+ end,
ok.
get_cmd(suite) -> [];
get_cmd(Config) when is_list(Config) ->
- ?line {ok, Node} = start_check(slave, heart_test),
+ {ok, Node} = start_check(slave, heart_test),
Cmd = "test",
- ?line ok = rpc:call(Node, heart, set_cmd, [Cmd]),
- ?line {ok, Cmd} = rpc:call(Node, heart, get_cmd, []),
+ ok = rpc:call(Node, heart, set_cmd, [Cmd]),
+ {ok, Cmd} = rpc:call(Node, heart, get_cmd, []),
stop_node(Node),
ok.
@@ -278,53 +276,50 @@ do_dont_drop(_,0) ->
[];
do_dont_drop(Config,N) ->
%% Name of first slave node
- ?line NN1 = atom_to_list(?MODULE) ++ "slave_1",
+ NN1 = atom_to_list(?MODULE) ++ "slave_1",
%% Name of node started by heart on failure
- ?line NN2 = atom_to_list(?MODULE) ++ "slave_2",
+ NN2 = atom_to_list(?MODULE) ++ "slave_2",
%% Name of node started by heart on success
- ?line NN3 = atom_to_list(?MODULE) ++ "slave_3",
- ?line Host = hd(tl(string:tokens(atom_to_list(node()),"@"))),
+ NN3 = atom_to_list(?MODULE) ++ "slave_3",
+ Host = hd(tl(string:tokens(atom_to_list(node()),"@"))),
%% The initial heart command
- ?line FirstCmd = erl() ++ name(NN2 ++ "@" ++ Host),
+ FirstCmd = erl() ++ name(NN2 ++ "@" ++ Host),
%% Separated the parameters to start_node_run for clarity...
- ?line Name = list_to_atom(NN1),
- ?line Env = [{"HEART_COMMAND", FirstCmd}],
- ?line Func = "start_heart_stress",
- ?line Arg = NN3 ++ "@" ++ Host ++ " " ++
+ Name = list_to_atom(NN1),
+ Env = [{"HEART_COMMAND", FirstCmd}],
+ Func = "start_heart_stress",
+ Arg = NN3 ++ "@" ++ Host ++ " " ++
filename:join(?config(data_dir, Config), "simple_echo"),
- ?line start_node_run(Name,Env,Func,Arg),
- ?line case wait_for_any_of(list_to_atom(NN2 ++ "@" ++ Host),
- list_to_atom(NN3 ++ "@" ++ Host)) of
- 2 ->
- ?line [ok | do_dont_drop(Config,N-1)];
- _ ->
- ?line false
- end.
+ start_node_run(Name,Env,Func,Arg),
+ case wait_for_any_of(list_to_atom(NN2 ++ "@" ++ Host),
+ list_to_atom(NN3 ++ "@" ++ Host)) of
+ 2 ->
+ [ok | do_dont_drop(Config,N-1)];
+ _ ->
+ false
+ end.
wait_for_any_of(N1,N2) ->
- ?line wait_for_any_of(N1,N2,45).
+ wait_for_any_of(N1,N2,45).
wait_for_any_of(_N1,_N2,0) ->
- ?line false;
+ false;
wait_for_any_of(N1,N2,Times) ->
- ?line receive
- after 1000 ->
- ?line ok
- end,
- ?line case net_adm:ping(N1) of
- pang ->
- ?line case net_adm:ping(N2) of
- pang ->
- ?line wait_for_any_of(N1,N2,Times - 1);
- pong ->
- ?line rpc:call(N2,init,stop,[]),
- ?line 2
- end;
- pong ->
- ?line rpc:call(N1,init,stop,[]),
- ?line 1
- end.
+ receive after 1000 -> ok end,
+ case net_adm:ping(N1) of
+ pang ->
+ case net_adm:ping(N2) of
+ pang ->
+ wait_for_any_of(N1,N2,Times - 1);
+ pong ->
+ rpc:call(N2,init,stop,[]),
+ 2
+ end;
+ pong ->
+ rpc:call(N1,init,stop,[]),
+ 1
+ end.
kill_pid(suite) ->
@@ -409,12 +404,12 @@ env_conv([{X,Y}|T]) ->
%%% Argument is the argument(s) to send through erl -s
%%%
start_node_run(Name, Env, Function, Argument) ->
- ?line PA = filename:dirname(code:which(?MODULE)),
- ?line Params = "-heart -env " ++ env_conv(Env) ++ " -pa " ++ PA ++
- " -s " ++
+ PA = filename:dirname(code:which(?MODULE)),
+ Params = "-heart -env " ++ env_conv(Env) ++ " -pa " ++ PA ++
+ " -s " ++
atom_conv(?MODULE) ++ " " ++ atom_conv(Function) ++ " " ++
atom_conv(Argument),
- ?line start_node(Name, Params).
+ start_node(Name, Params).
start_node(Name, Param) ->
test_server:start_node(Name, slave, [{args, Param}]).
--
cgit v1.2.3
From 7f341797febc67762af4fb430b0e69d21aad6dcf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?=
Date: Fri, 12 Oct 2012 17:54:30 +0200
Subject: test: Add test for heart restart on crash
* node_start_immediately_after_crash tests that heart restarts
beam upon a crash and will not generate a crash dump
---
lib/kernel/test/heart_SUITE.erl | 135 ++++++++++++++++++++++++++++------------
1 file changed, 95 insertions(+), 40 deletions(-)
(limited to 'lib')
diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl
index 943de48f6a..de278f9e69 100644
--- a/lib/kernel/test/heart_SUITE.erl
+++ b/lib/kernel/test/heart_SUITE.erl
@@ -22,7 +22,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2, start/1, restart/1,
- reboot/1, set_cmd/1, clear_cmd/1, get_cmd/1,
+ reboot/1, node_start_immediately_after_crash/1, set_cmd/1, clear_cmd/1, get_cmd/1,
dont_drop/1, kill_pid/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -57,8 +57,12 @@ end_per_testcase(_Func, Config) ->
%%-----------------------------------------------------------------
suite() -> [{ct_hooks,[ts_install_cth]}].
-all() ->
- [start, restart, reboot, set_cmd, clear_cmd, get_cmd, kill_pid].
+all() -> [
+ start, restart, reboot,
+ node_start_immediately_after_crash,
+ set_cmd, clear_cmd, get_cmd,
+ kill_pid
+ ].
groups() ->
[].
@@ -80,10 +84,15 @@ init_per_suite(Config) when is_list(Config) ->
end_per_suite(Config) when is_list(Config) ->
Config.
+
start_check(Type, Name) ->
+ start_check(Type, Name, []).
+start_check(Type, Name, Envs) ->
Args = case ?t:os_type() of
- {win32,_} -> "-heart -env HEART_COMMAND no_reboot";
- _ -> "-heart"
+ {win32,_} ->
+ "-heart " ++ env_encode([{"HEART_COMMAND", no_reboot}|Envs]);
+ _ ->
+ "-heart " ++ env_encode(Envs)
end,
{ok, Node} = case Type of
loose ->
@@ -123,6 +132,10 @@ start(Config) when is_list(Config) ->
%% Slave executes erlang:halt() on master nodedown.
%% Therefore the slave process has to be killed
%% before restart.
+
+%% restart
+%% Purpose:
+%% Check that a node is up and running after a init:restart/0
restart(doc) -> [];
restart(suite) ->
case ?t:os_type() of
@@ -141,23 +154,12 @@ restart(Config) when is_list(Config) ->
test_server:fail(node_not_closed)
end,
test_server:sleep(5000),
-
- case net_adm:ping(Node) of
- pong ->
- erlang:monitor_node(Node, true),
- rpc:call(Node, init, stop, []),
- receive
- {nodedown, Node} ->
- ok
- after 2000 ->
- test_server:fail(node_not_closed2)
- end,
- ok;
- _ ->
- test_server:fail(node_not_restarted)
- end,
+ node_check_up_down(Node, 2000),
loose_node:stop(Node).
+%% reboot
+%% Purpose:
+%% Check that a node is up and running after a init:reboot/0
reboot(doc) -> [];
reboot(suite) -> {req, [{time, 10}]};
reboot(Config) when is_list(Config) ->
@@ -174,21 +176,56 @@ reboot(Config) when is_list(Config) ->
test_server:fail(node_not_closed)
end,
test_server:sleep(5000),
+ node_check_up_down(Node, 2000),
+ ok.
+
+%% node_start_immediately_after_crash
+%% Purpose:
+%% Check that a node is up and running after a crash.
+%% This test exhausts the atom table on the remote node.
+%% ERL_CRASH_DUMP_SECONDS=0 will force beam not to dump an erl_crash.dump.
+node_start_immediately_after_crash(suite) -> {req, [{time, 10}]};
+node_start_immediately_after_crash(Config) when is_list(Config) ->
+ {ok, Node} = start_check(slave, heart_test, [{"ERL_CRASH_DUMP_SECONDS", "0"}]),
+
+ ok = rpc:call(Node, heart, set_cmd,
+ [atom_to_list(lib:progname()) ++
+ " -noshell -heart " ++ name(Node) ++ "&"]),
+
+ Mod = exhaust_atoms,
+
+ Code = generate(Mod, [], [
+ "do() -> " ++
+ " Set = lists:seq($a,$z), " ++
+ " [ list_to_atom([A,B,C,D,E]) || " ++
+ " A <- Set, B <- Set, C <- Set, E <- Set, D <- Set ]."
+ ]),
+
+ %% crash it with atom exhaustion
+ rpc:call(Node, erlang, load_module, [Mod, Code]),
+ rpc:cast(Node, Mod, do, []),
+
+
+ receive {nodedown, Node} -> ok
+ after 2000 -> test_server:fail(node_not_closed)
+ end,
+ test_server:sleep(5000),
+ node_check_up_down(Node, 2000),
+ ok.
+
+node_check_up_down(Node, Tmo) ->
case net_adm:ping(Node) of
pong ->
erlang:monitor_node(Node, true),
rpc:call(Node, init, reboot, []),
receive
- {nodedown, Node} ->
- ok
- after 2000 ->
+ {nodedown, Node} -> ok
+ after Tmo ->
test_server:fail(node_not_closed2)
- end,
- ok;
+ end;
_ ->
test_server:fail(node_not_rebooted)
- end,
- ok.
+ end.
%% Only tests bad command, correct behaviour is tested in reboot/1.
set_cmd(suite) -> [];
@@ -272,8 +309,7 @@ dont_drop(Config) when is_list(Config) ->
ok
end.
-do_dont_drop(_,0) ->
- [];
+do_dont_drop(_,0) -> [];
do_dont_drop(Config,N) ->
%% Name of first slave node
NN1 = atom_to_list(?MODULE) ++ "slave_1",
@@ -385,15 +421,13 @@ name([H|T], Name) ->
name(T, [H|Name]).
-atom_conv(A) when is_atom(A) ->
- atom_to_list(A);
-atom_conv(A) when is_list(A) ->
- A.
+enc(A) when is_atom(A) -> atom_to_list(A);
+enc(A) when is_binary(A) -> binary_to_list(A);
+enc(A) when is_list(A) -> A.
-env_conv([]) ->
- [];
-env_conv([{X,Y}|T]) ->
- atom_conv(X) ++ " \"" ++ atom_conv(Y) ++ "\" " ++ env_conv(T).
+env_encode([]) -> [];
+env_encode([{X,Y}|T]) ->
+ "-env " ++ enc(X) ++ " \"" ++ enc(Y) ++ "\" " ++ env_encode(T).
%%%
%%% Starts a node and runs a function in this
@@ -405,10 +439,10 @@ env_conv([{X,Y}|T]) ->
%%%
start_node_run(Name, Env, Function, Argument) ->
PA = filename:dirname(code:which(?MODULE)),
- Params = "-heart -env " ++ env_conv(Env) ++ " -pa " ++ PA ++
+ Params = "-heart " ++ env_encode(Env) ++ " -pa " ++ PA ++
" -s " ++
- atom_conv(?MODULE) ++ " " ++ atom_conv(Function) ++ " " ++
- atom_conv(Argument),
+ enc(?MODULE) ++ " " ++ enc(Function) ++ " " ++
+ enc(Argument),
start_node(Name, Params).
start_node(Name, Param) ->
@@ -475,3 +509,24 @@ suicide_by_heart() ->
{makaronipudding} ->
sallad
end.
+
+
+%% generate a module from binary
+generate(Module, Attributes, FunStrings) ->
+ FunForms = function_forms(FunStrings),
+ Forms = [
+ {attribute,1,module,Module},
+ {attribute,2,export,[FA || {FA,_} <- FunForms]}
+ ] ++ [{attribute, 3, A, V}|| {A, V} <- Attributes] ++
+ [ Function || {_, Function} <- FunForms],
+ {ok, Module, Bin} = compile:forms(Forms),
+ Bin.
+
+
+function_forms([]) -> [];
+function_forms([S|Ss]) ->
+ {ok, Ts,_} = erl_scan:string(S),
+ {ok, Form} = erl_parse:parse_form(Ts),
+ Fun = element(3, Form),
+ Arity = element(4, Form),
+ [{{Fun,Arity}, Form}|function_forms(Ss)].
--
cgit v1.2.3
From 30152914f61a1693fd17a2a4bcf36f8df96b7692 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?=
Date: Mon, 15 Oct 2012 14:22:14 +0200
Subject: test: Add test for heart restart on crash
* node_start_soon_after_crash tests that heart restarts
beam upon a crash and only lets beam write its crash
dump for a certain amount of time
---
lib/kernel/test/heart_SUITE.erl | 76 ++++++++++++++++++++++++++++-------------
1 file changed, 53 insertions(+), 23 deletions(-)
(limited to 'lib')
diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl
index de278f9e69..2bed8bee26 100644
--- a/lib/kernel/test/heart_SUITE.erl
+++ b/lib/kernel/test/heart_SUITE.erl
@@ -22,7 +22,10 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2, start/1, restart/1,
- reboot/1, node_start_immediately_after_crash/1, set_cmd/1, clear_cmd/1, get_cmd/1,
+ reboot/1,
+ node_start_immediately_after_crash/1,
+ node_start_soon_after_crash/1,
+ set_cmd/1, clear_cmd/1, get_cmd/1,
dont_drop/1, kill_pid/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -60,6 +63,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() -> [
start, restart, reboot,
node_start_immediately_after_crash,
+ node_start_soon_after_crash,
set_cmd, clear_cmd, get_cmd,
kill_pid
].
@@ -186,7 +190,7 @@ reboot(Config) when is_list(Config) ->
%% ERL_CRASH_DUMP_SECONDS=0 will force beam not to dump an erl_crash.dump.
node_start_immediately_after_crash(suite) -> {req, [{time, 10}]};
node_start_immediately_after_crash(Config) when is_list(Config) ->
- {ok, Node} = start_check(slave, heart_test, [{"ERL_CRASH_DUMP_SECONDS", "0"}]),
+ {ok, Node} = start_check(loose, heart_test_imm, [{"ERL_CRASH_DUMP_SECONDS", "0"}]),
ok = rpc:call(Node, heart, set_cmd,
[atom_to_list(lib:progname()) ++
@@ -195,9 +199,9 @@ node_start_immediately_after_crash(Config) when is_list(Config) ->
Mod = exhaust_atoms,
Code = generate(Mod, [], [
- "do() -> " ++
- " Set = lists:seq($a,$z), " ++
- " [ list_to_atom([A,B,C,D,E]) || " ++
+ "do() -> "
+ " Set = lists:seq($a,$z), "
+ " [ list_to_atom([A,B,C,D,E]) || "
" A <- Set, B <- Set, C <- Set, E <- Set, D <- Set ]."
]),
@@ -209,9 +213,44 @@ node_start_immediately_after_crash(Config) when is_list(Config) ->
receive {nodedown, Node} -> ok
after 2000 -> test_server:fail(node_not_closed)
end,
- test_server:sleep(5000),
+ test_server:sleep(3000),
node_check_up_down(Node, 2000),
- ok.
+ loose_node:stop(Node).
+
+%% node_start_soon_after_crash
+%% Purpose:
+%% Check that a node is up and running after a crash.
+%% This test exhausts the atom table on the remote node.
+%% ERL_CRASH_DUMP_SECONDS=10 will force beam
+%% to only dump an erl_crash.dump for 10 seconds.
+node_start_soon_after_crash(suite) -> {req, [{time, 10}]};
+node_start_soon_after_crash(Config) when is_list(Config) ->
+ {ok, Node} = start_check(loose, heart_test_soon, [{"ERL_CRASH_DUMP_SECONDS", "10"}]),
+
+ ok = rpc:call(Node, heart, set_cmd,
+ [atom_to_list(lib:progname()) ++
+ " -noshell -heart " ++ name(Node) ++ "&"]),
+
+ Mod = exhaust_atoms,
+
+ Code = generate(Mod, [], [
+ "do() -> "
+ " Set = lists:seq($a,$z), "
+ " [ list_to_atom([A,B,C,D,E]) || "
+ " A <- Set, B <- Set, C <- Set, E <- Set, D <- Set ]."
+ ]),
+
+ %% crash it with atom exhaustion
+ rpc:call(Node, erlang, load_module, [Mod, Code]),
+ rpc:cast(Node, Mod, do, []),
+
+ receive {nodedown, Node} -> ok
+ after 15000 -> test_server:fail(node_not_closed)
+ end,
+ test_server:sleep(20000),
+ node_check_up_down(Node, 15000),
+ loose_node:stop(Node).
+
node_check_up_down(Node, Tmo) ->
case net_adm:ping(Node) of
@@ -285,7 +324,7 @@ get_cmd(suite) -> [];
get_cmd(Config) when is_list(Config) ->
{ok, Node} = start_check(slave, heart_test),
Cmd = "test",
- ok = rpc:call(Node, heart, set_cmd, [Cmd]),
+ ok = rpc:call(Node, heart, set_cmd, [Cmd]),
{ok, Cmd} = rpc:call(Node, heart, get_cmd, []),
stop_node(Node),
ok.
@@ -378,9 +417,7 @@ do_kill_pid(_Config) ->
{ok,Node} = start_node_run(Name,Env,suicide_by_heart,[]),
ok = wait_for_node(Node,15),
erlang:monitor_node(Node, true),
- receive
- {nodedown,Node} ->
- ok
+ receive {nodedown,Node} -> ok
after 30000 ->
false
end.
@@ -388,23 +425,16 @@ do_kill_pid(_Config) ->
wait_for_node(_,0) ->
false;
wait_for_node(Node,N) ->
- receive
- after 1000 ->
- ok
- end,
+ receive after 1000 -> ok end,
case net_adm:ping(Node) of
- pong ->
- ok;
- pang ->
- wait_for_node(Node,N-1)
+ pong -> ok;
+ pang -> wait_for_node(Node,N-1)
end.
erl() ->
case os:type() of
- {win32,_} ->
- "werl ";
- _ ->
- "erl "
+ {win32,_} -> "werl ";
+ _ -> "erl "
end.
name(Node) when is_list(Node) -> name(Node,[]);
--
cgit v1.2.3
From e6ea3b07e25b09481b010558f8bfdfb57dcbb85e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?=
Date: Mon, 15 Oct 2012 16:22:47 +0200
Subject: doc: Document ERL_CRASH_DUMP_SECONDS behaviour
* heart reboot behaviour
* erl_crash.dump file write behaviour
---
lib/kernel/doc/src/heart.xml | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
(limited to 'lib')
diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml
index 26d1e27822..2826d3d00a 100644
--- a/lib/kernel/doc/src/heart.xml
+++ b/lib/kernel/doc/src/heart.xml
@@ -71,6 +71,39 @@
timeout and try to reboot the system. This can happen, for
example, if the system clock is adjusted automatically by use of
NTP (Network Time Protocol).
+
+
If a crash occurs, an will not be written
+ unless the environment variable is set.
+
+
+
+% erl -heart -env ERL_CRASH_DUMP_SECONDS 10 ...
+
+ Furthermore, has the following behaviour on
+ heart:
+
+
+
+
+ Suppresses the writing a crash dump file entirely,
+ thus rebooting the runtime system immediately.
+ This is the same as not setting the environment variable.
+
+
+
+
Setting the environment variable to a negative value will not reboot
+ the runtime system until the crash dump file has been completly written.
+
+
+
+
+ Heart will wait for S seconds to let the crash dump file be written.
+ After S seconds heart will reboot the runtime system regardless of
+ the crash dump file has been written or not.
+
+
+
+
In the following descriptions, all function fails with reason
badarg if heart is not started.
--
cgit v1.2.3
From 6f0a76a0f78f3483b561b5e59260e8ca968b052c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?=
Date: Mon, 22 Oct 2012 17:12:35 +0200
Subject: test: Relax timeouts for heart_SUITE
Timeouts were set too narrow and timedout on slow machines
---
lib/kernel/test/heart_SUITE.erl | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl
index 2bed8bee26..e64d2914c4 100644
--- a/lib/kernel/test/heart_SUITE.erl
+++ b/lib/kernel/test/heart_SUITE.erl
@@ -209,9 +209,14 @@ node_start_immediately_after_crash(Config) when is_list(Config) ->
rpc:call(Node, erlang, load_module, [Mod, Code]),
rpc:cast(Node, Mod, do, []),
+ T0 = now(),
- receive {nodedown, Node} -> ok
- after 2000 -> test_server:fail(node_not_closed)
+ receive {nodedown, Node} ->
+ test_server:format("Took ~.2f s. for node to go down~n", [timer:now_diff(now(), T0)/1000000]),
+ ok
+ %% timeout is very liberal here. nodedown is received in about 1 s. on linux (palantir)
+ %% and in about 10 s. on solaris (carcharoth)
+ after (15000*test_server:timetrap_scale_factor()) -> test_server:fail(node_not_closed)
end,
test_server:sleep(3000),
node_check_up_down(Node, 2000),
@@ -245,7 +250,7 @@ node_start_soon_after_crash(Config) when is_list(Config) ->
rpc:cast(Node, Mod, do, []),
receive {nodedown, Node} -> ok
- after 15000 -> test_server:fail(node_not_closed)
+ after (15000*test_server:timetrap_scale_factor()) -> test_server:fail(node_not_closed)
end,
test_server:sleep(20000),
node_check_up_down(Node, 15000),
--
cgit v1.2.3