From 7bfbabb0a099b9dbd34363ffe3dc0c03918b1f3b Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 19 Sep 2011 11:09:56 +0200 Subject: Export write_events and add option to return a string --- lib/stdlib/src/error_logger_tty_h.erl | 69 ++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/lib/stdlib/src/error_logger_tty_h.erl b/lib/stdlib/src/error_logger_tty_h.erl index 435e57aa0e..fa13fbb2bd 100644 --- a/lib/stdlib/src/error_logger_tty_h.erl +++ b/lib/stdlib/src/error_logger_tty_h.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -34,10 +34,12 @@ handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]). +-export([write_event/2]). + %% This one is used when we takeover from the simple error_logger. init({[], {error_logger, Buf}}) -> User = set_group_leader(), - write_events(Buf), + write_events(Buf,io), {ok, {User, error_logger}}; %% This one is used if someone took over from us, and now wants to %% go back. @@ -52,7 +54,7 @@ init([]) -> handle_event({_Type, GL, _Msg}, State) when node(GL) =/= node() -> {ok, State}; handle_event(Event, State) -> - write_event(tag_event(Event)), + write_event(tag_event(Event),io), {ok, State}. handle_info({'EXIT', User, _Reason}, {User, PrevHandler}) -> @@ -64,10 +66,10 @@ handle_info({'EXIT', User, _Reason}, {User, PrevHandler}) -> PrevHandler, go_back} end; handle_info({emulator, GL, Chars}, State) when node(GL) == node() -> - write_event(tag_event({emulator, GL, Chars})), + write_event(tag_event({emulator, GL, Chars}),io), {ok, State}; handle_info({emulator, noproc, Chars}, State) -> - write_event(tag_event({emulator, noproc, Chars})), + write_event(tag_event({emulator, noproc, Chars}),io), {ok, State}; handle_info(_, State) -> {ok, State}. @@ -97,65 +99,65 @@ set_group_leader() -> tag_event(Event) -> {erlang:localtime(), Event}. -write_events(Events) -> write_events1(lists:reverse(Events)). +write_events(Events,IOMod) -> write_events1(lists:reverse(Events),IOMod). -write_events1([Event|Es]) -> - write_event(Event), - write_events1(Es); -write_events1([]) -> +write_events1([Event|Es],IOMod) -> + write_event(Event,IOMod), + write_events1(Es,IOMod); +write_events1([],_IOMod) -> ok. -write_event({Time, {error, _GL, {Pid, Format, Args}}}) -> +write_event({Time, {error, _GL, {Pid, Format, Args}}},IOMod) -> T = write_time(maybe_utc(Time)), case catch io_lib:format(add_node(Format,Pid), Args) of S when is_list(S) -> - format(T ++ S); + format(IOMod, T ++ S); _ -> F = add_node("ERROR: ~p - ~p~n", Pid), - format(T ++ F, [Format,Args]) + format(IOMod, T ++ F, [Format,Args]) end; -write_event({Time, {emulator, _GL, Chars}}) -> +write_event({Time, {emulator, _GL, Chars}},IOMod) -> T = write_time(maybe_utc(Time)), case catch io_lib:format(Chars, []) of S when is_list(S) -> - format(T ++ S); + format(IOMod, T ++ S); _ -> - format(T ++ "ERROR: ~p ~n", [Chars]) + format(IOMod, T ++ "ERROR: ~p ~n", [Chars]) end; -write_event({Time, {info, _GL, {Pid, Info, _}}}) -> +write_event({Time, {info, _GL, {Pid, Info, _}}},IOMod) -> T = write_time(maybe_utc(Time)), - format(T ++ add_node("~p~n",Pid),[Info]); -write_event({Time, {error_report, _GL, {Pid, std_error, Rep}}}) -> + format(IOMod, T ++ add_node("~p~n",Pid),[Info]); +write_event({Time, {error_report, _GL, {Pid, std_error, Rep}}},IOMod) -> T = write_time(maybe_utc(Time)), S = format_report(Rep), - format(T ++ S ++ add_node("", Pid)); -write_event({Time, {info_report, _GL, {Pid, std_info, Rep}}}) -> + format(IOMod, T ++ S ++ add_node("", Pid)); +write_event({Time, {info_report, _GL, {Pid, std_info, Rep}}},IOMod) -> T = write_time(maybe_utc(Time), "INFO REPORT"), S = format_report(Rep), - format(T ++ S ++ add_node("", Pid)); -write_event({Time, {info_msg, _GL, {Pid, Format, Args}}}) -> + format(IOMod, T ++ S ++ add_node("", Pid)); +write_event({Time, {info_msg, _GL, {Pid, Format, Args}}},IOMod) -> T = write_time(maybe_utc(Time), "INFO REPORT"), case catch io_lib:format(add_node(Format,Pid), Args) of S when is_list(S) -> - format(T ++ S); + format(IOMod, T ++ S); _ -> F = add_node("ERROR: ~p - ~p~n", Pid), - format(T ++ F, [Format,Args]) + format(IOMod, T ++ F, [Format,Args]) end; -write_event({Time, {warning_report, _GL, {Pid, std_warning, Rep}}}) -> +write_event({Time, {warning_report, _GL, {Pid, std_warning, Rep}}},IOMod) -> T = write_time(maybe_utc(Time), "WARNING REPORT"), S = format_report(Rep), - format(T ++ S ++ add_node("", Pid)); -write_event({Time, {warning_msg, _GL, {Pid, Format, Args}}}) -> + format(IOMod, T ++ S ++ add_node("", Pid)); +write_event({Time, {warning_msg, _GL, {Pid, Format, Args}}},IOMod) -> T = write_time(maybe_utc(Time), "WARNING REPORT"), case catch io_lib:format(add_node(Format,Pid), Args) of S when is_list(S) -> - format(T ++ S); + format(IOMod, T ++ S); _ -> F = add_node("ERROR: ~p - ~p~n", Pid), - format(T ++ F, [Format,Args]) + format(IOMod, T ++ F, [Format,Args]) end; -write_event({_Time, _Error}) -> +write_event({_Time, _Error},_IOMod) -> ok. maybe_utc(Time) -> @@ -178,8 +180,9 @@ maybe_utc(Time) -> Time end. -format(String) -> io:format(user, String, []). -format(String, Args) -> io:format(user, String, Args). +format(IOMod, String) -> format(IOMod, String, []). +format(io_lib, String, Args) -> io_lib:format(String, Args); +format(io, String, Args) -> io:format(user, String, Args). format_report(Rep) when is_list(Rep) -> case string_p(Rep) of -- cgit v1.2.3 From 97273a38297ab03f727c4c7bdbb3b0491bdcfb8f Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 20 Sep 2011 10:04:12 +0200 Subject: Add -enable_builtin_hooks config option This option allows ct users to disable the default hooks which are installed when common_test is started. The builtin hooks themselved are listed in ct_hooks. OTP-9564 --- lib/common_test/src/ct_hooks.erl | 27 ++++++++- lib/common_test/src/ct_run.erl | 106 ++++++++++++++++++++++-------------- lib/common_test/src/ct_testspec.erl | 5 ++ lib/common_test/src/ct_util.hrl | 1 + 4 files changed, 97 insertions(+), 42 deletions(-) diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl index f243b87f54..886195aae5 100644 --- a/lib/common_test/src/ct_hooks.erl +++ b/lib/common_test/src/ct_hooks.erl @@ -34,6 +34,12 @@ %% If you change this, remember to update ct_util:look -> stop clause as well. -define(config_name, ct_hooks). +%% All of the hooks which are to be started by default. Remove by issuing +%% -enable_builtin_hooks false to when starting common test. +-define(BUILTIN_HOOKS,[#ct_hook_config{ module = cth_log_redirect, + opts = [], + prio = ctfirst }]). + -record(ct_hook_config, {id, module, prio, scope, opts = [], state = []}). %% ------------------------------------------------------------------------- @@ -44,7 +50,8 @@ -spec init(State :: term()) -> ok | {error, Reason :: term()}. init(Opts) -> - call(get_new_hooks(Opts, undefined), ok, init, []). + call(get_new_hooks(Opts, undefined) ++ get_builtin_hooks(Opts), + ok, init, []). %% @doc Called after all suites are done. @@ -283,6 +290,14 @@ get_new_hooks(Config) when is_list(Config) -> get_new_hooks(_Config) -> []. +get_builtin_hooks(Opts) -> + case proplists:get_value(enable_builtin_hooks,Opts) of + false -> + []; + _Else -> + [{HookConf, call_id, undefined} || HookConf <- ?BUILTIN_HOOKS] + end. + save_suite_data_async(Hooks) -> ct_util:save_suite_data_async(?config_name, Hooks). @@ -290,7 +305,7 @@ get_hooks() -> lists:keysort(#ct_hook_config.prio,ct_util:read_suite_data(?config_name)). %% Sort all calls in this order: -%% call_id < call_init < Hook Priority 1 < .. < Hook Priority N +%% call_id < call_init < ctfirst < Priority 1 < .. < Priority N < ctlast %% If Hook Priority is equal, check when it has been installed and %% sort on that instead. resort(Calls, Hooks) -> @@ -311,6 +326,14 @@ resort(Calls, Hooks) -> %% If priorities are equal, we check the position in the %% hooks list pos(Id1,Hooks) < pos(Id2,Hooks); + P1 == ctfirst -> + true; + P2 == ctfirst -> + false; + P1 == ctlast -> + false; + P2 == ctlast -> + true; true -> P1 < P2 end diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index 877ec9c7dd..0715b8abf8 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -55,6 +55,7 @@ config = [], event_handlers = [], ct_hooks = [], + enable_builtin_hooks = true, include = [], silent_connections, stylesheet, @@ -173,6 +174,10 @@ script_start1(Parent, Args) -> end, false, Args), EvHandlers = event_handler_args2opts(Args), CTHooks = ct_hooks_args2opts(Args), + EnableBuiltinHooks = get_start_opt(enable_builtin_hooks, + fun([CT]) -> list_to_atom(CT); + ([]) -> true + end, true, Args), %% check flags and set corresponding application env variables @@ -237,6 +242,7 @@ script_start1(Parent, Args) -> StartOpts = #opts{label = Label, vts = Vts, shell = Shell, cover = Cover, logdir = LogDir, event_handlers = EvHandlers, ct_hooks = CTHooks, + enable_builtin_hooks = EnableBuiltinHooks, include = IncludeDirs, silent_connections = SilentConns, stylesheet = Stylesheet, @@ -311,6 +317,11 @@ script_start2(StartOpts = #opts{vts = undefined, AllCTHooks = merge_vals( [StartOpts#opts.ct_hooks, SpecStartOpts#opts.ct_hooks]), + + EnableBuiltinHooks = + choose_val( + StartOpts#opts.enable_builtin_hooks, + SpecStartOpts#opts.enable_builtin_hooks), AllInclude = merge_vals([StartOpts#opts.include, SpecStartOpts#opts.include]), @@ -323,6 +334,8 @@ script_start2(StartOpts = #opts{vts = undefined, config = SpecStartOpts#opts.config, event_handlers = AllEvHs, ct_hooks = AllCTHooks, + enable_builtin_hooks = + EnableBuiltinHooks, include = AllInclude, multiply_timetraps = MultTT, scale_timetraps = ScaleTT}} @@ -339,9 +352,7 @@ script_start2(StartOpts = #opts{vts = undefined, {[],_} -> {error,no_testspec_specified}; {undefined,_} -> % no testspec used - case check_and_install_configfiles(InitConfig, TheLogDir, - Opts#opts.event_handlers, - Opts#opts.ct_hooks) of + case check_and_install_configfiles(InitConfig, TheLogDir, Opts) of ok -> % go on read tests from start flags script_start3(Opts#opts{config=InitConfig, logdir=TheLogDir}, Args); @@ -351,9 +362,7 @@ script_start2(StartOpts = #opts{vts = undefined, {_,_} -> % testspec used %% merge config from start flags with config from testspec AllConfig = merge_vals([InitConfig, Opts#opts.config]), - case check_and_install_configfiles(AllConfig, TheLogDir, - Opts#opts.event_handlers, - Opts#opts.ct_hooks) of + case check_and_install_configfiles(AllConfig, TheLogDir, Opts) of ok -> % read tests from spec {Run,Skip} = ct_testspec:prepare_tests(Terms, node()), do_run(Run, Skip, Opts#opts{config=AllConfig, @@ -367,9 +376,7 @@ script_start2(StartOpts, Args) -> %% read config/userconfig from start flags InitConfig = ct_config:prepare_config_list(Args), LogDir = which(logdir, StartOpts#opts.logdir), - case check_and_install_configfiles(InitConfig, LogDir, - StartOpts#opts.event_handlers, - StartOpts#opts.ct_hooks) of + case check_and_install_configfiles(InitConfig, LogDir, StartOpts) of ok -> % go on read tests from start flags script_start3(StartOpts#opts{config=InitConfig, logdir=LogDir}, Args); @@ -377,12 +384,17 @@ script_start2(StartOpts, Args) -> Error end. -check_and_install_configfiles(Configs, LogDir, EvHandlers, CTHooks) -> +check_and_install_configfiles( + Configs, LogDir, #opts{ + event_handlers = EvHandlers, + ct_hooks = CTHooks, + enable_builtin_hooks = EnableBuiltinHooks} ) -> case ct_config:check_config_files(Configs) of false -> install([{config,Configs}, {event_handler,EvHandlers}, - {ct_hooks,CTHooks}], LogDir); + {ct_hooks,CTHooks}, + {enable_builtin_hooks,EnableBuiltinHooks}], LogDir); {value,{error,{nofile,File}}} -> {error,{cant_read_config_file,File}}; {value,{error,{wrong_config,Message}}}-> @@ -451,18 +463,19 @@ script_start4(#opts{vts = true, config = Config, event_handlers = EvHandlers, script_start4(#opts{label = Label, shell = true, config = Config, event_handlers = EvHandlers, ct_hooks = CTHooks, + enable_builtin_hooks = EnableBuiltinHooks, logdir = LogDir, testspecs = Specs}, _Args) -> %% label - used by ct_logs application:set_env(common_test, test_label, Label), - InstallOpts = [{config,Config},{event_handler,EvHandlers}, - {ct_hooks, CTHooks}], if Config == [] -> ok; true -> io:format("\nInstalling: ~p\n\n", [Config]) end, - case install(InstallOpts) of + case install([{config,Config},{event_handler,EvHandlers}, + {ct_hooks, CTHooks}, + {enable_builtin_hooks,EnableBuiltinHooks}]) of ok -> ct_util:start(interactive, LogDir), log_ts_names(Specs), @@ -682,6 +695,11 @@ run_test1(StartOpts) -> %% CT Hooks CTHooks = get_start_opt(ct_hooks, value, [], StartOpts), + EnableBuiltinHooks = get_start_opt(enable_builtin_hooks, + fun(EBH) when EBH == true; + EBH == false -> + EBH + end, true, StartOpts), %% silent connections SilentConns = get_start_opt(silent_connections, @@ -754,6 +772,7 @@ run_test1(StartOpts) -> cover = Cover, step = Step, logdir = LogDir, config = CfgFiles, event_handlers = EvHandlers, ct_hooks = CTHooks, + enable_builtin_hooks = EnableBuiltinHooks, include = Include, silent_connections = SilentConns, stylesheet = Stylesheet, @@ -808,24 +827,28 @@ run_spec_file(Relaxed, AllCTHooks = merge_vals([Opts#opts.ct_hooks, SpecOpts#opts.ct_hooks]), + EnableBuiltinHooks = choose_val(Opts#opts.enable_builtin_hooks, + SpecOpts#opts.enable_builtin_hooks), application:set_env(common_test, include, AllInclude), - case check_and_install_configfiles(AllConfig, - which(logdir,LogDir), - AllEvHs, - AllCTHooks) of + Opts1 = Opts#opts{label = Label, + cover = Cover, + logdir = which(logdir, LogDir), + config = AllConfig, + event_handlers = AllEvHs, + include = AllInclude, + testspecs = AbsSpecs, + multiply_timetraps = MultTT, + scale_timetraps = ScaleTT, + ct_hooks = AllCTHooks, + enable_builtin_hooks = EnableBuiltinHooks + }, + + case check_and_install_configfiles(AllConfig,Opts1#opts.logdir, + Opts1) of ok -> - Opts1 = Opts#opts{label = Label, - cover = Cover, - logdir = which(logdir, LogDir), - config = AllConfig, - event_handlers = AllEvHs, - include = AllInclude, - testspecs = AbsSpecs, - multiply_timetraps = MultTT, - scale_timetraps = ScaleTT, - ct_hooks = AllCTHooks}, + {Run,Skip} = ct_testspec:prepare_tests(TS, node()), reformat_result(catch do_run(Run, Skip, Opts1, StartOpts)); {error,GCFReason} -> @@ -834,13 +857,10 @@ run_spec_file(Relaxed, end. run_prepared(Run, Skip, Opts = #opts{logdir = LogDir, - config = CfgFiles, - event_handlers = EvHandlers, - ct_hooks = CTHooks}, + config = CfgFiles }, StartOpts) -> LogDir1 = which(logdir, LogDir), - case check_and_install_configfiles(CfgFiles, LogDir1, - EvHandlers, CTHooks) of + case check_and_install_configfiles(CfgFiles, LogDir1, Opts) of ok -> reformat_result(catch do_run(Run, Skip, Opts#opts{logdir = LogDir1}, StartOpts)); @@ -872,7 +892,8 @@ check_config_file(Callback, File)-> run_dir(Opts = #opts{logdir = LogDir, config = CfgFiles, event_handlers = EvHandlers, - ct_hooks = CTHook }, StartOpts) -> + ct_hooks = CTHook, + enable_builtin_hooks = EnableBuiltinHooks }, StartOpts) -> LogDir1 = which(logdir, LogDir), Opts1 = Opts#opts{logdir = LogDir1}, AbsCfgFiles = @@ -895,7 +916,8 @@ run_dir(Opts = #opts{logdir = LogDir, end, CfgFiles), case install([{config,AbsCfgFiles}, {event_handler,EvHandlers}, - {ct_hooks, CTHook}], LogDir1) of + {ct_hooks, CTHook}, + {enable_builtin_hooks,EnableBuiltinHooks}], LogDir1) of ok -> ok; {error,IReason} -> exit(IReason) end, @@ -999,9 +1021,8 @@ run_testspec1(TestSpec) -> end, application:set_env(common_test, include, AllInclude), LogDir1 = which(logdir,Opts#opts.logdir), - case check_and_install_configfiles(Opts#opts.config, LogDir1, - Opts#opts.event_handlers, - Opts#opts.ct_hooks) of + case check_and_install_configfiles( + Opts#opts.config, LogDir1, Opts) of ok -> Opts1 = Opts#opts{testspecs = [], logdir = LogDir1, @@ -1020,6 +1041,7 @@ get_data_for_node(#testspec{label = Labels, userconfig = UsrCfgs, event_handler = EvHs, ct_hooks = CTHooks, + enable_builtin_hooks = EnableBuiltinHooks, include = Incl, multiply_timetraps = MTs, scale_timetraps = STs}, Node) -> @@ -1042,6 +1064,7 @@ get_data_for_node(#testspec{label = Labels, config = ConfigFiles, event_handlers = EvHandlers, ct_hooks = FiltCTHooks, + enable_builtin_hooks = EnableBuiltinHooks, include = Include, multiply_timetraps = MT, scale_timetraps = ST}. @@ -2067,8 +2090,11 @@ get_start_opt(Key, IfExists, IfNotExists, Args) -> end. ct_hooks_args2opts(Args) -> - ct_hooks_args2opts( - proplists:get_value(ct_hooks, Args, []),[]). + lists:foldl(fun({ct_hooks,Hooks}, Acc) -> + ct_hooks_args2opts(Hooks,Acc); + (_,Acc) -> + Acc + end,[],Args). ct_hooks_args2opts([CTH,Arg,Prio,"and"| Rest],Acc) -> ct_hooks_args2opts(Rest,[{list_to_atom(CTH), diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl index d845358bb2..96971ccfc7 100644 --- a/lib/common_test/src/ct_testspec.erl +++ b/lib/common_test/src/ct_testspec.erl @@ -646,6 +646,10 @@ add_tests([{ct_hooks, _Node, []}|Ts], Spec) -> add_tests([{ct_hooks, Hooks}|Ts], Spec) -> add_tests([{ct_hooks, all_nodes, Hooks}|Ts], Spec); +%% -- enable_builtin_hooks -- +add_tests([{enable_builtin_hooks,Bool}|Ts],Spec) -> + add_tests(Ts, Spec#testspec{ enable_builtin_hooks = Bool }); + %% --- include --- add_tests([{include,all_nodes,InclDirs}|Ts],Spec) -> Tests = lists:map(fun(N) -> {include,N,InclDirs} end, list_nodes(Spec)), @@ -1104,6 +1108,7 @@ valid_terms() -> {event_handler,4}, {ct_hooks,2}, {ct_hooks,3}, + {enable_builtin_hooks,1}, {multiply_timetraps,2}, {multiply_timetraps,3}, {scale_timetraps,2}, diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl index 556f88c84d..dbe9d9b4e6 100644 --- a/lib/common_test/src/ct_util.hrl +++ b/lib/common_test/src/ct_util.hrl @@ -37,6 +37,7 @@ userconfig=[], event_handler=[], ct_hooks=[], + enable_builtin_hooks=true, include=[], multiply_timetraps=[], scale_timetraps=[], -- cgit v1.2.3 From 4bd25eb6aa89d15509148a0b9a5da64a035be841 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 19 Sep 2011 11:17:28 +0200 Subject: Add a hook for redirecting SASL and error_logger messages SASL and error_logger messaged can now be redirected to the common_test log using a hook which is bundled with common_test. --- lib/common_test/src/Makefile | 3 +- lib/common_test/src/cth_log_redirect.erl | 87 ++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 lib/common_test/src/cth_log_redirect.erl diff --git a/lib/common_test/src/Makefile b/lib/common_test/src/Makefile index 84b122b5e4..51624fbde7 100644 --- a/lib/common_test/src/Makefile +++ b/lib/common_test/src/Makefile @@ -69,7 +69,8 @@ MODULES= \ ct_config_xml \ ct_slave \ ct_hooks\ - ct_hooks_lock + ct_hooks_lock\ + cth_log_redirect TARGET_MODULES= $(MODULES:%=$(EBIN)/%) diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl new file mode 100644 index 0000000000..67899c392d --- /dev/null +++ b/lib/common_test/src/cth_log_redirect.erl @@ -0,0 +1,87 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(cth_log_redirect). + +%%% @doc Common Test Framework functions handling test specifications. +%%% +%%%

This module redirects sasl and error logger info to common test log.

+%%% @end + + +%% CTH Callbacks +-export([id/1, init/2, pre_init_per_testcase/3, post_end_per_testcase/4]). + +%% Event handler Callbacks +-export([init/1, + handle_event/2, handle_call/2, handle_info/2, + terminate/2]). + +-record(state, { }). + +id(_Opts) -> + ?MODULE. + +init(?MODULE, _Opts) -> + error_logger:add_report_handler(?MODULE), + #state{ }. + +pre_init_per_testcase(_Testcase, Config, State) -> + {Config, State}. + +post_end_per_testcase(_TestCase, _Config, Result, State) -> + {Result, State}. + +%% Copied and modified from sasl_report_tty_h.erl +init(Type) -> + {ok, Type}. + +handle_event({_Type, GL, _Msg}, State) when node(GL) /= node() -> + {ok, State}; +handle_event(Event, Type) -> + case proplists:get_value(sasl, application:which_applications()) of + undefined -> + sasl_not_started; + _Else -> + {ok, ErrLogType} = application:get_env(sasl, errlog_type), + SReport = sasl_report:format_report(group_leader(), ErrLogType, + tag_event(Event)), + if is_list(SReport) -> + ct:log(sasl, SReport, []); + true -> %% Report is an atom if no logging is to be done + ignore + end + end, + EReport = error_logger_tty_h:write_event( + tag_event(Event),io_lib), + if is_list(EReport) -> + ct:log(error_logger, EReport, []); + true -> %% Report is an atom if no logging is to be done + ignore + end, + {ok, Type}. + +handle_info(_,State) -> {ok, State}. + +handle_call(_Query, _Type) -> {error, bad_query}. + +terminate(_Reason, _Type) -> + []. + +tag_event(Event) -> + {calendar:local_time(), Event}. -- cgit v1.2.3 From c047574239981e29681d1bd0ec4390fdd64c00ab Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Fri, 16 Sep 2011 17:18:22 +0200 Subject: Add ct_log:ct_log funcion This function is used to force logging to CT framework log instead of test case log. --- lib/common_test/src/ct_logs.erl | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl index b839521e24..6a90441d53 100644 --- a/lib/common_test/src/ct_logs.erl +++ b/lib/common_test/src/ct_logs.erl @@ -36,7 +36,7 @@ -export([make_all_suites_index/1,make_all_runs_index/1]). %% Logging stuff directly from testcase --export([tc_log/3,tc_print/3,tc_pal/3, +-export([tc_log/3,tc_print/3,tc_pal/3,ct_log/3, basic_html/0]). %% Simulate logger process for use without ct environment running @@ -360,6 +360,23 @@ tc_pal(Category,Format,Args) -> ok. +%%%----------------------------------------------------------------- +%%% @spec tc_pal(Category,Format,Args) -> ok +%%% Category = atom() +%%% Format = string() +%%% Args = list() +%%% +%%% @doc Print and log to the ct framework log +%%% +%%%

This function is called by internal ct functions to +%%% force logging to the ct framework log

+ct_log(Category,Format,Args) -> + cast({ct_log,[{div_header(Category),[]}, + {Format,Args}, + {div_footer(),[]}]}), + ok. + + %%%================================================================= %%% Internal functions int_header() -> @@ -516,7 +533,12 @@ logger_loop(State) -> {clear_stylesheet,_} when State#logger_state.stylesheet == undefined -> logger_loop(State); {clear_stylesheet,_} -> - logger_loop(State#logger_state{stylesheet=undefined}); + logger_loop(State#logger_state{stylesheet=undefined}); + {ct_log, List} -> + Fd = State#logger_state.ct_log_fd, + [begin io:format(Fd,Str,Args),io:nl(Fd) end || + {Str,Args} <- List], + logger_loop(State); stop -> io:format(State#logger_state.ct_log_fd, int_header()++int_footer(), -- cgit v1.2.3 From 4d620ed2b9896762666fd5005f937f2229e5d242 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Fri, 16 Sep 2011 17:19:17 +0200 Subject: Force logging to framework log for parallel tests When parallel tests are run all logs are redirected to use ct_logs:ct_log instead of ct_logs:tc_log. --- lib/common_test/src/cth_log_redirect.erl | 50 +++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl index 67899c392d..21458c5903 100644 --- a/lib/common_test/src/cth_log_redirect.erl +++ b/lib/common_test/src/cth_log_redirect.erl @@ -25,36 +25,46 @@ %% CTH Callbacks --export([id/1, init/2, pre_init_per_testcase/3, post_end_per_testcase/4]). +-export([id/1, init/2, post_init_per_group/4, pre_end_per_group/3]). %% Event handler Callbacks -export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2]). --record(state, { }). - id(_Opts) -> ?MODULE. init(?MODULE, _Opts) -> error_logger:add_report_handler(?MODULE), - #state{ }. + tc_log. + +post_init_per_group(Group, Config, Result, tc_log) -> + case lists:member(parallel,proplists:get_value( + tc_group_properties,Config,[])) of + true -> + {Result, {set_log_func(ct_log),Group}}; + false -> + {Result, tc_log} + end; +post_init_per_group(_Group, _Config, Result, State) -> + {Result, State}. -pre_init_per_testcase(_Testcase, Config, State) -> + +pre_end_per_group(Group, Config, {ct_log, Group}) -> + {Config, set_log_func(tc_log)}; +pre_end_per_group(_Group, Config, State) -> {Config, State}. -post_end_per_testcase(_TestCase, _Config, Result, State) -> - {Result, State}. %% Copied and modified from sasl_report_tty_h.erl -init(Type) -> - {ok, Type}. +init(_Type) -> + {ok, tc_log}. handle_event({_Type, GL, _Msg}, State) when node(GL) /= node() -> {ok, State}; -handle_event(Event, Type) -> - case proplists:get_value(sasl, application:which_applications()) of +handle_event(Event, LogFunc) -> + case lists:keyfind(sasl, 1, application:which_applications()) of undefined -> sasl_not_started; _Else -> @@ -62,7 +72,7 @@ handle_event(Event, Type) -> SReport = sasl_report:format_report(group_leader(), ErrLogType, tag_event(Event)), if is_list(SReport) -> - ct:log(sasl, SReport, []); + ct_logs:LogFunc(sasl, SReport, []); true -> %% Report is an atom if no logging is to be done ignore end @@ -70,12 +80,15 @@ handle_event(Event, Type) -> EReport = error_logger_tty_h:write_event( tag_event(Event),io_lib), if is_list(EReport) -> - ct:log(error_logger, EReport, []); + ct_logs:LogFunc(error_logger, EReport, []); true -> %% Report is an atom if no logging is to be done ignore end, - {ok, Type}. + {ok, LogFunc}. +handle_info({set_logfunc,NewLogFunc,Reply},_) -> + Reply ! {ok,NewLogFunc}, + {ok, NewLogFunc}; handle_info(_,State) -> {ok, State}. handle_call(_Query, _Type) -> {error, bad_query}. @@ -85,3 +98,12 @@ terminate(_Reason, _Type) -> tag_event(Event) -> {calendar:local_time(), Event}. + +set_log_func(Func) -> + error_logger ! {set_logfunc, Func, self()}, + receive + {ok,Func} -> + Func + after 1000 -> + tc_log + end. -- cgit v1.2.3 From 8906e44ddafe608d25c509d9adbc523b8f055ab7 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 20 Sep 2011 10:48:57 +0200 Subject: Update cth_log_redirect to wait for all error_logger events before ending test --- lib/common_test/src/cth_log_redirect.erl | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl index 21458c5903..54e86e2b95 100644 --- a/lib/common_test/src/cth_log_redirect.erl +++ b/lib/common_test/src/cth_log_redirect.erl @@ -25,7 +25,8 @@ %% CTH Callbacks --export([id/1, init/2, post_init_per_group/4, pre_end_per_group/3]). +-export([id/1, init/2, post_init_per_group/4, pre_end_per_group/3, + post_end_per_testcase/4]). %% Event handler Callbacks -export([init/1, @@ -50,6 +51,11 @@ post_init_per_group(Group, Config, Result, tc_log) -> post_init_per_group(_Group, _Config, Result, State) -> {Result, State}. +post_end_per_testcase(_TC, _Config, Result, State) -> + %% Make sure that the event queue is flushed + %% before ending this test case. + gen_event:call(error_logger, ?MODULE, flush), + {Result, State}. pre_end_per_group(Group, Config, {ct_log, Group}) -> {Config, set_log_func(tc_log)}; @@ -86,12 +92,14 @@ handle_event(Event, LogFunc) -> end, {ok, LogFunc}. -handle_info({set_logfunc,NewLogFunc,Reply},_) -> - Reply ! {ok,NewLogFunc}, - {ok, NewLogFunc}; + handle_info(_,State) -> {ok, State}. -handle_call(_Query, _Type) -> {error, bad_query}. +handle_call(flush,State) -> + {ok, ok, State}; +handle_call({set_logfunc,NewLogFunc},_) -> + {ok, NewLogFunc, NewLogFunc}; +handle_call(_Query, _State) -> {error, bad_query}. terminate(_Reason, _Type) -> []. @@ -100,10 +108,4 @@ tag_event(Event) -> {calendar:local_time(), Event}. set_log_func(Func) -> - error_logger ! {set_logfunc, Func, self()}, - receive - {ok,Func} -> - Func - after 1000 -> - tc_log - end. + gen_event:call(error_logger, ?MODULE, {set_logfunc, Func}). -- cgit v1.2.3 From b7271367289625d5d2d22d95e1170c0cc26c07af Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 20 Sep 2011 11:11:16 +0200 Subject: Correct wrong match from lists:keyfind --- lib/common_test/src/cth_log_redirect.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl index 54e86e2b95..14663b7738 100644 --- a/lib/common_test/src/cth_log_redirect.erl +++ b/lib/common_test/src/cth_log_redirect.erl @@ -71,7 +71,7 @@ handle_event({_Type, GL, _Msg}, State) when node(GL) /= node() -> {ok, State}; handle_event(Event, LogFunc) -> case lists:keyfind(sasl, 1, application:which_applications()) of - undefined -> + false -> sasl_not_started; _Else -> {ok, ErrLogType} = application:get_env(sasl, errlog_type), -- cgit v1.2.3 From 7d0d76f3a8170ddb5a3b07fd46fce835bb631cef Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 20 Sep 2011 15:42:54 +0200 Subject: Add documentation for cth_log_redirect and built-in hooks OTP-9564 --- lib/common_test/doc/src/ct_hooks_chapter.xml | 32 ++++++++++++++++++++++++++++ lib/common_test/doc/src/run_test_chapter.xml | 10 ++++++++- lib/common_test/src/ct.erl | 2 +- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/lib/common_test/doc/src/ct_hooks_chapter.xml b/lib/common_test/doc/src/ct_hooks_chapter.xml index dbb4310040..3b9620d0f2 100644 --- a/lib/common_test/doc/src/ct_hooks_chapter.xml +++ b/lib/common_test/doc/src/ct_hooks_chapter.xml @@ -405,6 +405,38 @@ terminate(State) -> ok. + +
+ Built-in CTHs +

Common Test is delivered with a couple of general purpose CTHs that + can be enabled by the user to provide some generic testing functionality. + Some of these are enabled by default when starting running common_test, + they can be disabled by setting enable_builtin_hooks to + false on the command line or in the test specification. In the + table below there is a list of all current CTHs which are delivered with + Common Test.

+ + + + CTH Name + Is Built-in + Description + + + cth_log_redirect + yes + Captures all error_logger and SASL logging events and prints them + to the current test case log. If an event can not be associated with a + testcase it will be printed in the common test framework log. This will + happen for testcases which are run in parallel and events which occur + inbetween testcases. You can configure the level of + SASL events report + using the normal SASL mechanisms. + +
+ +
+ diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml index e668568795..816aa5b1eb 100644 --- a/lib/common_test/doc/src/run_test_chapter.xml +++ b/lib/common_test/doc/src/run_test_chapter.xml @@ -150,6 +150,8 @@ event handlers including start arguments. ]]>, to install Common Test Hooks including start arguments. + ]]>, to enable/disable + Built-in Common Test Hooks. Default is true. , specifies include directories (see above). , disables the automatic test suite compilation feature (see above). ]]>, extends timetrap @@ -450,6 +452,8 @@ {ct_hooks, CTHModules}. {ct_hooks, NodeRefs, CTHModules}. + + {enable_builtin_hooks, Bool}.

