aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel')
-rw-r--r--lib/kernel/doc/src/heart.xml33
-rw-r--r--lib/kernel/src/heart.erl3
-rw-r--r--lib/kernel/test/global_SUITE.erl119
-rw-r--r--lib/kernel/test/heart_SUITE.erl401
-rw-r--r--lib/kernel/test/interactive_shell_SUITE.erl213
-rw-r--r--lib/kernel/test/wrap_log_reader_SUITE.erl2
-rw-r--r--lib/kernel/vsn.mk2
7 files changed, 471 insertions, 302 deletions
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).</p>
+
+ <p> If a crash occurs, an <c><![CDATA[erl_crash.dump]]></c> will <em>not</em> be written
+ unless the environment variable <c><![CDATA[ERL_CRASH_DUMP_SECONDS]]></c> is set.
+ </p>
+
+ <pre>
+% <input>erl -heart -env ERL_CRASH_DUMP_SECONDS 10 ...</input></pre>
+ <p>
+ Furthermore, <c><![CDATA[ERL_CRASH_DUMP_SECONDS]]></c> has the following behaviour on
+ <c>heart</c>:
+ </p>
+ <taglist>
+ <tag><c><![CDATA[ERL_CRASH_DUMP_SECONDS=0]]></c></tag>
+ <item><p>
+ Suppresses the writing a crash dump file entirely,
+ thus rebooting the runtime system immediately.
+ This is the same as not setting the environment variable.
+ </p>
+ </item>
+ <tag><c><![CDATA[ERL_CRASH_DUMP_SECONDS=-1]]></c></tag>
+ <item><p> Setting the environment variable to a negative value will not reboot
+ the runtime system until the crash dump file has been completly written.
+ </p>
+ </item>
+ <tag><c><![CDATA[ERL_CRASH_DUMP_SECONDS=S]]></c></tag>
+ <item><p>
+ Heart will wait for <c>S</c> seconds to let the crash dump file be written.
+ After <c>S</c> seconds <c>heart</c> will reboot the runtime system regardless of
+ the crash dump file has been written or not.
+ </p>
+ </item>
+ </taglist>
+
<p>In the following descriptions, all function fails with reason
<c>badarg</c> if <c>heart</c> is not started.</p>
</description>
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},
diff --git a/lib/kernel/test/global_SUITE.erl b/lib/kernel/test/global_SUITE.erl
index 60035b50a0..6eb2134644 100644
--- a/lib/kernel/test/global_SUITE.erl
+++ b/lib/kernel/test/global_SUITE.erl
@@ -168,7 +168,7 @@ end_per_testcase(_Case, Config) ->
register_1(suite) -> [];
register_1(Config) when is_list(Config) ->
Timeout = 15,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
P = spawn_link(?MODULE, lock_global, [self(), Config]),
@@ -195,7 +195,6 @@ register_1(Config) when is_list(Config) ->
?line _ = global:unregister_name(foo),
write_high_level_trace(Config),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
lock_global(Parent, Config) ->
@@ -238,7 +237,7 @@ lock_global(Parent, Config) ->
both_known_1(suite) -> [];
both_known_1(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
@@ -316,7 +315,6 @@ both_known_1(Config) when is_list(Config) ->
stop_node(Cp3),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
lost_unregister(suite) -> [];
@@ -324,7 +322,7 @@ lost_unregister(doc) ->
["OTP-6428. An unregistered name reappears."];
lost_unregister(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
@@ -361,7 +359,6 @@ lost_unregister(Config) when is_list(Config) ->
stop_node(B),
stop_node(C),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
-define(UNTIL_LOOP, 300).
@@ -448,7 +445,7 @@ lock_global2(Id, Parent) ->
names(suite) -> [];
names(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -532,7 +529,6 @@ names(Config) when is_list(Config) ->
?line ?UNTIL(undefined =:= global:whereis_name(test)),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
names_hidden(suite) -> [];
@@ -541,7 +537,7 @@ names_hidden(doc) ->
"visible nodes."];
names_hidden(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -639,13 +635,12 @@ names_hidden(Config) when is_list(Config) ->
stop_node(Cp3),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
locks(suite) -> [];
locks(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line {ok, Cp1} = start_node(cp1, Config),
@@ -750,7 +745,6 @@ locks(Config) when is_list(Config) ->
?line test_server:sleep(10),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
@@ -760,7 +754,7 @@ locks_hidden(doc) ->
"visible nodes."];
locks_hidden(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNodes = nodes(),
@@ -833,14 +827,13 @@ locks_hidden(Config) when is_list(Config) ->
stop_node(Cp3),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
bad_input(suite) -> [];
bad_input(Config) when is_list(Config) ->
Timeout = 15,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
Pid = whereis(global_name_server),
@@ -854,13 +847,12 @@ bad_input(Config) when is_list(Config) ->
?line {'EXIT', _} = (catch global:trans({id, self()}, {m,f}, [node()], -1)),
?line Pid = whereis(global_name_server),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
names_and_locks(suite) -> [];
names_and_locks(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -922,7 +914,6 @@ names_and_locks(Config) when is_list(Config) ->
stop_node(Cp3),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
lock_die(suite) -> [];
@@ -930,7 +921,7 @@ lock_die(doc) ->
["OTP-6341. Remove locks using monitors."];
lock_die(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -964,7 +955,6 @@ lock_die(Config) when is_list(Config) ->
stop_node(Cp1),
stop_node(Cp2),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
name_die(suite) -> [];
@@ -972,7 +962,7 @@ name_die(doc) ->
["OTP-6341. Remove names using monitors."];
name_die(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -1027,7 +1017,6 @@ name_die(Config) when is_list(Config) ->
write_high_level_trace(Config),
stop_nodes(Cps),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
kill_pid(Pid, File, Config) ->
@@ -1040,7 +1029,7 @@ basic_partition(doc) ->
["Tests that two partitioned networks exchange correct info."];
basic_partition(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -1088,7 +1077,6 @@ basic_partition(Config) when is_list(Config) ->
stop_node(Cp2),
stop_node(Cp3),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
basic_name_partition(suite) ->
@@ -1099,7 +1087,7 @@ basic_name_partition(doc) ->
"during connect phase are handled correctly."];
basic_name_partition(Config) when is_list(Config) ->
Timeout = 60,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -1167,7 +1155,6 @@ basic_name_partition(Config) when is_list(Config) ->
stop_node(Cp2),
stop_node(Cp3),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
%Peer nodes cp0 - cp6 are started. Break apart the connections from
@@ -1190,7 +1177,7 @@ advanced_partition(doc) ->
"partitioned networks connect."];
advanced_partition(Config) when is_list(Config) ->
Timeout = 60,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -1278,7 +1265,6 @@ advanced_partition(Config) when is_list(Config) ->
stop_node(Cp5),
stop_node(Cp6),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
%Peer nodes cp0 - cp6 are started, and partitioned just like in
@@ -1297,7 +1283,7 @@ stress_partition(doc) ->
"go up/down a bit."];
stress_partition(Config) when is_list(Config) ->
Timeout = 90,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -1377,7 +1363,6 @@ stress_partition(Config) when is_list(Config) ->
stop_node(Cp7),
stop_node(Cp8),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
@@ -1408,7 +1393,7 @@ ring(doc) ->
"Make sure that there's just one winner."];
ring(Config) when is_list(Config) ->
Timeout = 60,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -1486,7 +1471,6 @@ ring(Config) when is_list(Config) ->
stop_node(Cp7),
stop_node(Cp8),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
simple_ring(suite) ->
@@ -1499,7 +1483,7 @@ simple_ring(doc) ->
"Make sure that there's just one winner."];
simple_ring(Config) when is_list(Config) ->
Timeout = 60,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -1565,7 +1549,6 @@ simple_ring(Config) when is_list(Config) ->
stop_node(Cp4),
stop_node(Cp5),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
line(suite) ->
@@ -1576,7 +1559,7 @@ line(doc) ->
"Make sure that there's just one winner."];
line(Config) when is_list(Config) ->
Timeout = 60,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -1655,7 +1638,6 @@ line(Config) when is_list(Config) ->
stop_node(Cp7),
stop_node(Cp8),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
@@ -1669,7 +1651,7 @@ simple_line(doc) ->
"Make sure that there's just one winner."];
simple_line(Config) when is_list(Config) ->
Timeout = 60,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -1735,7 +1717,6 @@ simple_line(Config) when is_list(Config) ->
stop_node(Cp4),
stop_node(Cp5),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
otp_1849(suite) -> [];
@@ -1743,7 +1724,7 @@ otp_1849(doc) ->
["Test ticket: Global should keep track of all pids that set the same lock."];
otp_1849(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line {ok, Cp1} = start_node(cp1, Config),
@@ -1822,7 +1803,6 @@ otp_1849(Config) when is_list(Config) ->
stop_node(Cp2),
stop_node(Cp3),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
@@ -1840,7 +1820,7 @@ otp_3162(Config) when is_list(Config) ->
do_otp_3162(StartFun, Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line [Cp1, Cp2, Cp3] = StartFun(),
@@ -1898,7 +1878,6 @@ do_otp_3162(StartFun, Config) ->
stop_node(Cp2),
stop_node(Cp3),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
@@ -1907,7 +1886,7 @@ otp_5640(doc) ->
["OTP-5640. 'allow' multiple names for registered processes."];
otp_5640(Config) when is_list(Config) ->
Timeout = 25,
- ?line Dog = test_server:timetrap(test_server:seconds(Timeout)),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
init_condition(Config),
?line {ok, B} = start_node(b, Config),
@@ -1965,7 +1944,6 @@ otp_5640(Config) when is_list(Config) ->
write_high_level_trace(Config),
stop_node(B),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
otp_5640_proc(_Parent) ->
@@ -1979,7 +1957,7 @@ otp_5737(doc) ->
["OTP-5737. set_lock/3 and trans/4 accept Retries = 0."];
otp_5737(Config) when is_list(Config) ->
Timeout = 25,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
@@ -2000,7 +1978,6 @@ otp_5737(Config) when is_list(Config) ->
write_high_level_trace(Config),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
otp_6931(suite) -> [];
@@ -2025,7 +2002,7 @@ simple_disconnect(suite) -> [];
simple_disconnect(doc) -> ["OTP-5563. Disconnected nodes (not partitions)"];
simple_disconnect(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -2075,7 +2052,6 @@ simple_disconnect(Config) when is_list(Config) ->
write_high_level_trace(Config),
stop_nodes(Cps),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
%% Not used right now.
@@ -2118,7 +2094,7 @@ simple_resolve(suite) -> [];
simple_resolve(doc) -> ["OTP-5563. Partitions and names."];
simple_resolve(Config) when is_list(Config) ->
Timeout = 360,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -2245,7 +2221,6 @@ simple_resolve(Config) when is_list(Config) ->
write_high_level_trace(Config),
stop_nodes(Cps),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
simple_resolve2(suite) -> [];
@@ -2255,7 +2230,7 @@ simple_resolve2(Config) when is_list(Config) ->
%% always work to re-start z_2. "Cannot be a global bug."
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -2283,7 +2258,6 @@ simple_resolve2(Config) when is_list(Config) ->
write_high_level_trace(Config),
stop_nodes(Cps), % Not all nodes may be present, but it works anyway.
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
simple_resolve3(suite) -> [];
@@ -2292,7 +2266,7 @@ simple_resolve3(Config) when is_list(Config) ->
%% Continuation of simple_resolve.
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -2320,7 +2294,6 @@ simple_resolve3(Config) when is_list(Config) ->
write_high_level_trace(Config),
stop_nodes(Cps), % Not all nodes may be present, but it works anyway.
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
res({Res,Resolver}, [N1, A2, Z2], Cf) ->
@@ -2504,7 +2477,7 @@ leftover_name(suite) -> [];
leftover_name(doc) -> ["OTP-5563. Bug: nodedown while synching."];
leftover_name(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -2565,7 +2538,6 @@ leftover_name(Config) when is_list(Config) ->
write_high_level_trace(Config),
stop_nodes(Cps),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
%% Runs on n_1
@@ -2604,7 +2576,7 @@ re_register_name(Config) when is_list(Config) ->
%% occupied by links, that's all.
%% Later: now monitors are checked.
Timeout = 15,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
Me = self(),
@@ -2618,7 +2590,6 @@ re_register_name(Config) when is_list(Config) ->
receive {Pid2, MonitoredBy2} -> [_] = MonitoredBy2 end,
?line _ = global:unregister_name(name),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
proc(Parent) ->
@@ -2652,7 +2623,7 @@ do_name_exit(StartFun, Version, Config) ->
%% The current release uses monitors so this test is not so relevant.
Timeout = 60,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -2692,7 +2663,6 @@ do_name_exit(StartFun, Version, Config) ->
write_high_level_trace(Config),
stop_nodes(Cps),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
long_lock(Parent) ->
@@ -2709,7 +2679,7 @@ external_nodes(suite) -> [];
external_nodes(doc) -> ["OTP-5563. External nodes (cnodes)."];
external_nodes(Config) when is_list(Config) ->
Timeout = 30,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -2793,7 +2763,6 @@ external_nodes(Config) when is_list(Config) ->
?line ?UNTIL(length(get_ext_names()) =:= 0),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
get_ext_names() ->
@@ -2845,8 +2814,8 @@ many_nodes(suite) ->
many_nodes(doc) ->
["OTP-5770. Start many nodes. Make them connect at the same time."];
many_nodes(Config) when is_list(Config) ->
- Timeout = 180,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ Timeout = 240,
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -2902,7 +2871,6 @@ many_nodes(Config) when is_list(Config) ->
write_high_level_trace(Config),
?line stop_nodes(Cps),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
Diff = Time2 - Time,
Return = lists:flatten(io_lib:format("~w nodes took ~w ms",
[N_cps, Diff])),
@@ -2988,7 +2956,7 @@ sync_0(doc) ->
["OTP-5770. sync/0."];
sync_0(Config) when is_list(Config) ->
Timeout = 180,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
@@ -3013,7 +2981,6 @@ sync_0(Config) when is_list(Config) ->
stop_nodes(Cps),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
start_and_sync([]) ->
@@ -3031,7 +2998,7 @@ global_groups_change(suite) -> [];
global_groups_change(doc) -> ["Test change of global_groups parameter."];
global_groups_change(Config) ->
Timeout = 90,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line M = from($@, atom_to_list(node())),
@@ -3376,7 +3343,6 @@ global_groups_change(Config) ->
stop_node(CpE),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
sync_and_wait(Node) ->
@@ -3919,7 +3885,7 @@ global_lost_nodes(doc) ->
["Tests that locally loaded nodes do not loose contact with other nodes."];
global_lost_nodes(Config) when is_list(Config) ->
Timeout = 60,
- Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
@@ -3943,7 +3909,6 @@ global_lost_nodes(Config) when is_list(Config) ->
?line stop_node(Node1),
?line stop_node(Node2),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
global_load(MyName, OtherNode, OtherName) ->
@@ -3994,7 +3959,7 @@ mass_death(doc) ->
["Tests the simultaneous death of many processes with registered names"];
mass_death(Config) when is_list(Config) ->
Timeout = 90,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line OrigNames = global:registered_names(),
@@ -4023,9 +3988,9 @@ mass_death(Config) when is_list(Config) ->
{H,M,S} = time(),
io:format("Started probing: ~.4.0w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w~n",
[YYYY,MM,DD,H,M,S]),
- wait_mass_death(Dog, Nodes, OrigNames, erlang:now(), Config).
+ wait_mass_death(Nodes, OrigNames, erlang:now(), Config).
-wait_mass_death(Dog, Nodes, OrigNames, Then, Config) ->
+wait_mass_death(Nodes, OrigNames, Then, Config) ->
?line Names = global:registered_names(),
?line
case Names--OrigNames of
@@ -4036,12 +4001,11 @@ wait_mass_death(Dog, Nodes, OrigNames, Then, Config) ->
stop_node(Node)
end, Nodes),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
{comment,lists:flatten(io_lib:format("~.3f s~n", [T/1000.0]))};
Ndiff ->
?line io:format("Ndiff: ~p~n", [Ndiff]),
?line test_server:sleep(1000),
- ?line wait_mass_death(Dog, Nodes, OrigNames, Then, Config)
+ ?line wait_mass_death(Nodes, OrigNames, Then, Config)
end.
mass_spawn([]) ->
@@ -4213,7 +4177,7 @@ garbage_messages(suite) ->
[];
garbage_messages(Config) when is_list(Config) ->
Timeout = 25,
- ?line Dog = test_server:timetrap({seconds,Timeout}),
+ ct:timetrap({seconds,Timeout}),
init_high_level_trace(Timeout),
?line init_condition(Config),
?line [Slave] = start_nodes([garbage_messages], slave, Config),
@@ -4233,7 +4197,6 @@ garbage_messages(Config) when is_list(Config) ->
write_high_level_trace(Config),
?line stop_node(Slave),
?line init_condition(Config),
- ?line test_server:timetrap_cancel(Dog),
ok.
wait_for_ready_net(Config) ->
diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl
index 233e438dc9..e64d2914c4 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, 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]).
@@ -38,15 +41,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).
@@ -57,8 +60,13 @@ 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,
+ node_start_soon_after_crash,
+ set_cmd, clear_cmd, get_cmd,
+ kill_pid
+ ].
groups() ->
[].
@@ -80,17 +88,22 @@ 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"
- end,
+ {win32,_} ->
+ "-heart " ++ env_encode([{"HEART_COMMAND", no_reboot}|Envs]);
+ _ ->
+ "-heart " ++ env_encode(Envs)
+ 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 +116,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
@@ -125,6 +136,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
@@ -134,8 +149,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
@@ -143,32 +158,21 @@ restart(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, 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) ->
{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 +180,119 @@ 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,
+ 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(loose, heart_test_imm, [{"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, []),
+
+ T0 = now(),
+
+ 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),
+ 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:timetrap_scale_factor()) -> 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
+ pong ->
+ erlang:monitor_node(Node, true),
+ rpc:call(Node, init, reboot, []),
+ receive
+ {nodedown, Node} -> ok
+ after Tmo ->
+ test_server:fail(node_not_closed2)
+ end;
+ _ ->
+ test_server:fail(node_not_rebooted)
+ end.
+
%% 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 +300,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 +317,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.
@@ -274,57 +353,53 @@ 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
- ?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) ->
@@ -347,9 +422,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.
@@ -357,23 +430,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,[]);
@@ -390,15 +456,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
@@ -409,12 +473,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 " ++
- atom_conv(?MODULE) ++ " " ++ atom_conv(Function) ++ " " ++
- atom_conv(Argument),
- ?line start_node(Name, Params).
+ PA = filename:dirname(code:which(?MODULE)),
+ Params = "-heart " ++ env_encode(Env) ++ " -pa " ++ PA ++
+ " -s " ++
+ enc(?MODULE) ++ " " ++ enc(Function) ++ " " ++
+ enc(Argument),
+ start_node(Name, Params).
start_node(Name, Param) ->
test_server:start_node(Name, slave, [{args, Param}]).
@@ -480,3 +544,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)].
diff --git a/lib/kernel/test/interactive_shell_SUITE.erl b/lib/kernel/test/interactive_shell_SUITE.erl
index 4787f19250..7549e2c83e 100644
--- a/lib/kernel/test/interactive_shell_SUITE.erl
+++ b/lib/kernel/test/interactive_shell_SUITE.erl
@@ -30,19 +30,10 @@
init_per_testcase(_Func, Config) ->
Dog = test_server:timetrap(test_server:seconds(60)),
- Term = case os:getenv("TERM") of
- List when is_list(List) ->
- List;
- _ ->
- "dumb"
- end,
- os:putenv("TERM","vt100"),
- [{watchdog,Dog},{term,Term}|Config].
+ [{watchdog,Dog}|Config].
end_per_testcase(_Func, Config) ->
Dog = ?config(watchdog, Config),
- Term = ?config(term,Config),
- os:putenv("TERM",Term),
test_server:timetrap_cancel(Dog).
@@ -56,9 +47,19 @@ groups() ->
[].
init_per_suite(Config) ->
- Config.
+ Term = case os:getenv("TERM") of
+ List when is_list(List) ->
+ List;
+ _ ->
+ "dumb"
+ end,
+ os:putenv("TERM","vt100"),
+ DefShell = get_default_shell(),
+ [{default_shell,DefShell},{term,Term}|Config].
-end_per_suite(_Config) ->
+end_per_suite(Config) ->
+ Term = ?config(term,Config),
+ os:putenv("TERM",Term),
ok.
init_per_group(_GroupName, Config) ->
@@ -78,70 +79,118 @@ end_per_group(_GroupName, Config) ->
get_columns_and_rows(suite) -> [];
get_columns_and_rows(doc) -> ["Test that the shell can access columns and rows"];
get_columns_and_rows(Config) when is_list(Config) ->
- ?line rtnode([{putline,""},
- {putline, "2."},
- {getline, "2"},
- {putline,"io:columns()."},
-%% Behaviour change in R12B-5, returns 80
-%% {getline,"{error,enotsup}"},
- {getline,"{ok,80}"},
- {putline,"io:rows()."},
-%% Behaviour change in R12B-5, returns 24
-%% {getline,"{error,enotsup}"}
- {getline,"{ok,24}"}
- ],[]),
- ?line rtnode([{putline,""},
- {putline, "2."},
- {getline, "2"},
- {putline,"io:columns()."},
- {getline,"{ok,90}"},
- {putline,"io:rows()."},
- {getline,"{ok,40}"}],
- [],
- "stty rows 40; stty columns 90; ").
+ case proplists:get_value(default_shell,Config) of
+ old ->
+ %% Old shell tests
+ ?dbg(old_shell),
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline,"io:columns()."},
+ {getline_re,".*{error,enotsup}"},
+ {putline,"io:rows()."},
+ {getline_re,".*{error,enotsup}"}
+
+ ],[]),
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline,"io:columns()."},
+ {getline_re,".*{ok,90}"},
+ {putline,"io:rows()."},
+ {getline_re,".*{ok,40}"}],
+ [],
+ "stty rows 40; stty columns 90; ");
+ new ->
+ % New shell tests
+ ?dbg(new_shell),
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline,"io:columns()."},
+ %% Behaviour change in R12B-5, returns 80
+ %% {getline,"{error,enotsup}"},
+ {getline,"{ok,80}"},
+ {putline,"io:rows()."},
+ %% Behaviour change in R12B-5, returns 24
+ %% {getline,"{error,enotsup}"}
+ {getline,"{ok,24}"}
+ ],[]),
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline,"io:columns()."},
+ {getline,"{ok,90}"},
+ {putline,"io:rows()."},
+ {getline,"{ok,40}"}],
+ [],
+ "stty rows 40; stty columns 90; ")
+ end.
exit_initial(suite) -> [];
exit_initial(doc) -> ["Tests that exit of initial shell restarts shell"];
exit_initial(Config) when is_list(Config) ->
- ?line rtnode([{putline,""},
- {putline, "2."},
- {getline, "2"},
- {putline,"exit()."},
- {getline,""},
- {getline,"Eshell"},
- {putline,""},
- {putline,"35."},
- {getline,"35"}],[]).
+ case proplists:get_value(default_shell,Config) of
+ old ->
+ rtnode([{putline,""},
+ {putline, "2."},
+ {getline_re, ".*2"},
+ {putline,"exit()."},
+ {getline,""},
+ {getline,"Eshell"},
+ {putline,""},
+ {putline,"35."},
+ {getline_re,".*35"}],[]);
+ new ->
+ rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline,"exit()."},
+ {getline,""},
+ {getline,"Eshell"},
+ {putline,""},
+ {putline,"35."},
+ {getline_re,"35"}],[])
+ end.
job_control_local(suite) -> [];
job_control_local(doc) -> [ "Tests that local shell can be "
"started by means of job control" ];
job_control_local(Config) when is_list(Config) ->
- ?line rtnode([{putline,""},
- {putline, "2."},
- {getline, "2"},
- {putline,[7]},
- {sleep,timeout(short)},
- {putline,""},
- {getline," -->"},
- {putline,"s"},
- {putline,"c"},
- {putline_raw,""},
- {getline,"Eshell"},
- {putline_raw,""},
- {getline,"1>"},
- {putline,"35."},
- {getline,"35"}],[]).
+ case proplists:get_value(default_shell,Config) of
+ old ->
+ %% Old shell tests
+ {skip,"No new shell found"};
+ new ->
+ %% New shell tests
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline,[7]},
+ {sleep,timeout(short)},
+ {putline,""},
+ {getline," -->"},
+ {putline,"s"},
+ {putline,"c"},
+ {putline_raw,""},
+ {getline,"Eshell"},
+ {putline_raw,""},
+ {getline,"1>"},
+ {putline,"35."},
+ {getline,"35"}],[])
+ end.
job_control_remote(suite) -> [];
job_control_remote(doc) -> [ "Tests that remote shell can be "
"started by means of job control" ];
job_control_remote(Config) when is_list(Config) ->
- case node() of
- nonode@nohost ->
+ case {node(),proplists:get_value(default_shell,Config)} of
+ {nonode@nohost,_} ->
?line exit(not_distributed);
+ {_,old} ->
+ {skip,"No new shell found"};
_ ->
?line RNode = create_nodename(),
?line MyNode = atom_to_list(node()),
@@ -190,9 +239,11 @@ job_control_remote_noshell(doc) ->
[ "Tests that remote shell can be "
"started by means of job control to -noshell node" ];
job_control_remote_noshell(Config) when is_list(Config) ->
- case node() of
- nonode@nohost ->
+ case {node(),proplists:get_value(default_shell,Config)} of
+ {nonode@nohost,_} ->
?line exit(not_distributed);
+ {_,old} ->
+ {skip,"No new shell found"};
_ ->
?line RNode = create_nodename(),
?line NSNode = start_noshell_node(interactive_shell_noshell),
@@ -351,6 +402,33 @@ get_and_put(CPid, [{getline, Match}|T],N) ->
end
end;
+%% Hey ho copy paste from stdlib/io_proto_SUITE
+get_and_put(CPid, [{getline_re, Match}|T],N) ->
+ ?dbg({getline_re, Match}),
+ CPid ! {self(), {get_line, timeout(normal)}},
+ receive
+ {get_line, timeout} ->
+ error_logger:error_msg("~p: getline_re timeout waiting for \"~s\" "
+ "(command number ~p, skipped: ~p)~n",
+ [?MODULE, Match,N,get(getline_skipped)]),
+ {error, timeout};
+ {get_line, Data} ->
+ ?dbg({data,Data}),
+ case re:run(Data, Match,[{capture,none}]) of
+ match ->
+ erase(getline_skipped),
+ get_and_put(CPid, T,N+1);
+ _ ->
+ case get(getline_skipped) of
+ undefined ->
+ put(getline_skipped,[Data]);
+ List ->
+ put(getline_skipped,List ++ [Data])
+ end,
+ get_and_put(CPid, [{getline_re, Match}|T],N)
+ end
+ end;
+
get_and_put(CPid, [{putline_raw, Line}|T],N) ->
?dbg({putline_raw, Line}),
CPid ! {self(), {send_line, Line}},
@@ -631,6 +709,13 @@ get_data_within(Port, Timeout, Acc) ->
timeout
end.
-
-
-
+get_default_shell() ->
+ try
+ rtnode([{putline,""},
+ {putline, "whereis(user_drv)."},
+ {getline, "undefined"}],[]),
+ old
+ catch E:R ->
+ ?dbg({E,R}),
+ new
+ end.
diff --git a/lib/kernel/test/wrap_log_reader_SUITE.erl b/lib/kernel/test/wrap_log_reader_SUITE.erl
index 96dc3e6d33..6c47fda9c5 100644
--- a/lib/kernel/test/wrap_log_reader_SUITE.erl
+++ b/lib/kernel/test/wrap_log_reader_SUITE.erl
@@ -557,7 +557,7 @@ rec(M, Where) ->
M ->
ok;
Else -> ?t:fail({error, {Where, Else}})
- after 1000 -> ?t:fail({error, {Where, time_out}})
+ after 5000 -> ?t:fail({error, {Where, time_out}})
end.
pps() ->
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index c494f8a864..7254d714eb 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 2.15.2
+KERNEL_VSN = 2.15.3