Date: Thu, 7 May 2015 20:34:30 +0000 (UTC) From: Jimmy Olgeni <olgeni@FreeBSD.org> To: ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org Subject: svn commit: r385668 - in head/lang: erlang erlang-java erlang-runtime17 erlang-runtime17/files erlang-wx erlang/files Message-ID: <201505072034.t47KYU9L053577@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: olgeni Date: Thu May 7 20:34:30 2015 New Revision: 385668 URL: https://svnweb.freebsd.org/changeset/ports/385668 Log: Upgrade all Erlang 17 ports to 17.5.3. Added: head/lang/erlang-runtime17/files/patch-otp-17.5.3 (contents, props changed) head/lang/erlang/files/patch-otp-17.5.3 (contents, props changed) Modified: head/lang/erlang-java/Makefile head/lang/erlang-runtime17/Makefile head/lang/erlang-wx/Makefile head/lang/erlang/Makefile Modified: head/lang/erlang-java/Makefile ============================================================================== --- head/lang/erlang-java/Makefile Thu May 7 20:31:03 2015 (r385667) +++ head/lang/erlang-java/Makefile Thu May 7 20:34:30 2015 (r385668) @@ -1,7 +1,7 @@ # $FreeBSD$ PORTNAME= erlang -PORTVERSION= 17.5.2 +PORTVERSION= 17.5.3 CATEGORIES= lang parallel java MASTER_SITES= http://www.erlang.org/download/:erlangorg \ http://erlang.stacken.kth.se/download/:erlangorg \ @@ -25,8 +25,7 @@ OPTIONS_DEFINE= DOCS ERL_RELEASE= 17.5 -USES= gmake -USE_AUTOTOOLS= autoconf:env +USES= autoreconf gmake GNU_CONFIGURE= yes LDFLAGS+= -L${LOCALBASE}/lib Modified: head/lang/erlang-runtime17/Makefile ============================================================================== --- head/lang/erlang-runtime17/Makefile Thu May 7 20:31:03 2015 (r385667) +++ head/lang/erlang-runtime17/Makefile Thu May 7 20:34:30 2015 (r385668) @@ -2,8 +2,7 @@ # $FreeBSD$ PORTNAME= erlang -PORTVERSION= 17.5.2 -PORTREVISION= 2 +PORTVERSION= 17.5.3 CATEGORIES= lang parallel java MASTER_SITES= http://www.erlang.org/download/:erlangorg \ http://erlang.stacken.kth.se/download/:erlangorg \ @@ -186,6 +185,10 @@ post-install: ${TAR} --unlink -xzpf ${DISTDIR}/${DIST_SUBDIR}/${ERLANG_DOCS} \ -C ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB} + ${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/erts-6.4/* \ + ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/erts-6.4.1 + ${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/erts-6.4 + ${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/inets-5.10.6/* \ ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/inets-5.10.7 ${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/inets-5.10.6 @@ -194,6 +197,22 @@ post-install: ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/ssh-3.2.2 ${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/ssh-3.2 + ${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/common_test-1.10/* \ + ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/common_test-1.10.1 + ${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/common_test-1.10 + + ${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/diameter-1.9/* \ + ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/diameter-1.9.1 + ${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/diameter-1.9 + + ${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/snmp-5.1.1/* \ + ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/snmp-5.1.2 + ${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/snmp-5.1.1 + + ${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/test_server-3.8/* \ + ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/test_server-3.8.1 + ${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/test_server-3.8 + ${INSTALL_DATA} ${WRKSRC}/lib/dialyzer/doc/*.txt \ ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/dialyzer-*/doc/ .endif Added: head/lang/erlang-runtime17/files/patch-otp-17.5.3 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/lang/erlang-runtime17/files/patch-otp-17.5.3 Thu May 7 20:34:30 2015 (r385668) @@ -0,0 +1,3738 @@ +diff --git OTP_VERSION OTP_VERSION +index 808ab16..f32d20d 100644 +--- OTP_VERSION ++++ OTP_VERSION +@@ -1 +1 @@ +-17.5.2 ++17.5.3 +diff --git erts/doc/src/notes.xml erts/doc/src/notes.xml +index a2b4ae4..35e6e55 100644 +--- erts/doc/src/notes.xml ++++ erts/doc/src/notes.xml +@@ -30,6 +30,22 @@ + </header> + <p>This document describes the changes made to the ERTS application.</p> + ++<section><title>Erts 6.4.1</title> ++ ++ <section><title>Fixed Bugs and Malfunctions</title> ++ <list> ++ <item> ++ <p> ++ The VTS mode in Common Test has been modified to use a ++ private version of the Webtool application (ct_webtool).</p> ++ <p> ++ Own Id: OTP-12704 Aux Id: OTP-10922 </p> ++ </item> ++ </list> ++ </section> ++ ++</section> ++ + <section><title>Erts 6.4</title> + + <section><title>Fixed Bugs and Malfunctions</title> +diff --git erts/etc/common/ct_run.c erts/etc/common/ct_run.c +index bb59b93..9e67b94 100644 +--- erts/etc/common/ct_run.c ++++ erts/etc/common/ct_run.c +@@ -239,7 +239,7 @@ int main(int argc, char** argv) + */ + + if (ct_mode == VTS_MODE) { +- PUSH4("-s", "webtool", "script_start", "vts"); ++ PUSH4("-s", "ct_webtool", "script_start", "vts"); + if (browser[0] != '\0') PUSH(browser); + PUSH3("-s", "ct_run", "script_start"); + } +diff --git erts/vsn.mk erts/vsn.mk +index abc9c0b..9e5aa99 100644 +--- erts/vsn.mk ++++ erts/vsn.mk +@@ -17,7 +17,7 @@ + # %CopyrightEnd% + # + +-VSN = 6.4 ++VSN = 6.4.1 + + # Port number 4365 in 4.2 + # Port number 4366 in 4.3 +diff --git lib/common_test/doc/src/notes.xml lib/common_test/doc/src/notes.xml +index 822ebf1..472e3b7 100644 +--- lib/common_test/doc/src/notes.xml ++++ lib/common_test/doc/src/notes.xml +@@ -32,6 +32,66 @@ + <file>notes.xml</file> + </header> + ++<section><title>Common_Test 1.10.1</title> ++ ++ <section><title>Fixed Bugs and Malfunctions</title> ++ <list> ++ <item> ++ <p> ++ A fault in the Common Test logger process, that caused ++ the application to crash when running on a long name ++ node, has been corrected.</p> ++ <p> ++ Own Id: OTP-12643</p> ++ </item> ++ <item> ++ <p> ++ A 'wait_for_prompt' option in ct_telnet:expect/3 has been ++ introduced which forces the function to not return until ++ a prompt string has been received, even if other expect ++ patterns have already been found.</p> ++ <p> ++ Own Id: OTP-12688 Aux Id: seq12818 </p> ++ </item> ++ <item> ++ <p> ++ If the last expression in a test case causes a timetrap ++ timeout, the stack trace is ignored and not printed to ++ the test case log file. This happens because the ++ {Suite,TestCase,Line} info is not available in the stack ++ trace in this scenario, due to tail call elimination. ++ Common Test has been modified to handle this situation by ++ inserting a {Suite,TestCase,last_expr} tuple in the ++ correct place and printing the stack trace as expected.</p> ++ <p> ++ Own Id: OTP-12697 Aux Id: seq12848 </p> ++ </item> ++ <item> ++ <p> ++ Fixed a buffer problem in ct_netconfc which could cause ++ that some messages where buffered forever.</p> ++ <p> ++ Own Id: OTP-12698 Aux Id: seq12844 </p> ++ </item> ++ <item> ++ <p> ++ The VTS mode in Common Test has been modified to use a ++ private version of the Webtool application (ct_webtool).</p> ++ <p> ++ Own Id: OTP-12704 Aux Id: OTP-10922 </p> ++ </item> ++ <item> ++ <p> ++ Add possibility to add user capabilities in ++ <c>ct_netconfc:hello/3</c>.</p> ++ <p> ++ Own Id: OTP-12707 Aux Id: seq12846 </p> ++ </item> ++ </list> ++ </section> ++ ++</section> ++ + <section><title>Common_Test 1.10</title> + + <section><title>Fixed Bugs and Malfunctions</title> +diff --git lib/common_test/src/Makefile lib/common_test/src/Makefile +index 8d74546..449cba6 100644 +--- lib/common_test/src/Makefile ++++ lib/common_test/src/Makefile +@@ -62,6 +62,8 @@ MODULES= \ + ct_telnet_client \ + ct_make \ + vts \ ++ ct_webtool \ ++ ct_webtool_sup \ + unix_telnet \ + ct_config \ + ct_config_plain \ +diff --git lib/common_test/src/ct_logs.erl lib/common_test/src/ct_logs.erl +index dc118ed..fa55a97 100644 +--- lib/common_test/src/ct_logs.erl ++++ lib/common_test/src/ct_logs.erl +@@ -1908,13 +1908,14 @@ sort_all_runs(Dirs) -> + sort_ct_runs(Dirs) -> + %% Directory naming: <Prefix>.NodeName.Date_Time[/...] + %% Sort on Date_Time string: "YYYY-MM-DD_HH.MM.SS" +- lists:sort(fun(Dir1,Dir2) -> +- [_Prefix,_Node1,DateHH1,MM1,SS1] = +- string:tokens(filename:dirname(Dir1),[$.]), +- [_Prefix,_Node2,DateHH2,MM2,SS2] = +- string:tokens(filename:dirname(Dir2),[$.]), +- {DateHH1,MM1,SS1} =< {DateHH2,MM2,SS2} +- end, Dirs). ++ lists:sort( ++ fun(Dir1,Dir2) -> ++ [SS1,MM1,DateHH1 | _] = ++ lists:reverse(string:tokens(filename:dirname(Dir1),[$.])), ++ [SS2,MM2,DateHH2 | _] = ++ lists:reverse(string:tokens(filename:dirname(Dir2),[$.])), ++ {DateHH1,MM1,SS1} =< {DateHH2,MM2,SS2} ++ end, Dirs). + + dir_diff_all_runs(Dirs, LogCache) -> + case LogCache#log_cache.all_runs of +diff --git lib/common_test/src/ct_netconfc.erl lib/common_test/src/ct_netconfc.erl +index 85fb1ea..80ffb51 100644 +--- lib/common_test/src/ct_netconfc.erl ++++ lib/common_test/src/ct_netconfc.erl +@@ -172,6 +172,7 @@ + only_open/2, + hello/1, + hello/2, ++ hello/3, + close_session/1, + close_session/2, + kill_session/2, +@@ -456,23 +457,35 @@ only_open(KeyOrName, ExtraOpts) -> + + %%---------------------------------------------------------------------- + %% @spec hello(Client) -> Result +-%% @equiv hello(Client, infinity) ++%% @equiv hello(Client, [], infinity) + hello(Client) -> +- hello(Client,?DEFAULT_TIMEOUT). ++ hello(Client,[],?DEFAULT_TIMEOUT). + + %%---------------------------------------------------------------------- + -spec hello(Client,Timeout) -> Result when + Client :: handle(), + Timeout :: timeout(), + Result :: ok | {error,error_reason()}. +-%% @doc Exchange `hello' messages with the server. +-%% +-%% Sends a `hello' message to the server and waits for the return. +-%% +-%% @end +-%%---------------------------------------------------------------------- ++%% @spec hello(Client, Timeout) -> Result ++%% @equiv hello(Client, [], Timeout) + hello(Client,Timeout) -> +- call(Client, {hello, Timeout}). ++ hello(Client,[],Timeout). ++ ++%%---------------------------------------------------------------------- ++-spec hello(Client,Options,Timeout) -> Result when ++ Client :: handle(), ++ Options :: [{capability, [string()]}], ++ Timeout :: timeout(), ++ Result :: ok | {error,error_reason()}. ++%% @doc Exchange `hello' messages with the server. ++%% ++%% Adds optional capabilities and sends a `hello' message to the ++%% server and waits for the return. ++%% @end ++%%---------------------------------------------------------------------- ++hello(Client,Options,Timeout) -> ++ call(Client, {hello, Options, Timeout}). ++ + + %%---------------------------------------------------------------------- + %% @spec get_session_id(Client) -> Result +@@ -1040,9 +1053,9 @@ terminate(_, #state{connection=Connection}) -> + ok. + + %% @private +-handle_msg({hello,Timeout}, From, ++handle_msg({hello, Options, Timeout}, From, + #state{connection=Connection,hello_status=HelloStatus} = State) -> +- case do_send(Connection, client_hello()) of ++ case do_send(Connection, client_hello(Options)) of + ok -> + case HelloStatus of + undefined -> +@@ -1118,7 +1131,9 @@ handle_msg({Ref,timeout},#state{pending=Pending} = State) -> + close_session -> stop; + _ -> noreply + end, +- {R,State#state{pending=Pending1}}. ++ %% Halfhearted try to get in correct state, this matches ++ %% the implementation before this patch ++ {R,State#state{pending=Pending1, buff= <<>>}}. + + %% @private + %% Called by ct_util_server to close registered connections before terminate. +@@ -1222,10 +1237,14 @@ set_request_timer(T) -> + + + %%%----------------------------------------------------------------- +-client_hello() -> ++client_hello(Options) when is_list(Options) -> ++ UserCaps = [{capability, UserCap} || ++ {capability, UserCap} <- Options, ++ is_list(hd(UserCap))], + {hello, ?NETCONF_NAMESPACE_ATTR, + [{capabilities, +- [{capability,[?NETCONF_BASE_CAP++?NETCONF_BASE_CAP_VSN]}]}]}. ++ [{capability,[?NETCONF_BASE_CAP++?NETCONF_BASE_CAP_VSN]}| ++ UserCaps]}]}. + + %%%----------------------------------------------------------------- + +@@ -1308,72 +1327,54 @@ to_xml_doc(Simple) -> + + %%%----------------------------------------------------------------- + %%% Parse and handle received XML data +-handle_data(NewData,#state{connection=Connection,buff=Buff} = State) -> ++handle_data(NewData,#state{connection=Connection,buff=Buff0} = State0) -> + log(Connection,recv,NewData), +- Data = <<Buff/binary,NewData/binary>>, +- case xmerl_sax_parser:stream(<<>>, +- [{continuation_fun,fun sax_cont/1}, +- {continuation_state,{Data,Connection,false}}, +- {event_fun,fun sax_event/3}, +- {event_state,[]}]) of +- {ok, Simple, Rest} -> +- decode(Simple,State#state{buff=Rest}); +- {fatal_error,_Loc,Reason,_EndTags,_EventState} -> +- ?error(Connection#connection.name,[{parse_error,Reason}, +- {buffer,Buff}, +- {new_data,NewData}]), +- case Reason of +- {could_not_fetch_data,Msg} -> +- handle_msg(Msg,State#state{buff = <<>>}); +- _Other -> +- Pending1 = +- case State#state.pending of +- [] -> +- []; +- Pending -> +- %% Assuming the first request gets the +- %% first answer +- P=#pending{tref=TRef,caller=Caller} = +- lists:last(Pending), +- _ = timer:cancel(TRef), +- Reason1 = {failed_to_parse_received_data,Reason}, +- ct_gen_conn:return(Caller,{error,Reason1}), +- lists:delete(P,Pending) +- end, +- {noreply,State#state{pending=Pending1,buff = <<>>}} +- end +- end. +- +-%%%----------------------------------------------------------------- +-%%% Parsing of XML data +-%% Contiuation function for the sax parser +-sax_cont(done) -> +- {<<>>,done}; +-sax_cont({Data,Connection,false}) -> ++ Data = append_wo_initial_nl(Buff0,NewData), + case binary:split(Data,[?END_TAG],[]) of +- [All] -> +- %% No end tag found. Remove what could be a part +- %% of an end tag from the data and save for next +- %% iteration +- SafeSize = size(All)-5, +- <<New:SafeSize/binary,Save:5/binary>> = All, +- {New,{Save,Connection,true}}; +- [_Msg,_Rest]=Msgs -> +- %% We have at least one full message. Any excess data will +- %% be returned from xmerl_sax_parser:stream/2 in the Rest +- %% parameter. +- {list_to_binary(Msgs),done} +- end; +-sax_cont({Data,Connection,true}) -> +- case ssh_receive_data() of +- {ok,Bin} -> +- log(Connection,recv,Bin), +- sax_cont({<<Data/binary,Bin/binary>>,Connection,false}); +- {error,Reason} -> +- throw({could_not_fetch_data,Reason}) ++ [_NoEndTagFound] -> ++ {noreply, State0#state{buff=Data}}; ++ [FirstMsg,Buff1] -> ++ SaxArgs = [{event_fun,fun sax_event/3}, {event_state,[]}], ++ case xmerl_sax_parser:stream(FirstMsg, SaxArgs) of ++ {ok, Simple, _Thrash} -> ++ case decode(Simple, State0#state{buff=Buff1}) of ++ {noreply, #state{buff=Buff} = State} when Buff =/= <<>> -> ++ %% Recurse if we have more data in buffer ++ handle_data(<<>>, State); ++ Other -> ++ Other ++ end; ++ {fatal_error,_Loc,Reason,_EndTags,_EventState} -> ++ ?error(Connection#connection.name, ++ [{parse_error,Reason}, ++ {buffer, Buff0}, ++ {new_data,NewData}]), ++ handle_error(Reason, State0#state{buff= <<>>}) ++ end + end. + ++%% 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>>. + ++handle_error(Reason, State) -> ++ Pending1 = case State#state.pending of ++ [] -> []; ++ Pending -> ++ %% Assuming the first request gets the ++ %% first answer ++ P=#pending{tref=TRef,caller=Caller} = ++ lists:last(Pending), ++ _ = timer:cancel(TRef), ++ Reason1 = {failed_to_parse_received_data,Reason}, ++ ct_gen_conn:return(Caller,{error,Reason1}), ++ lists:delete(P,Pending) ++ end, ++ {noreply, State#state{pending=Pending1}}. + + %% Event function for the sax parser. It builds a simple XML structure. + %% Care is taken to keep namespace attributes and prefixes as in the original XML. +@@ -1836,16 +1837,6 @@ get_tag([]) -> + + %%%----------------------------------------------------------------- + %%% SSH stuff +-ssh_receive_data() -> +- receive +- {ssh_cm, CM, {data, Ch, _Type, Data}} -> +- ssh_connection:adjust_window(CM,Ch,size(Data)), +- {ok, Data}; +- {ssh_cm, _CM, {Closed, _Ch}} = X when Closed == closed; Closed == eof -> +- {error,X}; +- {_Ref,timeout} = X -> +- {error,X} +- end. + + ssh_open(#options{host=Host,timeout=Timeout,port=Port,ssh=SshOpts,name=Name}) -> + case ssh:connect(Host, Port, +diff --git lib/common_test/src/ct_run.erl lib/common_test/src/ct_run.erl +index 4a12481..be547b4 100644 +--- lib/common_test/src/ct_run.erl ++++ lib/common_test/src/ct_run.erl +@@ -225,18 +225,24 @@ finish(Tracing, ExitStatus, Args) -> + if ExitStatus == interactive_mode -> + interactive_mode; + true -> +- %% it's possible to tell CT to finish execution with a call +- %% to a different function than the normal halt/1 BIF +- %% (meant to be used mainly for reading the CT exit status) +- case get_start_opt(halt_with, +- fun([HaltMod,HaltFunc]) -> +- {list_to_atom(HaltMod), +- list_to_atom(HaltFunc)} end, +- Args) of +- undefined -> +- halt(ExitStatus); +- {M,F} -> +- apply(M, F, [ExitStatus]) ++ case get_start_opt(vts, true, Args) of ++ true -> ++ %% VTS mode, don't halt the node ++ ok; ++ _ -> ++ %% it's possible to tell CT to finish execution with a call ++ %% to a different function than the normal halt/1 BIF ++ %% (meant to be used mainly for reading the CT exit status) ++ case get_start_opt(halt_with, ++ fun([HaltMod,HaltFunc]) -> ++ {list_to_atom(HaltMod), ++ list_to_atom(HaltFunc)} end, ++ Args) of ++ undefined -> ++ halt(ExitStatus); ++ {M,F} -> ++ apply(M, F, [ExitStatus]) ++ end + end + end. + +@@ -244,7 +250,7 @@ script_start1(Parent, Args) -> + %% read general start flags + Label = get_start_opt(label, fun([Lbl]) -> Lbl end, Args), + Profile = get_start_opt(profile, fun([Prof]) -> Prof end, Args), +- Vts = get_start_opt(vts, true, Args), ++ Vts = get_start_opt(vts, true, undefined, Args), + Shell = get_start_opt(shell, true, Args), + Cover = get_start_opt(cover, fun([CoverFile]) -> ?abs(CoverFile) end, Args), + CoverStop = get_start_opt(cover_stop, +@@ -330,8 +336,8 @@ script_start1(Parent, Args) -> + Stylesheet = get_start_opt(stylesheet, + fun([SS]) -> ?abs(SS) end, Args), + %% basic_html - used by ct_logs +- BasicHtml = case proplists:get_value(basic_html, Args) of +- undefined -> ++ BasicHtml = case {Vts,proplists:get_value(basic_html, Args)} of ++ {undefined,undefined} -> + application:set_env(common_test, basic_html, false), + undefined; + _ -> +@@ -364,9 +370,10 @@ script_start1(Parent, Args) -> + scale_timetraps = ScaleTT, + create_priv_dir = CreatePrivDir, + starter = script}, +- ++ + %% check if log files should be refreshed or go on to run tests... + Result = run_or_refresh(Opts, Args), ++ + %% send final results to starting process waiting in script_start/0 + Parent ! {self(), Result}. + +@@ -757,21 +764,6 @@ script_start4(Opts = #opts{tests = Tests}, Args) -> + %%% @doc Print usage information for <code>ct_run</code>. + script_usage() -> + io:format("\n\nUsage:\n\n"), +- io:format("Run tests in web based GUI:\n\n" +- "\tct_run -vts [-browser Browser]" +- "\n\t[-config ConfigFile1 ConfigFile2 .. ConfigFileN]" +- "\n\t[-decrypt_key Key] | [-decrypt_file KeyFile]" +- "\n\t[-dir TestDir1 TestDir2 .. TestDirN] |" +- "\n\t[-suite Suite [-case Case]]" +- "\n\t[-logopts LogOpt1 LogOpt2 .. LogOptN]" +- "\n\t[-verbosity GenVLvl | [CategoryVLvl1 .. CategoryVLvlN]]" +- "\n\t[-include InclDir1 InclDir2 .. InclDirN]" +- "\n\t[-no_auto_compile]" +- "\n\t[-abort_if_missing_suites]" +- "\n\t[-multiply_timetraps N]" +- "\n\t[-scale_timetraps]" +- "\n\t[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]" +- "\n\t[-basic_html]\n\n"), + io:format("Run tests from command line:\n\n" + "\tct_run [-dir TestDir1 TestDir2 .. TestDirN] |" + "\n\t[[-dir TestDir] -suite Suite1 Suite2 .. SuiteN" +@@ -831,7 +823,22 @@ script_usage() -> + io:format("Run CT in interactive mode:\n\n" + "\tct_run -shell" + "\n\t[-config ConfigFile1 ConfigFile2 .. ConfigFileN]" +- "\n\t[-decrypt_key Key] | [-decrypt_file KeyFile]\n\n"). ++ "\n\t[-decrypt_key Key] | [-decrypt_file KeyFile]\n\n"), ++ io:format("Run tests in web based GUI:\n\n" ++ "\tct_run -vts [-browser Browser]" ++ "\n\t[-config ConfigFile1 ConfigFile2 .. ConfigFileN]" ++ "\n\t[-decrypt_key Key] | [-decrypt_file KeyFile]" ++ "\n\t[-dir TestDir1 TestDir2 .. TestDirN] |" ++ "\n\t[-suite Suite [-case Case]]" ++ "\n\t[-logopts LogOpt1 LogOpt2 .. LogOptN]" ++ "\n\t[-verbosity GenVLvl | [CategoryVLvl1 .. CategoryVLvlN]]" ++ "\n\t[-include InclDir1 InclDir2 .. InclDirN]" ++ "\n\t[-no_auto_compile]" ++ "\n\t[-abort_if_missing_suites]" ++ "\n\t[-multiply_timetraps N]" ++ "\n\t[-scale_timetraps]" ++ "\n\t[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]" ++ "\n\t[-basic_html]\n\n"). + + %%%----------------------------------------------------------------- + %%% @hidden +diff --git lib/common_test/src/ct_telnet.erl lib/common_test/src/ct_telnet.erl +index d906a26..844f537 100644 +--- lib/common_test/src/ct_telnet.erl ++++ lib/common_test/src/ct_telnet.erl +@@ -486,7 +486,8 @@ expect(Connection,Patterns) -> + %%% Opts = [Opt] + %%% Opt = {idle_timeout,IdleTimeout} | {total_timeout,TotalTimeout} | + %%% repeat | {repeat,N} | sequence | {halt,HaltPatterns} | +-%%% ignore_prompt | no_prompt_check ++%%% ignore_prompt | no_prompt_check | wait_for_prompt | ++%%% {wait_for_prompt,Prompt} + %%% IdleTimeout = infinity | integer() + %%% TotalTimeout = infinity | integer() + %%% N = integer() +@@ -499,9 +500,9 @@ expect(Connection,Patterns) -> + %%% + %%% @doc Get data from telnet and wait for the expected pattern. + %%% +-%%% <p><code>Pattern</code> can be a POSIX regular expression. If more +-%%% than one pattern is given, the function returns when the first +-%%% match is found.</p> ++%%% <p><code>Pattern</code> can be a POSIX regular expression. The function ++%%% returns as soon as a pattern has been successfully matched (at least one, ++%%% in the case of multiple patterns).</p> + %%% + %%% <p><code>RxMatch</code> is a list of matched strings. It looks + %%% like this: <code>[FullMatch, SubMatch1, SubMatch2, ...]</code> +@@ -524,10 +525,13 @@ expect(Connection,Patterns) -> + %%% milliseconds, <code>{error,timeout}</code> is returned. The default + %%% value is <code>infinity</code> (i.e. no time limit).</p> + %%% +-%%% <p>The function will always return when a prompt is found, unless +-%%% any of the <code>ignore_prompt</code> or +-%%% <code>no_prompt_check</code> options are used, in which case it +-%%% will return when a match is found or after a timeout.</p> ++%%% <p>The function will return when a prompt is received, even if no ++%%% pattern has yet been matched. In this event, ++%%% <code>{error,{prompt,Prompt}}</code> is returned. ++%%% However, this behaviour may be modified with the ++%%% <code>ignore_prompt</code> or <code>no_prompt_check</code> option, which ++%%% tells <code>expect</code> to return only when a match is found or after a ++%%% timeout.</p> + %%% + %%% <p>If the <code>ignore_prompt</code> option is used, + %%% <code>ct_telnet</code> will ignore any prompt found. This option +@@ -541,6 +545,13 @@ expect(Connection,Patterns) -> + %%% is useful if, for instance, the <code>Pattern</code> itself + %%% matches the prompt.</p> + %%% ++%%% <p>The <code>wait_for_prompt</code> option forces <code>ct_telnet</code> ++%%% to wait until the prompt string has been received before returning ++%%% (even if a pattern has already been matched). This is equal to calling: ++%%% <code>expect(Conn, Patterns++[{prompt,Prompt}], [sequence|Opts])</code>. ++%%% Note that <code>idle_timeout</code> and <code>total_timeout</code> ++%%% may abort the operation of waiting for prompt.</p> ++%%% + %%% <p>The <code>repeat</code> option indicates that the pattern(s) + %%% shall be matched multiple times. If <code>N</code> is given, the + %%% pattern(s) will be matched <code>N</code> times, and the function +@@ -653,18 +664,21 @@ handle_msg({cmd,Cmd,Opts},State) -> + start_gen_log(heading(cmd,State#state.name)), + log(State,cmd,"Cmd: ~p",[Cmd]), + ++ %% whatever is in the buffer from previous operations ++ %% will be ignored as we go ahead with this telnet cmd ++ + debug_cont_gen_log("Throwing Buffer:",[]), + debug_log_lines(State#state.buffer), + + case {State#state.type,State#state.prompt} of +- {ts,_} -> ++ {ts,_} -> + silent_teln_expect(State#state.name, + State#state.teln_pid, + State#state.buffer, + prompt, + State#state.prx, + [{idle_timeout,2000}]); +- {ip,false} -> ++ {ip,false} -> + silent_teln_expect(State#state.name, + State#state.teln_pid, + State#state.buffer, +@@ -1029,10 +1043,12 @@ teln_expect(Name,Pid,Data,Pattern0,Prx,Opts) -> + end, + + PromptCheck = get_prompt_check(Opts), +- Seq = get_seq(Opts), +- Pattern = convert_pattern(Pattern0,Seq), + +- {IdleTimeout,TotalTimeout} = get_timeouts(Opts), ++ {WaitForPrompt,Pattern1,Opts1} = wait_for_prompt(Pattern0,Opts), ++ ++ Seq = get_seq(Opts1), ++ Pattern2 = convert_pattern(Pattern1,Seq), ++ {IdleTimeout,TotalTimeout} = get_timeouts(Opts1), + + EO = #eo{teln_pid=Pid, + prx=Prx, +@@ -1042,9 +1058,16 @@ teln_expect(Name,Pid,Data,Pattern0,Prx,Opts) -> + haltpatterns=HaltPatterns, + prompt_check=PromptCheck}, + +- case get_repeat(Opts) of ++ case get_repeat(Opts1) of + false -> +- case teln_expect1(Name,Pid,Data,Pattern,[],EO) of ++ case teln_expect1(Name,Pid,Data,Pattern2,[],EO) of ++ {ok,Matched,Rest} when WaitForPrompt -> ++ case lists:reverse(Matched) of ++ [{prompt,_},Matched1] -> ++ {ok,Matched1,Rest}; ++ [{prompt,_}|Matched1] -> ++ {ok,lists:reverse(Matched1),Rest} ++ end; + {ok,Matched,Rest} -> + {ok,Matched,Rest}; + {halt,Why,Rest} -> +@@ -1054,7 +1077,7 @@ teln_expect(Name,Pid,Data,Pattern0,Prx,Opts) -> + end; + N -> + EO1 = EO#eo{repeat=N}, +- repeat_expect(Name,Pid,Data,Pattern,[],EO1) ++ repeat_expect(Name,Pid,Data,Pattern2,[],EO1) + end. + + convert_pattern(Pattern,Seq) +@@ -1118,6 +1141,40 @@ get_ignore_prompt(Opts) -> + get_prompt_check(Opts) -> + not lists:member(no_prompt_check,Opts). + ++wait_for_prompt(Pattern, Opts) -> ++ case lists:member(wait_for_prompt, Opts) of ++ true -> ++ wait_for_prompt1(prompt, Pattern, ++ lists:delete(wait_for_prompt,Opts)); ++ false -> ++ case proplists:get_value(wait_for_prompt, Opts) of ++ undefined -> ++ {false,Pattern,Opts}; ++ PromptStr -> ++ wait_for_prompt1({prompt,PromptStr}, Pattern, ++ proplists:delete(wait_for_prompt,Opts)) ++ end ++ end. ++ ++wait_for_prompt1(Prompt, [Ch|_] = Pattern, Opts) when is_integer(Ch) -> ++ wait_for_prompt2(Prompt, [Pattern], Opts); ++wait_for_prompt1(Prompt, Pattern, Opts) when is_list(Pattern) -> ++ wait_for_prompt2(Prompt, Pattern, Opts); ++wait_for_prompt1(Prompt, Pattern, Opts) -> ++ wait_for_prompt2(Prompt, [Pattern], Opts). ++ ++wait_for_prompt2(Prompt, Pattern, Opts) -> ++ Pattern1 = case lists:reverse(Pattern) of ++ [prompt|_] -> Pattern; ++ [{prompt,_}|_] -> Pattern; ++ _ -> Pattern ++ [Prompt] ++ end, ++ Opts1 = case lists:member(sequence, Opts) of ++ true -> Opts; ++ false -> [sequence|Opts] ++ end, ++ {true,Pattern1,Opts1}. ++ + %% Repeat either single or sequence. All match results are accumulated + %% and returned when a halt condition is fulllfilled. + repeat_expect(_Name,_Pid,Rest,_Pattern,Acc,#eo{repeat=0}) -> +@@ -1210,7 +1267,7 @@ get_data1(Pid) -> + %% 1) Single expect. + %% First the whole data chunk is searched for a prompt (to avoid doing + %% a regexp match for the prompt at each line). +-%% If we are searching for anyting else, the datachunk is split into ++%% If we are searching for anything else, the datachunk is split into + %% lines and each line is matched against each pattern. + + %% one_expect: split data chunk at prompts +@@ -1227,7 +1284,7 @@ one_expect(Name,Pid,Data,Pattern,EO) -> + log(name_or_pid(Name,Pid),"PROMPT: ~ts",[PromptType]), + {match,{prompt,PromptType},Rest}; + [{prompt,_OtherPromptType}] -> +- %% Only searching for one specific prompt, not thisone ++ %% Only searching for one specific prompt, not this one + log_lines(Name,Pid,UptoPrompt), + {nomatch,Rest}; + _ -> +diff --git lib/common_test/src/ct_webtool.erl lib/common_test/src/ct_webtool.erl +new file mode 100644 +index 0000000..b67a7c2 +--- /dev/null ++++ lib/common_test/src/ct_webtool.erl +@@ -0,0 +1,1207 @@ ++%% ++%% %CopyrightBegin% ++%% ++%% Copyright Ericsson AB 2001-2010. 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(ct_webtool). ++-behaviour(gen_server). ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%% %% ++%% The general idea is: %% ++%% %% ++%% %% ++%% 1. Scan through the path for *.tool files and find all the web %% ++%% based tools. Query each tool for configuration data. %% ++%% 2. Add Alias for Erlscript and html for each tool to %% ++%% the webserver configuration data. %% ++%% 3. Start the webserver. %% ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++ ++%% API functions ++-export([start/0, start/2, stop/0]). ++ ++%% Starting Webtool from a shell script ++-export([script_start/0, script_start/1]). ++ ++%% Web api ++-export([started_tools/2, toolbar/2, start_tools/2, stop_tools/2]). ++ ++%% API against other tools ++-export([is_localhost/0]). ++ ++%% Debug export s ++-export([get_tools1/1]). ++-export([debug/1, stop_debug/0, debug_app/1]). ++ ++%% gen_server callbacks ++-export([init/1, handle_call/3, handle_cast/2, handle_info/2, ++ terminate/2, code_change/3]). ++ ++-include_lib("kernel/include/file.hrl"). ++-include_lib("stdlib/include/ms_transform.hrl"). ++ ++-record(state,{priv_dir,app_data,supvis,web_data,started=[]}). ++ ++-define(MAX_NUMBER_OF_WEBTOOLS,256). ++-define(DEFAULT_PORT,8888).% must be >1024 or the user must be root on unix ++-define(DEFAULT_ADDR,{127,0,0,1}). ++ ++-define(WEBTOOL_ALIAS,{ct_webtool,[{alias,{erl_alias,"/ct_webtool",[ct_webtool]}}]}). ++-define(HEADER,"Pragma:no-cache\r\n Content-type: text/html\r\n\r\n"). ++-define(HTML_HEADER,"<HTML>\r\n<HEAD>\r\n<TITLE>WebTool</TITLE>\r\n</HEAD>\r\n<BODY BGCOLOR=\"#FFFFFF\">\r\n"). ++-define(HTML_HEADER_RELOAD,"<HTML>\r\n<HEAD>\r\n<TITLE>WebTool ++ </TITLE>\r\n</HEAD>\r\n ++ <BODY BGCOLOR=\"#FFFFFF\" onLoad=reloadCompiledList()>\r\n"). ++ ++-define(HTML_END,"</BODY></HTML>"). ++ ++-define(SEND_URL_TIMEOUT,5000). ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%% %% ++%% For debugging only. %% ++%% %% ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%% Start tracing with ++%% debug(Functions). ++%% Functions = local | global | FunctionList ++%% FunctionList = [Function] ++%% Function = {FunctionName,Arity} | FunctionName | ++%% {Module, FunctionName, Arity} | {Module,FunctionName} ++debug(F) -> ++ ttb:tracer(all,[{file,"webtool.trc"}]), % tracing all nodes ++ ttb:p(all,[call,timestamp]), ++ MS = [{'_',[],[{return_trace},{message,{caller}}]}], ++ tp(F,MS), ++ ttb:ctp(?MODULE,stop_debug), % don't want tracing of the stop_debug func ++ ok. ++tp(local,MS) -> % all functions ++ ttb:tpl(?MODULE,MS); ++tp(global,MS) -> % all exported functions ++ ttb:tp(?MODULE,MS); ++tp([{M,F,A}|T],MS) -> % Other module ++ ttb:tpl(M,F,A,MS), ++ tp(T,MS); ++tp([{M,F}|T],MS) when is_atom(F) -> % Other module ++ ttb:tpl(M,F,MS), ++ tp(T,MS); ++tp([{F,A}|T],MS) -> % function/arity ++ ttb:tpl(?MODULE,F,A,MS), ++ tp(T,MS); ++tp([F|T],MS) -> % function ++ ttb:tpl(?MODULE,F,MS), ++ tp(T,MS); ++tp([],_MS) -> ++ ok. ++stop_debug() -> ++ ttb:stop([format]). ++ ++debug_app(Mod) -> ++ ttb:tracer(all,[{file,"webtool_app.trc"},{handler,{fun out/4,true}}]), ++ ttb:p(all,[call,timestamp]), ++ MS = [{'_',[],[{return_trace},{message,{caller}}]}], ++ ttb:tp(Mod,MS), ++ ok. ++ ++out(_,{trace_ts,Pid,call,MFA={M,F,A},{W,_,_},TS},_,S) ++ when W==webtool;W==mod_esi-> ++ io:format("~w: (~p)~ncall ~s~n", [TS,Pid,ffunc(MFA)]), ++ [{M,F,length(A)}|S]; ++out(_,{trace_ts,Pid,return_from,MFA,R,TS},_,[MFA|S]) -> ++ io:format("~w: (~p)~nreturned from ~s -> ~p~n", [TS,Pid,ffunc(MFA),R]), ++ S; ++out(_,_,_,_) -> ++ ok. ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%% %% ++%% Functions called via script. %% ++%% %% ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++script_start() -> ++ usage(), ++ halt(). ++script_start([App]) -> ++ DefaultBrowser = ++ case os:type() of ++ {win32,_} -> iexplore; ++ _ -> firefox ++ end, ++ script_start([App,DefaultBrowser]); ++script_start([App,Browser]) -> ++ io:format("Starting webtool...\n"), ++ start(), ++ AvailableApps = get_applications(), ++ {OSType,_} = os:type(), ++ case lists:keysearch(App,1,AvailableApps) of ++ {value,{App,StartPage}} -> ++ io:format("Starting ~w...\n",[App]), ++ start_tools([],"app=" ++ atom_to_list(App)), ++ PortStr = integer_to_list(get_port()), ++ Url = case StartPage of ++ "/" ++ Page -> ++ "http://localhost:" ++ PortStr ++ "/" ++ Page; ++ _ -> ++ "http://localhost:" ++ PortStr ++ "/" ++ StartPage ++ end, ++ case Browser of ++ none -> ++ ok; ++ iexplore when OSType == win32-> ++ io:format("Starting internet explorer...\n"), ++ {ok,R} = win32reg:open(""), ++ Key="\\local_machine\\SOFTWARE\\Microsoft\\IE Setup\\Setup", ++ win32reg:change_key(R,Key), ++ {ok,Val} = win32reg:value(R,"Path"), ++ IExplore=filename:join(win32reg:expand(Val),"iexplore.exe"), ++ os:cmd("\"" ++ IExplore ++ "\" " ++ Url); ++ _ when OSType == win32 -> ++ io:format("Starting ~w...\n",[Browser]), ++ os:cmd("\"" ++ atom_to_list(Browser) ++ "\" " ++ Url); ++ B when B==firefox; B==mozilla -> ++ io:format("Sending URL to ~w...",[Browser]), ++ BStr = atom_to_list(Browser), ++ SendCmd = BStr ++ " -raise -remote \'openUrl(" ++ ++ Url ++ ")\'", ++ Port = open_port({spawn,SendCmd},[exit_status]), ++ receive ++ {Port,{exit_status,0}} -> ++ io:format("done\n"), ++ ok; ++ {Port,{exit_status,_Error}} -> ++ io:format(" not running, starting ~w...\n", ++ [Browser]), ++ os:cmd(BStr ++ " " ++ Url), ++ ok ++ after ?SEND_URL_TIMEOUT -> ++ io:format(" failed, starting ~w...\n",[Browser]), ++ erlang:port_close(Port), ++ os:cmd(BStr ++ " " ++ Url) ++ end; ++ _ -> ++ io:format("Starting ~w...\n",[Browser]), ++ os:cmd(atom_to_list(Browser) ++ " " ++ Url) ++ end, ++ ok; ++ false -> ++ stop(), ++ io:format("\n{error,{unknown_app,~p}}\n",[App]), ++ halt() ++ end. ++ ++usage() -> ++ io:format("Starting webtool...\n"), ++ start(), ++ Apps = lists:map(fun({A,_}) -> A end,get_applications()), ++ io:format( ++ "\nUsage: start_webtool application [ browser ]\n" ++ "\nAvailable applications are: ~p\n" ++ "Default browser is \'iexplore\' (Internet Explorer) on Windows " ++ "or else \'firefox\'\n", ++ [Apps]), ++ stop(). ++ ++ ++get_applications() -> *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201505072034.t47KYU9L053577>