1: %%
    2: %% %CopyrightBegin%
    3: %% 
    4: %% Copyright Ericsson AB 1997-2011. All Rights Reserved.
    5: %% 
    6: %% The contents of this file are subject to the Erlang Public License,
    7: %% Version 1.1, (the "License"); you may not use this file except in
    8: %% compliance with the License. You should have received a copy of the
    9: %% Erlang Public License along with this software. If not, it can be
   10: %% retrieved online at http://www.erlang.org/.
   11: %% 
   12: %% Software distributed under the License is distributed on an "AS IS"
   13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   14: %% the License for the specific language governing rights and limitations
   15: %% under the License.
   16: %% 
   17: %% %CopyrightEnd%
   18: %%
   19: 
   20: -module(after_SUITE).
   21: 
   22: %% Tests receive after.
   23: 
   24: -include_lib("test_server/include/test_server.hrl").
   25: 
   26: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   27: 	 init_per_group/2,end_per_group/2, 
   28: 	 t_after/1, receive_after/1, receive_after_big/1,
   29: 	 receive_after_errors/1, receive_var_zero/1, receive_zero/1,
   30: 	 multi_timeout/1, receive_after_32bit/1]).
   31: 
   32: -export([init_per_testcase/2, end_per_testcase/2]).
   33: 
   34: %% Internal exports.
   35: 
   36: -export([timeout_g/0]).
   37: 
   38: suite() -> [{ct_hooks,[ts_install_cth]}].
   39: 
   40: all() -> 
   41:     [t_after, receive_after, receive_after_big,
   42:      receive_after_errors, receive_var_zero, receive_zero,
   43:      multi_timeout, receive_after_32bit].
   44: 
   45: groups() -> 
   46:     [].
   47: 
   48: init_per_suite(Config) ->
   49:     Config.
   50: 
   51: end_per_suite(_Config) ->
   52:     ok.
   53: 
   54: init_per_group(_GroupName, Config) ->
   55:     Config.
   56: 
   57: end_per_group(_GroupName, Config) ->
   58:     Config.
   59: 
   60: 
   61: init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
   62:     Dog=?t:timetrap(?t:minutes(3)),
   63:     [{watchdog, Dog}|Config].
   64: 
   65: end_per_testcase(_Func, Config) ->
   66:     Dog=?config(watchdog, Config),
   67:     ?t:timetrap_cancel(Dog).
   68: 
   69: %% Tests for an old round-off error in 'receive after'."
   70: t_after(Config) when is_list(Config) ->
   71:     ?line spawn(fun frequent_process/0),
   72:     ?line Period = test_server:minutes(1),
   73:     ?line Before = erlang:now(),
   74:     receive
   75: 	after Period ->
   76: 		?line After = erlang:now(),
   77: 		?line report(Period, Before, After)
   78: 	end.
   79: 
   80: 
   81: report(Period, Before, After) ->
   82:     ?line Elapsed = (element(1, After)*1000000000
   83: 		     +element(2, After)*1000
   84: 		     +element(3, After) div 1000) -
   85: 	(element(1,Before)*1000000000
   86: 	 + element(2,Before)*1000 + element(3,Before) div 1000),
   87:     ?line case Elapsed*100 / Period of
   88: 	      Percent when Percent > 100.10 ->
   89: 		  ?line test_server:fail({too_inaccurate, Percent});
   90: 	      Percent when Percent < 100.0 ->
   91: 		  ?line test_server:fail({too_early, Percent});
   92: 	      Percent ->
   93: 		  ?line Comment = io_lib:format("Elapsed/expected: ~.2f %",
   94: 						[Percent]),
   95: 		  {comment, lists:flatten(Comment)}
   96: 	  end.
   97: 
   98: frequent_process() ->
   99:     receive
  100: 	after 100 ->
  101: 		?line frequent_process()
  102: 	end.
  103: 
  104: receive_after(doc) ->
  105:     "Test that 'receive after' works (doesn't hang). "
  106:     "The test takes 10 seconds to complete.";
  107: receive_after(Config) when is_list(Config) ->
  108:     ?line receive_after1(5000).
  109: 
  110: receive_after1(1) ->
  111:     ?line io:format("Testing: receive after ~p~n", [1]), 
  112:     ?line receive after 1 -> ok end;
  113: receive_after1(N) -> 
  114:     ?line io:format("Testing: receive after ~p~n", [N]), 
  115:     ?line receive after N -> receive_after1(N div 2) end.
  116: 
  117: receive_after_big(Config) when is_list(Config) ->
  118:     %% Test that 'receive after' with a 32 bit number works.
  119:     receive_after_big1(16#f7654321),
  120:     receive_after_big2().
  121: 
  122: receive_after_big1(Timeout) ->
  123:     Self = self(),
  124:     erlang:yield(),
  125:     spawn(fun() -> Self ! here_is_a_message end),
  126:     ok = receive
  127: 	     here_is_a_message ->
  128: 		 ok
  129: 	 after Timeout ->
  130: 		 %% We test that the timeout can be set,
  131: 		 %% not that an timeout occurs after the appropriate delay
  132: 		 %% (48 days, 56 minutes, 48 seconds)!
  133: 		 timeout
  134: 	 end.
  135: 
  136: receive_after_big2() ->
  137:     Self = self(),
  138:     erlang:yield(),
  139:     spawn(fun() -> Self ! here_is_a_message end),
  140:     ok = receive
  141: 	     here_is_a_message ->
  142: 		 ok
  143: 	 after 16#f7999977 ->
  144: 		 %% We only test that the timeout can be set.
  145: 		 timeout
  146: 	 end.
  147: 
  148: -define(TryAfter(Timeout), 
  149: 	{'EXIT',{timeout_value,_}} = (catch receive mission -> exit(impossible) after Timeout -> ok end),
  150: 	{'EXIT',{timeout_value,_}} = (catch receive after Timeout -> ok end),
  151: 	try_after(Timeout)).
  152: 
  153: %% Test error cases for 'receive after'.
  154: receive_after_errors(Config) when is_list(Config) ->
  155:     ?line ?TryAfter(-1),
  156:     ?line ?TryAfter(0.0),
  157:     ?line ?TryAfter(3.14),
  158:     ?line ?TryAfter(16#100000000),
  159:     ?line ?TryAfter(392347129847294724972398472984729847129874),
  160:     ?line ?TryAfter(16#3fffffffffffffff),
  161:     ?line ?TryAfter(16#ffffffffffffffff),
  162:     ?line ?TryAfter(-16#100000000),
  163:     ?line ?TryAfter(-3891278094774921784123987129848),
  164:     ?line ?TryAfter(xxx),
  165:     ok.
  166: 
  167: try_after(Timeout) ->
  168:     {'EXIT',{timeout_value,_}} = (catch receive after Timeout -> ok end).
  169: 
  170: receive_var_zero(doc) -> "Test 'after Z', when Z == 0.";
  171: receive_var_zero(Config) when is_list(Config) ->
  172:     self() ! x,
  173:     self() ! y,
  174:     Z = zero(),
  175:     timeout = receive
  176: 		  z -> ok
  177: 	      after Z -> timeout
  178: 	      end,
  179:     timeout = receive
  180: 	      after Z -> timeout
  181: 	      end,
  182:     self() ! w,
  183:     receive
  184: 	x -> ok;
  185: 	Other ->
  186: 	    ?line ?t:fail({bad_message,Other})
  187:     end.
  188: 
  189: zero() -> 0.
  190: 
  191: %% Test 'after 0'.
  192: receive_zero(Config) when is_list(Config) ->
  193:     self() ! x,
  194:     self() ! y,
  195:     timeout = receive
  196: 		  z -> ok
  197: 	      after 0 ->
  198: 		      timeout
  199: 	      end,
  200:     self() ! w,
  201:     timeout = receive
  202:               after 0 -> timeout
  203:               end,
  204:     receive
  205: 	x -> ok;
  206: 	Other ->
  207: 	    ?line ?t:fail({bad_message,Other})
  208:     end.
  209: 
  210: multi_timeout(doc) ->
  211:     "Test for catching invalid assertion in erl_message.c (in queue_message)."
  212:     "This failed (dumped core) with debug-compiled emulator.";
  213: multi_timeout(Config) when is_list(Config) ->
  214:     ?line P = spawn(?MODULE, timeout_g, []),
  215:     ?line P ! a,
  216:     ?line P ! b,
  217:     ?line receive
  218: 	  after 1000 -> ok
  219: 	  end,
  220:     ?line P ! c,
  221:     ?line receive
  222: 	  after 1000 -> ok
  223: 	  end,
  224:     ?line P ! d,
  225:     ok.
  226: 
  227: timeout_g() ->
  228:     ?line receive
  229: 	a -> ok
  230:     end,
  231:     ?line receive
  232: 	  after 100000 -> ok
  233: 	  end,
  234:     ok.
  235: 
  236: %% OTP-7493: Timeout for 32 bit numbers (such as 16#ffffFFFF) could
  237: %% timeout at once.
  238: receive_after_32bit(Config) when is_list(Config) ->
  239:     T = 16#ffffFFFF,
  240:     Pids = [spawn_link(fun() -> recv_after_32bit(I, T) end) ||
  241: 	       I <- lists:seq(1, 2048)],
  242: 
  243:     %% Wait two seconds for any of the processes to timeout too early.
  244:     receive after 2000 -> ok end,
  245: 
  246:     %% Kill the processes.
  247:     [begin unlink(Pid), exit(Pid, kill) end || Pid <- Pids],
  248:     ok.
  249: 
  250: recv_after_32bit(I, T) when I rem 2 =:= 0 ->
  251:     receive after T -> exit(timeout) end;
  252: recv_after_32bit(_, _) ->
  253:     receive after 16#ffffFFFF -> exit(timeout) end.
  254: