diff options
Diffstat (limited to 'lib/kernel/test/seq_trace_SUITE.erl')
-rw-r--r-- | lib/kernel/test/seq_trace_SUITE.erl | 578 |
1 files changed, 327 insertions, 251 deletions
diff --git a/lib/kernel/test/seq_trace_SUITE.erl b/lib/kernel/test/seq_trace_SUITE.erl index 6a63f7bc9c..cf4bf11328 100644 --- a/lib/kernel/test/seq_trace_SUITE.erl +++ b/lib/kernel/test/seq_trace_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2011. All Rights Reserved. +%% Copyright Ericsson AB 1998-2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -25,30 +25,29 @@ -export([token_set_get/1, tracer_set_get/1, print/1, send/1, distributed_send/1, recv/1, distributed_recv/1, trace_exit/1, distributed_exit/1, call/1, port/1, - match_set_seq_token/1, gc_seq_token/1]). + match_set_seq_token/1, gc_seq_token/1, label_capability_mismatch/1]). -% internal exports +%% internal exports -export([simple_tracer/2, one_time_receiver/0, one_time_receiver/1, start_tracer/0, stop_tracer/1, do_match_set_seq_token/1, do_gc_seq_token/1, countdown_start/2]). - %-define(line_trace, 1). --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). -define(TIMESTAMP_MODES, [no_timestamp, timestamp, monotonic_timestamp, strict_monotonic_timestamp]). --define(default_timeout, ?t:minutes(1)). - -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,1}}]. all() -> [token_set_get, tracer_set_get, print, send, distributed_send, recv, distributed_recv, trace_exit, distributed_exit, call, port, match_set_seq_token, - gc_seq_token]. + gc_seq_token, label_capability_mismatch]. groups() -> []. @@ -67,18 +66,13 @@ end_per_group(_GroupName, Config) -> init_per_testcase(_Case, Config) -> - ?line Dog = test_server:timetrap(?default_timeout), - [{watchdog, Dog}|Config]. + Config. -end_per_testcase(_Case, Config) -> - Dog=?config(watchdog, Config), - test_server:timetrap_cancel(Dog), +end_per_testcase(_Case, _Config) -> ok. %% Verifies that the set_token and get_token functions work as expected -token_set_get(doc) -> []; -token_set_get(suite) -> []; token_set_get(Config) when is_list(Config) -> do_token_set_get(timestamp), do_token_set_get(monotonic_timestamp), @@ -91,371 +85,436 @@ do_token_set_get(TsType) -> strict_monotonic_timestamp -> 23; monotonic_timestamp -> 39 end, - ?line Self = self(), - ?line seq_trace:reset_trace(), + Self = self(), + seq_trace:reset_trace(), %% Test that initial seq_trace is disabled - ?line [] = seq_trace:get_token(), + [] = seq_trace:get_token(), %% Test setting and reading the different fields - ?line 0 = seq_trace:set_token(label,17), - ?line {label,17} = seq_trace:get_token(label), - ?line false = seq_trace:set_token(print,true), - ?line {print,true} = seq_trace:get_token(print), - ?line false = seq_trace:set_token(send,true), - ?line {send,true} = seq_trace:get_token(send), - ?line false = seq_trace:set_token('receive',true), - ?line {'receive',true} = seq_trace:get_token('receive'), - ?line false = seq_trace:set_token(TsType,true), - ?line {TsType,true} = seq_trace:get_token(TsType), + 0 = seq_trace:set_token(label,{my_label,1}), + {label,{my_label,1}} = seq_trace:get_token(label), + false = seq_trace:set_token(print,true), + {print,true} = seq_trace:get_token(print), + false = seq_trace:set_token(send,true), + {send,true} = seq_trace:get_token(send), + false = seq_trace:set_token('receive',true), + {'receive',true} = seq_trace:get_token('receive'), + false = seq_trace:set_token(TsType,true), + {TsType,true} = seq_trace:get_token(TsType), %% Check the whole token - ?line {Flags,17,0,Self,0} = seq_trace:get_token(), % all flags are set + {Flags,{my_label,1},0,Self,0} = seq_trace:get_token(), % all flags are set %% Test setting and reading the 'serial' field - ?line {0,0} = seq_trace:set_token(serial,{3,5}), - ?line {serial,{3,5}} = seq_trace:get_token(serial), + {0,0} = seq_trace:set_token(serial,{3,5}), + {serial,{3,5}} = seq_trace:get_token(serial), %% Check the whole token, test that a whole token can be set and get - ?line {Flags,17,5,Self,3} = seq_trace:get_token(), - ?line seq_trace:set_token({Flags,19,7,Self,5}), - ?line {Flags,19,7,Self,5} = seq_trace:get_token(), + {Flags,{my_label,1},5,Self,3} = seq_trace:get_token(), + seq_trace:set_token({Flags,19,7,Self,5}), + {Flags,19,7,Self,5} = seq_trace:get_token(), %% Check that receive timeout does not reset token - ?line receive after 0 -> ok end, - ?line {Flags,19,7,Self,5} = seq_trace:get_token(), + receive after 0 -> ok end, + {Flags,19,7,Self,5} = seq_trace:get_token(), %% Check that token can be unset - ?line {Flags,19,7,Self,5} = seq_trace:set_token([]), - ?line [] = seq_trace:get_token(), + {Flags,19,7,Self,5} = seq_trace:set_token([]), + [] = seq_trace:get_token(), %% Check that Previous serial counter survived unset token - ?line 0 = seq_trace:set_token(label, 17), - ?line {0,17,0,Self,5} = seq_trace:get_token(), + 0 = seq_trace:set_token(label, 17), + {0,17,0,Self,5} = seq_trace:get_token(), %% Check that reset_trace resets the token and clears %% the Previous serial counter - ?line seq_trace:reset_trace(), - ?line [] = seq_trace:get_token(), - ?line 0 = seq_trace:set_token(label, 19), - ?line {0,19,0,Self,0} = seq_trace:get_token(), + seq_trace:reset_trace(), + [] = seq_trace:get_token(), + 0 = seq_trace:set_token(label, 19), + {0,19,0,Self,0} = seq_trace:get_token(), %% Cleanup - ?line seq_trace:reset_trace(), + seq_trace:reset_trace(), ok. -tracer_set_get(doc) -> []; -tracer_set_get(suite) -> []; tracer_set_get(Config) when is_list(Config) -> - ?line Self = self(), - ?line seq_trace:set_system_tracer(self()), - ?line Self = seq_trace:get_system_tracer(), - ?line Self = seq_trace:set_system_tracer(false), - ?line false = seq_trace:get_system_tracer(), + Self = self(), + seq_trace:set_system_tracer(self()), + Self = seq_trace:get_system_tracer(), + Self = seq_trace:set_system_tracer(false), + false = seq_trace:get_system_tracer(), %% Set the system tracer to a port. - ?line Port = load_tracer(Config), - ?line seq_trace:set_system_tracer(Port), - ?line Port = seq_trace:get_system_tracer(), - ?line Port = seq_trace:set_system_tracer(false), - ?line false = seq_trace:get_system_tracer(), + Port = load_tracer(Config), + seq_trace:set_system_tracer(Port), + Port = seq_trace:get_system_tracer(), + Port = seq_trace:set_system_tracer(false), + false = seq_trace:get_system_tracer(), ok. -print(doc) -> []; -print(suite) -> []; print(Config) when is_list(Config) -> lists:foreach(fun do_print/1, ?TIMESTAMP_MODES). do_print(TsType) -> - ?line start_tracer(), - ?line set_token_flags([print, TsType]), - ?line seq_trace:print(0,print1), - ?line seq_trace:print(1,print2), - ?line seq_trace:print(print3), - ?line seq_trace:reset_trace(), - ?line [{0,{print,_,_,[],print1}, Ts0}, + start_tracer(), + set_token_flags([print, TsType]), + seq_trace:print(0,print1), + seq_trace:print(1,print2), + seq_trace:print(print3), + seq_trace:reset_trace(), + [{0,{print,_,_,[],print1}, Ts0}, {0,{print,_,_,[],print3}, Ts1}] = stop_tracer(2), check_ts(TsType, Ts0), check_ts(TsType, Ts1). -send(doc) -> []; -send(suite) -> []; send(Config) when is_list(Config) -> lists:foreach(fun do_send/1, ?TIMESTAMP_MODES). do_send(TsType) -> - ?line seq_trace:reset_trace(), - ?line start_tracer(), - ?line Receiver = spawn(?MODULE,one_time_receiver,[]), - ?line set_token_flags([send, TsType]), - ?line Receiver ! send, - ?line Self = self(), - ?line seq_trace:reset_trace(), - ?line [{0,{send,_,Self,Receiver,send}, Ts}] = stop_tracer(1), + seq_trace:reset_trace(), + start_tracer(), + Receiver = spawn(?MODULE,one_time_receiver,[]), + Label = make_ref(), + seq_trace:set_token(label,Label), + set_token_flags([send, TsType]), + Receiver ! send, + Self = self(), + seq_trace:reset_trace(), + [{Label,{send,_,Self,Receiver,send}, Ts}] = stop_tracer(1), check_ts(TsType, Ts). -distributed_send(doc) -> []; -distributed_send(suite) -> []; distributed_send(Config) when is_list(Config) -> lists:foreach(fun do_distributed_send/1, ?TIMESTAMP_MODES). do_distributed_send(TsType) -> - ?line {ok,Node} = start_node(seq_trace_other,[]), - ?line {_,Dir} = code:is_loaded(?MODULE), - ?line Mdir = filename:dirname(Dir), - ?line true = rpc:call(Node,code,add_patha,[Mdir]), - ?line seq_trace:reset_trace(), - ?line start_tracer(), - ?line Receiver = spawn(Node,?MODULE,one_time_receiver,[]), - ?line set_token_flags([send,TsType]), - ?line Receiver ! send, - ?line Self = self(), - ?line seq_trace:reset_trace(), - ?line stop_node(Node), - ?line [{0,{send,_,Self,Receiver,send}, Ts}] = stop_tracer(1), + {ok,Node} = start_node(seq_trace_other,[]), + {_,Dir} = code:is_loaded(?MODULE), + Mdir = filename:dirname(Dir), + true = rpc:call(Node,code,add_patha,[Mdir]), + seq_trace:reset_trace(), + start_tracer(), + Receiver = spawn(Node,?MODULE,one_time_receiver,[]), + + %% Make sure complex labels survive the trip. + Label = make_ref(), + seq_trace:set_token(label,Label), + set_token_flags([send,TsType]), + + Receiver ! send, + Self = self(), + seq_trace:reset_trace(), + stop_node(Node), + [{Label,{send,_,Self,Receiver,send}, Ts}] = stop_tracer(1), check_ts(TsType, Ts). - -recv(doc) -> []; -recv(suite) -> []; + recv(Config) when is_list(Config) -> lists:foreach(fun do_recv/1, ?TIMESTAMP_MODES). do_recv(TsType) -> - ?line seq_trace:reset_trace(), - ?line start_tracer(), - ?line Receiver = spawn(?MODULE,one_time_receiver,[]), - ?line set_token_flags(['receive',TsType]), - ?line Receiver ! 'receive', + seq_trace:reset_trace(), + start_tracer(), + Receiver = spawn(?MODULE,one_time_receiver,[]), + set_token_flags(['receive',TsType]), + Receiver ! 'receive', %% let the other process receive the message: - ?line receive after 1 -> ok end, - ?line Self = self(), - ?line seq_trace:reset_trace(), - ?line [{0,{'receive',_,Self,Receiver,'receive'}, Ts}] = stop_tracer(1), + receive after 1 -> ok end, + Self = self(), + seq_trace:reset_trace(), + [{0,{'receive',_,Self,Receiver,'receive'}, Ts}] = stop_tracer(1), check_ts(TsType, Ts). -distributed_recv(doc) -> []; -distributed_recv(suite) -> []; distributed_recv(Config) when is_list(Config) -> lists:foreach(fun do_distributed_recv/1, ?TIMESTAMP_MODES). do_distributed_recv(TsType) -> - ?line {ok,Node} = start_node(seq_trace_other,[]), - ?line {_,Dir} = code:is_loaded(?MODULE), - ?line Mdir = filename:dirname(Dir), - ?line true = rpc:call(Node,code,add_patha,[Mdir]), - ?line seq_trace:reset_trace(), - ?line rpc:call(Node,?MODULE,start_tracer,[]), - ?line Receiver = spawn(Node,?MODULE,one_time_receiver,[]), - ?line set_token_flags(['receive',TsType]), - ?line Receiver ! 'receive', + {ok,Node} = start_node(seq_trace_other,[]), + {_,Dir} = code:is_loaded(?MODULE), + Mdir = filename:dirname(Dir), + true = rpc:call(Node,code,add_patha,[Mdir]), + seq_trace:reset_trace(), + rpc:call(Node,?MODULE,start_tracer,[]), + Receiver = spawn(Node,?MODULE,one_time_receiver,[]), + + %% Make sure complex labels survive the trip. + Label = make_ref(), + seq_trace:set_token(label,Label), + set_token_flags(['receive',TsType]), + + Receiver ! 'receive', %% let the other process receive the message: - ?line receive after 1 -> ok end, - ?line Self = self(), - ?line seq_trace:reset_trace(), - ?line Result = rpc:call(Node,?MODULE,stop_tracer,[1]), - ?line stop_node(Node), - ?line ok = io:format("~p~n",[Result]), - ?line [{0,{'receive',_,Self,Receiver,'receive'}, Ts}] = Result, + receive after 1 -> ok end, + Self = self(), + seq_trace:reset_trace(), + Result = rpc:call(Node,?MODULE,stop_tracer,[1]), + stop_node(Node), + ok = io:format("~p~n",[Result]), + [{Label,{'receive',_,Self,Receiver,'receive'}, Ts}] = Result, check_ts(TsType, Ts). -trace_exit(doc) -> []; -trace_exit(suite) -> []; trace_exit(Config) when is_list(Config) -> lists:foreach(fun do_trace_exit/1, ?TIMESTAMP_MODES). do_trace_exit(TsType) -> - ?line seq_trace:reset_trace(), - ?line start_tracer(), - ?line Receiver = spawn_link(?MODULE, one_time_receiver, [exit]), - ?line process_flag(trap_exit, true), - ?line set_token_flags([send, TsType]), - ?line Receiver ! {before, exit}, + seq_trace:reset_trace(), + start_tracer(), + Receiver = spawn_link(?MODULE, one_time_receiver, [exit]), + process_flag(trap_exit, true), + + %% Make sure complex labels survive the trip. + Label = make_ref(), + seq_trace:set_token(label,Label), + set_token_flags([send, TsType]), + + Receiver ! {before, exit}, %% let the other process receive the message: - ?line receive + receive {'EXIT', Receiver, {exit, {before, exit}}} -> seq_trace:set_token([]); Other -> seq_trace:set_token([]), - ?t:fail({received, Other}) + ct:fail({received, Other}) end, - ?line Self = self(), - ?line Result = stop_tracer(2), - ?line seq_trace:reset_trace(), - ?line ok = io:format("~p~n", [Result]), - ?line [{0, {send, {0,1}, Self, Receiver, {before, exit}}, Ts0}, - {0, {send, {1,2}, Receiver, Self, + Self = self(), + Result = stop_tracer(2), + seq_trace:reset_trace(), + ok = io:format("~p~n", [Result]), + [{Label, {send, {0,1}, Self, Receiver, {before, exit}}, Ts0}, + {Label, {send, {1,2}, Receiver, Self, {'EXIT', Receiver, {exit, {before, exit}}}}, Ts1}] = Result, check_ts(TsType, Ts0), check_ts(TsType, Ts1). -distributed_exit(doc) -> []; -distributed_exit(suite) -> []; distributed_exit(Config) when is_list(Config) -> lists:foreach(fun do_distributed_exit/1, ?TIMESTAMP_MODES). do_distributed_exit(TsType) -> - ?line {ok, Node} = start_node(seq_trace_other, []), - ?line {_, Dir} = code:is_loaded(?MODULE), - ?line Mdir = filename:dirname(Dir), - ?line true = rpc:call(Node, code, add_patha, [Mdir]), - ?line seq_trace:reset_trace(), - ?line rpc:call(Node, ?MODULE, start_tracer,[]), - ?line Receiver = spawn_link(Node, ?MODULE, one_time_receiver, [exit]), - ?line process_flag(trap_exit, true), - ?line set_token_flags([send, TsType]), - ?line Receiver ! {before, exit}, + {ok, Node} = start_node(seq_trace_other, []), + {_, Dir} = code:is_loaded(?MODULE), + Mdir = filename:dirname(Dir), + true = rpc:call(Node, code, add_patha, [Mdir]), + seq_trace:reset_trace(), + rpc:call(Node, ?MODULE, start_tracer,[]), + Receiver = spawn_link(Node, ?MODULE, one_time_receiver, [exit]), + process_flag(trap_exit, true), + set_token_flags([send, TsType]), + Receiver ! {before, exit}, %% let the other process receive the message: - ?line receive + receive {'EXIT', Receiver, {exit, {before, exit}}} -> seq_trace:set_token([]); Other -> seq_trace:set_token([]), - ?t:fail({received, Other}) + ct:fail({received, Other}) end, - ?line Self = self(), - ?line Result = rpc:call(Node, ?MODULE, stop_tracer, [1]), - ?line seq_trace:reset_trace(), - ?line stop_node(Node), - ?line ok = io:format("~p~n", [Result]), - ?line [{0, {send, {1, 2}, Receiver, Self, + Self = self(), + Result = rpc:call(Node, ?MODULE, stop_tracer, [1]), + seq_trace:reset_trace(), + stop_node(Node), + ok = io:format("~p~n", [Result]), + [{0, {send, {1, 2}, Receiver, Self, {'EXIT', Receiver, {exit, {before, exit}}}}, Ts}] = Result, check_ts(TsType, Ts). +label_capability_mismatch(Config) when is_list(Config) -> + Releases = ["20_latest"], + Available = [Rel || Rel <- Releases, test_server:is_release_available(Rel)], + case Available of + [] -> {skipped, "No incompatible releases available"}; + _ -> + lists:foreach(fun do_incompatible_labels/1, Available), + lists:foreach(fun do_compatible_labels/1, Available), + ok + end. + +do_incompatible_labels(Rel) -> + Cookie = atom_to_list(erlang:get_cookie()), + {ok, Node} = test_server:start_node( + list_to_atom(atom_to_list(?MODULE)++"_"++Rel), peer, + [{args, " -setcookie "++Cookie}, {erl, [{release, Rel}]}]), + + {_,Dir} = code:is_loaded(?MODULE), + Mdir = filename:dirname(Dir), + true = rpc:call(Node,code,add_patha,[Mdir]), + seq_trace:reset_trace(), + rpc:call(Node,?MODULE,start_tracer,[]), + Receiver = spawn(Node,?MODULE,one_time_receiver,[]), + + %% This node does not support arbitrary labels, so it must fail with a + %% timeout as the token is dropped silently. + seq_trace:set_token(label,make_ref()), + seq_trace:set_token('receive',true), + + Receiver ! 'receive', + %% let the other process receive the message: + receive after 10 -> ok end, + seq_trace:reset_trace(), + + {error,timeout} = rpc:call(Node,?MODULE,stop_tracer,[1]), + stop_node(Node), + ok. + +do_compatible_labels(Rel) -> + Cookie = atom_to_list(erlang:get_cookie()), + {ok, Node} = test_server:start_node( + list_to_atom(atom_to_list(?MODULE)++"_"++Rel), peer, + [{args, " -setcookie "++Cookie}, {erl, [{release, Rel}]}]), + + {_,Dir} = code:is_loaded(?MODULE), + Mdir = filename:dirname(Dir), + true = rpc:call(Node,code,add_patha,[Mdir]), + seq_trace:reset_trace(), + rpc:call(Node,?MODULE,start_tracer,[]), + Receiver = spawn(Node,?MODULE,one_time_receiver,[]), + + %% This node does not support arbitrary labels, but small integers should + %% still work. + Label = 1234, + seq_trace:set_token(label,Label), + seq_trace:set_token('receive',true), + + Receiver ! 'receive', + %% let the other process receive the message: + receive after 10 -> ok end, + Self = self(), + seq_trace:reset_trace(), + Result = rpc:call(Node,?MODULE,stop_tracer,[1]), + stop_node(Node), + ok = io:format("~p~n",[Result]), + [{Label,{'receive',_,Self,Receiver,'receive'}, _}] = Result, + ok. + call(doc) -> "Tests special forms {is_seq_trace} and {get_seq_token} " "in trace match specs."; -call(suite) -> - []; call(Config) when is_list(Config) -> - ?line Self = self(), - ?line seq_trace:reset_trace(), - ?line TrA = transparent_tracer(), - ?line 1 = + Self = self(), + seq_trace:reset_trace(), + TrA = transparent_tracer(), + 1 = erlang:trace(Self, true, [call, set_on_spawn, {tracer, TrA(pid)}]), - ?line 1 = + 1 = erlang:trace_pattern({?MODULE, call_tracee_1, 1}, [{'_', [], [{message, {{{self}, {get_seq_token}}}}]}], [local]), - ?line 1 = + 1 = erlang:trace_pattern({?MODULE, call_tracee_2, 1}, [{'_', [{is_seq_trace}], [{message, {{{self}, {get_seq_token}}}}]}], [local]), - ?line RefA = make_ref(), - ?line Pid2A = spawn_link( + RefA = make_ref(), + Pid2A = spawn_link( fun() -> receive {_, msg, RefA} -> ok end, RefA = call_tracee_2(RefA), Self ! {self(), msg, RefA} end), - ?line Pid1A = spawn_link( + Pid1A = spawn_link( fun() -> receive {_, msg, RefA} -> ok end, RefA = call_tracee_1(RefA), Pid2A ! {self(), msg, RefA} end), - ?line Pid1A ! {Self, msg, RefA}, + Pid1A ! {Self, msg, RefA}, %% The message is passed Self -> Pid1B -> Pid2B -> Self. %% Traced functions are called in Pid1B and Pid2B. - ?line receive {Pid2A, msg, RefA} -> ok end, + receive {Pid2A, msg, RefA} -> ok end, %% Only call_tracee1 will be traced since the guard for %% call_tracee2 requires a sequential trace. The trace %% token is undefined. - ?line Token2A = [], - ?line {ok, [{trace, Pid1A, call, + Token2A = [], + {ok, [{trace, Pid1A, call, {?MODULE, call_tracee_1, [RefA]}, {Pid1A, Token2A}}]} = TrA({stop, 1}), - ?line seq_trace:reset_trace(), + seq_trace:reset_trace(), - ?line TrB = transparent_tracer(), - ?line 1 = + TrB = transparent_tracer(), + 1 = erlang:trace(Self, true, [call, set_on_spawn, {tracer, TrB(pid)}]), - ?line Label = 17, - ?line seq_trace:set_token(label, Label), % Token enters here!! - ?line RefB = make_ref(), - ?line Pid2B = spawn_link( + Label = 17, + seq_trace:set_token(label, Label), % Token enters here!! + RefB = make_ref(), + Pid2B = spawn_link( fun() -> receive {_, msg, RefB} -> ok end, RefB = call_tracee_2(RefB), Self ! {self(), msg, RefB} end), - ?line Pid1B = spawn_link( + Pid1B = spawn_link( fun() -> receive {_, msg, RefB} -> ok end, RefB = call_tracee_1(RefB), Pid2B ! {self(), msg, RefB} end), - ?line Pid1B ! {Self, msg, RefB}, + Pid1B ! {Self, msg, RefB}, %% The message is passed Self -> Pid1B -> Pid2B -> Self, and the %% seq_trace token follows invisibly. Traced functions are %% called in Pid1B and Pid2B. Seq_trace flags == 0 so no %% seq_trace messages are generated. - ?line receive {Pid2B, msg, RefB} -> ok end, + receive {Pid2B, msg, RefB} -> ok end, %% The values of these counters {.., 1, _, 0}, {.., 2, _, 1} %% depend on that seq_trace has been reset just before this test. - ?line Token1B = {0, Label, 1, Self, 0}, - ?line Token2B = {0, Label, 2, Pid1B, 1}, - ?line {ok, [{trace, Pid1B, call, + Token1B = {0, Label, 1, Self, 0}, + Token2B = {0, Label, 2, Pid1B, 1}, + {ok, [{trace, Pid1B, call, {?MODULE, call_tracee_1, [RefB]}, {Pid1B, Token1B}}, {trace, Pid2B, call, {?MODULE, call_tracee_2, [RefB]}, {Pid2B, Token2B}}]} = TrB({stop,2}), - ?line seq_trace:reset_trace(), + seq_trace:reset_trace(), ok. -port(doc) -> - "Send trace messages to a port."; -port(suite) -> []; +%% Send trace messages to a port. port(Config) when is_list(Config) -> lists:foreach(fun (TsType) -> do_port(TsType, Config) end, ?TIMESTAMP_MODES). do_port(TsType, Config) -> io:format("Testing ~p~n",[TsType]), - ?line Port = load_tracer(Config), - ?line seq_trace:set_system_tracer(Port), + Port = load_tracer(Config), + seq_trace:set_system_tracer(Port), - ?line set_token_flags([print, TsType]), - ?line Small = [small,term], - ?line seq_trace:print(0, Small), - ?line case get_port_message(Port) of + set_token_flags([print, TsType]), + Small = [small,term], + seq_trace:print(0, Small), + case get_port_message(Port) of {seq_trace,0,{print,_,_,[],Small}} when TsType == no_timestamp -> ok; {seq_trace,0,{print,_,_,[],Small},Ts0} when TsType /= no_timestamp -> check_ts(TsType, Ts0), ok; Other -> - ?line seq_trace:reset_trace(), - ?line ?t:fail({unexpected,Other}) + seq_trace:reset_trace(), + ct:fail({unexpected,Other}) end, %% OTP-4218 Messages from ports should not affect seq trace token. %% %% Check if trace token still is active on this process after %% the get_port_message/1 above that receives from a port. - ?line OtherSmall = [other | Small], - ?line seq_trace:print(0, OtherSmall), - ?line seq_trace:reset_trace(), - ?line case get_port_message(Port) of + OtherSmall = [other | Small], + seq_trace:print(0, OtherSmall), + seq_trace:reset_trace(), + case get_port_message(Port) of {seq_trace,0,{print,_,_,[],OtherSmall}} when TsType == no_timestamp -> ok; {seq_trace,0,{print,_,_,[],OtherSmall}, Ts1} when TsType /= no_timestamp -> check_ts(TsType, Ts1), ok; Other1 -> - ?line ?t:fail({unexpected,Other1}) + ct:fail({unexpected,Other1}) end, - ?line seq_trace:set_token(print, true), - ?line Huge = huge_data(), - ?line seq_trace:print(0, Huge), - ?line seq_trace:reset_trace(), - ?line case get_port_message(Port) of + seq_trace:set_token(print, true), + Huge = huge_data(), + seq_trace:print(0, Huge), + seq_trace:reset_trace(), + case get_port_message(Port) of {seq_trace,0,{print,_,_,[],Huge}} -> ok; Other2 -> - ?line ?t:fail({unexpected,Other2}) + ct:fail({unexpected,Other2}) end, unlink(Port), exit(Port,kill), @@ -466,21 +525,19 @@ get_port_message(Port) -> {Port,{data,Bin}} when is_binary(Bin) -> binary_to_term(Bin); Other -> - ?t:fail({unexpected,Other}) + ct:fail({unexpected,Other}) after 5000 -> - ?t:fail(timeout) + ct:fail(timeout) end. -match_set_seq_token(suite) -> - []; match_set_seq_token(doc) -> ["Tests that match spec function set_seq_token does not " "corrupt the heap"]; match_set_seq_token(Config) when is_list(Config) -> - ?line Parent = self(), - ?line Timetrap = test_server:timetrap(test_server:seconds(20)), + Parent = self(), + %% OTP-4222 Match spec 'set_seq_token' corrupts heap %% %% This test crashes the emulator if the bug in question is present, @@ -488,13 +545,13 @@ match_set_seq_token(Config) when is_list(Config) -> %% %% All the timeout stuff is here to get decent accuracy of the error %% return value, instead of just 'timeout'. - % - ?line {ok, Sandbox} = start_node(seq_trace_other, []), - ?line true = rpc:call(Sandbox, code, add_patha, + %% + {ok, Sandbox} = start_node(seq_trace_other, []), + true = rpc:call(Sandbox, code, add_patha, [filename:dirname(code:which(?MODULE))]), - ?line Lbl = 4711, + Lbl = 4711, %% Do the possibly crashing test - ?line P1 = + P1 = spawn( fun () -> Parent ! {self(), @@ -502,16 +559,16 @@ match_set_seq_token(Config) when is_list(Config) -> ?MODULE, do_match_set_seq_token, [Lbl])} end), %% Probe the node with a simple rpc request, to see if it is alive. - ?line P2 = + P2 = spawn( fun () -> receive after 4000 -> ok end, Parent ! {self(), rpc:call(Sandbox, erlang, abs, [-1])} end), %% If the test node hangs completely, this timer expires. - ?line R3 = erlang:start_timer(8000, self(), void), + R3 = erlang:start_timer(8000, self(), void), %% - ?line {ok, Log} = + {ok, Log} = receive {P1, Result} -> exit(P2, done), @@ -526,10 +583,15 @@ match_set_seq_token(Config) when is_list(Config) -> exit(P2, timeout), {error, "Test node hung"} end, - ?line ok = check_match_set_seq_token_log(Lbl, Log), + + %% Sort the log on Pid, as events from different processes + %% are not guaranteed to arrive in a certain order to the + %% tracer + SortedLog = lists:keysort(2, Log), + + ok = check_match_set_seq_token_log(Lbl, SortedLog), %% - ?line stop_node(Sandbox), - ?line test_server:timetrap_cancel(Timetrap), + stop_node(Sandbox), ok. %% OTP-4222 Match spec 'set_seq_token' corrupts heap @@ -580,13 +642,13 @@ do_match_set_seq_token(Label) -> check_match_set_seq_token_log( Label, - [{trace,C,call,{?MODULE,countdown,[B,Ref]}, {0,Label,0,C,0}}, + [{trace,B,call,{?MODULE,bounce, [Ref]}, {0,Label,2,B,1}}, + {trace,B,call,{?MODULE,bounce, [Ref]}, {0,Label,4,B,3}}, + {trace,B,call,{?MODULE,bounce, [Ref]}, {0,Label,6,B,5}}, + {trace,C,call,{?MODULE,countdown,[B,Ref]}, {0,Label,0,C,0}}, {trace,C,call,{?MODULE,countdown,[B,Ref,3]},{0,Label,0,C,0}}, - {trace,B,call,{?MODULE,bounce, [Ref]}, {0,Label,2,B,1}}, {trace,C,call,{?MODULE,countdown,[B,Ref,2]},{0,Label,2,B,1}}, - {trace,B,call,{?MODULE,bounce, [Ref]}, {0,Label,4,B,3}}, {trace,C,call,{?MODULE,countdown,[B,Ref,1]},{0,Label,4,B,3}}, - {trace,B,call,{?MODULE,bounce, [Ref]}, {0,Label,6,B,5}}, {trace,C,call,{?MODULE,countdown,[B,Ref,0]},{0,Label,6,B,5}} ]) -> ok; @@ -621,14 +683,12 @@ bounce(Ref) -> -gc_seq_token(suite) -> - []; gc_seq_token(doc) -> ["Tests that a seq_trace token on a message in the inqueue ", "can be garbage collected."]; gc_seq_token(Config) when is_list(Config) -> - ?line Parent = self(), - ?line Timetrap = test_server:timetrap(test_server:seconds(20)), + Parent = self(), + %% OTP-4555 Seq trace token causes free mem read in gc %% %% This test crashes the emulator if the bug in question is present, @@ -636,13 +696,13 @@ gc_seq_token(Config) when is_list(Config) -> %% %% All the timeout stuff is here to get decent accuracy of the error %% return value, instead of just 'timeout'. - % - ?line {ok, Sandbox} = start_node(seq_trace_other, []), - ?line true = rpc:call(Sandbox, code, add_patha, + %% + {ok, Sandbox} = start_node(seq_trace_other, []), + true = rpc:call(Sandbox, code, add_patha, [filename:dirname(code:which(?MODULE))]), - ?line Label = 4711, + Label = 4711, %% Do the possibly crashing test - ?line P1 = + P1 = spawn( fun () -> Parent ! {self(), @@ -650,16 +710,16 @@ gc_seq_token(Config) when is_list(Config) -> ?MODULE, do_gc_seq_token, [Label])} end), %% Probe the node with a simple rpc request, to see if it is alive. - ?line P2 = + P2 = spawn( fun () -> receive after 4000 -> ok end, Parent ! {self(), rpc:call(Sandbox, erlang, abs, [-1])} end), %% If the test node hangs completely, this timer expires. - ?line R3 = erlang:start_timer(8000, self(), void), + R3 = erlang:start_timer(8000, self(), void), %% - ?line ok = + ok = receive {P1, Result} -> exit(P2, done), @@ -675,8 +735,7 @@ gc_seq_token(Config) when is_list(Config) -> {error, "Test node hung"} end, %% - ?line stop_node(Sandbox), - ?line test_server:timetrap_cancel(Timetrap), + stop_node(Sandbox), ok. do_gc_seq_token(Label) -> @@ -724,6 +783,24 @@ do_shrink(N) -> erlang:garbage_collect(), do_shrink(N-1). +%% Test that messages from a port does not clear the token +port_clean_token(Config) when is_list(Config) -> + seq_trace:reset_trace(), + Label = make_ref(), + seq_trace:set_token(label, Label), + {label,Label} = seq_trace:get_token(label), + + %% Create a port and get messages from it + %% We use os:cmd as a convenience as it does + %% open_port, port_command, port_close and receives replies. + %% Maybe it is not ideal to rely on the internal implementation + %% of os:cmd but it will have to do. + os:cmd("ls"), + + %% Make sure that the seq_trace token is still there + {label,Label} = seq_trace:get_token(label), + + ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -819,7 +896,6 @@ start_tracer() -> seq_trace:set_system_tracer(Pid), Pid. - set_token_flags([]) -> ok; set_token_flags([no_timestamp|Flags]) -> @@ -836,7 +912,7 @@ check_ts(no_timestamp, Ts) -> no_timestamp = Ts catch _ : _ -> - ?t:fail({unexpected_timestamp, Ts}) + ct:fail({unexpected_timestamp, Ts}) end, ok; check_ts(timestamp, Ts) -> @@ -847,7 +923,7 @@ check_ts(timestamp, Ts) -> true = is_integer(Us) catch _ : _ -> - ?t:fail({unexpected_timestamp, Ts}) + ct:fail({unexpected_timestamp, Ts}) end, ok; check_ts(monotonic_timestamp, Ts) -> @@ -855,7 +931,7 @@ check_ts(monotonic_timestamp, Ts) -> true = is_integer(Ts) catch _ : _ -> - ?t:fail({unexpected_timestamp, Ts}) + ct:fail({unexpected_timestamp, Ts}) end, ok; check_ts(strict_monotonic_timestamp, Ts) -> @@ -865,10 +941,10 @@ check_ts(strict_monotonic_timestamp, Ts) -> true = is_integer(UMI) catch _ : _ -> - ?t:fail({unexpected_timestamp, Ts}) + ct:fail({unexpected_timestamp, Ts}) end, ok. - + start_node(Name, Param) -> test_server:start_node(Name, slave, [{args, Param}]). @@ -876,7 +952,7 @@ stop_node(Node) -> test_server:stop_node(Node). load_tracer(Config) -> - Path = ?config(data_dir, Config), + Path = proplists:get_value(data_dir, Config), ok = erl_ddll:load_driver(Path, echo_drv), open_port({spawn,echo_drv}, [eof,binary]). |