From 7bfbabb0a099b9dbd34363ffe3dc0c03918b1f3b Mon Sep 17 00:00:00 2001
From: Lukas Larsson
Date: Mon, 19 Sep 2011 11:09:56 +0200
Subject: Export write_events and add option to return a string
---
lib/stdlib/src/error_logger_tty_h.erl | 69 ++++++++++++++++++-----------------
1 file changed, 36 insertions(+), 33 deletions(-)
diff --git a/lib/stdlib/src/error_logger_tty_h.erl b/lib/stdlib/src/error_logger_tty_h.erl
index 435e57aa0e..fa13fbb2bd 100644
--- a/lib/stdlib/src/error_logger_tty_h.erl
+++ b/lib/stdlib/src/error_logger_tty_h.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. 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
@@ -34,10 +34,12 @@
handle_event/2, handle_call/2, handle_info/2,
terminate/2, code_change/3]).
+-export([write_event/2]).
+
%% This one is used when we takeover from the simple error_logger.
init({[], {error_logger, Buf}}) ->
User = set_group_leader(),
- write_events(Buf),
+ write_events(Buf,io),
{ok, {User, error_logger}};
%% This one is used if someone took over from us, and now wants to
%% go back.
@@ -52,7 +54,7 @@ init([]) ->
handle_event({_Type, GL, _Msg}, State) when node(GL) =/= node() ->
{ok, State};
handle_event(Event, State) ->
- write_event(tag_event(Event)),
+ write_event(tag_event(Event),io),
{ok, State}.
handle_info({'EXIT', User, _Reason}, {User, PrevHandler}) ->
@@ -64,10 +66,10 @@ handle_info({'EXIT', User, _Reason}, {User, PrevHandler}) ->
PrevHandler, go_back}
end;
handle_info({emulator, GL, Chars}, State) when node(GL) == node() ->
- write_event(tag_event({emulator, GL, Chars})),
+ write_event(tag_event({emulator, GL, Chars}),io),
{ok, State};
handle_info({emulator, noproc, Chars}, State) ->
- write_event(tag_event({emulator, noproc, Chars})),
+ write_event(tag_event({emulator, noproc, Chars}),io),
{ok, State};
handle_info(_, State) ->
{ok, State}.
@@ -97,65 +99,65 @@ set_group_leader() ->
tag_event(Event) ->
{erlang:localtime(), Event}.
-write_events(Events) -> write_events1(lists:reverse(Events)).
+write_events(Events,IOMod) -> write_events1(lists:reverse(Events),IOMod).
-write_events1([Event|Es]) ->
- write_event(Event),
- write_events1(Es);
-write_events1([]) ->
+write_events1([Event|Es],IOMod) ->
+ write_event(Event,IOMod),
+ write_events1(Es,IOMod);
+write_events1([],_IOMod) ->
ok.
-write_event({Time, {error, _GL, {Pid, Format, Args}}}) ->
+write_event({Time, {error, _GL, {Pid, Format, Args}}},IOMod) ->
T = write_time(maybe_utc(Time)),
case catch io_lib:format(add_node(Format,Pid), Args) of
S when is_list(S) ->
- format(T ++ S);
+ format(IOMod, T ++ S);
_ ->
F = add_node("ERROR: ~p - ~p~n", Pid),
- format(T ++ F, [Format,Args])
+ format(IOMod, T ++ F, [Format,Args])
end;
-write_event({Time, {emulator, _GL, Chars}}) ->
+write_event({Time, {emulator, _GL, Chars}},IOMod) ->
T = write_time(maybe_utc(Time)),
case catch io_lib:format(Chars, []) of
S when is_list(S) ->
- format(T ++ S);
+ format(IOMod, T ++ S);
_ ->
- format(T ++ "ERROR: ~p ~n", [Chars])
+ format(IOMod, T ++ "ERROR: ~p ~n", [Chars])
end;
-write_event({Time, {info, _GL, {Pid, Info, _}}}) ->
+write_event({Time, {info, _GL, {Pid, Info, _}}},IOMod) ->
T = write_time(maybe_utc(Time)),
- format(T ++ add_node("~p~n",Pid),[Info]);
-write_event({Time, {error_report, _GL, {Pid, std_error, Rep}}}) ->
+ format(IOMod, T ++ add_node("~p~n",Pid),[Info]);
+write_event({Time, {error_report, _GL, {Pid, std_error, Rep}}},IOMod) ->
T = write_time(maybe_utc(Time)),
S = format_report(Rep),
- format(T ++ S ++ add_node("", Pid));
-write_event({Time, {info_report, _GL, {Pid, std_info, Rep}}}) ->
+ format(IOMod, T ++ S ++ add_node("", Pid));
+write_event({Time, {info_report, _GL, {Pid, std_info, Rep}}},IOMod) ->
T = write_time(maybe_utc(Time), "INFO REPORT"),
S = format_report(Rep),
- format(T ++ S ++ add_node("", Pid));
-write_event({Time, {info_msg, _GL, {Pid, Format, Args}}}) ->
+ format(IOMod, T ++ S ++ add_node("", Pid));
+write_event({Time, {info_msg, _GL, {Pid, Format, Args}}},IOMod) ->
T = write_time(maybe_utc(Time), "INFO REPORT"),
case catch io_lib:format(add_node(Format,Pid), Args) of
S when is_list(S) ->
- format(T ++ S);
+ format(IOMod, T ++ S);
_ ->
F = add_node("ERROR: ~p - ~p~n", Pid),
- format(T ++ F, [Format,Args])
+ format(IOMod, T ++ F, [Format,Args])
end;
-write_event({Time, {warning_report, _GL, {Pid, std_warning, Rep}}}) ->
+write_event({Time, {warning_report, _GL, {Pid, std_warning, Rep}}},IOMod) ->
T = write_time(maybe_utc(Time), "WARNING REPORT"),
S = format_report(Rep),
- format(T ++ S ++ add_node("", Pid));
-write_event({Time, {warning_msg, _GL, {Pid, Format, Args}}}) ->
+ format(IOMod, T ++ S ++ add_node("", Pid));
+write_event({Time, {warning_msg, _GL, {Pid, Format, Args}}},IOMod) ->
T = write_time(maybe_utc(Time), "WARNING REPORT"),
case catch io_lib:format(add_node(Format,Pid), Args) of
S when is_list(S) ->
- format(T ++ S);
+ format(IOMod, T ++ S);
_ ->
F = add_node("ERROR: ~p - ~p~n", Pid),
- format(T ++ F, [Format,Args])
+ format(IOMod, T ++ F, [Format,Args])
end;
-write_event({_Time, _Error}) ->
+write_event({_Time, _Error},_IOMod) ->
ok.
maybe_utc(Time) ->
@@ -178,8 +180,9 @@ maybe_utc(Time) ->
Time
end.
-format(String) -> io:format(user, String, []).
-format(String, Args) -> io:format(user, String, Args).
+format(IOMod, String) -> format(IOMod, String, []).
+format(io_lib, String, Args) -> io_lib:format(String, Args);
+format(io, String, Args) -> io:format(user, String, Args).
format_report(Rep) when is_list(Rep) ->
case string_p(Rep) of
--
cgit v1.2.3
From 97273a38297ab03f727c4c7bdbb3b0491bdcfb8f Mon Sep 17 00:00:00 2001
From: Lukas Larsson
Date: Tue, 20 Sep 2011 10:04:12 +0200
Subject: Add -enable_builtin_hooks config option
This option allows ct users to disable the default
hooks which are installed when common_test is started.
The builtin hooks themselved are listed in ct_hooks.
OTP-9564
---
lib/common_test/src/ct_hooks.erl | 27 ++++++++-
lib/common_test/src/ct_run.erl | 106 ++++++++++++++++++++++--------------
lib/common_test/src/ct_testspec.erl | 5 ++
lib/common_test/src/ct_util.hrl | 1 +
4 files changed, 97 insertions(+), 42 deletions(-)
diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl
index f243b87f54..886195aae5 100644
--- a/lib/common_test/src/ct_hooks.erl
+++ b/lib/common_test/src/ct_hooks.erl
@@ -34,6 +34,12 @@
%% If you change this, remember to update ct_util:look -> stop clause as well.
-define(config_name, ct_hooks).
+%% All of the hooks which are to be started by default. Remove by issuing
+%% -enable_builtin_hooks false to when starting common test.
+-define(BUILTIN_HOOKS,[#ct_hook_config{ module = cth_log_redirect,
+ opts = [],
+ prio = ctfirst }]).
+
-record(ct_hook_config, {id, module, prio, scope, opts = [], state = []}).
%% -------------------------------------------------------------------------
@@ -44,7 +50,8 @@
-spec init(State :: term()) -> ok |
{error, Reason :: term()}.
init(Opts) ->
- call(get_new_hooks(Opts, undefined), ok, init, []).
+ call(get_new_hooks(Opts, undefined) ++ get_builtin_hooks(Opts),
+ ok, init, []).
%% @doc Called after all suites are done.
@@ -283,6 +290,14 @@ get_new_hooks(Config) when is_list(Config) ->
get_new_hooks(_Config) ->
[].
+get_builtin_hooks(Opts) ->
+ case proplists:get_value(enable_builtin_hooks,Opts) of
+ false ->
+ [];
+ _Else ->
+ [{HookConf, call_id, undefined} || HookConf <- ?BUILTIN_HOOKS]
+ end.
+
save_suite_data_async(Hooks) ->
ct_util:save_suite_data_async(?config_name, Hooks).
@@ -290,7 +305,7 @@ get_hooks() ->
lists:keysort(#ct_hook_config.prio,ct_util:read_suite_data(?config_name)).
%% Sort all calls in this order:
-%% call_id < call_init < Hook Priority 1 < .. < Hook Priority N
+%% call_id < call_init < ctfirst < Priority 1 < .. < Priority N < ctlast
%% If Hook Priority is equal, check when it has been installed and
%% sort on that instead.
resort(Calls, Hooks) ->
@@ -311,6 +326,14 @@ resort(Calls, Hooks) ->
%% If priorities are equal, we check the position in the
%% hooks list
pos(Id1,Hooks) < pos(Id2,Hooks);
+ P1 == ctfirst ->
+ true;
+ P2 == ctfirst ->
+ false;
+ P1 == ctlast ->
+ false;
+ P2 == ctlast ->
+ true;
true ->
P1 < P2
end
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 877ec9c7dd..0715b8abf8 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -55,6 +55,7 @@
config = [],
event_handlers = [],
ct_hooks = [],
+ enable_builtin_hooks = true,
include = [],
silent_connections,
stylesheet,
@@ -173,6 +174,10 @@ script_start1(Parent, Args) ->
end, false, Args),
EvHandlers = event_handler_args2opts(Args),
CTHooks = ct_hooks_args2opts(Args),
+ EnableBuiltinHooks = get_start_opt(enable_builtin_hooks,
+ fun([CT]) -> list_to_atom(CT);
+ ([]) -> true
+ end, true, Args),
%% check flags and set corresponding application env variables
@@ -237,6 +242,7 @@ script_start1(Parent, Args) ->
StartOpts = #opts{label = Label, vts = Vts, shell = Shell, cover = Cover,
logdir = LogDir, event_handlers = EvHandlers,
ct_hooks = CTHooks,
+ enable_builtin_hooks = EnableBuiltinHooks,
include = IncludeDirs,
silent_connections = SilentConns,
stylesheet = Stylesheet,
@@ -311,6 +317,11 @@ script_start2(StartOpts = #opts{vts = undefined,
AllCTHooks = merge_vals(
[StartOpts#opts.ct_hooks,
SpecStartOpts#opts.ct_hooks]),
+
+ EnableBuiltinHooks =
+ choose_val(
+ StartOpts#opts.enable_builtin_hooks,
+ SpecStartOpts#opts.enable_builtin_hooks),
AllInclude = merge_vals([StartOpts#opts.include,
SpecStartOpts#opts.include]),
@@ -323,6 +334,8 @@ script_start2(StartOpts = #opts{vts = undefined,
config = SpecStartOpts#opts.config,
event_handlers = AllEvHs,
ct_hooks = AllCTHooks,
+ enable_builtin_hooks =
+ EnableBuiltinHooks,
include = AllInclude,
multiply_timetraps = MultTT,
scale_timetraps = ScaleTT}}
@@ -339,9 +352,7 @@ script_start2(StartOpts = #opts{vts = undefined,
{[],_} ->
{error,no_testspec_specified};
{undefined,_} -> % no testspec used
- case check_and_install_configfiles(InitConfig, TheLogDir,
- Opts#opts.event_handlers,
- Opts#opts.ct_hooks) of
+ case check_and_install_configfiles(InitConfig, TheLogDir, Opts) of
ok -> % go on read tests from start flags
script_start3(Opts#opts{config=InitConfig,
logdir=TheLogDir}, Args);
@@ -351,9 +362,7 @@ script_start2(StartOpts = #opts{vts = undefined,
{_,_} -> % testspec used
%% merge config from start flags with config from testspec
AllConfig = merge_vals([InitConfig, Opts#opts.config]),
- case check_and_install_configfiles(AllConfig, TheLogDir,
- Opts#opts.event_handlers,
- Opts#opts.ct_hooks) of
+ case check_and_install_configfiles(AllConfig, TheLogDir, Opts) of
ok -> % read tests from spec
{Run,Skip} = ct_testspec:prepare_tests(Terms, node()),
do_run(Run, Skip, Opts#opts{config=AllConfig,
@@ -367,9 +376,7 @@ script_start2(StartOpts, Args) ->
%% read config/userconfig from start flags
InitConfig = ct_config:prepare_config_list(Args),
LogDir = which(logdir, StartOpts#opts.logdir),
- case check_and_install_configfiles(InitConfig, LogDir,
- StartOpts#opts.event_handlers,
- StartOpts#opts.ct_hooks) of
+ case check_and_install_configfiles(InitConfig, LogDir, StartOpts) of
ok -> % go on read tests from start flags
script_start3(StartOpts#opts{config=InitConfig,
logdir=LogDir}, Args);
@@ -377,12 +384,17 @@ script_start2(StartOpts, Args) ->
Error
end.
-check_and_install_configfiles(Configs, LogDir, EvHandlers, CTHooks) ->
+check_and_install_configfiles(
+ Configs, LogDir, #opts{
+ event_handlers = EvHandlers,
+ ct_hooks = CTHooks,
+ enable_builtin_hooks = EnableBuiltinHooks} ) ->
case ct_config:check_config_files(Configs) of
false ->
install([{config,Configs},
{event_handler,EvHandlers},
- {ct_hooks,CTHooks}], LogDir);
+ {ct_hooks,CTHooks},
+ {enable_builtin_hooks,EnableBuiltinHooks}], LogDir);
{value,{error,{nofile,File}}} ->
{error,{cant_read_config_file,File}};
{value,{error,{wrong_config,Message}}}->
@@ -451,18 +463,19 @@ script_start4(#opts{vts = true, config = Config, event_handlers = EvHandlers,
script_start4(#opts{label = Label, shell = true, config = Config,
event_handlers = EvHandlers,
ct_hooks = CTHooks,
+ enable_builtin_hooks = EnableBuiltinHooks,
logdir = LogDir, testspecs = Specs}, _Args) ->
%% label - used by ct_logs
application:set_env(common_test, test_label, Label),
- InstallOpts = [{config,Config},{event_handler,EvHandlers},
- {ct_hooks, CTHooks}],
if Config == [] ->
ok;
true ->
io:format("\nInstalling: ~p\n\n", [Config])
end,
- case install(InstallOpts) of
+ case install([{config,Config},{event_handler,EvHandlers},
+ {ct_hooks, CTHooks},
+ {enable_builtin_hooks,EnableBuiltinHooks}]) of
ok ->
ct_util:start(interactive, LogDir),
log_ts_names(Specs),
@@ -682,6 +695,11 @@ run_test1(StartOpts) ->
%% CT Hooks
CTHooks = get_start_opt(ct_hooks, value, [], StartOpts),
+ EnableBuiltinHooks = get_start_opt(enable_builtin_hooks,
+ fun(EBH) when EBH == true;
+ EBH == false ->
+ EBH
+ end, true, StartOpts),
%% silent connections
SilentConns = get_start_opt(silent_connections,
@@ -754,6 +772,7 @@ run_test1(StartOpts) ->
cover = Cover, step = Step, logdir = LogDir, config = CfgFiles,
event_handlers = EvHandlers,
ct_hooks = CTHooks,
+ enable_builtin_hooks = EnableBuiltinHooks,
include = Include,
silent_connections = SilentConns,
stylesheet = Stylesheet,
@@ -808,24 +827,28 @@ run_spec_file(Relaxed,
AllCTHooks = merge_vals([Opts#opts.ct_hooks,
SpecOpts#opts.ct_hooks]),
+ EnableBuiltinHooks = choose_val(Opts#opts.enable_builtin_hooks,
+ SpecOpts#opts.enable_builtin_hooks),
application:set_env(common_test, include, AllInclude),
- case check_and_install_configfiles(AllConfig,
- which(logdir,LogDir),
- AllEvHs,
- AllCTHooks) of
+ Opts1 = Opts#opts{label = Label,
+ cover = Cover,
+ logdir = which(logdir, LogDir),
+ config = AllConfig,
+ event_handlers = AllEvHs,
+ include = AllInclude,
+ testspecs = AbsSpecs,
+ multiply_timetraps = MultTT,
+ scale_timetraps = ScaleTT,
+ ct_hooks = AllCTHooks,
+ enable_builtin_hooks = EnableBuiltinHooks
+ },
+
+ case check_and_install_configfiles(AllConfig,Opts1#opts.logdir,
+ Opts1) of
ok ->
- Opts1 = Opts#opts{label = Label,
- cover = Cover,
- logdir = which(logdir, LogDir),
- config = AllConfig,
- event_handlers = AllEvHs,
- include = AllInclude,
- testspecs = AbsSpecs,
- multiply_timetraps = MultTT,
- scale_timetraps = ScaleTT,
- ct_hooks = AllCTHooks},
+
{Run,Skip} = ct_testspec:prepare_tests(TS, node()),
reformat_result(catch do_run(Run, Skip, Opts1, StartOpts));
{error,GCFReason} ->
@@ -834,13 +857,10 @@ run_spec_file(Relaxed,
end.
run_prepared(Run, Skip, Opts = #opts{logdir = LogDir,
- config = CfgFiles,
- event_handlers = EvHandlers,
- ct_hooks = CTHooks},
+ config = CfgFiles },
StartOpts) ->
LogDir1 = which(logdir, LogDir),
- case check_and_install_configfiles(CfgFiles, LogDir1,
- EvHandlers, CTHooks) of
+ case check_and_install_configfiles(CfgFiles, LogDir1, Opts) of
ok ->
reformat_result(catch do_run(Run, Skip, Opts#opts{logdir = LogDir1},
StartOpts));
@@ -872,7 +892,8 @@ check_config_file(Callback, File)->
run_dir(Opts = #opts{logdir = LogDir,
config = CfgFiles,
event_handlers = EvHandlers,
- ct_hooks = CTHook }, StartOpts) ->
+ ct_hooks = CTHook,
+ enable_builtin_hooks = EnableBuiltinHooks }, StartOpts) ->
LogDir1 = which(logdir, LogDir),
Opts1 = Opts#opts{logdir = LogDir1},
AbsCfgFiles =
@@ -895,7 +916,8 @@ run_dir(Opts = #opts{logdir = LogDir,
end, CfgFiles),
case install([{config,AbsCfgFiles},
{event_handler,EvHandlers},
- {ct_hooks, CTHook}], LogDir1) of
+ {ct_hooks, CTHook},
+ {enable_builtin_hooks,EnableBuiltinHooks}], LogDir1) of
ok -> ok;
{error,IReason} -> exit(IReason)
end,
@@ -999,9 +1021,8 @@ run_testspec1(TestSpec) ->
end,
application:set_env(common_test, include, AllInclude),
LogDir1 = which(logdir,Opts#opts.logdir),
- case check_and_install_configfiles(Opts#opts.config, LogDir1,
- Opts#opts.event_handlers,
- Opts#opts.ct_hooks) of
+ case check_and_install_configfiles(
+ Opts#opts.config, LogDir1, Opts) of
ok ->
Opts1 = Opts#opts{testspecs = [],
logdir = LogDir1,
@@ -1020,6 +1041,7 @@ get_data_for_node(#testspec{label = Labels,
userconfig = UsrCfgs,
event_handler = EvHs,
ct_hooks = CTHooks,
+ enable_builtin_hooks = EnableBuiltinHooks,
include = Incl,
multiply_timetraps = MTs,
scale_timetraps = STs}, Node) ->
@@ -1042,6 +1064,7 @@ get_data_for_node(#testspec{label = Labels,
config = ConfigFiles,
event_handlers = EvHandlers,
ct_hooks = FiltCTHooks,
+ enable_builtin_hooks = EnableBuiltinHooks,
include = Include,
multiply_timetraps = MT,
scale_timetraps = ST}.
@@ -2067,8 +2090,11 @@ get_start_opt(Key, IfExists, IfNotExists, Args) ->
end.
ct_hooks_args2opts(Args) ->
- ct_hooks_args2opts(
- proplists:get_value(ct_hooks, Args, []),[]).
+ lists:foldl(fun({ct_hooks,Hooks}, Acc) ->
+ ct_hooks_args2opts(Hooks,Acc);
+ (_,Acc) ->
+ Acc
+ end,[],Args).
ct_hooks_args2opts([CTH,Arg,Prio,"and"| Rest],Acc) ->
ct_hooks_args2opts(Rest,[{list_to_atom(CTH),
diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl
index d845358bb2..96971ccfc7 100644
--- a/lib/common_test/src/ct_testspec.erl
+++ b/lib/common_test/src/ct_testspec.erl
@@ -646,6 +646,10 @@ add_tests([{ct_hooks, _Node, []}|Ts], Spec) ->
add_tests([{ct_hooks, Hooks}|Ts], Spec) ->
add_tests([{ct_hooks, all_nodes, Hooks}|Ts], Spec);
+%% -- enable_builtin_hooks --
+add_tests([{enable_builtin_hooks,Bool}|Ts],Spec) ->
+ add_tests(Ts, Spec#testspec{ enable_builtin_hooks = Bool });
+
%% --- include ---
add_tests([{include,all_nodes,InclDirs}|Ts],Spec) ->
Tests = lists:map(fun(N) -> {include,N,InclDirs} end, list_nodes(Spec)),
@@ -1104,6 +1108,7 @@ valid_terms() ->
{event_handler,4},
{ct_hooks,2},
{ct_hooks,3},
+ {enable_builtin_hooks,1},
{multiply_timetraps,2},
{multiply_timetraps,3},
{scale_timetraps,2},
diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl
index 556f88c84d..dbe9d9b4e6 100644
--- a/lib/common_test/src/ct_util.hrl
+++ b/lib/common_test/src/ct_util.hrl
@@ -37,6 +37,7 @@
userconfig=[],
event_handler=[],
ct_hooks=[],
+ enable_builtin_hooks=true,
include=[],
multiply_timetraps=[],
scale_timetraps=[],
--
cgit v1.2.3
From 4bd25eb6aa89d15509148a0b9a5da64a035be841 Mon Sep 17 00:00:00 2001
From: Lukas Larsson
Date: Mon, 19 Sep 2011 11:17:28 +0200
Subject: Add a hook for redirecting SASL and error_logger messages
SASL and error_logger messaged can now be redirected to the
common_test log using a hook which is bundled with common_test.
---
lib/common_test/src/Makefile | 3 +-
lib/common_test/src/cth_log_redirect.erl | 87 ++++++++++++++++++++++++++++++++
2 files changed, 89 insertions(+), 1 deletion(-)
create mode 100644 lib/common_test/src/cth_log_redirect.erl
diff --git a/lib/common_test/src/Makefile b/lib/common_test/src/Makefile
index 84b122b5e4..51624fbde7 100644
--- a/lib/common_test/src/Makefile
+++ b/lib/common_test/src/Makefile
@@ -69,7 +69,8 @@ MODULES= \
ct_config_xml \
ct_slave \
ct_hooks\
- ct_hooks_lock
+ ct_hooks_lock\
+ cth_log_redirect
TARGET_MODULES= $(MODULES:%=$(EBIN)/%)
diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl
new file mode 100644
index 0000000000..67899c392d
--- /dev/null
+++ b/lib/common_test/src/cth_log_redirect.erl
@@ -0,0 +1,87 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011. 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(cth_log_redirect).
+
+%%% @doc Common Test Framework functions handling test specifications.
+%%%
+%%% This module redirects sasl and error logger info to common test log.
+%%% @end
+
+
+%% CTH Callbacks
+-export([id/1, init/2, pre_init_per_testcase/3, post_end_per_testcase/4]).
+
+%% Event handler Callbacks
+-export([init/1,
+ handle_event/2, handle_call/2, handle_info/2,
+ terminate/2]).
+
+-record(state, { }).
+
+id(_Opts) ->
+ ?MODULE.
+
+init(?MODULE, _Opts) ->
+ error_logger:add_report_handler(?MODULE),
+ #state{ }.
+
+pre_init_per_testcase(_Testcase, Config, State) ->
+ {Config, State}.
+
+post_end_per_testcase(_TestCase, _Config, Result, State) ->
+ {Result, State}.
+
+%% Copied and modified from sasl_report_tty_h.erl
+init(Type) ->
+ {ok, Type}.
+
+handle_event({_Type, GL, _Msg}, State) when node(GL) /= node() ->
+ {ok, State};
+handle_event(Event, Type) ->
+ case proplists:get_value(sasl, application:which_applications()) of
+ undefined ->
+ sasl_not_started;
+ _Else ->
+ {ok, ErrLogType} = application:get_env(sasl, errlog_type),
+ SReport = sasl_report:format_report(group_leader(), ErrLogType,
+ tag_event(Event)),
+ if is_list(SReport) ->
+ ct:log(sasl, SReport, []);
+ true -> %% Report is an atom if no logging is to be done
+ ignore
+ end
+ end,
+ EReport = error_logger_tty_h:write_event(
+ tag_event(Event),io_lib),
+ if is_list(EReport) ->
+ ct:log(error_logger, EReport, []);
+ true -> %% Report is an atom if no logging is to be done
+ ignore
+ end,
+ {ok, Type}.
+
+handle_info(_,State) -> {ok, State}.
+
+handle_call(_Query, _Type) -> {error, bad_query}.
+
+terminate(_Reason, _Type) ->
+ [].
+
+tag_event(Event) ->
+ {calendar:local_time(), Event}.
--
cgit v1.2.3
From c047574239981e29681d1bd0ec4390fdd64c00ab Mon Sep 17 00:00:00 2001
From: Lukas Larsson
Date: Fri, 16 Sep 2011 17:18:22 +0200
Subject: Add ct_log:ct_log funcion
This function is used to force logging to CT
framework log instead of test case log.
---
lib/common_test/src/ct_logs.erl | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index b839521e24..6a90441d53 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -36,7 +36,7 @@
-export([make_all_suites_index/1,make_all_runs_index/1]).
%% Logging stuff directly from testcase
--export([tc_log/3,tc_print/3,tc_pal/3,
+-export([tc_log/3,tc_print/3,tc_pal/3,ct_log/3,
basic_html/0]).
%% Simulate logger process for use without ct environment running
@@ -360,6 +360,23 @@ tc_pal(Category,Format,Args) ->
ok.
+%%%-----------------------------------------------------------------
+%%% @spec tc_pal(Category,Format,Args) -> ok
+%%% Category = atom()
+%%% Format = string()
+%%% Args = list()
+%%%
+%%% @doc Print and log to the ct framework log
+%%%
+%%% This function is called by internal ct functions to
+%%% force logging to the ct framework log
+ct_log(Category,Format,Args) ->
+ cast({ct_log,[{div_header(Category),[]},
+ {Format,Args},
+ {div_footer(),[]}]}),
+ ok.
+
+
%%%=================================================================
%%% Internal functions
int_header() ->
@@ -516,7 +533,12 @@ logger_loop(State) ->
{clear_stylesheet,_} when State#logger_state.stylesheet == undefined ->
logger_loop(State);
{clear_stylesheet,_} ->
- logger_loop(State#logger_state{stylesheet=undefined});
+ logger_loop(State#logger_state{stylesheet=undefined});
+ {ct_log, List} ->
+ Fd = State#logger_state.ct_log_fd,
+ [begin io:format(Fd,Str,Args),io:nl(Fd) end ||
+ {Str,Args} <- List],
+ logger_loop(State);
stop ->
io:format(State#logger_state.ct_log_fd,
int_header()++int_footer(),
--
cgit v1.2.3
From 4d620ed2b9896762666fd5005f937f2229e5d242 Mon Sep 17 00:00:00 2001
From: Lukas Larsson
Date: Fri, 16 Sep 2011 17:19:17 +0200
Subject: Force logging to framework log for parallel tests
When parallel tests are run all logs are redirected to use
ct_logs:ct_log instead of ct_logs:tc_log.
---
lib/common_test/src/cth_log_redirect.erl | 50 +++++++++++++++++++++++---------
1 file changed, 36 insertions(+), 14 deletions(-)
diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl
index 67899c392d..21458c5903 100644
--- a/lib/common_test/src/cth_log_redirect.erl
+++ b/lib/common_test/src/cth_log_redirect.erl
@@ -25,36 +25,46 @@
%% CTH Callbacks
--export([id/1, init/2, pre_init_per_testcase/3, post_end_per_testcase/4]).
+-export([id/1, init/2, post_init_per_group/4, pre_end_per_group/3]).
%% Event handler Callbacks
-export([init/1,
handle_event/2, handle_call/2, handle_info/2,
terminate/2]).
--record(state, { }).
-
id(_Opts) ->
?MODULE.
init(?MODULE, _Opts) ->
error_logger:add_report_handler(?MODULE),
- #state{ }.
+ tc_log.
+
+post_init_per_group(Group, Config, Result, tc_log) ->
+ case lists:member(parallel,proplists:get_value(
+ tc_group_properties,Config,[])) of
+ true ->
+ {Result, {set_log_func(ct_log),Group}};
+ false ->
+ {Result, tc_log}
+ end;
+post_init_per_group(_Group, _Config, Result, State) ->
+ {Result, State}.
-pre_init_per_testcase(_Testcase, Config, State) ->
+
+pre_end_per_group(Group, Config, {ct_log, Group}) ->
+ {Config, set_log_func(tc_log)};
+pre_end_per_group(_Group, Config, State) ->
{Config, State}.
-post_end_per_testcase(_TestCase, _Config, Result, State) ->
- {Result, State}.
%% Copied and modified from sasl_report_tty_h.erl
-init(Type) ->
- {ok, Type}.
+init(_Type) ->
+ {ok, tc_log}.
handle_event({_Type, GL, _Msg}, State) when node(GL) /= node() ->
{ok, State};
-handle_event(Event, Type) ->
- case proplists:get_value(sasl, application:which_applications()) of
+handle_event(Event, LogFunc) ->
+ case lists:keyfind(sasl, 1, application:which_applications()) of
undefined ->
sasl_not_started;
_Else ->
@@ -62,7 +72,7 @@ handle_event(Event, Type) ->
SReport = sasl_report:format_report(group_leader(), ErrLogType,
tag_event(Event)),
if is_list(SReport) ->
- ct:log(sasl, SReport, []);
+ ct_logs:LogFunc(sasl, SReport, []);
true -> %% Report is an atom if no logging is to be done
ignore
end
@@ -70,12 +80,15 @@ handle_event(Event, Type) ->
EReport = error_logger_tty_h:write_event(
tag_event(Event),io_lib),
if is_list(EReport) ->
- ct:log(error_logger, EReport, []);
+ ct_logs:LogFunc(error_logger, EReport, []);
true -> %% Report is an atom if no logging is to be done
ignore
end,
- {ok, Type}.
+ {ok, LogFunc}.
+handle_info({set_logfunc,NewLogFunc,Reply},_) ->
+ Reply ! {ok,NewLogFunc},
+ {ok, NewLogFunc};
handle_info(_,State) -> {ok, State}.
handle_call(_Query, _Type) -> {error, bad_query}.
@@ -85,3 +98,12 @@ terminate(_Reason, _Type) ->
tag_event(Event) ->
{calendar:local_time(), Event}.
+
+set_log_func(Func) ->
+ error_logger ! {set_logfunc, Func, self()},
+ receive
+ {ok,Func} ->
+ Func
+ after 1000 ->
+ tc_log
+ end.
--
cgit v1.2.3
From 8906e44ddafe608d25c509d9adbc523b8f055ab7 Mon Sep 17 00:00:00 2001
From: Lukas Larsson
Date: Tue, 20 Sep 2011 10:48:57 +0200
Subject: Update cth_log_redirect to wait for all error_logger events before
ending test
---
lib/common_test/src/cth_log_redirect.erl | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl
index 21458c5903..54e86e2b95 100644
--- a/lib/common_test/src/cth_log_redirect.erl
+++ b/lib/common_test/src/cth_log_redirect.erl
@@ -25,7 +25,8 @@
%% CTH Callbacks
--export([id/1, init/2, post_init_per_group/4, pre_end_per_group/3]).
+-export([id/1, init/2, post_init_per_group/4, pre_end_per_group/3,
+ post_end_per_testcase/4]).
%% Event handler Callbacks
-export([init/1,
@@ -50,6 +51,11 @@ post_init_per_group(Group, Config, Result, tc_log) ->
post_init_per_group(_Group, _Config, Result, State) ->
{Result, State}.
+post_end_per_testcase(_TC, _Config, Result, State) ->
+ %% Make sure that the event queue is flushed
+ %% before ending this test case.
+ gen_event:call(error_logger, ?MODULE, flush),
+ {Result, State}.
pre_end_per_group(Group, Config, {ct_log, Group}) ->
{Config, set_log_func(tc_log)};
@@ -86,12 +92,14 @@ handle_event(Event, LogFunc) ->
end,
{ok, LogFunc}.
-handle_info({set_logfunc,NewLogFunc,Reply},_) ->
- Reply ! {ok,NewLogFunc},
- {ok, NewLogFunc};
+
handle_info(_,State) -> {ok, State}.
-handle_call(_Query, _Type) -> {error, bad_query}.
+handle_call(flush,State) ->
+ {ok, ok, State};
+handle_call({set_logfunc,NewLogFunc},_) ->
+ {ok, NewLogFunc, NewLogFunc};
+handle_call(_Query, _State) -> {error, bad_query}.
terminate(_Reason, _Type) ->
[].
@@ -100,10 +108,4 @@ tag_event(Event) ->
{calendar:local_time(), Event}.
set_log_func(Func) ->
- error_logger ! {set_logfunc, Func, self()},
- receive
- {ok,Func} ->
- Func
- after 1000 ->
- tc_log
- end.
+ gen_event:call(error_logger, ?MODULE, {set_logfunc, Func}).
--
cgit v1.2.3
From b7271367289625d5d2d22d95e1170c0cc26c07af Mon Sep 17 00:00:00 2001
From: Lukas Larsson
Date: Tue, 20 Sep 2011 11:11:16 +0200
Subject: Correct wrong match from lists:keyfind
---
lib/common_test/src/cth_log_redirect.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl
index 54e86e2b95..14663b7738 100644
--- a/lib/common_test/src/cth_log_redirect.erl
+++ b/lib/common_test/src/cth_log_redirect.erl
@@ -71,7 +71,7 @@ handle_event({_Type, GL, _Msg}, State) when node(GL) /= node() ->
{ok, State};
handle_event(Event, LogFunc) ->
case lists:keyfind(sasl, 1, application:which_applications()) of
- undefined ->
+ false ->
sasl_not_started;
_Else ->
{ok, ErrLogType} = application:get_env(sasl, errlog_type),
--
cgit v1.2.3
From 7d0d76f3a8170ddb5a3b07fd46fce835bb631cef Mon Sep 17 00:00:00 2001
From: Lukas Larsson
Date: Tue, 20 Sep 2011 15:42:54 +0200
Subject: Add documentation for cth_log_redirect and built-in hooks
OTP-9564
---
lib/common_test/doc/src/ct_hooks_chapter.xml | 32 ++++++++++++++++++++++++++++
lib/common_test/doc/src/run_test_chapter.xml | 10 ++++++++-
lib/common_test/src/ct.erl | 2 +-
3 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/lib/common_test/doc/src/ct_hooks_chapter.xml b/lib/common_test/doc/src/ct_hooks_chapter.xml
index dbb4310040..3b9620d0f2 100644
--- a/lib/common_test/doc/src/ct_hooks_chapter.xml
+++ b/lib/common_test/doc/src/ct_hooks_chapter.xml
@@ -405,6 +405,38 @@ terminate(State) ->
ok.
+
+
+ Built-in CTHs
+ Common Test is delivered with a couple of general purpose CTHs that
+ can be enabled by the user to provide some generic testing functionality.
+ Some of these are enabled by default when starting running common_test,
+ they can be disabled by setting enable_builtin_hooks to
+ false on the command line or in the test specification. In the
+ table below there is a list of all current CTHs which are delivered with
+ Common Test.
+
+
+
+ CTH Name |
+ Is Built-in |
+ Description |
+
+
+ cth_log_redirect |
+ yes |
+ Captures all error_logger and SASL logging events and prints them
+ to the current test case log. If an event can not be associated with a
+ testcase it will be printed in the common test framework log. This will
+ happen for testcases which are run in parallel and events which occur
+ inbetween testcases. You can configure the level of
+ SASL events report
+ using the normal SASL mechanisms. |
+
+
+
+
+
diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml
index e668568795..816aa5b1eb 100644
--- a/lib/common_test/doc/src/run_test_chapter.xml
+++ b/lib/common_test/doc/src/run_test_chapter.xml
@@ -150,6 +150,8 @@
event handlers including start arguments.
- ]]>, to install
Common Test Hooks including start arguments.
+ - ]]>, to enable/disable
+ Built-in Common Test Hooks. Default is true.
- , specifies include directories (see above).
- , disables the automatic test suite compilation feature (see above).
- ]]>, extends timetrap
@@ -450,6 +452,8 @@
{ct_hooks, CTHModules}.
{ct_hooks, NodeRefs, CTHModules}.
+
+ {enable_builtin_hooks, Bool}.
Test terms:
@@ -631,7 +635,11 @@
The minor log file contain full details of every single test
case, each one in a separate file. This way the files should
be easy to compare with previous test runs, even if the set of
- test cases change.
+ test cases change. If SASL is running those logs will also be
+ printed there by the
+
+ cth_log_redirect built-in hook.
+
Which information goes where is user configurable via the
test server controller. Three threshold values determine what
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index 66da3ef742..3a96190256 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -149,7 +149,7 @@ run(TestDirs) ->
%%% {repeat,N} | {duration,DurTime} | {until,StopTime} |
%%% {force_stop,Bool} | {decrypt,DecryptKeyOrFile} |
%%% {refresh_logs,LogDir} | {basic_html,Bool} |
-%%% {ct_hooks, CTHs}
+%%% {ct_hooks, CTHs} | {enable_builtin_hooks,Bool}
%%% TestDirs = [string()] | string()
%%% Suites = [string()] | string()
%%% Cases = [atom()] | atom()
--
cgit v1.2.3