aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test/after_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/test/after_SUITE.erl')
-rw-r--r--erts/emulator/test/after_SUITE.erl233
1 files changed, 233 insertions, 0 deletions
diff --git a/erts/emulator/test/after_SUITE.erl b/erts/emulator/test/after_SUITE.erl
new file mode 100644
index 0000000000..3e1a871408
--- /dev/null
+++ b/erts/emulator/test/after_SUITE.erl
@@ -0,0 +1,233 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(after_SUITE).
+
+%% Tests receive after.
+
+-include("test_server.hrl").
+
+-export([all/1, t_after/1, receive_after/1, receive_after_big/1,
+ receive_after_errors/1, receive_var_zero/1, receive_zero/1,
+ multi_timeout/1, receive_after_32bit/1]).
+
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+%% Internal exports.
+
+-export([timeout_g/0]).
+
+all(suite) ->
+ [t_after, receive_after, receive_after_big, receive_after_errors,
+ receive_var_zero, receive_zero, multi_timeout, receive_after_32bit].
+
+init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
+ Dog=?t:timetrap(?t:minutes(3)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Func, Config) ->
+ Dog=?config(watchdog, Config),
+ ?t:timetrap_cancel(Dog).
+
+%% Tests for an old round-off error in 'receive after'."
+t_after(Config) when is_list(Config) ->
+ ?line spawn(fun frequent_process/0),
+ ?line Period = test_server:minutes(1),
+ ?line Before = erlang:now(),
+ receive
+ after Period ->
+ ?line After = erlang:now(),
+ ?line report(Period, Before, After)
+ end.
+
+
+report(Period, Before, After) ->
+ ?line Elapsed = (element(1, After)*1000000000
+ +element(2, After)*1000
+ +element(3, After) div 1000) -
+ (element(1,Before)*1000000000
+ + element(2,Before)*1000 + element(3,Before) div 1000),
+ ?line case Elapsed*100 / Period of
+ Percent when Percent > 100.10 ->
+ ?line test_server:fail({too_inaccurate, Percent});
+ Percent when Percent < 100.0 ->
+ ?line test_server:fail({too_early, Percent});
+ Percent ->
+ ?line Comment = io_lib:format("Elapsed/expected: ~.2f %",
+ [Percent]),
+ {comment, lists:flatten(Comment)}
+ end.
+
+frequent_process() ->
+ receive
+ after 100 ->
+ ?line frequent_process()
+ end.
+
+receive_after(doc) ->
+ "Test that 'receive after' works (doesn't hang). "
+ "The test takes 10 seconds to complete.";
+receive_after(Config) when is_list(Config) ->
+ ?line receive_after1(5000).
+
+receive_after1(1) ->
+ ?line io:format("Testing: receive after ~p~n", [1]),
+ ?line receive after 1 -> ok end;
+receive_after1(N) ->
+ ?line io:format("Testing: receive after ~p~n", [N]),
+ ?line receive after N -> receive_after1(N div 2) end.
+
+receive_after_big(Config) when is_list(Config) ->
+ %% Test that 'receive after' with a 32 bit number works.
+ receive_after_big1(16#f7654321),
+ receive_after_big2().
+
+receive_after_big1(Timeout) ->
+ Self = self(),
+ erlang:yield(),
+ spawn(fun() -> Self ! here_is_a_message end),
+ ok = receive
+ here_is_a_message ->
+ ok
+ after Timeout ->
+ %% We test that the timeout can be set,
+ %% not that an timeout occurs after the appropriate delay
+ %% (48 days, 56 minutes, 48 seconds)!
+ timeout
+ end.
+
+receive_after_big2() ->
+ Self = self(),
+ erlang:yield(),
+ spawn(fun() -> Self ! here_is_a_message end),
+ ok = receive
+ here_is_a_message ->
+ ok
+ after 16#f7999977 ->
+ %% We only test that the timeout can be set.
+ timeout
+ end.
+
+-define(TryAfter(Timeout),
+ {'EXIT',{timeout_value,_}} = (catch receive mission -> exit(impossible) after Timeout -> ok end),
+ {'EXIT',{timeout_value,_}} = (catch receive after Timeout -> ok end),
+ try_after(Timeout)).
+
+%% Test error cases for 'receive after'.
+receive_after_errors(Config) when is_list(Config) ->
+ ?line ?TryAfter(-1),
+ ?line ?TryAfter(0.0),
+ ?line ?TryAfter(3.14),
+ ?line ?TryAfter(16#100000000),
+ ?line ?TryAfter(392347129847294724972398472984729847129874),
+ ?line ?TryAfter(16#3fffffffffffffff),
+ ?line ?TryAfter(16#ffffffffffffffff),
+ ?line ?TryAfter(-16#100000000),
+ ?line ?TryAfter(-3891278094774921784123987129848),
+ ?line ?TryAfter(xxx),
+ ok.
+
+try_after(Timeout) ->
+ {'EXIT',{timeout_value,_}} = (catch receive after Timeout -> ok end).
+
+receive_var_zero(doc) -> "Test 'after Z', when Z == 0.";
+receive_var_zero(Config) when is_list(Config) ->
+ self() ! x,
+ self() ! y,
+ Z = zero(),
+ timeout = receive
+ z -> ok
+ after Z -> timeout
+ end,
+ timeout = receive
+ after Z -> timeout
+ end,
+ self() ! w,
+ receive
+ x -> ok;
+ Other ->
+ ?line ?t:fail({bad_message,Other})
+ end.
+
+zero() -> 0.
+
+%% Test 'after 0'.
+receive_zero(Config) when is_list(Config) ->
+ self() ! x,
+ self() ! y,
+ timeout = receive
+ z -> ok
+ after 0 ->
+ timeout
+ end,
+ self() ! w,
+ timeout = receive
+ after 0 -> timeout
+ end,
+ receive
+ x -> ok;
+ Other ->
+ ?line ?t:fail({bad_message,Other})
+ end.
+
+multi_timeout(doc) ->
+ "Test for catching invalid assertion in erl_message.c (in queue_message)."
+ "This failed (dumped core) with debug-compiled emulator.";
+multi_timeout(Config) when is_list(Config) ->
+ ?line P = spawn(?MODULE, timeout_g, []),
+ ?line P ! a,
+ ?line P ! b,
+ ?line receive
+ after 1000 -> ok
+ end,
+ ?line P ! c,
+ ?line receive
+ after 1000 -> ok
+ end,
+ ?line P ! d,
+ ok.
+
+timeout_g() ->
+ ?line receive
+ a -> ok
+ end,
+ ?line receive
+ after 100000 -> ok
+ end,
+ ok.
+
+%% OTP-7493: Timeout for 32 bit numbers (such as 16#ffffFFFF) could
+%% timeout at once.
+receive_after_32bit(Config) when is_list(Config) ->
+ T = 16#ffffFFFF,
+ Pids = [spawn_link(fun() -> recv_after_32bit(I, T) end) ||
+ I <- lists:seq(1, 2048)],
+
+ %% Wait two seconds for any of the processes to timeout too early.
+ receive after 2000 -> ok end,
+
+ %% Kill the processes.
+ [begin unlink(Pid), exit(Pid, kill) end || Pid <- Pids],
+ ok.
+
+recv_after_32bit(I, T) when I rem 2 =:= 0 ->
+ receive after T -> exit(timeout) end;
+recv_after_32bit(_, _) ->
+ receive after 16#ffffFFFF -> exit(timeout) end.
+