diff options
Diffstat (limited to 'lib/common_test')
-rw-r--r-- | lib/common_test/doc/src/ct_hooks_chapter.xml | 20 | ||||
-rw-r--r-- | lib/common_test/doc/src/event_handler_chapter.xml | 5 | ||||
-rw-r--r-- | lib/common_test/doc/src/notes.xml | 81 | ||||
-rw-r--r-- | lib/common_test/doc/src/run_test_chapter.xml | 16 | ||||
-rw-r--r-- | lib/common_test/src/ct_conn_log_h.erl | 27 | ||||
-rw-r--r-- | lib/common_test/src/ct_netconfc.erl | 75 | ||||
-rw-r--r-- | lib/common_test/src/ct_run.erl | 20 | ||||
-rw-r--r-- | lib/common_test/src/ct_slave.erl | 10 | ||||
-rw-r--r-- | lib/common_test/src/ct_snmp.erl | 18 | ||||
-rw-r--r-- | lib/common_test/src/ct_telnet.erl | 12 | ||||
-rw-r--r-- | lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl | 47 | ||||
-rw-r--r-- | lib/common_test/test/ct_netconfc_SUITE_data/ns.erl | 17 | ||||
-rw-r--r-- | lib/common_test/vsn.mk | 2 |
13 files changed, 255 insertions, 95 deletions
diff --git a/lib/common_test/doc/src/ct_hooks_chapter.xml b/lib/common_test/doc/src/ct_hooks_chapter.xml index d9892c66f7..3905e23dcc 100644 --- a/lib/common_test/doc/src/ct_hooks_chapter.xml +++ b/lib/common_test/doc/src/ct_hooks_chapter.xml @@ -30,8 +30,8 @@ <file>ct_hooks_chapter.xml</file> </header> - <marker id="general"></marker> <section> + <marker id="general"></marker> <title>General</title> <p> The <em>Common Test Hook</em> (henceforth called CTH) framework allows @@ -60,8 +60,8 @@ </section> - <marker id="installing"></marker> <section> + <marker id="installing"></marker> <title>Installing a CTH</title> <p>There are multiple ways to install a CTH in your test run. You can do it for all tests in a run, for specific test suites and for specific groups @@ -120,8 +120,8 @@ </section> </section> - <marker id="scope"/> <section> + <marker id="scope"/> <title>CTH Scope</title> <p>Once the CTH is installed into a certain test run it will be there until its scope is expired. The scope of a CTH depends on when it is @@ -208,8 +208,8 @@ </section> - <marker id="manipulating"/> <section> + <marker id="manipulating"/> <title>Manipulating tests</title> <p>It is through CTHs possible to manipulate the results of tests and configuration functions. The main purpose of doing this with CTHs is to @@ -226,8 +226,8 @@ makes it possible to use hooks as configuration fallbacks, or even completely replace all configuration functions with hook functions.</p> - <marker id="pre"/> <section> + <marker id="pre"/> <title>Pre Hooks</title> <p> It is possible in a CTH to hook in behaviour before @@ -263,8 +263,8 @@ </section> - <marker id="post"/> <section> + <marker id="post"/> <title>Post Hooks</title> <p>It is also possible in a CTH to hook in behaviour after <seealso marker="common_test#Module:init_per_suite-1">init_per_suite</seealso>, @@ -308,8 +308,8 @@ post_end_per_testcase(_TC, Config, Return, CTHState) -> </section> - <marker id="skip_n_fail"/> <section> + <marker id="skip_n_fail"/> <title>Skip and Fail hooks</title> <p> After any post hook has been executed for all installed CTHs, @@ -323,8 +323,8 @@ post_end_per_testcase(_TC, Config, Return, CTHState) -> </section> - <marker id="synchronizing"/> <section> + <marker id="synchronizing"/> <title>Synchronizing external user applications with Common Test</title> <p>CTHs can be used to synchronize test runs with external user applications. The init function may e.g. start and/or communicate with an application that @@ -351,8 +351,8 @@ post_end_per_testcase(_TC, Config, Return, CTHState) -> </p> </section> - <marker id="example"/> <section> + <marker id="example"/> <title>Example CTH</title> <p>The CTH below will log information about a test run into a format parseable by <seealso marker="kernel:file#consult-1">file:consult/1</seealso>. @@ -455,8 +455,8 @@ terminate(State) -> ok.</code> </section> - <marker id="builtin_cths"/> <section> + <marker id="builtin_cths"/> <title>Built-in CTHs</title> <p>Common Test is delivered with a couple of general purpose CTHs that can be enabled by the user to provide some generic testing functionality. diff --git a/lib/common_test/doc/src/event_handler_chapter.xml b/lib/common_test/doc/src/event_handler_chapter.xml index cb7033b196..78e5bb5e70 100644 --- a/lib/common_test/doc/src/event_handler_chapter.xml +++ b/lib/common_test/doc/src/event_handler_chapter.xml @@ -194,8 +194,9 @@ the current test case log file. </p></item> - <marker id="tc_done"/> - <item><c>#event{name = tc_done, data = {Suite,FuncOrGroup,Result}}</c> + <item> + <marker id="tc_done"/> + <c>#event{name = tc_done, data = {Suite,FuncOrGroup,Result}}</c> <p><c>Suite = atom()</c>, name of the suite.</p> <p><c>FuncOrGroup = Func | {Conf,GroupName,GroupProperties}</c></p> <p><c>Func = atom()</c>, name of test case or configuration function.</p> diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml index aaf6dffc88..9906db2c90 100644 --- a/lib/common_test/doc/src/notes.xml +++ b/lib/common_test/doc/src/notes.xml @@ -33,6 +33,66 @@ <file>notes.xml</file> </header> +<section><title>Common_Test 1.11.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + When data from the netconf server was split into many ssh + packages, the netconf client performed really bad. This + is now improved.</p> + <p> + Own Id: OTP-13007</p> + </item> + <item> + <p> + In ct_netconfc, if a timer expired 'at the same time' as + the server sent the rpc-reply, the timeout message might + already be in the client's message queue when the client + removed the timer ref from its 'pending' list. This + caused a crash in the client since the timer ref could no + longer be found when handling the timeout message. This + problem is now fixed by always flushing the timeout + message from the message queue when canceling a timer.</p> + <p> + Own Id: OTP-13008</p> + </item> + <item> + <p> + The error logger handler ct_conn_log_h did not respect + the 'silent' option, and tried to print to an undefined + file descriptor. This has been corrected.</p> + <p> + Own Id: OTP-13035</p> + </item> + <item> + <p> + If the user would let the test run proceed after test + suite compilation failure, Common Test did not set the + exit status to indicate failure as expected. This has + been corrected. Also, the 'abort_if_missing_suites' + option now makes Common Test abort the test run without + asking the user if compilation fails, even if access to + stdin/stdout exists.</p> + <p> + Own Id: OTP-13173 Aux Id: seq12978 </p> + </item> + <item> + <p> + With the Common Test 'create_priv_dir' start option set + to 'auto_per_tc', the name of the priv directory for a + configuration function could clash with the name of the + priv directory for a test case, which would cause Test + Server failure. This error has been corrected.</p> + <p> + Own Id: OTP-13181</p> + </item> + </list> + </section> + +</section> + <section><title>Common_Test 1.11</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -760,7 +820,7 @@ configuration function or test specification term), the affected test cases get the status <c>user_skipped</c> instead.</p> <p>This update has meant a few changes that - may affect Common Test users in various ways: <list> + may affect Common Test users in various ways:</p> <list> <item>The test results and statistics will be affected, which is important to know when running regression tests and comparing results to previous test runs.</item> @@ -780,7 +840,7 @@ <c>auto_skipped</c> rather than <c>user_skipped</c> as before.</item> <item>The event messages that Common Test generates during test runs have been affected by this - update. For details see OTP-11524.</item> </list> </p> + update. For details see OTP-11524.</item> </list> <p> Own Id: OTP-11305 Aux Id: OTP-11524 </p> </item> @@ -831,7 +891,7 @@ <item> <p>The following modifications have been made to the event messages that Common Test sends during test - execution: <list> <item>For the <c>tc_auto_skip</c> + execution:</p> <list> <item>For the <c>tc_auto_skip</c> event, the value of the <c>Func</c> element has changed from <c>end_per_group</c> to <c>{end_per_group,GroupName}</c>.</item> <item>When @@ -843,7 +903,7 @@ configuration name already in use, the <c>tc_done</c> event now reports the error with a tuple (of size 2) tagged <c>failed</c> instead of <c>skipped</c>.</item> - </list> Please see the Event Handling chapter in the + </list> <p>Please see the Event Handling chapter in the Common Test User's Guide for reference. </p> <p> Own Id: OTP-11524 Aux Id: OTP-11305 </p> @@ -1247,7 +1307,6 @@ <item> <p> Some bugfixes in <c>ct_snmp:</c></p> - <p> <list> <item> ct_snmp will now use the value of the 'agent_vsns' config variable when setting the 'variables' parameter to snmp application agent configuration. @@ -1255,14 +1314,13 @@ supported versions had to be specified twice. </item> <item> Snmp application failed to write notify.conf since ct_snmp gave the notify type as a string instead of an - atom. This has been corrected. </item> </list></p> + atom. This has been corrected. </item> </list> <p> Own Id: OTP-10432</p> </item> <item> <p> Some bugfixes in <c>ct_snmp</c>:</p> - <p> <list> <item> Functions <c>register_users/2</c>, <c>register_agents/2</c> and <c>register_usm_users/2</c>, and the corresponding <c>unregister_*/1</c> functions @@ -1279,7 +1337,7 @@ priv_dir instead of in the configuration dir (priv_dir/conf). This has been corrected. </item> <item> Arguments to <c>register_usm_users/2</c> were faulty - documented. This has been corrected. </item> </list></p> + documented. This has been corrected. </item> </list> <p> Own Id: OTP-10434 Aux Id: kunagi-264 [175] </p> </item> @@ -1343,7 +1401,7 @@ </item> <item> <p> - Update common test modules to handle unicode <list> + Update common test modules to handle unicode:</p> <list> <item> Use UTF-8 encoding for all HTML files, except the HTML version of the test suite generated with erl2html2:convert, which will have the same encoding as @@ -1354,7 +1412,7 @@ unicode:characters_to_list and unicode:characters_to_binary for conversion between binaries and strings instead of binary_to_list and - list_to_binary. </item> </list></p> + list_to_binary. </item> </list> <p> Own Id: OTP-10783</p> </item> @@ -1395,7 +1453,6 @@ <p> The following corrections/changes are done in the cth_surefire hook:</p> - <p> <list> <item> Earlier there would always be a 'properties' element under the 'testsuites' element. This would exist even if there were no 'property' element @@ -1428,7 +1485,7 @@ </item> <item> A new option named 'url_base' is added for this hook. If this option is used, a new attribute named 'url' will be added to the 'testcase' and 'testsuite' - elements. </item> </list></p> + elements. </item> </list> <p> Own Id: OTP-10589</p> </item> diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml index d80453fc98..082a587c8d 100644 --- a/lib/common_test/doc/src/run_test_chapter.xml +++ b/lib/common_test/doc/src/run_test_chapter.xml @@ -60,15 +60,15 @@ <p>If compilation should fail for one or more suites, the compilation errors are printed to tty and the operator is asked if the test run should proceed without the missing suites, or be aborted. If the operator chooses to proceed, - it is noted in the HTML log which tests have missing suites. If Common Test is - unable to prompt the user after compilation failure (if Common Test doesn't - control stdin), the test run will proceed automatically without the missing - suites. This behaviour can however be modified with the - <c><![CDATA[ct_run]]></c> flag <c><![CDATA[-abort_if_missing_suites]]></c>, + it is noted in the HTML log which tests have missing suites. Also, for each failed + compilation, the failed tests counter in the return value of + <c><![CDATA[ct:run_test/1]]></c> is incremented. If Common Test is unable to prompt + the user after compilation failure (if Common Test doesn't control stdin), the test + run will proceed automatically without the missing suites. In order to always + abort the test run (without operator interaction) if one or more suites fail + to compile, the <c><![CDATA[ct_run]]></c> flag <c><![CDATA[-abort_if_missing_suites]]></c>, or the <c><![CDATA[ct:run_test/1]]></c> option - <c><![CDATA[{abort_if_missing_suites,TrueOrFalse}]]></c>. If - <c><![CDATA[abort_if_missing_suites]]></c> is set (to true), the test run - will stop immediately if some suites fail to compile.</p> + <c><![CDATA[{abort_if_missing_suites,true}]]></c> should be set.</p> <p>Any help module (i.e. regular Erlang module with name not ending with "_SUITE") that resides in the same test object directory as a suite diff --git a/lib/common_test/src/ct_conn_log_h.erl b/lib/common_test/src/ct_conn_log_h.erl index 2dd4fdac05..f7615fdc14 100644 --- a/lib/common_test/src/ct_conn_log_h.erl +++ b/lib/common_test/src/ct_conn_log_h.erl @@ -104,18 +104,31 @@ terminate(_,#state{logs=Logs}) -> %%%----------------------------------------------------------------- %%% Writing reports write_report(_Time,#conn_log{header=false,module=ConnMod}=Info,Data,GL,State) -> - {LogType,Fd} = get_log(Info,GL,State), - io:format(Fd,"~n~ts",[format_data(ConnMod,LogType,Data)]); + case get_log(Info,GL,State) of + {silent,_} -> + ok; + {LogType,Fd} -> + io:format(Fd,"~n~ts",[format_data(ConnMod,LogType,Data)]) + end; write_report(Time,#conn_log{module=ConnMod}=Info,Data,GL,State) -> - {LogType,Fd} = get_log(Info,GL,State), - io:format(Fd,"~n~ts~ts~ts",[format_head(ConnMod,LogType,Time), - format_title(LogType,Info), - format_data(ConnMod,LogType,Data)]). + case get_log(Info,GL,State) of + {silent,_} -> + ok; + {LogType,Fd} -> + case format_data(ConnMod,LogType,Data) of + [] -> + ok; + FormattedData -> + io:format(Fd,"~n~ts~ts~ts",[format_head(ConnMod,LogType,Time), + format_title(LogType,Info), + FormattedData]) + end + end. write_error(Time,#conn_log{module=ConnMod}=Info,Report,GL,State) -> case get_log(Info,GL,State) of - {html,_} -> + {LogType,_} when LogType==html; LogType==silent -> %% The error will anyway be written in the html log by the %% sasl error handler, so don't write it again. ok; diff --git a/lib/common_test/src/ct_netconfc.erl b/lib/common_test/src/ct_netconfc.erl index 0de7bf03af..6e3d1ab1d8 100644 --- a/lib/common_test/src/ct_netconfc.erl +++ b/lib/common_test/src/ct_netconfc.erl @@ -1272,6 +1272,14 @@ set_request_timer(T) -> {ok,TRef} = timer:send_after(T,{Ref,timeout}), {Ref,TRef}. +%%%----------------------------------------------------------------- +cancel_request_timer(undefined,undefined) -> + ok; +cancel_request_timer(Ref,TRef) -> + _ = timer:cancel(TRef), + receive {Ref,timeout} -> ok + after 0 -> ok + end. %%%----------------------------------------------------------------- client_hello(Options) when is_list(Options) -> @@ -1366,11 +1374,18 @@ to_xml_doc(Simple) -> %%% Parse and handle received XML data handle_data(NewData,#state{connection=Connection,buff=Buff0} = State0) -> log(Connection,recv,NewData), - Data = append_wo_initial_nl(Buff0,NewData), - case binary:split(Data,[?END_TAG],[]) of + {Start,AddSz} = + case byte_size(Buff0) of + BSz when BSz<5 -> {0,BSz}; + BSz -> {BSz-5,5} + end, + Length = byte_size(NewData) + AddSz, + Data = <<Buff0/binary, NewData/binary>>, + case binary:split(Data,?END_TAG,[{scope,{Start,Length}}]) of [_NoEndTagFound] -> {noreply, State0#state{buff=Data}}; - [FirstMsg,Buff1] -> + [FirstMsg0,Buff1] -> + FirstMsg = remove_initial_nl(FirstMsg0), SaxArgs = [{event_fun,fun sax_event/3}, {event_state,[]}], case xmerl_sax_parser:stream(FirstMsg, SaxArgs) of {ok, Simple, _Thrash} -> @@ -1392,11 +1407,10 @@ handle_data(NewData,#state{connection=Connection,buff=Buff0} = State0) -> %% xml does not accept a leading nl and some netconf server add a nl after %% each ?END_TAG, ignore them -append_wo_initial_nl(<<>>,NewData) -> NewData; -append_wo_initial_nl(<<"\n", Data/binary>>, NewData) -> - append_wo_initial_nl(Data, NewData); -append_wo_initial_nl(Data, NewData) -> - <<Data/binary, NewData/binary>>. +remove_initial_nl(<<"\n", Data/binary>>) -> + remove_initial_nl(Data); +remove_initial_nl(Data) -> + Data. handle_error(Reason, State) -> Pending1 = case State#state.pending of @@ -1404,9 +1418,9 @@ handle_error(Reason, State) -> Pending -> %% Assuming the first request gets the %% first answer - P=#pending{tref=TRef,caller=Caller} = + P=#pending{tref=TRef,ref=Ref,caller=Caller} = lists:last(Pending), - _ = timer:cancel(TRef), + cancel_request_timer(Ref,TRef), Reason1 = {failed_to_parse_received_data,Reason}, ct_gen_conn:return(Caller,{error,Reason1}), lists:delete(P,Pending) @@ -1492,8 +1506,8 @@ decode({Tag,Attrs,_}=E, #state{connection=Connection,pending=Pending}=State) -> {error,Reason} -> {noreply,State#state{hello_status = {error,Reason}}} end; - #pending{tref=TRef,caller=Caller} -> - _ = timer:cancel(TRef), + #pending{tref=TRef,ref=Ref,caller=Caller} -> + cancel_request_timer(Ref,TRef), case decode_hello(E) of {ok,SessionId,Capabilities} -> ct_gen_conn:return(Caller,ok), @@ -1519,9 +1533,8 @@ decode({Tag,Attrs,_}=E, #state{connection=Connection,pending=Pending}=State) -> %% there is just one pending that matches (i.e. has %% undefined msg_id and op) case [P || P = #pending{msg_id=undefined,op=undefined} <- Pending] of - [#pending{tref=TRef, - caller=Caller}] -> - _ = timer:cancel(TRef), + [#pending{tref=TRef,ref=Ref,caller=Caller}] -> + cancel_request_timer(Ref,TRef), ct_gen_conn:return(Caller,E), {noreply,State#state{pending=[]}}; _ -> @@ -1542,8 +1555,8 @@ get_msg_id(Attrs) -> decode_rpc_reply(MsgId,{_,Attrs,Content0}=E,#state{pending=Pending} = State) -> case lists:keytake(MsgId,#pending.msg_id,Pending) of - {value, #pending{tref=TRef,op=Op,caller=Caller}, Pending1} -> - _ = timer:cancel(TRef), + {value, #pending{tref=TRef,ref=Ref,op=Op,caller=Caller}, Pending1} -> + cancel_request_timer(Ref,TRef), Content = forward_xmlns_attr(Attrs,Content0), {CallerReply,{ServerReply,State2}} = do_decode_rpc_reply(Op,Content,State#state{pending=Pending1}), @@ -1555,10 +1568,11 @@ decode_rpc_reply(MsgId,{_,Attrs,Content0}=E,#state{pending=Pending} = State) -> %% pending that matches (i.e. has undefined msg_id and op) case [P || P = #pending{msg_id=undefined,op=undefined} <- Pending] of [#pending{tref=TRef, + ref=Ref, msg_id=undefined, op=undefined, caller=Caller}] -> - _ = timer:cancel(TRef), + cancel_request_timer(Ref,TRef), ct_gen_conn:return(Caller,E), {noreply,State#state{pending=[]}}; _ -> @@ -1762,9 +1776,14 @@ format_data(How,Data) -> do_format_data(raw,Data) -> io_lib:format("~n~ts~n",[hide_password(Data)]); do_format_data(pretty,Data) -> - io_lib:format("~n~ts~n",[indent(Data)]); + maybe_io_lib_format(indent(Data)); do_format_data(html,Data) -> - io_lib:format("~n~ts~n",[html_format(Data)]). + maybe_io_lib_format(html_format(Data)). + +maybe_io_lib_format(<<>>) -> + []; +maybe_io_lib_format(String) -> + io_lib:format("~n~ts~n",[String]). %%%----------------------------------------------------------------- %%% Hide password elements from XML data @@ -1803,13 +1822,21 @@ indent1("<?"++Rest1,Indent1) -> Line++indent1(Rest2,Indent2); indent1("</"++Rest1,Indent1) -> %% Stop tag - {Line,Rest2,Indent2} = indent_line1(Rest1,Indent1,[$/,$<]), - "\n"++Line++indent1(Rest2,Indent2); + case indent_line1(Rest1,Indent1,[$/,$<]) of + {[],[],_} -> + []; + {Line,Rest2,Indent2} -> + "\n"++Line++indent1(Rest2,Indent2) + end; indent1("<"++Rest1,Indent1) -> %% Start- or empty tag put(tag,get_tag(Rest1)), - {Line,Rest2,Indent2} = indent_line(Rest1,Indent1,[$<]), - "\n"++Line++indent1(Rest2,Indent2); + case indent_line(Rest1,Indent1,[$<]) of + {[],[],_} -> + []; + {Line,Rest2,Indent2} -> + "\n"++Line++indent1(Rest2,Indent2) + end; indent1([H|T],Indent) -> [H|indent1(T,Indent)]; indent1([],_Indent) -> diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index ae91601f67..0b646ffd07 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -1771,7 +1771,18 @@ compile_and_run(Tests, Skip, Opts, Args) -> {Tests1,Skip1} -> ReleaseSh = proplists:get_value(release_shell, Args), ct_util:set_testdata({release_shell,ReleaseSh}), - possibly_spawn(ReleaseSh == true, Tests1, Skip1, Opts) + TestResult = + possibly_spawn(ReleaseSh == true, Tests1, Skip1, Opts), + case TestResult of + {Ok,Errors,Skipped} -> + NoOfMakeErrors = + lists:foldl(fun({_,BadMods}, X) -> + X + length(BadMods) + end, 0, SuiteMakeErrors), + {Ok,Errors+NoOfMakeErrors,Skipped}; + ErrorResult -> + ErrorResult + end catch _:BadFormat -> {error,BadFormat} @@ -2073,7 +2084,9 @@ final_skip([], Final) -> continue([], _) -> true; -continue(_MakeErrors, AbortIfMissingSuites) -> +continue(_MakeErrors, true) -> + false; +continue(_MakeErrors, _AbortIfMissingSuites) -> io:nl(), OldGl = group_leader(), case set_group_leader_same_as_shell() of @@ -2101,11 +2114,10 @@ continue(_MakeErrors, AbortIfMissingSuites) -> true end; false -> % no shell process to use - not AbortIfMissingSuites + true end. set_group_leader_same_as_shell() -> - %%! Locate the shell process... UGLY!!! GS2or3 = fun(P) -> case process_info(P,initial_call) of {initial_call,{group,server,X}} when X == 2 ; X == 3 -> diff --git a/lib/common_test/src/ct_slave.erl b/lib/common_test/src/ct_slave.erl index 32a1ff4dbc..0cd83b9f04 100644 --- a/lib/common_test/src/ct_slave.erl +++ b/lib/common_test/src/ct_slave.erl @@ -1,7 +1,7 @@ %%-------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2013. All Rights Reserved. +%% Copyright Ericsson AB 2010-2015. 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. @@ -134,7 +134,7 @@ start(Host, Node) -> %%% executed after startup of the node. Note that all used modules should be %%% present in the code path on the <code>Host</code>.</p> %%% -%%% <p>The timeouts are applied as follows: +%%% <p>The timeouts are applied as follows:</p> %%% <list> %%% <item> %%% <code>BootTimeout</code> - time to start the Erlang node, in seconds. @@ -154,7 +154,7 @@ start(Host, Node) -> %%% If this timeout occurs, the result %%% <code>{error, startup_timeout, NodeName}</code> is returned. %%% </item> -%%% </list></p> +%%% </list> %%% %%% <p>Option <code>monitor_master</code> specifies, if the slave node should be %%% stopped in case of master node stop. Defaults to false.</p> @@ -170,7 +170,7 @@ start(Host, Node) -> %%% <p>Option <code>env</code> specifies a list of environment variables %%% that will extended the environment.</p> %%% -%%% <p>Special return values are: +%%% <p>Special return values are:</p> %%% <list> %%% <item><code>{error, already_started, NodeName}</code> - if the node with %%% the given name is already started on a given host;</item> @@ -179,7 +179,7 @@ start(Host, Node) -> %%% <item><code>{error, not_alive, NodeName}</code> - if node on which the %%% <code>ct_slave:start/3</code> is called, is not alive. Note that %%% <code>NodeName</code> is the name of current node in this case.</item> -%%% </list></p> +%%% </list> %%% start(Host, Node, Opts) -> ENode = enodename(Host, Node), diff --git a/lib/common_test/src/ct_snmp.erl b/lib/common_test/src/ct_snmp.erl index 95098bdaca..bb0167eb22 100644 --- a/lib/common_test/src/ct_snmp.erl +++ b/lib/common_test/src/ct_snmp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2012. All Rights Reserved. +%% Copyright Ericsson AB 2004-2015. 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. @@ -20,7 +20,7 @@ %%% @doc Common Test user interface module for the OTP snmp application %%% -%%% The purpose of this module is to make snmp configuration easier for +%%% <p>The purpose of this module is to make snmp configuration easier for %%% the test case writer. Many test cases can use default values for common %%% operations and then no snmp configuration files need to be supplied. When %%% it is necessary to change particular configuration parameters, a subset @@ -31,7 +31,7 @@ %%% To simplify the test suite, Common Test keeps track %%% of some of the snmp manager information. This way the test suite doesn't %%% have to handle as many input parameters as it would if it had to interface the -%%% OTP snmp manager directly. +%%% OTP snmp manager directly.</p> %%% %%% <p> The following snmp manager and agent parameters are configurable: </p> %%% @@ -326,9 +326,9 @@ set_info(Config) -> %%% @doc Register the manager entity (=user) responsible for specific agent(s). %%% Corresponds to making an entry in users.conf. %%% -%%% This function will try to register the given users, without +%%% <p>This function will try to register the given users, without %%% checking if any of them already exist. In order to change an -%%% already registered user, the user must first be unregistered. +%%% already registered user, the user must first be unregistered.</p> register_users(MgrAgentConfName, Users) -> case setup_users(Users) of ok -> @@ -351,10 +351,10 @@ register_users(MgrAgentConfName, Users) -> %%% @doc Explicitly instruct the manager to handle this agent. %%% Corresponds to making an entry in agents.conf %%% -%%% This function will try to register the given managed agents, +%%% <p>This function will try to register the given managed agents, %%% without checking if any of them already exist. In order to change %%% an already registered managed agent, the agent must first be -%%% unregistered. +%%% unregistered.</p> register_agents(MgrAgentConfName, ManagedAgents) -> case setup_managed_agents(MgrAgentConfName,ManagedAgents) of ok -> @@ -378,9 +378,9 @@ register_agents(MgrAgentConfName, ManagedAgents) -> %%% @doc Explicitly instruct the manager to handle this USM user. %%% Corresponds to making an entry in usm.conf %%% -%%% This function will try to register the given users, without +%%% <p>This function will try to register the given users, without %%% checking if any of them already exist. In order to change an -%%% already registered user, the user must first be unregistered. +%%% already registered user, the user must first be unregistered.</p> register_usm_users(MgrAgentConfName, UsmUsers) -> EngineID = ct:get_config({MgrAgentConfName, engine_id}, ?ENGINE_ID), case setup_usm_users(UsmUsers, EngineID) of diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl index e9487e94db..4d3fd2d094 100644 --- a/lib/common_test/src/ct_telnet.erl +++ b/lib/common_test/src/ct_telnet.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2014. All Rights Reserved. +%% Copyright Ericsson AB 2003-2015. 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. @@ -327,16 +327,16 @@ cmd(Connection,Cmd) -> %%% Reason = term() %%% @doc Send a command via telnet and wait for prompt. %%% -%%% This function will by default add a newline to the end of the +%%% <p>This function will by default add a newline to the end of the %%% given command. If this is not desired, the option %%% `{newline,false}' can be used. This is necessary, for example, %%% when sending telnet command sequences (prefixed with the -%%% Interprete As Command, IAC, character). +%%% Interprete As Command, IAC, character).</p> %%% -%%% The option `timeout' specifies how long the client shall wait for +%%% <p>The option `timeout' specifies how long the client shall wait for %%% prompt. If the time expires, the function returns %%% `{error,timeout}'. See the module description for information -%%% about the default value for the command timeout. +%%% about the default value for the command timeout.</p> cmd(Connection,Cmd,Opts) when is_list(Opts) -> case check_cmd_opts(Opts) of ok -> @@ -378,7 +378,7 @@ cmdf(Connection,CmdFormat,Args) -> %%% @doc Send a telnet command and wait for prompt %%% (uses a format string and list of arguments to build the command). %%% -%%% See {@link cmd/3} further description. +%%% <p>See {@link cmd/3} further description.</p> cmdf(Connection,CmdFormat,Args,Opts) when is_list(Args) -> Cmd = lists:flatten(io_lib:format(CmdFormat,Args)), cmd(Connection,Cmd,Opts). diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl index 64ebfbc463..ea49e36608 100644 --- a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl +++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl @@ -36,7 +36,8 @@ -compile(export_all). suite() -> - [{ct_hooks, [{cth_conn_log, + [{timetrap,?default_timeout}, + {ct_hooks, [{cth_conn_log, [{ct_netconfc,[{log_type,html}, %will be overwritten by config {hosts,[my_named_connection,netconf1]}] }] @@ -72,7 +73,9 @@ all() -> invalid_opt, timeout_close_session, get, + get_a_lot, timeout_get, + flush_timeout_get, get_xpath, get_config, get_config_xpath, @@ -112,12 +115,9 @@ end_per_group(_GroupName, Config) -> init_per_testcase(_Case, Config) -> ets:delete_all_objects(ns_tab), - 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. init_per_suite(Config) -> @@ -351,6 +351,19 @@ get(Config) -> ?ok = ct_netconfc:close_session(Client), ok. +get_a_lot(Config) -> + DataDir = ?config(data_dir,Config), + {ok,Client} = open_success(DataDir), + Descr = lists:append(lists:duplicate(100,"Description of myserver! ")), + Server = {server,[{xmlns,"myns"}],[{name,[],["myserver"]}, + {description,[],[Descr]}]}, + Data = lists:duplicate(100,Server), + ?NS:expect_reply('get',{fragmented,{data,Data}}), + {ok,Data} = ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]}), + ?NS:expect_do_reply('close-session',close,ok), + ?ok = ct_netconfc:close_session(Client), + ok. + timeout_get(Config) -> DataDir = ?config(data_dir,Config), {ok,Client} = open_success(DataDir), @@ -360,6 +373,28 @@ timeout_get(Config) -> ?ok = ct_netconfc:close_session(Client), ok. +%% Test OTP-13008 "ct_netconfc crash when receiving unknown timeout" +%% If the timer expires "at the same time" as the rpc reply is +%% received, the timeout message might already be sent when the timer +%% is cancelled. This test checks that the timeout message is flushed +%% from the message queue. If it isn't, the client crashes and the +%% session can not be closed afterwards. +%% Note that we can only hope that the test case triggers the problem +%% every now and then, as it is very timing dependent... +flush_timeout_get(Config) -> + DataDir = ?config(data_dir,Config), + {ok,Client} = open_success(DataDir), + Data = [{server,[{xmlns,"myns"}],[{name,[],["myserver"]}]}], + ?NS:expect_reply('get',{data,Data}), + timer:sleep(1000), + case ct_netconfc:get(Client,{server,[{xmlns,"myns"}],[]},1) of + {error,timeout} -> ok; % problem not triggered + {ok,Data} -> ok % problem possibly triggered + end, + ?NS:expect_do_reply('close-session',close,ok), + ?ok = ct_netconfc:close_session(Client), + ok. + get_xpath(Config) -> DataDir = ?config(data_dir,Config), {ok,Client} = open_success(DataDir), diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl index 8c30383343..07893faabc 100644 --- a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl +++ b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl @@ -277,6 +277,18 @@ hupp_kill(State = #session{connection = ConnRef}) -> send({CM,Ch},Data) -> ssh_connection:send(CM, Ch, Data). +%%% Split into many small parts and send to client +send_frag({CM,Ch},Data) -> + Sz = rand:uniform(2000), + case Data of + <<Chunk:Sz/binary,Rest/binary>> -> + ssh_connection:send(CM, Ch, Chunk), + send_frag({CM,Ch},Rest); + Chunk -> + ssh_connection:send(CM, Ch, Chunk) + end. + + %%% Kill ssh connection kill({CM,_Ch}) -> ssh:close(CM). @@ -294,7 +306,7 @@ table_trans(Fun,Args) -> receive {table_trans_done,Result} -> Result - after 5000 -> + after 20000 -> exit(table_trans_timeout) end end. @@ -424,6 +436,9 @@ do(_, undefined) -> reply(_,undefined) -> ?dbg("no reply~n",[]), ok; +reply(ConnRef,{fragmented,Reply}) -> + ?dbg("Reply fragmented: ~p~n",[Reply]), + send_frag(ConnRef,make_msg(Reply)); reply(ConnRef,Reply) -> ?dbg("Reply: ~p~n",[Reply]), send(ConnRef, make_msg(Reply)). diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk index ff2bd20ab3..f33b705dcb 100644 --- a/lib/common_test/vsn.mk +++ b/lib/common_test/vsn.mk @@ -1 +1 @@ -COMMON_TEST_VSN = 1.11 +COMMON_TEST_VSN = 1.11.1 |