aboutsummaryrefslogtreecommitdiffstats
path: root/lib/common_test/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/common_test/src')
-rw-r--r--lib/common_test/src/ct.erl3
-rw-r--r--lib/common_test/src/ct_framework.erl70
-rw-r--r--lib/common_test/src/ct_logs.erl58
-rw-r--r--lib/common_test/src/ct_repeat.erl38
-rw-r--r--lib/common_test/src/ct_run.erl14
-rw-r--r--lib/common_test/src/ct_telnet.erl39
6 files changed, 138 insertions, 84 deletions
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index 04a95a53fa..e6732f7fc7 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -153,7 +153,7 @@ run(TestDirs) ->
%%% {auto_compile,Bool} | {create_priv_dir,CreatePrivDir} |
%%% {multiply_timetraps,M} | {scale_timetraps,Bool} |
%%% {repeat,N} | {duration,DurTime} | {until,StopTime} |
-%%% {force_stop,Bool} | {decrypt,DecryptKeyOrFile} |
+%%% {force_stop,ForceStop} | {decrypt,DecryptKeyOrFile} |
%%% {refresh_logs,LogDir} | {logopts,LogOpts} |
%%% {verbosity,VLevels} | {basic_html,Bool} |
%%% {ct_hooks, CTHs} | {enable_builtin_hooks,Bool} |
@@ -184,6 +184,7 @@ run(TestDirs) ->
%%% N = integer()
%%% DurTime = string(HHMMSS)
%%% StopTime = string(YYMoMoDDHHMMSS) | string(HHMMSS)
+%%% ForceStop = skip_rest | Bool
%%% DecryptKeyOrFile = {key,DecryptKey} | {file,DecryptFile}
%%% DecryptKey = string()
%%% DecryptFile = string()
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index 5fe4eaf511..b92fe1555f 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -64,38 +64,46 @@ init_tc(Mod,Func,Config) ->
ok
end,
- case ct_util:get_testdata(curr_tc) of
- {Suite,{suite0_failed,{require,Reason}}} ->
- {skip,{require_failed_in_suite0,Reason}};
- {Suite,{suite0_failed,_}=Failure} ->
- {skip,Failure};
+ case Func=/=end_per_suite
+ andalso Func=/=end_per_group
+ andalso ct_util:get_testdata(skip_rest) of
+ true ->
+ {skip,"Repeated test stopped by force_stop option"};
_ ->
- ct_util:update_testdata(curr_tc,
- fun(undefined) ->
- [{Suite,Func}];
- (Running) ->
- [{Suite,Func}|Running]
- end, [create]),
- case ct_util:read_suite_data({seq,Suite,Func}) of
- undefined ->
- init_tc1(Mod,Suite,Func,Config);
- Seq when is_atom(Seq) ->
- case ct_util:read_suite_data({seq,Suite,Seq}) of
- [Func|TCs] -> % this is the 1st case in Seq
- %% make sure no cases in this seq are
- %% marked as failed from an earlier execution
- %% in the same suite
- lists:foreach(
- fun(TC) ->
- ct_util:save_suite_data({seq,Suite,TC},
- Seq)
- end, TCs);
- _ ->
- ok
- end,
- init_tc1(Mod,Suite,Func,Config);
- {failed,Seq,BadFunc} ->
- {skip,{sequence_failed,Seq,BadFunc}}
+ case ct_util:get_testdata(curr_tc) of
+ {Suite,{suite0_failed,{require,Reason}}} ->
+ {skip,{require_failed_in_suite0,Reason}};
+ {Suite,{suite0_failed,_}=Failure} ->
+ {skip,Failure};
+ _ ->
+ ct_util:update_testdata(curr_tc,
+ fun(undefined) ->
+ [{Suite,Func}];
+ (Running) ->
+ [{Suite,Func}|Running]
+ end, [create]),
+ case ct_util:read_suite_data({seq,Suite,Func}) of
+ undefined ->
+ init_tc1(Mod,Suite,Func,Config);
+ Seq when is_atom(Seq) ->
+ case ct_util:read_suite_data({seq,Suite,Seq}) of
+ [Func|TCs] -> % this is the 1st case in Seq
+ %% make sure no cases in this seq are
+ %% marked as failed from an earlier execution
+ %% in the same suite
+ lists:foreach(
+ fun(TC) ->
+ ct_util:save_suite_data(
+ {seq,Suite,TC},
+ Seq)
+ end, TCs);
+ _ ->
+ ok
+ end,
+ init_tc1(Mod,Suite,Func,Config);
+ {failed,Seq,BadFunc} ->
+ {skip,{sequence_failed,Seq,BadFunc}}
+ end
end
end.
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index 29858a1fcb..2e9c714ba2 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -671,20 +671,21 @@ logger_loop(State) ->
case erlang:is_process_alive(TCGL) of
true ->
State1 = print_to_log(SyncOrAsync, Pid,
+ Category,
TCGL, List, State),
logger_loop(State1#logger_state{
tc_groupleaders = TCGLs});
false ->
%% Group leader is dead, so write to the
- %% CtLog instead
- Fd = State#logger_state.ct_log_fd,
- [begin io:format(Fd,Str,Args),
- io:nl(Fd) end || {Str,Args} <- List],
+ %% CtLog or unexpected_io log instead
+ unexpected_io(Pid,Category,List,State),
logger_loop(State)
end;
- {ct_log,Fd,TCGLs} ->
- [begin io:format(Fd,Str,Args),io:nl(Fd) end ||
- {Str,Args} <- List],
+ {ct_log,_Fd,TCGLs} ->
+ %% If category is ct_internal then write
+ %% to ct_log, else write to unexpected_io
+ %% log
+ unexpected_io(Pid,Category,List,State),
logger_loop(State#logger_state{
tc_groupleaders = TCGLs})
end;
@@ -778,27 +779,32 @@ create_io_fun(FromPid, State) ->
end
end.
-print_to_log(sync, FromPid, TCGL, List, State) ->
- IoFun = create_io_fun(FromPid, State),
+print_to_log(sync, FromPid, Category, TCGL, List, State) ->
%% in some situations (exceptions), the printout is made from the
%% test server IO process and there's no valid group leader to send to
- IoProc = if FromPid /= TCGL -> TCGL;
- true -> State#logger_state.ct_log_fd
- end,
- io:format(IoProc, "~ts", [lists:foldl(IoFun, [], List)]),
+ if FromPid /= TCGL ->
+ IoFun = create_io_fun(FromPid, State),
+ io:format(TCGL,"~ts", [lists:foldl(IoFun, [], List)]);
+ true ->
+ unexpected_io(FromPid,Category,List,State)
+ end,
State;
-print_to_log(async, FromPid, TCGL, List, State) ->
- IoFun = create_io_fun(FromPid, State),
+print_to_log(async, FromPid, Category, TCGL, List, State) ->
%% in some situations (exceptions), the printout is made from the
%% test server IO process and there's no valid group leader to send to
- IoProc = if FromPid /= TCGL -> TCGL;
- true -> State#logger_state.ct_log_fd
- end,
- Printer = fun() ->
- test_server:permit_io(IoProc, self()),
- io:format(IoProc, "~ts", [lists:foldl(IoFun, [], List)])
- end,
+ Printer =
+ if FromPid /= TCGL ->
+ IoFun = create_io_fun(FromPid, State),
+ fun() ->
+ test_server:permit_io(TCGL, self()),
+ io:format(TCGL, "~ts", [lists:foldl(IoFun, [], List)])
+ end;
+ true ->
+ fun() ->
+ unexpected_io(FromPid,Category,List,State)
+ end
+ end,
case State#logger_state.async_print_jobs of
[] ->
{_Pid,Ref} = spawn_monitor(Printer),
@@ -3041,3 +3047,11 @@ html_encoding(latin1) ->
"iso-8859-1";
html_encoding(utf8) ->
"utf-8".
+
+unexpected_io(Pid,ct_internal,List,#logger_state{ct_log_fd=Fd}=State) ->
+ IoFun = create_io_fun(Pid,State),
+ io:format(Fd, "~ts", [lists:foldl(IoFun, [], List)]);
+unexpected_io(Pid,_Category,List,State) ->
+ IoFun = create_io_fun(Pid,State),
+ Data = io_lib:format("~ts", [lists:foldl(IoFun, [], List)]),
+ test_server_io:print_unexpected(Data).
diff --git a/lib/common_test/src/ct_repeat.erl b/lib/common_test/src/ct_repeat.erl
index a47309c6ee..f4d9949776 100644
--- a/lib/common_test/src/ct_repeat.erl
+++ b/lib/common_test/src/ct_repeat.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. 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
@@ -23,7 +23,7 @@
%%% start flags (or equivalent ct:run_test/1 options) are supported:
%%% -until <StopTime>, StopTime = YYMoMoDDHHMMSS | HHMMSS
%%% -duration <DurTime>, DurTime = HHMMSS
-%%% -force_stop
+%%% -force_stop [skip_rest]
%%% -repeat <N>, N = integer()</p>
-module(ct_repeat).
@@ -62,12 +62,15 @@ loop_test(If,Args) when is_list(Args) ->
io:format("\nCommon Test: "
"Will repeat tests for ~s.\n\n",[ts(Secs)]),
TPid =
- case lists:keymember(force_stop,1,Args) of
- true ->
+ case proplists:get_value(force_stop,Args) of
+ False when False==false; False==undefined ->
+ undefined;
+ ForceStop ->
CtrlPid = self(),
- spawn(fun() -> stop_after(CtrlPid,Secs) end);
- false ->
- undefined
+ spawn(
+ fun() ->
+ stop_after(CtrlPid,Secs,ForceStop)
+ end)
end,
Args1 = [{loop_info,[{stop_time,Secs,StopTime,1}]} | Args],
loop(If,stop_time,0,Secs,StopTime,Args1,TPid,[])
@@ -212,7 +215,7 @@ get_stop_time(until,[Y1,Y2,Mo1,Mo2,D1,D2,H1,H2,Mi1,Mi2,S1,S2]) ->
list_to_integer([S1,S2])},
calendar:datetime_to_gregorian_seconds({Date,Time});
-get_stop_time(until,Time) ->
+get_stop_time(until,Time=[_,_,_,_,_,_]) ->
get_stop_time(until,"000000"++Time);
get_stop_time(duration,[H1,H2,Mi1,Mi2,S1,S2]) ->
@@ -227,10 +230,17 @@ cancel(Pid) ->
%% After Secs, abort will make the test_server finish the current
%% job, then empty the job queue and stop.
-stop_after(_CtrlPid,Secs) ->
+stop_after(_CtrlPid,Secs,ForceStop) ->
timer:sleep(Secs*1000),
+ case ForceStop of
+ SkipRest when SkipRest==skip_rest; SkipRest==["skip_rest"] ->
+ ct_util:set_testdata({skip_rest,true});
+ _ ->
+ ok
+ end,
test_server_ctrl:abort().
+
%% Callback from ct_run to print loop info to system log.
log_loop_info(Args) ->
case lists:keysearch(loop_info,1,Args) of
@@ -259,11 +269,11 @@ log_loop_info(Args) ->
io_lib:format("Test time remaining: ~w secs (~w%)\n",
[Secs,trunc((Secs/Secs0)*100)]),
LogStr4 =
- case lists:keymember(force_stop,1,Args) of
- true ->
- io_lib:format("force_stop is enabled",[]);
- _ ->
- ""
+ case proplists:get_value(force_stop,Args) of
+ False when False==false; False==undefined ->
+ "";
+ ForceStop ->
+ io_lib:format("force_stop is set to: ~w",[ForceStop])
end,
ct_logs:log("Test loop info",LogStr1++LogStr2++LogStr3++LogStr4,[])
end.
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index ebb1c87905..41d53c7b43 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -778,9 +778,9 @@ script_usage() ->
"\n\t[-scale_timetraps]"
"\n\t[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]"
"\n\t[-basic_html]"
- "\n\t[-repeat N [-force_stop]] |"
- "\n\t[-duration HHMMSS [-force_stop]] |"
- "\n\t[-until [YYMoMoDD]HHMMSS [-force_stop]]\n\n"),
+ "\n\t[-repeat N] |"
+ "\n\t[-duration HHMMSS [-force_stop [skip_rest]]] |"
+ "\n\t[-until [YYMoMoDD]HHMMSS [-force_stop [skip_rest]]]\n\n"),
io:format("Run tests using test specification:\n\n"
"\tct_run -spec TestSpec1 TestSpec2 .. TestSpecN"
"\n\t[-config ConfigFile1 ConfigFile2 .. ConfigFileN]"
@@ -802,9 +802,9 @@ script_usage() ->
"\n\t[-scale_timetraps]"
"\n\t[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]"
"\n\t[-basic_html]"
- "\n\t[-repeat N [-force_stop]] |"
- "\n\t[-duration HHMMSS [-force_stop]] |"
- "\n\t[-until [YYMoMoDD]HHMMSS [-force_stop]]\n\n"),
+ "\n\t[-repeat N] |"
+ "\n\t[-duration HHMMSS [-force_stop [skip_rest]]] |"
+ "\n\t[-until [YYMoMoDD]HHMMSS [-force_stop [skip_rest]]]\n\n"),
io:format("Refresh the HTML index files:\n\n"
"\tct_run -refresh_logs [LogDir]"
"[-logdir LogDir] "
@@ -2947,6 +2947,8 @@ opts2args(EnvStartOpts) ->
[];
({create_priv_dir,PD}) when is_atom(PD) ->
[{create_priv_dir,[atom_to_list(PD)]}];
+ ({force_stop,skip_rest}) ->
+ [{force_stop,["skip_rest"]}];
({force_stop,true}) ->
[{force_stop,[]}];
({force_stop,false}) ->
diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl
index 02186864a5..beb3c1d649 100644
--- a/lib/common_test/src/ct_telnet.erl
+++ b/lib/common_test/src/ct_telnet.erl
@@ -728,7 +728,8 @@ teln_get_all_data(Pid,Prx,Data,Acc,LastLine) ->
haltpatterns=[],
seq=false,
repeat=false,
- found_prompt=false}).
+ found_prompt=false,
+ wait_for_linebreak=true}).
%% @hidden
%% @doc Externally the silent_teln_expect function shall only be used
@@ -754,20 +755,25 @@ silent_teln_expect(Pid,Data,Pattern,Prx,Opts) ->
%% condition is fullfilled.
%% 3b) Repeat (sequence): 2) is repeated either N times or until a
%% halt condition is fullfilled.
-teln_expect(Pid,Data,Pattern0,Prx,Opts) -> HaltPatterns = case
- get_ignore_prompt(Opts) of true -> get_haltpatterns(Opts); false
- -> [prompt | get_haltpatterns(Opts)] end,
-
+teln_expect(Pid,Data,Pattern0,Prx,Opts) ->
+ HaltPatterns = case get_ignore_prompt(Opts) of
+ true ->
+ get_haltpatterns(Opts);
+ false ->
+ [prompt | get_haltpatterns(Opts)]
+ end,
+ WaitForLineBreak = get_line_break_opt(Opts),
Seq = get_seq(Opts),
Pattern = convert_pattern(Pattern0,Seq),
-
+
Timeout = get_timeout(Opts),
-
+
EO = #eo{teln_pid=Pid,
prx=Prx,
timeout=Timeout,
seq=Seq,
- haltpatterns=HaltPatterns},
+ haltpatterns=HaltPatterns,
+ wait_for_linebreak=WaitForLineBreak},
case get_repeat(Opts) of
false ->
@@ -808,6 +814,11 @@ get_timeout(Opts) ->
{value,{timeout,T}} -> T;
false -> ?DEFAULT_TIMEOUT
end.
+get_line_break_opt(Opts) ->
+ case lists:keysearch(wait_for_linebreak,1,Opts) of
+ {value,{wait_for_linebreak,false}} -> false;
+ _ -> true
+ end.
get_repeat(Opts) ->
case lists:keysearch(repeat,1,Opts) of
{value,{repeat,N}} when is_integer(N) ->
@@ -1004,8 +1015,9 @@ seq_expect1(Data,[],Acc,Rest,_EO) ->
%% Split prompt-chunk at lines
match_lines(Data,Patterns,EO) ->
FoundPrompt = EO#eo.found_prompt,
+ NeedLineBreak = EO#eo.wait_for_linebreak,
case one_line(Data,[]) of
- {noline,Rest} when FoundPrompt=/=false ->
+ {noline,Rest} when FoundPrompt=/=false, NeedLineBreak =:= true ->
%% This is the line including the prompt
case match_line(Rest,Patterns,FoundPrompt,EO) of
nomatch ->
@@ -1013,7 +1025,14 @@ match_lines(Data,Patterns,EO) ->
{Tag,Match} ->
{Tag,Match,[]}
end;
- {noline,Rest} ->
+ {noline,Rest} when NeedLineBreak =:= false ->
+ case match_line(Rest,Patterns,FoundPrompt,EO) of
+ nomatch ->
+ {nomatch,prompt};
+ {Tag,Match} ->
+ {Tag,Match,[]}
+ end;
+ {noline, Rest} ->
{nomatch,Rest};
{Line,Rest} ->
case match_line(Line,Patterns,false,EO) of