From 7c6504029f84c52de40a6b29b2fd1b17c053ccec Mon Sep 17 00:00:00 2001 From: Peter Andersson Date: Thu, 3 Jun 2010 14:34:09 +0200 Subject: Add event_handler_init start flag that can pass init arguments to event handlers Also changed: The userconfig option in ct:run_test/1 from 3-tuple to 2-tuple. --- lib/common_test/doc/src/run_test.xml | 10 +- lib/common_test/src/ct.erl | 5 +- lib/common_test/src/ct_config.erl | 21 ++-- lib/common_test/src/ct_run.erl | 154 ++++++++++++++++++--------- lib/common_test/test/ct_smoke_test_SUITE.erl | 18 ++-- lib/common_test/test/ct_test_support.erl | 19 +++- lib/common_test/test/ct_test_support_eh.erl | 17 ++- 7 files changed, 169 insertions(+), 75 deletions(-) diff --git a/lib/common_test/doc/src/run_test.xml b/lib/common_test/doc/src/run_test.xml index 49538a7483..f98cefd0ee 100644 --- a/lib/common_test/doc/src/run_test.xml +++ b/lib/common_test/doc/src/run_test.xml @@ -63,13 +63,15 @@ [-step [config | keep_inactive]] [-config ConfigFile1 ConfigFile2 .. ConfigFileN] [-userconfig CallbackModule1 ConfigString1 and CallbackModule2 - ConfigString2 and .. and CallbackModuleN ConfigStringN] + ConfigString2 and .. and CallbackModuleN ConfigStringN] [-decrypt_key Key] | [-decrypt_file KeyFile] [-logdir LogDir] [-silent_connections [ConnType1 ConnType2 .. ConnTypeN]] [-stylesheet CSSFile] [-cover CoverCfgFile] - [-event_handler EvHandler1 EvHandler2 .. EvHandlerN] + [-event_handler EvHandler1 EvHandler2 .. EvHandlerN] | + [-event_handler_init EvHandler1 InitArg1 and + EvHandler2 InitArg2 and .. EvHandlerN InitArgN] [-include InclDir1 InclDir2 .. InclDirN] [-no_auto_compile] [-repeat N [-force_stop]] | @@ -90,7 +92,9 @@ [-silent_connections [ConnType1 ConnType2 .. ConnTypeN]] [-stylesheet CSSFile] [-cover CoverCfgFile] - [-event_handler EvHandler1 EvHandler2 .. EvHandlerN] + [-event_handler EvHandler1 EvHandler2 .. EvHandlerN] | + [-event_handler_init EvHandler1 InitArg1 and + EvHandler2 InitArg2 and .. EvHandlerN InitArgN] [-include InclDir1 InclDir2 .. InclDirN] [-no_auto_compile] [-repeat N [-force_stop]] | diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl index 57035719e2..307d10428d 100644 --- a/lib/common_test/src/ct.erl +++ b/lib/common_test/src/ct.erl @@ -139,7 +139,7 @@ run(TestDirs) -> %%% @spec run_test(Opts) -> Result %%% Opts = [OptTuples] %%% OptTuples = {config,CfgFiles} | {dir,TestDirs} | {suite,Suites} | -%%% {userconfig, Callback, CfgFiles} | +%%% {userconfig, UserConfig} | %%% {testcase,Cases} | {group,Groups} | {spec,TestSpecs} | %%% {allow_user_terms,Bool} | {logdir,LogDir} | %%% {silent_connections,Conns} | {cover,CoverSpecFile} | @@ -149,6 +149,9 @@ run(TestDirs) -> %%% {force_stop,Bool} | {decrypt,DecryptKeyOrFile} | %%% {refresh_logs,LogDir} | {basic_html,Bool} %%% CfgFiles = [string()] | string() +%%% UserConfig = [{CallbackMod,CfgStrings}] | {CallbackMod,CfgStrings} +%%% CallbackMod = atom() +%%% CfgStrings = [string()] | string() %%% TestDirs = [string()] | string() %%% Suites = [string()] | string() %%% Cases = [atom()] | atom() diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl index ee84164ad7..a7b8a9e906 100644 --- a/lib/common_test/src/ct_config.erl +++ b/lib/common_test/src/ct_config.erl @@ -181,15 +181,22 @@ process_default_configs(Opts) -> process_user_configs(Opts, Acc) -> case lists:keytake(userconfig, 1, Opts) of - false-> - Acc; - {value, {userconfig, {Callback, []}}, NewOpts}-> + false -> + lists:reverse(Acc); + {value, {userconfig, Config=[{_,_}|_]}, NewOpts} -> + Acc1 = lists:map(fun({_Callback, []}=Cfg) -> + Cfg; + ({Callback, Files=[File|_]}) when is_list(File) -> + {Callback, Files}; + ({Callback, File=[C|_]}) when is_integer(C) -> + {Callback, [File]} + end, Config), + process_user_configs(NewOpts, lists:reverse(Acc1)++Acc); + {value, {userconfig, {Callback, []}}, NewOpts} -> process_user_configs(NewOpts, [{Callback, []} | Acc]); - {value, {userconfig, {Callback, Files=[File|_]}}, NewOpts} when - is_list(File) -> + {value, {userconfig, {Callback, Files=[File|_]}}, NewOpts} when is_list(File) -> process_user_configs(NewOpts, [{Callback, Files} | Acc]); - {value, {userconfig, {Callback, File=[C|_]}}, NewOpts} when - is_integer(C) -> + {value, {userconfig, {Callback, File=[C|_]}}, NewOpts} when is_integer(C) -> process_user_configs(NewOpts, [{Callback, [File]} | Acc]) end. diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index 2c7d72c812..ec9351f346 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -78,6 +78,9 @@ script_start() -> (_) -> true end, Init), Args = case application:get_env(common_test, run_test_start_opts) of {ok,EnvStartOpts} -> + %%! --- Mon May 31 22:59:29 2010 --- peppe was here! + io:format(user, "~nEnv1:~n~p~n~n~p~n", [EnvStartOpts,opts2args(EnvStartOpts)]), + merge_arguments(CtArgs ++ opts2args(EnvStartOpts)); _ -> merge_arguments(CtArgs) @@ -146,12 +149,10 @@ script_start1(Parent, Args) -> LogDir = get_start_opt(logdir, fun([LogD]) -> LogD end, Args), MultTT = get_start_opt(multiply_timetraps, fun(MT) -> MT end, 1, Args), ScaleTT = get_start_opt(scale_timetraps, fun(CT) -> CT end, false, Args), - EvHandlers = get_start_opt(event_handler, - fun(Handlers) -> - lists:map(fun(H) -> - {list_to_atom(H),[]} - end, Handlers) end, - [], Args), + EvHandlers = event_handler_args2opts(Args), + + %%! --- Mon May 31 23:16:45 2010 --- peppe was here! + io:format(user, "~nEvHandlers = ~p~n~n", [EvHandlers]), %% check flags and set corresponding application env variables @@ -505,7 +506,10 @@ install(Opts, LogDir) -> case whereis(ct_util_server) of undefined -> VarFile = variables_file_name(LogDir), + + %%! --- Tue Jun 1 00:20:33 2010 --- peppe was here! io:format("Varfile = ~p~n", [VarFile]), + case file:open(VarFile, [write]) of {ok,Fd} -> [io:format(Fd, "~p.\n", [Opt]) || Opt <- Opts], @@ -599,6 +603,10 @@ run_test1(StartOpts) -> end, Hs)) end, + %%! --- Mon May 31 23:16:45 2010 --- peppe was here! + io:format("~nEvHandlers = ~p~n~n", [EvHandlers]), + io:format(user, "~nEvHandlers = ~p~n~n", [EvHandlers]), + %% silent connections SilentConns = get_start_opt(silent_connections, fun(all) -> []; @@ -777,7 +785,7 @@ run_dir(Opts = #opts{logdir = LogDir, ok -> ok; {error,IReason} -> exit(IReason) end, - case lists:keysearch(dir, 1, Opts) of + case lists:keysearch(dir, 1, StartOpts) of {value,{_,Dirs=[Dir|_]}} when not is_integer(Dir), length(Dirs)>1 -> %% multiple dirs (no suite) @@ -790,11 +798,11 @@ run_dir(Opts = #opts{logdir = LogDir, (A) -> {".",A} end, - case lists:keysearch(suite, 1, Opts) of + case lists:keysearch(suite, 1, StartOpts) of {value,{_,Suite}} when is_integer(hd(Suite)) ; is_atom(Suite) -> {Dir,Mod} = S2M(Suite), - case listify(proplists:get_value(group, Opts, [])) ++ - listify(proplists:get_value(testcase, Opts, [])) of + case listify(proplists:get_value(group, StartOpts, [])) ++ + listify(proplists:get_value(testcase, StartOpts, [])) of [] -> do_run(tests(Dir, listify(Mod)), [], Opts, StartOpts); GsAndCs -> @@ -806,13 +814,13 @@ run_dir(Opts = #opts{logdir = LogDir, exit(no_tests_specified) end; {value,{_,Dir}} -> - case lists:keysearch(suite, 1, Opts) of + case lists:keysearch(suite, 1, StartOpts) of {value,{_,Suite}} when is_integer(hd(Suite)) ; is_atom(Suite) -> Mod = if is_atom(Suite) -> Suite; true -> list_to_atom(Suite) end, - case listify(proplists:get_value(group, Opts, [])) ++ - listify(proplists:get_value(testcase, Opts, [])) of + case listify(proplists:get_value(group, StartOpts, [])) ++ + listify(proplists:get_value(testcase, StartOpts, [])) of [] -> do_run(tests(Dir, listify(Mod)), [], Opts, StartOpts); GsAndCs -> @@ -1028,7 +1036,7 @@ do_run(Tests, Misc, LogDir) when is_list(Misc) -> CoverFile -> Opts#opts{cover = CoverFile} end, - do_run(Tests, [], Opts1#opts{tests = Tests, logdir = LogDir}, []). + do_run(Tests, [], Opts1#opts{logdir = LogDir}, []). do_run(Tests, Skip, Opts, Args) -> #opts{cover = Cover} = Opts, @@ -1759,46 +1767,29 @@ log_ts_names(Specs) -> [lists:flatten(List)]). merge_arguments(Args) -> - case proplists:get_value(ct_ignore, Args) of - undefined -> - merge_arguments(Args, [], []); - Ignore -> - merge_arguments(Args, [], [list_to_atom(I) || I <- Ignore]) - end. + merge_arguments(Args, []). -merge_arguments([LogDir={logdir,_}|Args], Merged, Ignore) -> - case lists:member(logdir, Ignore) of - true -> - merge_arguments(Args, Merged, Ignore); - false -> - merge_arguments(Args, handle_arg(replace, LogDir, Merged), Ignore) - end; -merge_arguments([CoverFile={cover,_}|Args], Merged, Ignore) -> - case lists:member(cover, Ignore) of - true -> - merge_arguments(Args, Merged, Ignore); - false -> - merge_arguments(Args, handle_arg(replace, CoverFile, Merged), Ignore) - end; -merge_arguments([{'case',TC}|Args], Merged, Ignore) -> - case lists:member('case', Ignore) of - true -> - merge_arguments(Args, Merged, Ignore); - false -> - merge_arguments(Args, handle_arg(merge, {testcase,TC}, Merged), Ignore) - end; -merge_arguments([Arg={Opt,_}|Args], Merged, Ignore) -> - case lists:member(Opt, Ignore) of - true -> - merge_arguments(Args, Merged, Ignore); - false -> - merge_arguments(Args, handle_arg(merge, Arg, Merged), Ignore) - end; -merge_arguments([], Merged, _Ignore) -> +merge_arguments([LogDir={logdir,_}|Args], Merged) -> + merge_arguments(Args, handle_arg(replace, LogDir, Merged)); + +merge_arguments([CoverFile={cover,_}|Args], Merged) -> + merge_arguments(Args, handle_arg(replace, CoverFile, Merged)); + +merge_arguments([{'case',TC}|Args], Merged) -> + merge_arguments(Args, handle_arg(merge, {testcase,TC}, Merged)); + +merge_arguments([Arg|Args], Merged) -> + merge_arguments(Args, handle_arg(merge, Arg, Merged)); + +merge_arguments([], Merged) -> Merged. handle_arg(replace, {Key,Elems}, [{Key,_}|Merged]) -> [{Key,Elems}|Merged]; +handle_arg(merge, {event_handler_init,Elems}, [{event_handler_init,PrevElems}|Merged]) -> + [{event_handler_init,PrevElems++["add"|Elems]}|Merged]; +handle_arg(merge, {userconfig,Elems}, [{userconfig,PrevElems}|Merged]) -> + [{userconfig,PrevElems++["add"|Elems]}|Merged]; handle_arg(merge, {Key,Elems}, [{Key,PrevElems}|Merged]) -> [{Key,PrevElems++Elems}|Merged]; handle_arg(Op, Arg, [Other|Merged]) -> @@ -1823,12 +1814,47 @@ get_start_opt(Key, IfExists, IfNotExists, Args) -> IfNotExists end. +event_handler_args2opts(Args) -> + case proplists:get_value(event_handler, Args) of + undefined -> + event_handler_args2opts([], Args); + EHs -> + event_handler_args2opts([{list_to_atom(EH),[]} || EH <- EHs], Args) + end. +event_handler_args2opts(Default, Args) -> + case proplists:get_value(event_handler_init, Args) of + undefined -> + Default; + EHs -> + event_handler_init_args2opts(EHs) + end. +event_handler_init_args2opts([EH, Arg, "and" | EHs]) -> + [{list_to_atom(EH),lists:flatten(io_lib:format("~s",[Arg]))} | + event_handler_init_args2opts(EHs)]; +event_handler_init_args2opts([EH, Arg]) -> + [{list_to_atom(EH),lists:flatten(io_lib:format("~s",[Arg]))}]; +event_handler_init_args2opts([]) -> + []. + %% this function translates ct:run_test/1 start options %% to run_test start arguments (on the init arguments format) - %% this is useful mainly for testing the ct_run start functions opts2args(EnvStartOpts) -> lists:flatmap(fun({config,CfgFiles}) -> - [{ct_config,CfgFiles}]; + [{ct_config,[CfgFiles]}]; + ({userconfig,{CBM,CfgStr=[X|_]}}) when is_integer(X) -> + [{userconfig,[atom_to_list(CBM),CfgStr]}]; + ({userconfig,{CBM,CfgStrs}}) when is_list(CfgStrs) -> + [{userconfig,[atom_to_list(CBM) | CfgStrs]}]; + ({userconfig,UserCfg}) when is_list(UserCfg) -> + Strs = + lists:map(fun({CBM,CfgStr=[X|_]}) when is_integer(X) -> + [atom_to_list(CBM),CfgStr,"and"]; + ({CBM,CfgStrs}) when is_list(CfgStrs) -> + [atom_to_list(CBM) | CfgStrs] ++ ["and"] + end, UserCfg), + [_LastAnd|StrsR] = lists:reverse(lists:flatten(Strs)), + [{userconfig,lists:reverse(StrsR)}]; ({testcase,Cases}) -> [{'case',[atom_to_list(C) || C <- Cases]}]; ({'case',Cases}) -> @@ -1850,13 +1876,37 @@ opts2args(EnvStartOpts) -> ({force_stop,false}) -> []; ({decrypt,{key,Key}}) -> - [{ct_decrypt_key,Key}]; + [{ct_decrypt_key,[Key]}]; ({decrypt,{file,File}}) -> - [{ct_decrypt_file,File}]; + [{ct_decrypt_file,[File]}]; ({basic_html,true}) -> ({basic_html,[]}); ({basic_html,false}) -> []; + ({event_handler,EH}) when is_atom(EH) -> + [{event_handler,[atom_to_list(EH)]}]; + ({event_handler,EHs}) when is_list(EHs) -> + [{event_handler,[atom_to_list(EH) || EH <- EHs]}]; + ({event_handler,{EH,Arg}}) when is_atom(EH) -> + ArgStr = lists:flatten(io_lib:format("~p", [Arg])), + [{event_handler_init,[atom_to_list(EH),ArgStr]}]; + ({event_handler,{EHs,Arg}}) when is_list(EHs) -> + ArgStr = lists:flatten(io_lib:format("~p", [Arg])), + Strs = lists:map(fun(EH) -> + [atom_to_list(EH),ArgStr,"and"] + end, EHs), + [_LastAnd|StrsR] = lists:reverse(lists:flatten(Strs)), + [{event_handler_init,lists:reverse(StrsR)}]; + ({Opt,As=[A|_]}) when is_atom(A) -> + [{Opt,[atom_to_list(Atom) || Atom <- As]}]; + ({Opt,Strs=[S|_]}) when is_list(S) -> + [{Opt,[Strs]}]; + ({Opt,A}) when is_atom(A) -> + [{Opt,[atom_to_list(A)]}]; + ({Opt,I}) when is_integer(I) -> + [{Opt,[integer_to_list(I)]}]; + ({Opt,S}) when is_list(S) -> + [{Opt,[S]}]; (Opt) -> Opt end, EnvStartOpts). diff --git a/lib/common_test/test/ct_smoke_test_SUITE.erl b/lib/common_test/test/ct_smoke_test_SUITE.erl index f1c695f614..76136b1d69 100644 --- a/lib/common_test/test/ct_smoke_test_SUITE.erl +++ b/lib/common_test/test/ct_smoke_test_SUITE.erl @@ -162,7 +162,7 @@ dir1(Config) when is_list(Config) -> ERPid = ct_test_support:start_event_receiver(Config), - ok = ct_test_support:run(ct, run_test, [Opts], Config), + {ok,ok} = ct_test_support:run(Opts, Config), Events = ct_test_support:get_events(ERPid, Config), @@ -191,7 +191,7 @@ dir2(Config) when is_list(Config) -> ERPid = ct_test_support:start_event_receiver(Config), - ok = ct_test_support:run(ct, run_test, [Opts], Config), + {ok,ok} = ct_test_support:run(Opts, Config), Events = ct_test_support:get_events(ERPid, Config), @@ -221,7 +221,7 @@ dir1_2(Config) when is_list(Config) -> ERPid = ct_test_support:start_event_receiver(Config), - ok = ct_test_support:run(ct, run_test, [Opts], Config), + {ok,ok} = ct_test_support:run(Opts, Config), Events = ct_test_support:get_events(ERPid, Config), @@ -251,7 +251,7 @@ suite11(Config) when is_list(Config) -> ERPid = ct_test_support:start_event_receiver(Config), - ok = ct_test_support:run(ct, run_test, [Opts], Config), + {ok,ok} = ct_test_support:run(Opts, Config), Events = ct_test_support:get_events(ERPid, Config), @@ -280,7 +280,7 @@ suite21(Config) when is_list(Config) -> ERPid = ct_test_support:start_event_receiver(Config), - ok = ct_test_support:run(ct, run_test, [Opts], Config), + {ok,ok} = ct_test_support:run(Opts, Config), Events = ct_test_support:get_events(ERPid, Config), @@ -311,7 +311,7 @@ suite11_21(Config) when is_list(Config) -> ERPid = ct_test_support:start_event_receiver(Config), - ok = ct_test_support:run(ct, run_test, [Opts], Config), + {ok,ok} = ct_test_support:run(Opts, Config), Events = ct_test_support:get_events(ERPid, Config), @@ -342,7 +342,7 @@ tc111(Config) when is_list(Config) -> ERPid = ct_test_support:start_event_receiver(Config), - ok = ct_test_support:run(ct, run_test, [Opts], Config), + {ok,ok} = ct_test_support:run(Opts, Config), Events = ct_test_support:get_events(ERPid, Config), @@ -372,7 +372,7 @@ tc211(Config) when is_list(Config) -> ERPid = ct_test_support:start_event_receiver(Config), - ok = ct_test_support:run(ct, run_test, [Opts], Config), + {ok,ok} = ct_test_support:run(Opts, Config), Events = ct_test_support:get_events(ERPid, Config), @@ -403,7 +403,7 @@ tc111_112(Config) when is_list(Config) -> ERPid = ct_test_support:start_event_receiver(Config), - ok = ct_test_support:run(ct, run_test, [Opts], Config), + {ok,ok} = ct_test_support:run(Opts, Config), Events = ct_test_support:get_events(ERPid, Config), diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl index 0ce103e111..c3dc706d9b 100644 --- a/lib/common_test/test/ct_test_support.erl +++ b/lib/common_test/test/ct_test_support.erl @@ -28,7 +28,7 @@ -export([init_per_suite/1, init_per_suite/2, end_per_suite/1, init_per_testcase/2, end_per_testcase/2, write_testspec/3, - run/4, get_opts/1, wait_for_ct_stop/1]). + run/2, run/4, get_opts/1, wait_for_ct_stop/1]). -export([handle_event/2, start_event_receiver/1, get_events/2, verify_events/3, reformat/2, log_events/3]). @@ -172,6 +172,23 @@ get_opts(Config) -> %%%----------------------------------------------------------------- %%% +run(Opts, Config) -> + CTNode = ?config(ct_node, Config), + Level = ?config(trace_level, Config), + %% use ct interface + test_server:format(Level, "Calling ct:run_test(~p) on ~p~n", + [Opts, CTNode]), + Result1 = rpc:call(CTNode, ct, run_test, [Opts]), + + %% use run_test interface (simulated) + test_server:format(Level, "Saving start opts on ~p: ~p~n", [CTNode,Opts]), + rpc:call(CTNode, application, set_env, [common_test, run_test_start_opts, Opts]), + test_server:format(Level, "Calling ct_run:script_start() on ~p~n", [CTNode]), + Result2 = rpc:call(CTNode, ct_run, script_start, []), + + {Result1,Result2}. + + run(M, F, A, Config) -> CTNode = ?config(ct_node, Config), Level = ?config(trace_level, Config), diff --git a/lib/common_test/test/ct_test_support_eh.erl b/lib/common_test/test/ct_test_support_eh.erl index fd3ae18746..1454d20e47 100644 --- a/lib/common_test/test/ct_test_support_eh.erl +++ b/lib/common_test/test/ct_test_support_eh.erl @@ -44,8 +44,20 @@ %% Description: Whenever a new event handler is added to an event manager, %% this function is called to initialize the event handler. %%-------------------------------------------------------------------- +init(String = [X|_]) when is_integer(X) -> + case erl_scan:string(String++".") of + {ok,Ts,_} -> + case erl_parse:parse_term(Ts) of + {ok,Args} -> + init(Args); + _ -> + init(String) + end; + _ -> + init(String) + end; + init(Args) -> - S1 = case lists:keysearch(cbm, 1, Args) of {_,{cbm,CBM}} -> #state{cbm=CBM}; @@ -58,7 +70,8 @@ init(Args) -> _ -> S1 end, - print(S2#state.trace_level, "Event Handler ~w started!~n", [?MODULE]), + print(S2#state.trace_level, "Event Handler ~w started with ~p~n", + [?MODULE,Args]), {ok,S2}. %%-------------------------------------------------------------------- -- cgit v1.2.3