Test terms:

@@ -631,7 +635,11 @@
       

The minor log file contain full details of every single test case, each one in a separate file. This way the files should be easy to compare with previous test runs, even if the set of - test cases change.

+ test cases change. If SASL is running those logs will also be + printed there by the + + cth_log_redirect built-in hook. +

Which information goes where is user configurable via the test server controller. Three threshold values determine what diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl index 66da3ef742..3a96190256 100644 --- a/lib/common_test/src/ct.erl +++ b/lib/common_test/src/ct.erl @@ -149,7 +149,7 @@ run(TestDirs) -> %%% {repeat,N} | {duration,DurTime} | {until,StopTime} | %%% {force_stop,Bool} | {decrypt,DecryptKeyOrFile} | %%% {refresh_logs,LogDir} | {basic_html,Bool} | -%%% {ct_hooks, CTHs} +%%% {ct_hooks, CTHs} | {enable_builtin_hooks,Bool} %%% TestDirs = [string()] | string() %%% Suites = [string()] | string() %%% Cases = [atom()] | atom() -- cgit v1.2.3 From 4a68d3ebd54342ed72300a957883ed73957054af Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Wed, 21 Sep 2011 23:13:06 +0200 Subject: Fix lost wakeup of scheduler when enqueuing auxiliary work When auxiliary work was enqueued on a scheduler, the wakeup of the scheduler in order to handle this work could be lost. Wakeups in order to handle ordinary work were not effected by this bug. The bug only effected runtime systems with SMP support as follows: * Deallocation of some ETS data structures could be delayed. * On Linux systems not using the NPTL thread library (typically ancient systems with kernel versions prior to 2.6) and Windows systems, the {Port, {exit_status, Status}} message from a terminating port program could be delayed. That is, it only effected port programs which had been started by passing exit_status as an option to open_port/2. --- erts/emulator/beam/erl_process.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 2704359a8f..8422d1378c 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -1151,13 +1151,6 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING)); goto sys_woken; } - if (!(flgs & ERTS_SSI_FLG_SLEEPING)) { - flgs = sched_prep_cont_spin_wait(ssi); - if (!(flgs & ERTS_SSI_FLG_WAITING)) { - ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING)); - goto sys_woken; - } - } /* * If we got new I/O tasks we aren't allowed to -- cgit v1.2.3 From ed2398b61852c4e2c7ca7067f6bb664d23b5e507 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 23 Sep 2011 13:39:56 +0200 Subject: Fixed version, release notes and appup in prep for release. --- lib/megaco/doc/src/notes.xml | 42 +++++++++++++++++++++++++++++++++++++ lib/megaco/src/app/megaco.appup.src | 11 ++++++++++ lib/megaco/vsn.mk | 2 +- 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/lib/megaco/doc/src/notes.xml b/lib/megaco/doc/src/notes.xml index 4f678a2a1b..2aba8db71b 100644 --- a/lib/megaco/doc/src/notes.xml +++ b/lib/megaco/doc/src/notes.xml @@ -36,6 +36,48 @@ section is the version number of Megaco.

+
Megaco 3.15.1.1 + +

Version 3.15.1.1 supports code replacement in runtime from/to + version 3.15.1 and 3.15.

+ +
+ Improvements and new features + + + + + +

Correct various XML errors.

+

Own Id: OTP-9550

+
+ +
+ +
+ +
+ Fixed bugs and malfunctions + +

-

+ + + +
+ +
+ +
Megaco 3.15.1

Version 3.15.1 supports code replacement in runtime from/to diff --git a/lib/megaco/src/app/megaco.appup.src b/lib/megaco/src/app/megaco.appup.src index 01b070d79f..7107178d1a 100644 --- a/lib/megaco/src/app/megaco.appup.src +++ b/lib/megaco/src/app/megaco.appup.src @@ -136,10 +136,17 @@ %% | %% v %% 3.15.1 +%% | +%% v +%% 3.15.1.1 %% %% {"%VSN%", [ + {"3.15.1", + [ + ] + }, {"3.15", [ {load_module, megaco_flex_scanner, soft_purge, soft_purge, []}, @@ -153,6 +160,10 @@ } ], [ + {"3.15.1", + [ + ] + }, {"3.15", [ {load_module, megaco_flex_scanner, soft_purge, soft_purge, []}, diff --git a/lib/megaco/vsn.mk b/lib/megaco/vsn.mk index 5f71712360..c1476488ca 100644 --- a/lib/megaco/vsn.mk +++ b/lib/megaco/vsn.mk @@ -18,6 +18,6 @@ # %CopyrightEnd% APPLICATION = megaco -MEGACO_VSN = 3.15.1 +MEGACO_VSN = 3.15.1.1 PRE_VSN = APP_VSN = "$(APPLICATION)-$(MEGACO_VSN)$(PRE_VSN)" -- cgit v1.2.3 From 981c94e91701beb1d4f0bd52c90e864fe56770d7 Mon Sep 17 00:00:00 2001 From: Lars Thorsen Date: Wed, 4 May 2011 12:38:45 +0200 Subject: [erl_docgen] Missing header level in PDF bookmarks menu The System documentation PDF file was missing a header level in the bookmarks menu and the copyright year generation for PDF's was not correct. --- lib/erl_docgen/priv/xsl/db_pdf.xsl | 21 +++++++++++---------- lib/erl_docgen/priv/xsl/db_pdf_params.xsl | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/erl_docgen/priv/xsl/db_pdf.xsl b/lib/erl_docgen/priv/xsl/db_pdf.xsl index 35f6349f70..48a7a026c1 100644 --- a/lib/erl_docgen/priv/xsl/db_pdf.xsl +++ b/lib/erl_docgen/priv/xsl/db_pdf.xsl @@ -732,22 +732,23 @@ + - - User's Guide - - + + + - - - + + + + @@ -934,9 +935,9 @@ - +     - User's Guide + diff --git a/lib/erl_docgen/priv/xsl/db_pdf_params.xsl b/lib/erl_docgen/priv/xsl/db_pdf_params.xsl index 3dfecf8b74..d2f0350cf1 100644 --- a/lib/erl_docgen/priv/xsl/db_pdf_params.xsl +++ b/lib/erl_docgen/priv/xsl/db_pdf_params.xsl @@ -29,7 +29,7 @@ - Copyright © - + Copyright © - -- cgit v1.2.3 From d5a4fc889fa358da380ec967075132b998fa8cbf Mon Sep 17 00:00:00 2001 From: Lars Thorsen Date: Thu, 1 Sep 2011 09:43:38 +0200 Subject: [erl_docgen] Fix eix file generation for new function spec references --- lib/erl_docgen/priv/xsl/db_eix.xsl | 180 +++++++++++++++++++++++++++---------- make/otp_release_targets.mk | 4 +- 2 files changed, 137 insertions(+), 47 deletions(-) diff --git a/lib/erl_docgen/priv/xsl/db_eix.xsl b/lib/erl_docgen/priv/xsl/db_eix.xsl index 4545322bc2..7a648ddfd7 100644 --- a/lib/erl_docgen/priv/xsl/db_eix.xsl +++ b/lib/erl_docgen/priv/xsl/db_eix.xsl @@ -22,10 +22,16 @@ + + + + %% %% Search data file for @@ -50,9 +56,7 @@ {".html", {function, {" ", ""}}, [ - - - + ]}. {".html", {module, " "}, [""]}. @@ -62,9 +66,7 @@ {".html", {function, {" ", ""}}, [ - - - + ]}. {".html", {clib, " "}, [""]}. @@ -91,69 +93,157 @@ - - + + + + + + + + + + + + + + + + + + + + Error in : + : + + /: + + + + + + + + + + - - + + + + ambiguous spec + unknown spec + + + + + + + + + + + + + + + + + + + + + + + + + + + + {" + ", " + ", " + -"} + + + + + + + , + + + + + + + - + + - - - - - - - - - - + + + + + + + + + + - + + - - + + - + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + {" ", " ( diff --git a/make/otp_release_targets.mk b/make/otp_release_targets.mk index 8058e634d4..229612630d 100644 --- a/make/otp_release_targets.mk +++ b/make/otp_release_targets.mk @@ -74,10 +74,10 @@ ifneq ($(XML_FILES),) # ---------------------------------------------------- # Generation of application index data # ---------------------------------------------------- -$(HTMLDIR)/$(APPLICATION).eix: $(XML_FILES) +$(HTMLDIR)/$(APPLICATION).eix: $(XML_FILES) $(SPECS_FILES) date=`date +"%B %e %Y"`; \ $(XSLTPROC) --stringparam docgen "$(DOCGEN)" \ - --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude \ + --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude $(TOP_SPECS_PARAM) \ -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_html_entities $(DOCGEN)/priv/xsl/db_eix.xsl book.xml > $@ docs: $(HTMLDIR)/$(APPLICATION).eix -- cgit v1.2.3 From 8cb06dd34e0febc6a147ca4a3d9775ad3baade83 Mon Sep 17 00:00:00 2001 From: Lars Thorsen Date: Wed, 10 Aug 2011 10:22:44 +0200 Subject: [xmerl] Fix streaming bug in xmerl_scan (Thanks to Simon Cornish) --- lib/xmerl/src/xmerl_scan.erl | 21 +++++++++++++-------- lib/xmerl/src/xmerl_xsd.erl | 6 +++--- lib/xmerl/test/xmerl_SUITE.erl | 23 +++++++++++++++++++++-- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl index e598c5f56d..25c6547497 100644 --- a/lib/xmerl/src/xmerl_scan.erl +++ b/lib/xmerl/src/xmerl_scan.erl @@ -2074,10 +2074,10 @@ scan_element(T, S, Pos, Name, StartL, StartC, Attrs, Lang, Parents, {AttName, NamespaceInfo, T1, S1} = scan_name(T, S), {T2, S2} = scan_eq(T1, S1), {AttType,_DefaultDecl} = get_att_type(S2,AttName,Name), - {AttValue, T3, S3,IsNorm} = scan_att_value(T2, S2, AttType), + {AttValue, T3a, S3a,IsNorm} = scan_att_value(T2, S2, AttType), %% check_default_value(S3,DefaultDecl,AttValue), NewNS = check_namespace(AttName, NamespaceInfo, AttValue, NS), - wfc_whitespace_betw_attrs(hd(T3),S3), + {T3,S3} = wfc_whitespace_betw_attrs(T3a,S3a), ?strip4, AttrPos = case Attrs of [] -> @@ -3284,12 +3284,17 @@ wfc_legal_char(Ch,S) -> end. -wfc_whitespace_betw_attrs(WS,_S) when ?whitespace(WS) -> - ok; -wfc_whitespace_betw_attrs($/,_S) -> - ok; -wfc_whitespace_betw_attrs($>,_S) -> - ok; +wfc_whitespace_betw_attrs([WS |_]=L,S) when ?whitespace(WS) -> + {L,S}; +wfc_whitespace_betw_attrs([$/ |_]=L,S) -> + {L,S}; +wfc_whitespace_betw_attrs([$> |_]=L,S) -> + {L,S}; +wfc_whitespace_betw_attrs([],S=#xmerl_scanner{continuation_fun = F}) -> + ?dbg("cont()...~n", []), + F(fun(MoreBytes, S1) -> wfc_whitespace_betw_attrs(MoreBytes, S1) end, + fun(S1) -> ?fatal(unexpected_end, S1) end, + S); wfc_whitespace_betw_attrs(_,S) -> ?fatal({whitespace_required_between_attributes},S). diff --git a/lib/xmerl/src/xmerl_xsd.erl b/lib/xmerl/src/xmerl_xsd.erl index 50c0a79016..dfdc6138ef 100644 --- a/lib/xmerl/src/xmerl_xsd.erl +++ b/lib/xmerl/src/xmerl_xsd.erl @@ -355,9 +355,9 @@ initiate_state(Opts,Schema) -> XSDBase = filename:dirname(Schema), {{state,S},RestOpts}=new_state(Opts), S2 = create_tables(S), - S3 = initiate_state2(S2#xsd_state{schema_name = Schema, xsd_base=XSDBase, - fetch_fun = fun fetch/2}, - RestOpts). + initiate_state2(S2#xsd_state{schema_name = Schema, xsd_base=XSDBase, + fetch_fun = fun fetch/2}, + RestOpts). initiate_state2(S,[]) -> S; diff --git a/lib/xmerl/test/xmerl_SUITE.erl b/lib/xmerl/test/xmerl_SUITE.erl index 0c809dbcb6..94c38d4d48 100644 --- a/lib/xmerl/test/xmerl_SUITE.erl +++ b/lib/xmerl/test/xmerl_SUITE.erl @@ -58,7 +58,7 @@ groups() -> {ticket_tests, [], [ticket_5998, ticket_7211, ticket_7214, ticket_7430, ticket_6873, ticket_7496, ticket_8156, ticket_8697, - ticket_9411]}, + ticket_9411, ticket_9457]}, {app_test, [], [{xmerl_app_test, all}]}, {appup_test, [], [{xmerl_appup_test, all}]}]. @@ -588,7 +588,26 @@ ticket_9411(Config) -> ?line {E, _} = xmerl_scan:string(Xml), ?line {E, _} = xmerl_xsd:validate(E, Schema). - +ticket_9457(suite) -> []; +ticket_9457(doc) -> + ["Test that xmerl_scan handles continuation correct when current input runs out at the end of an attribute value"]; +ticket_9457(Config) -> + Opts = [{continuation_fun, fun ticket_9457_cont/3, start}, {space, normalize}], + ?line {E, _} = xmerl_scan:string([], Opts). + +ticket_9457_cont(Continue, Exception, GlobalState) -> + case xmerl_scan:cont_state(GlobalState) of + start -> + G1 = xmerl_scan:cont_state(next, GlobalState), + Bytes = "\r\n + G1 = xmerl_scan:cont_state(last, GlobalState), + Bytes = ">blah\r\n", + Continue(Bytes, G1); + _ -> + Exception(GlobalState) + end. %%====================================================================== %% Support Functions -- cgit v1.2.3