diff options
Diffstat (limited to 'lib')
123 files changed, 2070 insertions, 1057 deletions
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl index cae7bea406..d7ae81a5ce 100644 --- a/lib/common_test/src/ct.erl +++ b/lib/common_test/src/ct.erl @@ -282,7 +282,7 @@ step(TestDir,Suite,Case,Opts) -> %%% <c>> ct_telnet:cmd(unix_telnet, "ls .").</c><br/> %%% <c>{ok,["ls","file1 ...",...]}</c></p> start_interactive() -> - ct_util:start(interactive), + _ = ct_util:start(interactive), ok. %%%----------------------------------------------------------------- diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl index b499bc8b05..99de311570 100644 --- a/lib/common_test/src/ct_config.erl +++ b/lib/common_test/src/ct_config.erl @@ -119,7 +119,8 @@ call(Msg) -> end. return({To,Ref},Result) -> - To ! {Ref, Result}. + To ! {Ref, Result}, + ok. loop(StartDir) -> receive @@ -128,11 +129,11 @@ loop(StartDir) -> return(From,Result), loop(StartDir); {{set_default_config,{Config,Scope}},From} -> - set_config(Config,{true,Scope}), + _ = set_config(Config,{true,Scope}), return(From,ok), loop(StartDir); {{set_default_config,{Name,Config,Scope}},From} -> - set_config(Name,Config,{true,Scope}), + _ = set_config(Name,Config,{true,Scope}), return(From,ok), loop(StartDir); {{delete_default_config,Scope},From} -> @@ -149,7 +150,7 @@ loop(StartDir) -> loop(StartDir); {{stop},From} -> ets:delete(?attr_table), - file:set_cwd(StartDir), + ok = file:set_cwd(StartDir), return(From,ok) end. @@ -257,7 +258,7 @@ read_config_files(Opts) -> read_config_files_int([{Callback, File}|Files], FunToSave) -> case Callback:read_config(File) of {ok, Config} -> - FunToSave(Config, Callback, File), + _ = FunToSave(Config, Callback, File), read_config_files_int(Files, FunToSave); {error, {ErrorName, ErrorDetail}} -> {user_error, {ErrorName, File, ErrorDetail}}; @@ -267,6 +268,15 @@ read_config_files_int([{Callback, File}|Files], FunToSave) -> read_config_files_int([], _FunToSave) -> ok. + +read_config_files(ConfigFiles, FunToSave) -> + case read_config_files_int(ConfigFiles, FunToSave) of + {user_error, Error} -> + {error, Error}; + ok -> + ok + end. + store_config(Config, Callback, File) when is_tuple(Config) -> store_config([Config], Callback, File); @@ -455,8 +465,12 @@ reload_conf(KeyOrName) -> undefined; HandlerList -> HandlerList2 = lists:usort(HandlerList), - read_config_files_int(HandlerList2, fun rewrite_config/3), - get_config(KeyOrName) + case read_config_files(HandlerList2, fun rewrite_config/3) of + ok -> + get_config(KeyOrName); + Error -> + Error + end end. release_allocated() -> @@ -490,16 +504,16 @@ associate(Name,_Key,Configs) -> associate_int(Name,Configs,os:getenv("COMMON_TEST_ALIAS_TOP")). associate_int(Name,Configs,"true") -> - lists:map(fun({K,_Config}) -> + lists:foreach(fun({K,_Config}) -> Cs = ets:match_object( ?attr_table, #ct_conf{key=element(1,K), name='_UNDEF',_='_'}), [ets:insert(?attr_table,C#ct_conf{name=Name}) || C <- Cs] - end,Configs); + end,Configs); associate_int(Name,Configs,_) -> - lists:map(fun({K,Config}) -> + lists:foreach(fun({K,Config}) -> Key = if is_tuple(K) -> element(1,K); is_atom(K) -> K end, @@ -511,7 +525,7 @@ associate_int(Name,Configs,_) -> [ets:insert(?attr_table,C#ct_conf{name=Name, value=Config}) || C <- Cs] - end,Configs). + end,Configs). @@ -576,7 +590,7 @@ encrypt_config_file(SrcFileName, EncryptFileName, {file,KeyFile}) -> end; encrypt_config_file(SrcFileName, EncryptFileName, {key,Key}) -> - crypto:start(), + _ = crypto:start(), {Key,IVec} = make_crypto_key(Key), case file:read_file(SrcFileName) of {ok,Bin0} -> @@ -615,7 +629,7 @@ decrypt_config_file(EncryptFileName, TargetFileName, {file,KeyFile}) -> end; decrypt_config_file(EncryptFileName, TargetFileName, {key,Key}) -> - crypto:start(), + _ = crypto:start(), {Key,IVec} = make_crypto_key(Key), case file:read_file(EncryptFileName) of {ok,Bin} -> @@ -778,14 +792,13 @@ prepare_config_list(Args) -> % TODO: add logging of the loaded configuration file to the CT FW log!!! add_config(Callback, []) -> - read_config_files_int([{Callback, []}], fun store_config/3); + read_config_files([{Callback, []}], fun store_config/3); add_config(Callback, [File|_Files]=Config) when is_list(File) -> lists:foreach(fun(CfgStr) -> - read_config_files_int([{Callback, CfgStr}], fun store_config/3) end, + read_config_files([{Callback, CfgStr}], fun store_config/3) end, Config); add_config(Callback, [C|_]=Config) when is_integer(C) -> - read_config_files_int([{Callback, Config}], fun store_config/3), - ok. + read_config_files([{Callback, Config}], fun store_config/3). remove_config(Callback, Config) -> ets:match_delete(?attr_table, diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index eb32f7f3fc..104515e57e 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -128,7 +128,7 @@ init_tc1(?MODULE,_,error_in_suite,_,[Config0]) when is_list(Config0) -> ct_event:notify(#event{name=tc_start, node=node(), data={?MODULE,error_in_suite}}), - ct_suite_init(?MODULE,error_in_suite,[],Config0), + _ = ct_suite_init(?MODULE,error_in_suite,[],Config0), case ?val(error,Config0) of undefined -> {fail,"unknown_error_in_suite"}; @@ -212,7 +212,7 @@ init_tc2(Mod,Suite,Func,HookFunc,SuiteInfo,MergeResult,Config) -> %% timetrap must be handled before require MergedInfo = timetrap_first(MergeResult, [], []), %% tell logger to use specified style sheet - case lists:keysearch(stylesheet,1,MergeResult++Config) of + _ = case lists:keysearch(stylesheet,1,MergeResult++Config) of {value,{stylesheet,SSFile}} -> ct_logs:set_stylesheet(Func,add_data_dir(SSFile,Config)); _ -> @@ -632,10 +632,10 @@ try_set_default(Name,Key,Info,Where) -> {_,[]} -> no_default; {'_UNDEF',_} -> - [ct_config:set_default_config([CfgVal],Where) || CfgVal <- CfgElems], + _ = [ct_config:set_default_config([CfgVal],Where) || CfgVal <- CfgElems], ok; _ -> - [ct_config:set_default_config(Name,[CfgVal],Where) || CfgVal <- CfgElems], + _ = [ct_config:set_default_config(Name,[CfgVal],Where) || CfgVal <- CfgElems], ok end. @@ -1315,7 +1315,7 @@ report(What,Data) -> %% top level test index page needs to be refreshed TestName = filename:basename(?val(topdir, Data), ".logs"), RunDir = ?val(rundir, Data), - ct_logs:make_all_suites_index({TestName,RunDir}), + _ = ct_logs:make_all_suites_index({TestName,RunDir}), ok; tests_start -> ok; diff --git a/lib/common_test/src/ct_ftp.erl b/lib/common_test/src/ct_ftp.erl index 48914864e4..84e664b387 100644 --- a/lib/common_test/src/ct_ftp.erl +++ b/lib/common_test/src/ct_ftp.erl @@ -292,7 +292,7 @@ init(KeyOrName,{IP,Port},{Username,Password}) -> end. ftp_connect(IP,Port,Username,Password) -> - inets:start(), + _ = inets:start(), case inets:start(ftpc,[{host,IP},{port,Port}]) of {ok,FtpPid} -> case ftp:user(FtpPid,Username,Password) of diff --git a/lib/common_test/src/ct_groups.erl b/lib/common_test/src/ct_groups.erl index dd04c5410a..1375e7dcc7 100644 --- a/lib/common_test/src/ct_groups.erl +++ b/lib/common_test/src/ct_groups.erl @@ -402,12 +402,7 @@ expand(Mod, Name, Defs) -> end. make_all_conf(Dir, Mod, Props, TestSpec) -> - case code:is_loaded(Mod) of - false -> - code:load_abs(filename:join(Dir,atom_to_list(Mod))); - _ -> - ok - end, + _ = load_abs(Dir, Mod), make_all_conf(Mod, Props, TestSpec). make_all_conf(Mod, Props, TestSpec) -> @@ -428,16 +423,19 @@ make_all_conf(Mod, Props, TestSpec) -> end. make_conf(Dir, Mod, Name, Props, TestSpec) -> + _ = load_abs(Dir, Mod), + make_conf(Mod, Name, Props, TestSpec). + +load_abs(Dir, Mod) -> case code:is_loaded(Mod) of false -> code:load_abs(filename:join(Dir,atom_to_list(Mod))); _ -> ok - end, - make_conf(Mod, Name, Props, TestSpec). + end. make_conf(Mod, Name, Props, TestSpec) -> - case code:is_loaded(Mod) of + _ = case code:is_loaded(Mod) of false -> code:load_file(Mod); _ -> diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl index 5422d449fd..c9a4abb5ee 100644 --- a/lib/common_test/src/ct_hooks.erl +++ b/lib/common_test/src/ct_hooks.erl @@ -408,7 +408,8 @@ catch_apply(M,F,A, Default) -> maybe_start_locker(Mod,GroupName,Opts) -> case lists:member(parallel,Opts) of true -> - {ok, _Pid} = ct_hooks_lock:start({Mod,GroupName}); + {ok, _Pid} = ct_hooks_lock:start({Mod,GroupName}), + ok; false -> ok end. diff --git a/lib/common_test/src/ct_hooks_lock.erl b/lib/common_test/src/ct_hooks_lock.erl index f41f259f7b..fea298e535 100644 --- a/lib/common_test/src/ct_hooks_lock.erl +++ b/lib/common_test/src/ct_hooks_lock.erl @@ -82,7 +82,7 @@ init(Id) -> %% @doc Handling call messages handle_call({stop,Id}, _From, #state{ id = Id, requests = Reqs } = State) -> - [gen_server:reply(Req, locker_stopped) || {Req,_ReqId} <- Reqs], + _ = [gen_server:reply(Req, locker_stopped) || {Req,_ReqId} <- Reqs], {stop, normal, stopped, State}; handle_call({stop,_Id}, _From, State) -> {reply, stopped, State}; diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl index 2a23e3274a..53245c596a 100644 --- a/lib/common_test/src/ct_logs.erl +++ b/lib/common_test/src/ct_logs.erl @@ -150,7 +150,7 @@ close(Info, StartDir) -> ok; CacheBin -> %% save final version of the log cache to file - file:write_file(?log_cache_name,CacheBin), + _ = file:write_file(?log_cache_name,CacheBin), put(ct_log_cache,undefined) end end, @@ -176,12 +176,12 @@ close(Info, StartDir) -> Error -> io:format("Warning! Cleanup failed: ~p~n", [Error]) end, - make_all_suites_index(stop), + _ = make_all_suites_index(stop), make_all_runs_index(stop), Cache2File(); true -> - file:set_cwd(".."), - make_all_suites_index(stop), + ok = file:set_cwd(".."), + _ = make_all_suites_index(stop), make_all_runs_index(stop), Cache2File(), case ct_util:get_profile_data(browser, StartDir) of @@ -252,16 +252,30 @@ call(Msg) -> end. return({To,Ref},Result) -> - To ! {Ref, Result}. + To ! {Ref, Result}, + ok. cast(Msg) -> case whereis(?MODULE) of undefined -> - {error,does_not_exist}; + io:format("Warning: ct_logs not started~n"), + {_,_,_,_,_,_,Content,_} = Msg, + FormatArgs = get_format_args(Content), + _ = [io:format(Format, Args) || {Format, Args} <- FormatArgs], + ok; _Pid -> - ?MODULE ! Msg + ?MODULE ! Msg, + ok end. +get_format_args(Content) -> + lists:map(fun(C) -> + case C of + {_, FA, _} -> FA; + {_, _} -> C + end + end, Content). + %%%----------------------------------------------------------------- %%% @spec init_tc(RefreshLog) -> ok %%% @@ -632,7 +646,7 @@ logger(Parent, Mode, Verbosity) -> end, %%! <--- - file:make_dir(Dir), + _ = file:make_dir(Dir), AbsDir = ?abs(Dir), put(ct_run_dir, AbsDir), @@ -672,7 +686,7 @@ logger(Parent, Mode, Verbosity) -> end end, - test_server_io:start_link(), + _ = test_server_io:start_link(), MiscIoName = filename:join(Dir, ?misc_io_log), {ok,MiscIoFd} = file:open(MiscIoName, [write,{encoding,utf8}]), @@ -702,13 +716,13 @@ logger(Parent, Mode, Verbosity) -> ct_event:notify(#event{name=start_logging,node=node(), data=AbsDir}), make_all_runs_index(start), - make_all_suites_index(start), + _ = make_all_suites_index(start), case Mode of interactive -> interactive_link(); _ -> ok end, - file:set_cwd(Dir), - make_last_run_index(Time), + ok = file:set_cwd(Dir), + _ = make_last_run_index(Time), CtLogFd = open_ctlog(?misc_io_log), io:format(CtLogFd,int_header()++int_footer(), [log_timestamp(?now),"Common Test Logger started"]), @@ -722,13 +736,13 @@ logger(Parent, Mode, Verbosity) -> GenLvl -> io:format(CtLogFd, "~-25s~3w~n", ["general level",GenLvl]) end, - [begin put({verbosity,Cat},VLvl), - if Cat == '$unspecified' -> + _ = [begin put({verbosity,Cat},VLvl), + if Cat == '$unspecified' -> ok; - true -> + true -> io:format(CtLogFd, "~-25w~3w~n", [Cat,VLvl]) - end - end || {Cat,VLvl} <- Verbosity], + end + end || {Cat,VLvl} <- Verbosity], io:nl(CtLogFd), TcEscChars = case application:get_env(common_test, esc_chars) of {ok,ECBool} -> ECBool; @@ -805,7 +819,7 @@ logger_loop(State) -> print_style(GL, IoFormat, State#logger_state.stylesheet), set_evmgr_gl(GL), TCGLs = add_tc_gl(TCPid,GL,State), - if not RefreshLog -> + _ = if not RefreshLog -> ok; true -> make_last_run_index(State#logger_state.start_time) @@ -832,7 +846,7 @@ logger_loop(State) -> return(From,{ok,filename:basename(State#logger_state.log_dir)}), logger_loop(State); {make_last_run_index,From} -> - make_last_run_index(State#logger_state.start_time), + _ = make_last_run_index(State#logger_state.start_time), return(From,get(ct_log_cache)), logger_loop(State); {set_stylesheet,_,SSFile} when State#logger_state.stylesheet == @@ -1170,7 +1184,7 @@ print_style_error(Fd, IoFormat, StyleSheet, Reason) -> close_ctlog(Fd) -> io:format(Fd, "\n</pre>\n", []), io:format(Fd, [xhtml("<br><br>\n", "<br /><br />\n") | footer()], []), - file:close(Fd). + ok = file:close(Fd). %%%----------------------------------------------------------------- %%% tc_io_format/3 @@ -1774,7 +1788,7 @@ count_cases(Dir) -> %% file yet. {0,0,0,0}; Summary -> - write_summary(SumFile, Summary), + _ = write_summary(SumFile, Summary), Summary end; {error, Reason} -> @@ -2089,7 +2103,7 @@ interactive_link() -> "</body>\n", "</html>\n" ], - file:write_file("last_interactive.html",unicode:characters_to_binary(Body)), + _ = file:write_file("last_interactive.html",unicode:characters_to_binary(Body)), io:format("~n~nUpdated ~ts\n" "Any CT activities will be logged here\n", [?abs("last_interactive.html")]). @@ -2220,9 +2234,9 @@ runentry(Dir, _, _) -> write_totals_file(Name,Label,Logs,Totals) -> AbsName = ?abs(Name), notify_and_lock_file(AbsName), - force_write_file(AbsName, - term_to_binary({atom_to_list(node()), - Label,Logs,Totals})), + _ = force_write_file(AbsName, + term_to_binary({atom_to_list(node()), + Label,Logs,Totals})), notify_and_unlock_file(AbsName). %% this function needs to convert from old formats to new so that old @@ -2267,7 +2281,7 @@ read_totals_file(Name) -> Result. force_write_file(Name,Contents) -> - force_delete(Name), + _ = force_delete(Name), file:write_file(Name,Contents). force_delete(Name) -> @@ -2818,18 +2832,18 @@ get_cache_data({ok,CacheBin}) -> true -> {ok,CacheRec}; false -> - file:delete(?log_cache_name), + _ = file:delete(?log_cache_name), {error,old_cache_file} end; _ -> - file:delete(?log_cache_name), + _ = file:delete(?log_cache_name), {error,invalid_cache_file} end; get_cache_data(NoCache) -> NoCache. cache_vsn() -> - application:load(common_test), + _ = application:load(common_test), case application:get_key(common_test,vsn) of {ok,VSN} -> VSN; diff --git a/lib/common_test/src/ct_master.erl b/lib/common_test/src/ct_master.erl index c4905b316f..4eef27d2a5 100644 --- a/lib/common_test/src/ct_master.erl +++ b/lib/common_test/src/ct_master.erl @@ -376,7 +376,7 @@ init_master(Parent,NodeOptsList,EvHandlers,MasterLogDir,LogDirs, end, %% start master event manager and add default handler - ct_master_event:start_link(), + {ok, _} = start_ct_master_event(), ct_master_event:add_handler(), %% add user handlers for master event manager Add = fun({H,Args}) -> @@ -398,6 +398,14 @@ init_master(Parent,NodeOptsList,EvHandlers,MasterLogDir,LogDirs, end, init_master1(Parent,NodeOptsList,InitOptions,LogDirs). +start_ct_master_event() -> + case ct_master_event:start_link() of + {error, {already_started, Pid}} -> + {ok, Pid}; + Else -> + Else + end. + init_master1(Parent,NodeOptsList,InitOptions,LogDirs) -> {Inaccessible,NodeOptsList1,InitOptions1} = init_nodes(NodeOptsList, InitOptions), @@ -658,7 +666,7 @@ refresh_logs([D|Dirs],Refreshed) -> {ok,Cwd} = file:get_cwd(), case catch ct_run:refresh_logs(D) of {'EXIT',Reason} -> - file:set_cwd(Cwd), + ok = file:set_cwd(Cwd), refresh_logs(Dirs,[{D,{error,Reason}}|Refreshed]); Result -> refresh_logs(Dirs,[{D,Result}|Refreshed]) @@ -701,7 +709,7 @@ init_node_ctrl(MasterPid,Cookie,Opts) -> end, %% start a local event manager - ct_event:start_link(), + {ok, _} = start_ct_event(), ct_event:add_handler([{master,MasterPid}]), %% log("Running test with options: ~p~n", [Opts]), @@ -721,6 +729,14 @@ init_node_ctrl(MasterPid,Cookie,Opts) -> "Can't report result!~n~n", [MasterNode]) end. +start_ct_event() -> + case ct_event:start_link() of + {error, {already_started, Pid}} -> + {ok, Pid}; + Else -> + Else + end. + %%%----------------------------------------------------------------- %%% Event handling %%%----------------------------------------------------------------- @@ -778,7 +794,7 @@ reply(Result,To) -> ok. init_nodes(NodeOptions, InitOptions)-> - ping_nodes(NodeOptions), + _ = ping_nodes(NodeOptions), start_nodes(InitOptions), eval_on_nodes(InitOptions), {Inaccessible, NodeOptions1}=ping_nodes(NodeOptions), diff --git a/lib/common_test/src/ct_master_logs.erl b/lib/common_test/src/ct_master_logs.erl index 39f87a7f09..a2542171f8 100644 --- a/lib/common_test/src/ct_master_logs.erl +++ b/lib/common_test/src/ct_master_logs.erl @@ -91,8 +91,8 @@ init(Parent,LogDir,Nodes) -> Time = calendar:local_time(), RunDir = make_dirname(Time), RunDirAbs = filename:join(LogDir,RunDir), - file:make_dir(RunDirAbs), - write_details_file(RunDirAbs,{node(),Nodes}), + ok = make_dir(RunDirAbs), + _ = write_details_file(RunDirAbs,{node(),Nodes}), case basic_html() of true -> @@ -128,7 +128,7 @@ init(Parent,LogDir,Nodes) -> end end, - make_all_runs_index(LogDir), + _ = make_all_runs_index(LogDir), CtLogFd = open_ct_master_log(RunDirAbs), NodeStr = lists:flatten(lists:map(fun(N) -> @@ -181,7 +181,7 @@ loop(State) -> lists:foreach(Fun,List), loop(State); {make_all_runs_index,From} -> - make_all_runs_index(State#state.logdir), + _ = make_all_runs_index(State#state.logdir), return(From,State#state.logdir), loop(State); {{nodedir,Node,RunDir},From} -> @@ -189,12 +189,12 @@ loop(State) -> return(From,ok), loop(State); stop -> - make_all_runs_index(State#state.logdir), + _ = make_all_runs_index(State#state.logdir), io:format(State#state.log_fd, int_header()++int_footer(), [log_timestamp(?now),"Finished!"]), - close_ct_master_log(State#state.log_fd), - close_nodedir_index(State#state.nodedir_ix_fd), + _ = close_ct_master_log(State#state.log_fd), + _ = close_nodedir_index(State#state.nodedir_ix_fd), ok end. @@ -496,7 +496,7 @@ make_relative(Dir) -> ct_logs:make_relative(Dir). force_write_file(Name,Contents) -> - force_delete(Name), + _ = force_delete(Name), file:write_file(Name,Contents). force_delete(Name) -> @@ -534,13 +534,34 @@ call(Msg) -> end. return({To,Ref},Result) -> - To ! {Ref, Result}. + To ! {Ref, Result}, + ok. cast(Msg) -> case whereis(?MODULE) of undefined -> - {error,does_not_exist}; + io:format("Warning: ct_master_logs not started~n"), + {_,_,Content} = Msg, + FormatArgs = get_format_args(Content), + _ = [io:format(Format, Args) || {Format, Args} <- FormatArgs], + ok; _Pid -> - ?MODULE ! Msg + ?MODULE ! Msg, + ok end. +get_format_args(Content) -> + lists:map(fun(C) -> + case C of + {_, FA, _} -> FA; + _ -> C + end + end, Content). + +make_dir(Dir) -> + case file:make_dir(Dir) of + {error, exist} -> + ok; + Else -> + Else + end. diff --git a/lib/common_test/src/ct_property_test.erl b/lib/common_test/src/ct_property_test.erl index 7dc78e949a..12c3d726d3 100644 --- a/lib/common_test/src/ct_property_test.erl +++ b/lib/common_test/src/ct_property_test.erl @@ -161,7 +161,9 @@ property_tests_path(Dir, Config) -> add_code_pathz(Dir) -> case lists:member(Dir, code:get_path()) of true -> ok; - false -> code:add_pathz(Dir) + false -> + true = code:add_pathz(Dir), + ok end. compile_tests(Path, ToolModule) -> @@ -171,10 +173,10 @@ compile_tests(Path, ToolModule) -> {ok,FileNames} = file:list_dir("."), BeamFiles = [F || F<-FileNames, filename:extension(F) == ".beam"], - [file:delete(F) || F<-BeamFiles], + _ = [file:delete(F) || F<-BeamFiles], ct:pal("Compiling in ~p:~n Deleted ~p~n MacroDefs=~p",[Path,BeamFiles,MacroDefs]), Result = make:all([load|MacroDefs]), - file:set_cwd(Cwd), + ok = file:set_cwd(Cwd), Result. diff --git a/lib/common_test/src/ct_release_test.erl b/lib/common_test/src/ct_release_test.erl index 4e0f88cf5f..d783f8d04e 100644 --- a/lib/common_test/src/ct_release_test.erl +++ b/lib/common_test/src/ct_release_test.erl @@ -342,7 +342,7 @@ cleanup(Config) -> end end, AllNodes), - [rpc:call(Node,erlang,halt,[]) || Node <- Nodes], + _ = [rpc:call(Node,erlang,halt,[]) || Node <- Nodes], Config. %%----------------------------------------------------------------- @@ -552,14 +552,14 @@ target_system(Apps,CreateDir,InstallDir,{FromVsn,_,AllAppsVsns,Path}) -> %% Add bin and log dirs BinDir = filename:join([InstallDir, "bin"]), - file:make_dir(BinDir), - file:make_dir(filename:join(InstallDir,"log")), + ok = make_dir(BinDir), + ok = make_dir(filename:join(InstallDir,"log")), %% Delete start scripts - they will be added later ErtsBinDir = filename:join([InstallDir, "erts-" ++ ErtsVsn, "bin"]), - file:delete(filename:join([ErtsBinDir, "erl"])), - file:delete(filename:join([ErtsBinDir, "start"])), - file:delete(filename:join([ErtsBinDir, "start_erl"])), + ok = delete_file(filename:join([ErtsBinDir, "erl"])), + ok = delete_file(filename:join([ErtsBinDir, "start"])), + ok = delete_file(filename:join([ErtsBinDir, "start_erl"])), %% Copy .boot to bin/start.boot copy_file(RelName++".boot",filename:join([BinDir, "start.boot"])), @@ -680,7 +680,7 @@ do_upgrade({Cb,InitState},FromVsn,FromAppsVsns,ToRel,ToAppsVsns,InstallDir) -> %% even if install_release returned {ok,...} there might be an %% emulator restart (instruction restart_emulator), so we must %% always make sure the node is running. - wait_node_up(current,ToVsn,ToAppsVsns), + {ok, _} = wait_node_up(current,ToVsn,ToAppsVsns), [{"OTP upgrade test",ToVsn,_,current}, {"OTP upgrade test",FromVsn,_,permanent}] = @@ -703,7 +703,7 @@ do_upgrade({Cb,InitState},FromVsn,FromAppsVsns,ToRel,ToAppsVsns,InstallDir) -> %% even if install_release returned {ok,...} there might be an %% emulator restart (instruction restart_emulator), so we must %% always make sure the node is running. - wait_node_up(current,FromVsn,FromAppsVsns), + {ok, _} = wait_node_up(current,FromVsn,FromAppsVsns), [{"OTP upgrade test",ToVsn,_,permanent}, {"OTP upgrade test",FromVsn,_,current}] = @@ -854,7 +854,7 @@ copy_file(Src, Dest, Opts) -> case lists:member(preserve, Opts) of true -> {ok, FileInfo} = file:read_file_info(Src), - file:write_file_info(Dest, FileInfo); + ok = file:write_file_info(Dest, FileInfo); false -> ok end. @@ -862,8 +862,8 @@ copy_file(Src, Dest, Opts) -> write_file(FName, Conts) -> Enc = file:native_name_encoding(), {ok, Fd} = file:open(FName, [write]), - file:write(Fd, unicode:characters_to_binary(Conts,Enc,Enc)), - file:close(Fd). + ok = file:write(Fd, unicode:characters_to_binary(Conts,Enc,Enc)), + ok = file:close(Fd). %% Substitute all occurrences of %Var% for Val in the given scripts subst_src_scripts(Scripts, SrcDir, DestDir, Vars, Opts) -> @@ -944,3 +944,19 @@ rm_rf(Dir) -> _ -> ok end. + +delete_file(FileName) -> + case file:delete(FileName) of + {error, enoent} -> + ok; + Else -> + Else + end. + +make_dir(Dir) -> + case file:make_dir(Dir) of + {error, eexist} -> + ok; + Else -> + Else + end. diff --git a/lib/common_test/src/ct_repeat.erl b/lib/common_test/src/ct_repeat.erl index 31c5755c7e..dac596a135 100644 --- a/lib/common_test/src/ct_repeat.erl +++ b/lib/common_test/src/ct_repeat.erl @@ -44,13 +44,13 @@ loop_test(If,Args) when is_list(Args) -> false; E = {error,_} -> io:format("Common Test error: ~p\n\n",[E]), - file:set_cwd(Cwd), + ok = file:set_cwd(Cwd), E; {repeat,N} -> io:format("\nCommon Test: Will repeat tests ~w times.\n\n",[N]), Args1 = [{loop_info,[{repeat,1,N}]} | Args], Result = loop(If,repeat,0,N,undefined,Args1,undefined,[]), - file:set_cwd(Cwd), + ok = file:set_cwd(Cwd), Result; {stop_time,StopTime} -> Result = @@ -76,7 +76,7 @@ loop_test(If,Args) when is_list(Args) -> Args1 = [{loop_info,[{stop_time,Secs,StopTime,1}]} | Args], loop(If,stop_time,0,Secs,StopTime,Args1,TPid,[]) end, - file:set_cwd(Cwd), + ok = file:set_cwd(Cwd), Result end. diff --git a/lib/common_test/src/ct_rpc.erl b/lib/common_test/src/ct_rpc.erl index cbcc212bb8..b4a0bc9d74 100644 --- a/lib/common_test/src/ct_rpc.erl +++ b/lib/common_test/src/ct_rpc.erl @@ -81,7 +81,7 @@ app_node(App, [], _, _) -> app_node(App, _Candidates = [CandidateNode | Nodes], FailOnBadRPC, Cookie) -> Cookie0 = set_the_cookie(Cookie), Result = rpc:call(CandidateNode, application, which_applications, []), - set_the_cookie(Cookie0), + _ = set_the_cookie(Cookie0), case Result of {badrpc,Reason} when FailOnBadRPC == true -> ct:fail({Reason,CandidateNode}); @@ -145,7 +145,7 @@ call({Fun, FunArgs}, Module, Function, Args, TimeOut, Cookie) -> call(Node, Module, Function, Args, TimeOut, Cookie) when is_atom(Node) -> Cookie0 = set_the_cookie(Cookie), Result = rpc:call(Node, Module, Function, Args, TimeOut), - set_the_cookie(Cookie0), + _ = set_the_cookie(Cookie0), Result. %%% @spec cast(Node, Module, Function, Args) -> ok @@ -190,7 +190,7 @@ cast({Fun, FunArgs}, Module, Function, Args, Cookie) -> cast(Node, Module, Function, Args, Cookie) when is_atom(Node) -> Cookie0 = set_the_cookie(Cookie), true = rpc:cast(Node, Module, Function, Args), - set_the_cookie(Cookie0), + _ = set_the_cookie(Cookie0), ok. diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index 1e5f935198..fbb9c7ab60 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -400,21 +400,21 @@ run_or_refresh(Opts = #opts{logdir = LogDir}, Args) -> [RefreshDir] -> ?abs(RefreshDir) end, {ok,Cwd} = file:get_cwd(), - file:set_cwd(LogDir1), + ok = file:set_cwd(LogDir1), %% give the shell time to print version etc timer:sleep(500), io:nl(), case catch ct_logs:make_all_runs_index(refresh) of {'EXIT',ARReason} -> - file:set_cwd(Cwd), + ok = file:set_cwd(Cwd), {error,{all_runs_index,ARReason}}; _ -> case catch ct_logs:make_all_suites_index(refresh) of {'EXIT',ASReason} -> - file:set_cwd(Cwd), + ok = file:set_cwd(Cwd), {error,{all_suites_index,ASReason}}; _ -> - file:set_cwd(Cwd), + ok = file:set_cwd(Cwd), io:format("Logs in ~ts refreshed!~n~n", [LogDir1]), timer:sleep(500), % time to flush io before quitting @@ -756,8 +756,8 @@ script_start4(#opts{label = Label, profile = Profile, {ct_hooks, CTHooks}, {enable_builtin_hooks,EnableBuiltinHooks}]) of ok -> - ct_util:start(interactive, LogDir, - add_verbosity_defaults(Verbosity)), + _ = ct_util:start(interactive, LogDir, + add_verbosity_defaults(Verbosity)), ct_util:set_testdata({logopts, LogOpts}), log_ts_names(Specs), io:nl(), @@ -901,9 +901,8 @@ install(Opts, LogDir) -> VarFile = variables_file_name(LogDir), case file:open(VarFile, [write]) of {ok,Fd} -> - [io:format(Fd, "~p.\n", [Opt]) || Opt <- ConfOpts ], - file:close(Fd), - ok; + _ = [io:format(Fd, "~p.\n", [Opt]) || Opt <- ConfOpts], + ok = file:close(Fd); {error,Reason} -> io:format("CT failed to install configuration data. Please " "verify that the log directory exists and that " @@ -960,7 +959,7 @@ run_test1(StartOpts) when is_list(StartOpts) -> false -> case catch run_test2(StartOpts) of {'EXIT',Reason} -> - file:set_cwd(Cwd), + ok = file:set_cwd(Cwd), {error,Reason}; Result -> Result @@ -971,7 +970,7 @@ run_test1(StartOpts) when is_list(StartOpts) -> stop_trace(Tracing), exit(Res); RefreshDir -> - refresh_logs(?abs(RefreshDir)), + ok = refresh_logs(?abs(RefreshDir)), exit(done) end. @@ -1209,7 +1208,6 @@ run_all_specs([], _, _, TotResult) -> end; run_all_specs([{Specs,TS} | TSs], Opts, StartOpts, TotResult) -> - log_ts_names(Specs), Combined = #opts{config = TSConfig} = combine_test_opts(TS, Specs, Opts), AllConfig = merge_vals([Opts#opts.config, TSConfig]), try run_one_spec(TS, @@ -1430,7 +1428,7 @@ run_testspec1(TestSpec) -> io:format("~nCommon Test starting (cwd is ~ts)~n~n", [Cwd]), case catch run_testspec2(TestSpec) of {'EXIT',Reason} -> - file:set_cwd(Cwd), + ok = file:set_cwd(Cwd), exit({error,Reason}); Result -> exit(Result) @@ -1562,15 +1560,15 @@ refresh_logs(LogDir) -> _ -> case catch ct_logs:make_all_suites_index(refresh) of {'EXIT',ASReason} -> - file:set_cwd(Cwd), + ok = file:set_cwd(Cwd), {error,{all_suites_index,ASReason}}; _ -> case catch ct_logs:make_all_runs_index(refresh) of {'EXIT',ARReason} -> - file:set_cwd(Cwd), + ok = file:set_cwd(Cwd), {error,{all_runs_index,ARReason}}; _ -> - file:set_cwd(Cwd), + ok = file:set_cwd(Cwd), io:format("Logs in ~ts refreshed!~n",[LogDir]), ok end @@ -1610,22 +1608,34 @@ delistify(E) -> E. %%% @hidden %%% @equiv ct:run/3 run(TestDir, Suite, Cases) -> - install([]), - reformat_result(catch do_run(tests(TestDir, Suite, Cases), [])). + case install([]) of + ok -> + reformat_result(catch do_run(tests(TestDir, Suite, Cases), [])); + Error -> + Error + end. %%%----------------------------------------------------------------- %%% @hidden %%% @equiv ct:run/2 run(TestDir, Suite) when is_list(TestDir), is_integer(hd(TestDir)) -> - install([]), - reformat_result(catch do_run(tests(TestDir, Suite), [])). + case install([]) of + ok -> + reformat_result(catch do_run(tests(TestDir, Suite), [])); + Error -> + Error + end. %%%----------------------------------------------------------------- %%% @hidden %%% @equiv ct:run/1 run(TestDirs) -> - install([]), - reformat_result(catch do_run(tests(TestDirs), [])). + case install([]) of + ok -> + reformat_result(catch do_run(tests(TestDirs), [])); + Error -> + Error + end. reformat_result({'EXIT',{user_error,Reason}}) -> {error,Reason}; @@ -2017,7 +2027,7 @@ save_make_errors(Errors) -> "Error compiling or locating the " "following suites: ~n~p",[Suites]), %% save the info for logger - file:write_file(?missing_suites_info,term_to_binary(Errors)), + ok = file:write_file(?missing_suites_info,term_to_binary(Errors)), Errors. get_bad_suites([{{_TestDir,_Suite},Failed}|Errors], BadSuites) -> @@ -2234,7 +2244,7 @@ do_run_test(Tests, Skip, Opts0) -> end, application:set_env(test_server, esc_chars, EscChars), - test_server_ctrl:start_link(local), + {ok, _} = test_server_ctrl:start_link(local), %% let test_server expand the test tuples and count no of cases {Suites,NoOfCases} = count_test_cases(Tests, Skip), @@ -2295,7 +2305,7 @@ do_run_test(Tests, Skip, Opts0) -> lists:foreach(fun(Suite) -> maybe_cleanup_interpret(Suite, Opts#opts.step) end, CleanUp), - [code:del_path(Dir) || Dir <- AddedToPath], + _ = [code:del_path(Dir) || Dir <- AddedToPath], %% If a severe error has occurred in the test_server, %% we will generate an exception here. @@ -2422,7 +2432,7 @@ count_test_cases(Tests, Skip) -> SendResult = fun(Me, Result) -> Me ! {no_of_cases,Result} end, TSPid = test_server_ctrl:start_get_totals(SendResult), Ref = erlang:monitor(process, TSPid), - add_jobs(Tests, Skip, #opts{}, []), + _ = add_jobs(Tests, Skip, #opts{}, []), Counted = (catch count_test_cases1(length(Tests), 0, [], Ref)), erlang:demonitor(Ref, [flush]), case Counted of @@ -2776,14 +2786,14 @@ maybe_interpret1(Suite, Cases, StepOpts) when is_list(Cases) -> maybe_interpret2(Suite, Cases, StepOpts) -> set_break_on_config(Suite, StepOpts), - [begin try i:ib(Suite, Case, 1) of + _ = [begin try i:ib(Suite, Case, 1) of _ -> ok catch _:_Error -> io:format(user, "Invalid breakpoint: ~w:~w/1~n", [Suite,Case]) end - end || Case <- Cases, is_atom(Case)], + end || Case <- Cases, is_atom(Case)], test_server_ctrl:multiply_timetraps(infinity), WinOp = case lists:member(keep_inactive, ensure_atom(StepOpts)) of true -> no_kill; @@ -2802,12 +2812,12 @@ set_break_on_config(Suite, StepOpts) -> false -> ok end end, - SetBPIfExists(init_per_suite, 1), - SetBPIfExists(init_per_group, 2), - SetBPIfExists(init_per_testcase, 2), - SetBPIfExists(end_per_testcase, 2), - SetBPIfExists(end_per_group, 2), - SetBPIfExists(end_per_suite, 1); + ok = SetBPIfExists(init_per_suite, 1), + ok = SetBPIfExists(init_per_group, 2), + ok = SetBPIfExists(init_per_testcase, 2), + ok = SetBPIfExists(end_per_testcase, 2), + ok = SetBPIfExists(end_per_group, 2), + ok = SetBPIfExists(end_per_suite, 1); false -> ok end. @@ -2984,31 +2994,31 @@ add_verbosity_defaults(VLvls) -> %% relative dirs "post run_test erl_args" is not kept! rel_to_abs(CtArgs) -> {PA,PZ} = get_pa_pz(CtArgs, [], []), - [begin + _ = [begin Dir = rm_trailing_slash(D), Abs = make_abs(Dir), - if Dir /= Abs -> - code:del_path(Dir), - code:del_path(Abs), + _ = if Dir /= Abs -> + _ = code:del_path(Dir), + _ = code:del_path(Abs), io:format(user, "Converting ~p to ~p and re-inserting " "with add_pathz/1~n", [Dir, Abs]); true -> - code:del_path(Dir) + _ = code:del_path(Dir) end, code:add_pathz(Abs) end || D <- PZ], - [begin + _ = [begin Dir = rm_trailing_slash(D), Abs = make_abs(Dir), - if Dir /= Abs -> - code:del_path(Dir), - code:del_path(Abs), + _ = if Dir /= Abs -> + _ = code:del_path(Dir), + _ = code:del_path(Abs), io:format(user, "Converting ~p to ~p and re-inserting " "with add_patha/1~n", [Dir, Abs]); true -> - code:del_path(Dir) + _ = code:del_path(Dir) end, code:add_patha(Abs) end || D <- PA], diff --git a/lib/common_test/src/ct_slave.erl b/lib/common_test/src/ct_slave.erl index 3ad3937548..571958ca03 100644 --- a/lib/common_test/src/ct_slave.erl +++ b/lib/common_test/src/ct_slave.erl @@ -325,7 +325,7 @@ do_start(Host, Node, Options) -> Functions end, MasterHost = gethostname(), - if + _ = if MasterHost == Host -> spawn_local_node(Node, Options); true-> @@ -359,7 +359,7 @@ do_start(Host, Node, Options) -> pang-> {error, boot_timeout, ENode} end, - case Result of + _ = case Result of {ok, ENode}-> ok; {error, Timeout, ENode} @@ -422,7 +422,7 @@ spawn_remote_node(Host, Node, Options) -> {_, _}-> [{user, Username}, {password, Password}] end ++ [{silently_accept_hosts, true}] ++ SSHOpts, - application:ensure_all_started(ssh), + {ok, _} = application:ensure_all_started(ssh), {ok, SSHConnRef} = ssh:connect(atom_to_list(Host), SSHPort, SSHOptions), {ok, SSHChannelId} = ssh_connection:session_channel(SSHConnRef, infinity), ssh_setenv(SSHConnRef, SSHChannelId, Env), diff --git a/lib/common_test/src/ct_snmp.erl b/lib/common_test/src/ct_snmp.erl index bb0167eb22..2c59b19196 100644 --- a/lib/common_test/src/ct_snmp.erl +++ b/lib/common_test/src/ct_snmp.erl @@ -221,9 +221,17 @@ start(Config, MgrAgentConfName, SnmpAppConfName) -> Config, SysName, AgentManagerIP, IP), setup_manager(StartManager, MgrAgentConfName, SnmpAppConfName, Config, AgentManagerIP), - application:start(snmp), + ok = start_application(snmp), manager_register(StartManager, MgrAgentConfName). + +start_application(App) -> + case application:start(App) of + {error, {already_started, App}} -> + ok; + Else -> + Else + end. %%% @spec stop(Config) -> ok %%% Config = [{Key, Value}] @@ -233,8 +241,8 @@ start(Config, MgrAgentConfName, SnmpAppConfName) -> %%% @doc Stops the snmp manager and/or agent removes all files created. stop(Config) -> PrivDir = ?config(priv_dir, Config), - application:stop(snmp), - application:stop(mnesia), + ok = application:stop(snmp), + ok = application:stop(mnesia), MgrDir = filename:join(PrivDir,"mgr"), ConfDir = filename:join(PrivDir, "conf"), DbDir = filename:join(PrivDir,"db"), @@ -311,7 +319,7 @@ set_info(Config) -> SetLogFile = filename:join(PrivDir, ?CT_SNMP_LOG_FILE), case file:consult(SetLogFile) of {ok, SetInfo} -> - file:delete(SetLogFile), + ok = delete_file(SetLogFile), lists:reverse(SetInfo); _ -> [] @@ -513,7 +521,7 @@ unload_mibs(Mibs) -> prepare_snmp_env() -> %% To make sure application:set_env is not overwritten by any %% app-file settings. - application:load(snmp), + _ = application:load(snmp), %% Fix for older versions of snmp where there are some %% inappropriate default values for alway starting an @@ -533,7 +541,7 @@ setup_manager(true, MgrConfName, SnmpConfName, Config, IP) -> Users = [], Agents = [], Usms = [], - file:make_dir(MgrDir), + ok = make_dir(MgrDir), snmp_config:write_manager_snmp_files(MgrDir, IP, Port, MaxMsgSize, EngineID, Users, Agents, Usms), @@ -549,7 +557,7 @@ setup_agent(false,_, _, _, _, _, _) -> ok; setup_agent(true, AgentConfName, SnmpConfName, Config, SysName, ManagerIP, AgentIP) -> - application:start(mnesia), + ok = start_application(mnesia), PrivDir = ?config(priv_dir, Config), Vsns = ct:get_config({AgentConfName, agent_vsns}, ?CONF_FILE_VER), TrapUdp = ct:get_config({AgentConfName, agent_trap_udp}, ?TRAP_UDP), @@ -565,8 +573,8 @@ setup_agent(true, AgentConfName, SnmpConfName, ConfDir = filename:join(PrivDir, "conf"), DbDir = filename:join(PrivDir,"db"), - file:make_dir(ConfDir), - file:make_dir(DbDir), + ok = make_dir(ConfDir), + ok = make_dir(DbDir), snmp_config:write_agent_snmp_files(ConfDir, Vsns, ManagerIP, TrapUdp, AgentIP, AgentUdp, SysName, NotifType, SecType, Passwd, @@ -684,7 +692,7 @@ log(PrivDir, Agent, {_, _, Varbinds}, NewVarsAndVals) -> File = filename:join(PrivDir, ?CT_SNMP_LOG_FILE), {ok, Fd} = file:open(File, [write, append]), io:format(Fd, "~p.~n", [{Agent, OldVarsAndVals, NewVarsAndVals}]), - file:close(Fd), + ok = file:close(Fd), ok. %%%--------------------------------------------------------------------------- del_dir(Dir) -> @@ -692,7 +700,7 @@ del_dir(Dir) -> FullPathFiles = lists:map(fun(File) -> filename:join(Dir, File) end, Files), lists:foreach(fun file:delete/1, FullPathFiles), - file:del_dir(Dir), + ok = delete_dir(Dir), ok. %%%--------------------------------------------------------------------------- agent_conf(Agent, MgrAgentConfName) -> @@ -738,8 +746,8 @@ override_contexts(Config, {data_dir_file, File}) -> override_contexts(Config, Contexts) -> Dir = filename:join(?config(priv_dir, Config),"conf"), File = filename:join(Dir,"context.conf"), - file:delete(File), - snmp_config:write_agent_context_config(Dir, "", Contexts). + ok = delete_file(File), + ok = snmp_config:write_agent_context_config(Dir, "", Contexts). %%%--------------------------------------------------------------------------- override_sysinfo(_, undefined) -> @@ -754,8 +762,8 @@ override_sysinfo(Config, {data_dir_file, File}) -> override_sysinfo(Config, SysInfo) -> Dir = filename:join(?config(priv_dir, Config),"conf"), File = filename:join(Dir,"standard.conf"), - file:delete(File), - snmp_config:write_agent_standard_config(Dir, "", SysInfo). + ok = delete_file(File), + ok = snmp_config:write_agent_standard_config(Dir, "", SysInfo). %%%--------------------------------------------------------------------------- override_target_address(_, undefined) -> @@ -769,8 +777,8 @@ override_target_address(Config, {data_dir_file, File}) -> override_target_address(Config, TargetAddressConf) -> Dir = filename:join(?config(priv_dir, Config),"conf"), File = filename:join(Dir,"target_addr.conf"), - file:delete(File), - snmp_config:write_agent_target_addr_config(Dir, "", TargetAddressConf). + ok = delete_file(File), + ok = snmp_config:write_agent_target_addr_config(Dir, "", TargetAddressConf). %%%--------------------------------------------------------------------------- @@ -785,8 +793,8 @@ override_target_params(Config, {data_dir_file, File}) -> override_target_params(Config, TargetParamsConf) -> Dir = filename:join(?config(priv_dir, Config),"conf"), File = filename:join(Dir,"target_params.conf"), - file:delete(File), - snmp_config:write_agent_target_params_config(Dir, "", TargetParamsConf). + ok = delete_file(File), + ok = snmp_config:write_agent_target_params_config(Dir, "", TargetParamsConf). %%%--------------------------------------------------------------------------- override_notify(_, undefined) -> @@ -800,8 +808,8 @@ override_notify(Config, {data_dir_file, File}) -> override_notify(Config, NotifyConf) -> Dir = filename:join(?config(priv_dir, Config),"conf"), File = filename:join(Dir,"notify.conf"), - file:delete(File), - snmp_config:write_agent_notify_config(Dir, "", NotifyConf). + ok = delete_file(File), + ok = snmp_config:write_agent_notify_config(Dir, "", NotifyConf). %%%--------------------------------------------------------------------------- override_usm(_, undefined) -> @@ -815,8 +823,8 @@ override_usm(Config, {data_dir_file, File}) -> override_usm(Config, UsmConf) -> Dir = filename:join(?config(priv_dir, Config),"conf"), File = filename:join(Dir,"usm.conf"), - file:delete(File), - snmp_config:write_agent_usm_config(Dir, "", UsmConf). + ok = delete_file(File), + ok = snmp_config:write_agent_usm_config(Dir, "", UsmConf). %%%-------------------------------------------------------------------------- override_community(_, undefined) -> @@ -830,8 +838,8 @@ override_community(Config, {data_dir_file, File}) -> override_community(Config, CommunityConf) -> Dir = filename:join(?config(priv_dir, Config),"conf"), File = filename:join(Dir,"community.conf"), - file:delete(File), - snmp_config:write_agent_community_config(Dir, "", CommunityConf). + ok = delete_file(File), + ok = snmp_config:write_agent_community_config(Dir, "", CommunityConf). %%%--------------------------------------------------------------------------- @@ -846,8 +854,8 @@ override_vacm(Config, {data_dir_file, File}) -> override_vacm(Config, VacmConf) -> Dir = filename:join(?config(priv_dir, Config),"conf"), File = filename:join(Dir,"vacm.conf"), - file:delete(File), - snmp_config:write_agent_vacm_config(Dir, "", VacmConf). + ok = delete_file(File), + ok = snmp_config:write_agent_vacm_config(Dir, "", VacmConf). %%%--------------------------------------------------------------------------- @@ -861,3 +869,21 @@ while_ok(Fun,[H|T]) -> end; while_ok(_Fun,[]) -> ok. + +delete_file(FileName) -> + case file:delete(FileName) of + {error, enoent} -> ok; + Else -> Else + end. + +make_dir(Dir) -> + case file:make_dir(Dir) of + {error, eexist} -> ok; + Else -> Else + end. + +delete_dir(Dir) -> + case file:del_dir(Dir) of + {error, enoent} -> ok; + Else -> Else + end. diff --git a/lib/common_test/src/ct_ssh.erl b/lib/common_test/src/ct_ssh.erl index 92d912052e..6ab3bf036c 100644 --- a/lib/common_test/src/ct_ssh.erl +++ b/lib/common_test/src/ct_ssh.erl @@ -962,8 +962,8 @@ init(KeyOrName, {ConnType,Addr,Port}, AllOpts) -> end, [], AllOpts1), FinalOptions = [{silently_accept_hosts,true}, {user_interaction,false} | Options], - crypto:start(), - ssh:start(), + _ = crypto:start(), + _ = ssh:start(), Result = case ConnType of ssh -> ssh:connect(Addr, Port, FinalOptions); diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl index f5f4f648f4..8fb411ec4f 100644 --- a/lib/common_test/src/ct_telnet.erl +++ b/lib/common_test/src/ct_telnet.erl @@ -605,7 +605,7 @@ init(Name,{Ip,Port,Type},{TargetMod,KeepAlive,Extra}) -> set_telnet_defaults(Settings,#state{}) end, %% Handle old user versions of TargetMod - code:ensure_loaded(TargetMod), + _ = code:ensure_loaded(TargetMod), try case erlang:function_exported(TargetMod,connect,7) of true -> @@ -688,7 +688,7 @@ handle_msg({cmd,Cmd,Opts},State) -> debug_cont_gen_log("Throwing Buffer:",[]), debug_log_lines(State#state.buffer), - case {State#state.type,State#state.prompt} of + _ = case {State#state.type,State#state.prompt} of {ts,_} -> silent_teln_expect(State#state.name, State#state.teln_pid, @@ -735,7 +735,7 @@ handle_msg({send,Cmd,Opts},State) -> debug_cont_gen_log("Throwing Buffer:",[]), debug_log_lines(State#state.buffer), - case {State#state.type,State#state.prompt} of + _ = case {State#state.type,State#state.prompt} of {ts,_} -> silent_teln_expect(State#state.name, State#state.teln_pid, diff --git a/lib/common_test/src/ct_telnet_client.erl b/lib/common_test/src/ct_telnet_client.erl index 1f1311776f..5df7e279ac 100644 --- a/lib/common_test/src/ct_telnet_client.erl +++ b/lib/common_test/src/ct_telnet_client.erl @@ -272,7 +272,7 @@ send(Data, Sock, ConnName) -> _:_ -> ok end end, - gen_tcp:send(Sock, Data), + ok = gen_tcp:send(Sock, Data), ok. %% [IAC,IAC] = buffer data value 255 @@ -284,7 +284,7 @@ check_msg(Sock, [?IAC | Cs], Acc) -> case get_cmd(Cs) of {Cmd,Cs1} -> cmd_dbg("Got",Cmd), - respond_cmd(Cmd, Sock), + ok = respond_cmd(Cmd, Sock), check_msg(Sock, Cs1, Acc); error -> Acc diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl index d5a8e3fbc0..82a8743cf0 100644 --- a/lib/common_test/src/ct_util.erl +++ b/lib/common_test/src/ct_util.erl @@ -131,14 +131,14 @@ do_start(Parent, Mode, LogDir, Verbosity) -> create_table(?suite_table,#suite_data.key), create_table(?verbosity_table,1), - [ets:insert(?verbosity_table,{Cat,Lvl}) || {Cat,Lvl} <- Verbosity], + _ = [ets:insert(?verbosity_table,{Cat,Lvl}) || {Cat,Lvl} <- Verbosity], {ok,StartDir} = file:get_cwd(), case file:set_cwd(LogDir) of ok -> ok; E -> exit(E) end, - DoExit = fun(Reason) -> file:set_cwd(StartDir), exit(Reason) end, + DoExit = fun(Reason) -> ok = file:set_cwd(StartDir), exit(Reason) end, Opts = case read_opts() of {ok,Opts1} -> Opts1; @@ -169,7 +169,7 @@ do_start(Parent, Mode, LogDir, Verbosity) -> end, %% add user event handlers - case lists:keysearch(event_handler,1,Opts) of + _ = case lists:keysearch(event_handler,1,Opts) of {value,{_,Handlers}} -> Add = fun({H,Args}) -> case catch gen_event:add_handler(?CT_EVMGR_REF,H,Args) of @@ -195,7 +195,7 @@ do_start(Parent, Mode, LogDir, Verbosity) -> data={StartTime, lists:flatten(TestLogDir)}}), %% Initialize ct_hooks - try ct_hooks:init(Opts) of + _ = try ct_hooks:init(Opts) of ok -> Parent ! {self(),started}; {fail,CTHReason} -> @@ -228,7 +228,8 @@ create_table(TableName,KeyPos) -> create_table(TableName,set,KeyPos). create_table(TableName,Type,KeyPos) -> catch ets:delete(TableName), - ets:new(TableName,[Type,named_table,public,{keypos,KeyPos}]). + _ = ets:new(TableName,[Type,named_table,public,{keypos,KeyPos}]), + ok. read_opts() -> case file:consult(ct_run:variables_file_name("./")) of @@ -473,7 +474,7 @@ loop(Mode,TestData,StartDir) -> ct_logs:close(Info, StartDir), ct_event:stop(), ct_config:stop(), - file:set_cwd(StartDir), + ok = file:set_cwd(StartDir), return(From, Info); {Ref, _Msg} when is_reference(Ref) -> %% This clause is used when doing cast operations. @@ -505,7 +506,7 @@ loop(Mode,TestData,StartDir) -> %% Let process crash in case of error, this shouldn't happen! io:format("\n\nct_util_server got EXIT " "from ~w: ~p\n\n", [Pid,Reason]), - file:set_cwd(StartDir), + ok = file:set_cwd(StartDir), exit(Reason) end end. @@ -1035,10 +1036,12 @@ call(Msg, Timeout) -> end. return({To,Ref},Result) -> - To ! {Ref, Result}. + To ! {Ref, Result}, + ok. cast(Msg) -> - ct_util_server ! {Msg, {ct_util_server, make_ref()}}. + ct_util_server ! {Msg, {ct_util_server, make_ref()}}, + ok. seconds(T) -> test_server:seconds(T). @@ -1074,7 +1077,7 @@ abs_name2([],Acc) -> open_url(iexplore, Args, URL) -> {ok,R} = win32reg:open([read]), ok = win32reg:change_key(R,"applications\\iexplore.exe\\shell\\open\\command"), - case win32reg:values(R) of + _ = case win32reg:values(R) of {ok, Paths} -> Path = proplists:get_value(default, Paths), [Cmd | _] = string:tokens(Path, "%"), diff --git a/lib/common_test/src/ct_webtool.erl b/lib/common_test/src/ct_webtool.erl index 6cbcd98cc3..87af442fd3 100644 --- a/lib/common_test/src/ct_webtool.erl +++ b/lib/common_test/src/ct_webtool.erl @@ -84,27 +84,27 @@ %% 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]), + {ok, _} = ttb:tracer(all,[{file,"webtool.trc"}]), % tracing all nodes + {ok, _} = 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 + _ = tp(F,MS), + {ok, _} = 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), + {ok, _} = 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), + {ok, _} = ttb:tpl(M,F,MS), tp(T,MS); tp([{F,A}|T],MS) -> % function/arity - ttb:tpl(?MODULE,F,A,MS), + {ok, _} = ttb:tpl(?MODULE,F,A,MS), tp(T,MS); tp([F|T],MS) -> % function - ttb:tpl(?MODULE,F,MS), + {ok, _} = ttb:tpl(?MODULE,F,MS), tp(T,MS); tp([],_MS) -> ok. @@ -112,10 +112,10 @@ 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]), + {ok, _} = ttb:tracer(all,[{file,"webtool_app.trc"},{handler,{fun out/4,true}}]), + {ok, _} = ttb:p(all,[call,timestamp]), MS = [{'_',[],[{return_trace},{message,{caller}}]}], - ttb:tp(Mod,MS), + {ok, _} = ttb:tp(Mod,MS), ok. out(_,{trace_ts,Pid,call,MFA={M,F,A},{W,_,_},TS},_,S) @@ -145,7 +145,7 @@ script_start([App]) -> script_start([App,DefaultBrowser]); script_start([App,Browser]) -> io:format("Starting webtool...\n"), - start(), + {ok, _} = start(), AvailableApps = get_applications(), {OSType,_} = os:type(), case lists:keysearch(App,1,AvailableApps) of @@ -159,14 +159,14 @@ script_start([App,Browser]) -> _ -> "http://localhost:" ++ PortStr ++ "/" ++ StartPage end, - case Browser of + _ = 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 = win32reg:change_key(R,Key), {ok,Val} = win32reg:value(R,"Path"), IExplore=filename:join(win32reg:expand(Val),"iexplore.exe"), os:cmd("\"" ++ IExplore ++ "\" " ++ Url); @@ -186,7 +186,7 @@ script_start([App,Browser]) -> {Port,{exit_status,_Error}} -> io:format(" not running, starting ~w...\n", [Browser]), - os:cmd(BStr ++ " " ++ Url), + _ = os:cmd(BStr ++ " " ++ Url), ok after ?SEND_URL_TIMEOUT -> io:format(" failed, starting ~w...\n",[Browser]), @@ -206,7 +206,7 @@ script_start([App,Browser]) -> usage() -> io:format("Starting webtool...\n"), - start(), + {ok, _} = start(), Apps = lists:map(fun({A,_}) -> A end,get_applications()), io:format( "\nUsage: start_webtool application [ browser ]\n" @@ -254,7 +254,12 @@ start(Path,Port) when is_integer(Port)-> start(Path,Data0)-> Data = Data0 ++ rest_of_standard_data(), - gen_server:start({local,ct_web_tool},ct_webtool,{Path,Data},[]). + case gen_server:start({local,ct_web_tool},ct_webtool,{Path,Data},[]) of + {error, {already_started, Pid}} -> + {ok, Pid}; + Else -> + Else + end. stop()-> gen_server:call(ct_web_tool,stoppit). diff --git a/lib/common_test/src/cth_conn_log.erl b/lib/common_test/src/cth_conn_log.erl index 0501c6ed1c..883da0da0a 100644 --- a/lib/common_test/src/cth_conn_log.erl +++ b/lib/common_test/src/cth_conn_log.erl @@ -170,7 +170,7 @@ post_end_per_testcase(TestCase,_Config,Return,CthState) -> end, case ct_util:update_testdata(?MODULE, Update) of deleted -> - [ct_util:delete_testdata({?MODULE,ConnMod}) || + _ = [ct_util:delete_testdata({?MODULE,ConnMod}) || {ConnMod,_} <- CthState], error_logger:delete_report_handler(ct_conn_log_h); {error,no_response} -> diff --git a/lib/common_test/src/erl2html2.erl b/lib/common_test/src/erl2html2.erl index a1e0bf3879..e819f345de 100644 --- a/lib/common_test/src/erl2html2.erl +++ b/lib/common_test/src/erl2html2.erl @@ -62,15 +62,15 @@ convert(File, Dest, InclPath, Header) -> {ok,SFd} -> case file:open(Dest,[write,raw]) of {ok,DFd} -> - file:write(DFd,[Header,"<pre>\n"]), + ok = file:write(DFd,[Header,"<pre>\n"]), _Lines = build_html(SFd,DFd,encoding(File),Functions), - file:write(DFd,["</pre>\n",footer(), + ok = file:write(DFd,["</pre>\n",footer(), "</body>\n</html>\n"]), %% {_, Time2} = statistics(runtime), %% io:format("Converted ~p lines in ~.2f Seconds.~n", %% [_Lines, Time2/1000]), - file:close(SFd), - file:close(DFd), + ok = file:close(SFd), + ok = file:close(DFd), ok; Error -> Error @@ -138,7 +138,7 @@ parse_non_preprocessed_file(File) -> case file:open(File, []) of {ok,Epp} -> Forms = parse_non_preprocessed_file(Epp, File, 1), - file:close(Epp), + ok = file:close(Epp), {ok,Forms}; Error = {error,_E} -> Error @@ -205,14 +205,14 @@ build_html(SFd,DFd,Encoding,FuncsAndCs) -> %% line of last expression in function found build_html(SFd,DFd,Enc,{ok,Str},LastL,FuncsAndCs,_IsFuncDef,{F,LastL}) -> LastLineLink = test_server_ctrl:uri_encode(F++"-last_expr",utf8), - file:write(DFd,["<a name=\"", - to_raw_list(LastLineLink,Enc),"\"/>"]), + ok = file:write(DFd,["<a name=\"", + to_raw_list(LastLineLink,Enc),"\"/>"]), build_html(SFd,DFd,Enc,{ok,Str},LastL,FuncsAndCs,true,undefined); %% function start line found build_html(SFd,DFd,Enc,{ok,Str},L0,[{F,A,L0,LastL}|FuncsAndCs], _IsFuncDef,_FAndLastL) -> FALink = test_server_ctrl:uri_encode(F++"-"++integer_to_list(A),utf8), - file:write(DFd,["<a name=\"",to_raw_list(FALink,Enc),"\"/>"]), + ok = file:write(DFd,["<a name=\"",to_raw_list(FALink,Enc),"\"/>"]), build_html(SFd,DFd,Enc,{ok,Str},L0,FuncsAndCs,true,{F,LastL}); build_html(SFd,DFd,Enc,{ok,Str},L,[{clause,L}|FuncsAndCs], _IsFuncDef,FAndLastL) -> @@ -220,7 +220,7 @@ build_html(SFd,DFd,Enc,{ok,Str},L,[{clause,L}|FuncsAndCs], build_html(SFd,DFd,Enc,{ok,Str},L,FuncsAndCs,IsFuncDef,FAndLastL) -> LStr = line_number(L), Str1 = line(Str,IsFuncDef), - file:write(DFd,[LStr,Str1]), + ok = file:write(DFd,[LStr,Str1]), build_html(SFd,DFd,Enc,file:read_line(SFd),L+1,FuncsAndCs,false,FAndLastL); build_html(_SFd,_DFd,_Enc,eof,L,_FuncsAndCs,_IsFuncDef,_FAndLastL) -> L. diff --git a/lib/common_test/src/test_server.erl b/lib/common_test/src/test_server.erl index 919526c5d7..924086f2bd 100644 --- a/lib/common_test/src/test_server.erl +++ b/lib/common_test/src/test_server.erl @@ -21,7 +21,7 @@ -define(DEFAULT_TIMETRAP_SECS, 60). %%% TEST_SERVER_CTRL INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --export([run_test_case_apply/1,init_target_info/0,init_purify/0]). +-export([run_test_case_apply/1,init_target_info/0]). -export([cover_compile/1,cover_analyse/2]). %%% TEST_SERVER_SUP INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -49,10 +49,6 @@ -export([break/1,break/2,break/3,continue/0,continue/1]). -%%% DEBUGGER INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --export([purify_new_leaks/0, purify_format/2, purify_new_fds_inuse/0, - purify_is_running/0]). - %%% PRIVATE EXPORTED %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -export([]). @@ -73,10 +69,6 @@ init_target_info() -> username=test_server_sup:get_username(), cookie=atom_to_list(erlang:get_cookie())}. -init_purify() -> - purify_new_leaks(). - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% cover_compile(#cover{app=App,incl=Include,excl=Exclude,cross=Cross}) -> %% {ok,#cover{mods=AnalyseModules}} | {error,Reason} @@ -100,7 +92,7 @@ cover_compile(CoverInfo=#cover{app=none,incl=Include,cross=Cross}) -> case length(CompileMods) of 0 -> io:fwrite("WARNING: No modules to cover compile!\n\n",[]), - cover:start(), % start cover server anyway + {ok, _} = start_cover(), % start cover server anyway {ok,CoverInfo#cover{mods=[]}}; N -> io:fwrite("Cover compiling ~w modules - " @@ -115,7 +107,7 @@ cover_compile(CoverInfo=#cover{app=App,excl=all,incl=Include,cross=Cross}) -> case length(CompileMods) of 0 -> io:fwrite("WARNING: No modules to cover compile!\n\n",[]), - cover:start(), % start cover server anyway + {ok, _} = start_cover(), % start cover server anyway {ok,CoverInfo#cover{mods=[]}}; N -> io:fwrite("Cover compiling '~w' (~w files) - " @@ -158,7 +150,7 @@ cover_compile(CoverInfo=#cover{app=App,excl=Exclude, case length(CompileMods) of 0 -> io:fwrite("WARNING: No modules to cover compile!\n\n",[]), - cover:start(), % start cover server anyway + {ok, _} = start_cover(), % start cover server anyway {ok,CoverInfo#cover{mods=[]}}; N -> io:fwrite("Cover compiling '~w' (~w files) - " @@ -175,11 +167,11 @@ module_names(Beams) -> do_cover_compile(Modules) -> - cover:start(), + {ok, _} = start_cover(), Sticky = prepare_cover_compile(Modules,[]), R = cover:compile_beam(Modules), - [warn_compile(Error) || Error <- R,element(1,Error)=/=ok], - [code:stick_mod(M) || M <- Sticky], + _ = [warn_compile(Error) || Error <- R,element(1,Error)=/=ok], + _ = [code:stick_mod(M) || M <- Sticky], ok. warn_compile({error,{Reason,Module}}) -> @@ -366,9 +358,7 @@ stick_all_sticky(Node,Sticky) -> %% compensate timetraps for runtime delays introduced by e.g. tools like %% cover. -run_test_case_apply({CaseNum,Mod,Func,Args,Name, - RunInit,TimetrapData}) -> - purify_format("Test case #~w ~w:~w/1", [CaseNum, Mod, Func]), +run_test_case_apply({Mod,Func,Args,Name,RunInit,TimetrapData}) -> case os:getenv("TS_RUN_VALGRIND") of false -> ok; @@ -380,7 +370,6 @@ run_test_case_apply({CaseNum,Mod,Func,Args,Name, Result = run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData), ProcAft = erlang:system_info(process_count), - purify_new_leaks(), DetFail = get(test_server_detected_fail), {Result,DetFail,ProcBef,ProcAft}. @@ -585,7 +574,8 @@ run_test_case_msgloop(#st{ref=Ref,pid=Pid,end_conf_pid=EndConfPid0}=St0) -> {user_timetrap,Pid,_TrapTime,StartTime,E={user_timetrap_error,_},_} -> case update_user_timetraps(Pid, StartTime) of proceed -> - self() ! {abort_current_testcase,E,Pid}; + self() ! {abort_current_testcase,E,Pid}, + ok; ignore -> ok end, @@ -600,7 +590,8 @@ run_test_case_msgloop(#st{ref=Ref,pid=Pid,end_conf_pid=EndConfPid0}=St0) -> true -> TrapTime end, - timetrap(TrapTime, TotalTime, Pid, Scale); + _ = timetrap(TrapTime, TotalTime, Pid, Scale), + ok; ignore -> ok end, @@ -724,7 +715,7 @@ do_call_end_conf(Starter,Mod,Func,Data,TCExitReason,Conf,TVal) -> Supervisor = self(), EndConfApply = fun() -> - timetrap(TVal), + _ = timetrap(TVal), %% We can't handle fails or skips here %% (neither input nor output). The error can %% be read from Conf though (tc_status). @@ -775,7 +766,8 @@ print_end_conf_result(Mod,Func,Conf,Cause,Error) -> " ~s!\n\tReason: ~ts\n", [Mod,Func,Conf,Cause,ErrorStr]) end, - group_leader() ! {printout,12,Str2Print}. + group_leader() ! {printout,12,Str2Print}, + ok. spawn_fw_call(Mod,IPTC={init_per_testcase,Func},CurrConf,Pid, @@ -1287,7 +1279,9 @@ user_callback({CBMod,CBFunc}, Mod, Func, InitOrEnd, Args) -> init_per_testcase(Mod, Func, Args) -> case code:is_loaded(Mod) of - false -> code:load_file(Mod); + false -> + _ = code:load_file(Mod), + ok; _ -> ok end, case erlang:function_exported(Mod, init_per_testcase, 2) of @@ -1355,7 +1349,8 @@ print_init_conf_result(Line,Cause,Reason) -> "\tLocation: ~ts\n\tReason: ~ts\n", [Cause,FormattedLoc,ReasonStr]) end, - group_leader() ! {printout,12,Str2Print}. + group_leader() ! {printout,12,Str2Print}, + ok. end_per_testcase(Mod, Func, Conf) -> @@ -1426,7 +1421,8 @@ print_end_tc_warning(EndFunc,Reason,Cause,Loc) -> "Reason: ~ts\nLine: ~ts\n", [EndFunc,Cause,ReasonStr,FormattedLoc]) end, - group_leader() ! {printout,12,Str2Print}. + group_leader() ! {printout,12,Str2Print}, + ok. get_loc() -> get(test_server_loc). @@ -1657,7 +1653,8 @@ messages_get() -> %% %% Make sure proceeding IO from FromPid won't get rejected permit_io(GroupLeader, FromPid) -> - GroupLeader ! {permit_io,FromPid}. + GroupLeader ! {permit_io,FromPid}, + ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% sleep(Time) -> ok @@ -1829,7 +1826,6 @@ timetrap_scale_factor() -> timetrap_scale_factor([ { 2, fun() -> has_lock_checking() end}, { 3, fun() -> has_superfluous_schedulers() end}, - { 5, fun() -> purify_is_running() end}, { 6, fun() -> is_debug() end}, {10, fun() -> is_cover() end} ]). @@ -2129,7 +2125,8 @@ timetrap_cancel_all(TCPid, SendToServer) -> ok; Timers -> [timetrap_cancel_one(Handle, false) || - {Handle,Pid,_} <- Timers, Pid == TCPid] + {Handle,Pid,_} <- Timers, Pid == TCPid], + ok end, case get(test_server_user_timetrap) of undefined -> @@ -2139,13 +2136,15 @@ timetrap_cancel_all(TCPid, SendToServer) -> {UserTTSup,_StartTime} -> remove_user_timetrap(UserTTSup), put(test_server_user_timetrap, - proplists:delete(TCPid, UserTTs)); + proplists:delete(TCPid, UserTTs)), + ok; undefined -> ok end end, if SendToServer == true -> - group_leader() ! {timetrap_cancel_all,TCPid,self()}; + group_leader() ! {timetrap_cancel_all,TCPid,self()}, + ok; true -> ok end, @@ -2560,10 +2559,11 @@ run_on_shielded_node(Fun, CArgs) when is_function(Fun), is_list(CArgs) -> -spec start_job_proxy_fun(_, _) -> fun(() -> no_return()). start_job_proxy_fun(Master, Fun) -> fun () -> - start_job_proxy(), + _ = start_job_proxy(), receive Ref -> - Master ! {Ref, Fun()} + Master ! {Ref, Fun()}, + ok end, receive after infinity -> infinity end end. @@ -2729,64 +2729,25 @@ is_commercial() -> _ -> true end. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% DEBUGGER INTERFACE %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% purify_is_running() -> false|true -%% -%% Tests if Purify is currently running. - -purify_is_running() -> - case catch erlang:system_info({error_checker, running}) of - {'EXIT', _} -> false; - Res -> Res - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% purify_new_leaks() -> false|BytesLeaked -%% BytesLeaked = integer() -%% -%% Checks for new memory leaks if Purify is active. -%% Returns the number of bytes leaked, or false if Purify -%% is not running. -purify_new_leaks() -> - case catch erlang:system_info({error_checker, memory}) of - {'EXIT', _} -> false; - Leaked when is_integer(Leaked) -> Leaked - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% purify_new_fds_inuse() -> false|FdsInuse -%% FdsInuse = integer() -%% -%% Checks for new file descriptors in use. -%% Returns the number of new file descriptors in use, or false -%% if Purify is not running. -purify_new_fds_inuse() -> - case catch erlang:system_info({error_checker, fd}) of - {'EXIT', _} -> false; - Inuse when is_integer(Inuse) -> Inuse - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% purify_format(Format, Args) -> ok -%% Format = string() -%% Args = lists() -%% -%% Outputs the formatted string to Purify's logfile,if Purify is active. -purify_format(Format, Args) -> - (catch erlang:system_info({error_checker, io_lib:format(Format, Args)})), - ok. - - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% Apply given function and reply to caller or proxy. %% do_sync_apply(Proxy, From, {M,F,A}) -> Result = apply(M, F, A), - if is_pid(Proxy) -> Proxy ! {sync_result_proxy,From,Result}; - true -> From ! {sync_result,Result} + if is_pid(Proxy) -> + Proxy ! {sync_result_proxy,From,Result}, + ok; + true -> + From ! {sync_result,Result}, + ok end. + +start_cover() -> + case cover:start() of + {error, {already_started, Pid}} -> + {ok, Pid}; + Else -> + Else + end. + diff --git a/lib/common_test/src/test_server_ctrl.erl b/lib/common_test/src/test_server_ctrl.erl index ff960c22a5..b52e4bef9b 100644 --- a/lib/common_test/src/test_server_ctrl.erl +++ b/lib/common_test/src/test_server_ctrl.erl @@ -294,7 +294,7 @@ start_link(_) -> start() -> case gen_server:start({local,?MODULE}, ?MODULE, [], []) of - {ok, Pid} -> + {error, {already_started, Pid}} -> {ok, Pid}; Other -> Other @@ -302,7 +302,7 @@ start() -> start_link() -> case gen_server:start_link({local,?MODULE}, ?MODULE, [], []) of - {ok, Pid} -> + {error, {already_started, Pid}} -> {ok, Pid}; Other -> Other @@ -512,7 +512,7 @@ init([]) -> TI = TI0#target_info{host=TargetHost, naming=naming(), master=TargetHost}, - ets:new(slave_tab, [named_table,set,public,{keypos,2}]), + _ = ets:new(slave_tab, [named_table,set,public,{keypos,2}]), set_hosts([TI#target_info.host]), {ok,State#state{target_info=TI}}. @@ -867,7 +867,7 @@ handle_call({create_priv_dir,Value}, _From, State) -> handle_call({testcase_callback,ModFunc}, _From, State) -> case ModFunc of {Mod,Func} -> - case code:is_loaded(Mod) of + _ = case code:is_loaded(Mod) of {file,_} -> ok; false -> @@ -1079,8 +1079,8 @@ terminate(_Reason, State) -> false -> ok; Sock -> test_server_node:stop_tracer_node(Sock) end, - kill_all_jobs(State#state.jobs), - test_server_node:kill_nodes(), + ok = kill_all_jobs(State#state.jobs), + _ = test_server_node:kill_nodes(), ok. kill_all_jobs([{_Name,JobPid}|Jobs]) -> @@ -1125,7 +1125,7 @@ spawn_tester(Mod, Func, Args, Dir, Name, Levels, RejectIoReqs, init_tester(Mod, Func, Args, Dir, Name, {_,_,MinLev}=Levels, RejectIoReqs, CreatePrivDir, TCCallback, ExtraTools) -> process_flag(trap_exit, true), - test_server_io:start_link(), + _ = test_server_io:start_link(), put(test_server_name, Name), put(test_server_dir, Dir), put(test_server_total_time, 0), @@ -1199,8 +1199,7 @@ init_tester(Mod, Func, Args, Dir, Name, {_,_,MinLev}=Levels, {UnexpectedIoName,UnexpectedIoFooter} = get(test_server_unexpected_footer), {ok,UnexpectedIoFd} = open_html_file(UnexpectedIoName, [append]), io:put_chars(UnexpectedIoFd, "\n</pre>\n"++UnexpectedIoFooter), - file:close(UnexpectedIoFd), - ok. + ok = file:close(UnexpectedIoFd). report_severe_error(Reason) -> test_server_sup:framework_call(report, [severe_error,Reason]). @@ -1927,7 +1926,7 @@ html_convert_modules([Mod|Mods]) -> Name = atom_to_list(Mod), DestFile = filename:join(DestDir, downcase(Name)++?src_listing_ext), - html_possibly_convert(SrcFile1, SrcFileInfo, DestFile), + _ = html_possibly_convert(SrcFile1, SrcFileInfo, DestFile), html_convert_modules(Mods) end; _Other -> @@ -2066,7 +2065,7 @@ add_init_and_end_per_suite([], LastMod, LastRef, FwMod) -> end. do_add_init_and_end_per_suite(LastMod, LastRef, Mod, FwMod) -> - case code:is_loaded(Mod) of + _ = case code:is_loaded(Mod) of false -> code:load_file(Mod); _ -> ok end, @@ -2140,7 +2139,6 @@ do_add_end_per_suite_and_skip(LastMod, LastRef, Mod, FwMod) -> %% Runs the specified tests, then displays/logs the summary. run_test_cases(TestSpec, Config, TimetrapData) -> - test_server:init_purify(), case lists:member(no_src, get(test_server_logopts)) of true -> ok; @@ -2323,7 +2321,7 @@ run_test_cases_loop([{SkipTag,{Type,Ref,Case,Comment},SkipMode}|Cases], Config, TimetrapData, Mode, Status) when ((SkipTag==auto_skip_case) or (SkipTag==skip_case)) and ((Type==conf) or (Type==make)) -> - file:set_cwd(filename:dirname(get(test_server_dir))), + ok = file:set_cwd(filename:dirname(get(test_server_dir))), CurrIOHandler = get(test_server_common_io_handler), ParentMode = tl(Mode), @@ -2339,7 +2337,7 @@ run_test_cases_loop([{SkipTag,{Type,Ref,Case,Comment},SkipMode}|Cases], false -> %% this is a skipped end conf for a top level parallel %% group, buffered io can be flushed - handle_test_case_io_and_status(), + _ = handle_test_case_io_and_status(), set_io_buffering(undefined), {Mod,Func} = skip_case(AutoOrUser, Ref, 0, Case, Comment, false, SkipMode), @@ -2351,7 +2349,7 @@ run_test_cases_loop([{SkipTag,{Type,Ref,Case,Comment},SkipMode}|Cases], _ -> %% this is a skipped end conf for a parallel group nested %% under a parallel group (io buffering is active) - wait_for_cases(Ref), + _ = wait_for_cases(Ref), {Mod,Func} = skip_case(AutoOrUser, Ref, 0, Case, Comment, true, SkipMode), ConfData = {Mod,{Func,get_name(SkipMode)},Comment}, @@ -2459,7 +2457,7 @@ run_test_cases_loop([{auto_skip_case,{Case,Comment},SkipMode}|Cases], run_test_cases_loop([{skip_case,{{Mod,all}=Case,Comment},SkipMode}|Cases], Config, TimetrapData, Mode, Status) -> - skip_case(user, undefined, 0, Case, Comment, false, SkipMode), + _ = skip_case(user, undefined, 0, Case, Comment, false, SkipMode), test_server_sup:framework_call(report, [tc_user_skip, {Mod,{all,get_name(SkipMode)}, Comment}]), @@ -2489,7 +2487,7 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0, %% collect results from the test case processes %% and calc total time OkSkipFail = handle_test_case_io_and_status(), - file:set_cwd(filename:dirname(get(test_server_dir))), + ok = file:set_cwd(filename:dirname(get(test_server_dir))), After = ?now, Before = get(test_server_parallel_start_time), Elapsed = timer:now_diff(After, Before)/1000000, @@ -3582,7 +3580,7 @@ handle_io_and_exit_loop([], [{undefined,CurrPid,CaseNum,Mod,Func}|Ps] = Cases, O handle_io_and_exit_loop(Refs, [{Ref,CurrPid,CaseNum,Mod,Func}|Ps] = Cases, Ok,Skip,Fail) -> receive {started,_,CurrPid,CaseNum,Mod,Func} -> - handle_io_and_exits(self(), CurrPid, CaseNum, Mod, Func, Cases), + _ = handle_io_and_exits(self(), CurrPid, CaseNum, Mod, Func, Cases), Refs1 = case Refs of [Ref|Rs] -> % must be end conf case for subgroup @@ -3658,7 +3656,7 @@ handle_io_and_exits(Main, CurrPid, CaseNum, Mod, Func, Cases) -> %% about the execution time and the return value of the test case function. run_test_case(Ref, Num, Mod, Func, Args, RunInit, TimetrapData) -> - file:set_cwd(filename:dirname(get(test_server_dir))), + ok = file:set_cwd(filename:dirname(get(test_server_dir))), run_test_case1(Ref, Num, Mod, Func, Args, RunInit, TimetrapData, [], self()). @@ -3668,7 +3666,7 @@ run_test_case(Ref, Num, Mod, Func, Args, skip_init, TimetrapData, Mode) -> TimetrapData, Mode, self()); run_test_case(Ref, Num, Mod, Func, Args, RunInit, TimetrapData, Mode) -> - file:set_cwd(filename:dirname(get(test_server_dir))), + ok = file:set_cwd(filename:dirname(get(test_server_dir))), Main = self(), case check_prop(parallel, Mode) of false -> @@ -3682,7 +3680,7 @@ run_test_case(Ref, Num, Mod, Func, Args, RunInit, TimetrapData, Mode) -> spawn_link( fun() -> process_flag(trap_exit, true), - [put(Key, Val) || {Key,Val} <- Dictionary], + _ = [put(Key, Val) || {Key,Val} <- Dictionary], set_io_buffering({tc,Main}), run_test_case1(Ref, Num, Mod, Func, Args, RunInit, TimetrapData, Mode, Main) @@ -3699,7 +3697,8 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, false -> ok; true -> test_server_io:start_transaction(), - Main ! {started,Ref,self(),Num,Mod,Func} + Main ! {started,Ref,self(),Num,Mod,Func}, + ok end, TSDir = get(test_server_dir), @@ -3774,7 +3773,7 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, %% run the test case {Result,DetectedFail,ProcsBefore,ProcsAfter} = - run_test_case_apply(Num, Mod, Func, [UpdatedArgs], GrName, + run_test_case_apply(Mod, Func, [UpdatedArgs], GrName, RunInit, TimetrapData), {Time,RetVal,Loc,Opts,Comment} = case Result of @@ -3906,7 +3905,8 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, true -> test_server_io:end_transaction(), Main ! {finished,Ref,self(),Num,Mod,Func, - ?mod_result(Status),{Time,RetVal,Opts}} + ?mod_result(Status),{Time,RetVal,Opts}}, + ok end, {Time,RetVal,Opts}. @@ -4329,7 +4329,7 @@ do_format_exception(Reason={Error,Stack}) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% run_test_case_apply(CaseNum, Mod, Func, Args, Name, RunInit, +%% run_test_case_apply(Mod, Func, Args, Name, RunInit, %% TimetrapData) -> %% {{Time,RetVal,Loc,Opts,Comment},DetectedFail,ProcessesBefore,ProcessesAfter} | %% {{died,Reason,unknown,Comment},DetectedFail,ProcessesBefore,ProcessesAfter} @@ -4343,9 +4343,9 @@ do_format_exception(Reason={Error,Stack}) -> %% ProcessesBefore = ProcessesAfter = integer() %% -run_test_case_apply(CaseNum, Mod, Func, Args, Name, RunInit, +run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) -> - test_server:run_test_case_apply({CaseNum,Mod,Func,Args,Name,RunInit, + test_server:run_test_case_apply({Mod,Func,Args,Name,RunInit, TimetrapData}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -5276,7 +5276,8 @@ check_cross([]) -> %% This per application analysis writes the file cover.html in the %% application's run.<timestamp> directory. stop_cover(#cover{}=CoverInfo, TestDir) -> - cover_analyse(CoverInfo, TestDir); + cover_analyse(CoverInfo, TestDir), + ok; stop_cover(_CoverInfo, _TestDir) -> %% Cover is probably controlled by the framework ok. @@ -5315,7 +5316,7 @@ cover_analyse(CoverInfo, TestDir) -> [?cross_coverlog_name]), io:fwrite(CoverLog, "<p>CoverFile: <code>~tp</code>\n", [CoverFile]), - write_cross_cover_info(TestDir,Cross), + ok = write_cross_cover_info(TestDir,Cross), case length(cover:imported_modules()) of Imps when Imps > 0 -> @@ -5329,7 +5330,7 @@ cover_analyse(CoverInfo, TestDir) -> io:fwrite(CoverLog, "<p>Excluded module(s): <code>~tp</code>\n", [Excluded]), Coverage = test_server:cover_analyse(TestDir, CoverInfo), - write_binary_file(filename:join(TestDir,?raw_coverlog_name), + ok = write_binary_file(filename:join(TestDir,?raw_coverlog_name), term_to_binary(Coverage)), case lists:filter(fun({_M,{_,_,_}}) -> false; @@ -5344,8 +5345,8 @@ cover_analyse(CoverInfo, TestDir) -> end, TotPercent = write_cover_result_table(CoverLog, Coverage), - write_binary_file(filename:join(TestDir, ?cover_total), - term_to_binary(TotPercent)). + ok = write_binary_file(filename:join(TestDir, ?cover_total), + term_to_binary(TotPercent)). %% Cover analysis - accumulated over multiple tests %% This can be executed on any node after all tests are finished. @@ -5395,7 +5396,7 @@ write_cross_cover_info(Dir,Cross) -> write_cross_cover_logs([{Tag,Coverage}|T],TagDirMods) -> case lists:keyfind(Tag,1,TagDirMods) of {_,Dir,Mods} when Mods=/=[] -> - write_binary_file(filename:join(Dir,?raw_cross_coverlog_name), + ok = write_binary_file(filename:join(Dir,?raw_cross_coverlog_name), term_to_binary(Coverage)), CoverLogName = filename:join(Dir,?cross_coverlog_name), {ok,CoverLog} = open_html_file(CoverLogName), diff --git a/lib/common_test/src/test_server_gl.erl b/lib/common_test/src/test_server_gl.erl index 333c8fc06e..7d6fe64b92 100644 --- a/lib/common_test/src/test_server_gl.erl +++ b/lib/common_test/src/test_server_gl.erl @@ -185,7 +185,7 @@ handle_info({capture,Cap0}, St) -> end, {noreply,St#st{capture=Cap}}; handle_info({io_request,From,ReplyAs,Req}=IoReq, St) -> - try io_req(Req, From, St) of + _ = try io_req(Req, From, St) of passthrough -> group_leader() ! IoReq; {EscapeHtml,Data} -> @@ -197,7 +197,8 @@ handle_info({io_request,From,ReplyAs,Req}=IoReq, St) -> #st{capture=none} -> ok; #st{capture=CapturePid} -> - CapturePid ! {captured,Data} + CapturePid ! {captured,Data}, + ok end, case EscapeHtml andalso St#st.escape_chars of true -> diff --git a/lib/common_test/src/test_server_io.erl b/lib/common_test/src/test_server_io.erl index 8c5c0aef35..3d5238052b 100644 --- a/lib/common_test/src/test_server_io.erl +++ b/lib/common_test/src/test_server_io.erl @@ -215,7 +215,7 @@ handle_call({set_fd,Tag,Fd}, _From, #st{fds=Fds0,tags=Tags0, true -> %% Fd ready, print anything buffered for associated Tag lists:filtermap(fun({T,From,Str}) when T == Tag -> - output(From, Tag, Str, St1), + _ = output(From, Tag, Str, St1), false; (_) -> true @@ -274,14 +274,15 @@ handle_call(reset_state, _From, #st{fds=Fds,tags=Tags,gls=Gls, end end, Tags), GlList = gb_sets:to_list(Gls), - [test_server_gl:stop(GL) || GL <- GlList], + _ = [test_server_gl:stop(GL) || GL <- GlList], timer:sleep(100), case lists:filter(fun(GlPid) -> is_process_alive(GlPid) end, GlList) of [] -> ok; _ -> timer:sleep(2000), - [exit(GL, kill) || GL <- GlList] + [exit(GL, kill) || GL <- GlList], + ok end, Empty = gb_trees:empty(), {ok,Shared} = test_server_gl:start_link(), @@ -304,7 +305,7 @@ handle_call({stop,FdTags}, From, #st{fds=Fds0,tags=Tags0, none -> {Fds,Tags}; {value,Fd} -> - file:close(Fd), + _ = file:close(Fd), {gb_trees:delete(Tag, Fds), lists:delete(Tag, Tags)} end @@ -333,7 +334,7 @@ handle_info({'EXIT',_Pid,Reason}, _St) -> handle_info(stop_group_leaders, #st{gls=Gls}=St) -> %% Stop the remaining group leaders. GlPids = gb_sets:to_list(Gls), - [test_server_gl:stop(GL) || GL <- GlPids], + _ = [test_server_gl:stop(GL) || GL <- GlPids], timer:sleep(100), Wait = case lists:filter(fun(GlPid) -> is_process_alive(GlPid) end, GlPids) of @@ -344,7 +345,7 @@ handle_info(stop_group_leaders, #st{gls=Gls}=St) -> {noreply,St}; handle_info(kill_group_leaders, #st{gls=Gls,stopping=From, pending_ops=Ops}=St) -> - [exit(GL, kill) || GL <- gb_sets:to_list(Gls)], + _ = [exit(GL, kill) || GL <- gb_sets:to_list(Gls)], if From /= undefined -> gen_server:reply(From, ok); true -> % reply has been sent already @@ -434,7 +435,7 @@ do_print_buffered(Q0, St) -> eot -> Q; {Tag,Str} -> - do_output(Tag, Str, undefined, St), + _ = do_output(Tag, Str, undefined, St), do_print_buffered(Q, St) end. @@ -448,5 +449,5 @@ gc(#st{gls=Gls0}) -> InUse = ordsets:from_list(InUse0), Gls = gb_sets:to_list(Gls0), NotUsed = ordsets:subtract(Gls, InUse), - [test_server_gl:stop(Pid) || Pid <- NotUsed], + _ = [test_server_gl:stop(Pid) || Pid <- NotUsed], ok. diff --git a/lib/common_test/src/test_server_node.erl b/lib/common_test/src/test_server_node.erl index c64399e485..0b406c54cc 100644 --- a/lib/common_test/src/test_server_node.erl +++ b/lib/common_test/src/test_server_node.erl @@ -198,9 +198,9 @@ trc_loop(Sock,Patterns,Type) -> gen_tcp:close(Sock) end. add_nodes(Nodes,Patterns,_Type) -> - ttb:tracer(Nodes,[{file,{local, test_server}}, - {handler, {{?MODULE,handle_debug},initial}}]), - ttb:p(all,[call,timestamp]), + {ok, _} = ttb:tracer(Nodes,[{file,{local, test_server}}, + {handler, {{?MODULE,handle_debug},initial}}]), + {ok, _} = ttb:p(all,[call,timestamp]), lists:foreach(fun({TP,M,F,A,Pat}) -> ttb:TP(M,F,A,Pat); ({CTP,M,F,A}) -> ttb:CTP(M,F,A) end, @@ -360,8 +360,8 @@ start_node_peer(SlaveName, OptList, From, TI) -> -spec wait_for_node_started_fun(_, _, _, _, _) -> fun(() -> no_return()). wait_for_node_started_fun(LSock, Tmo, Cleanup, TI, Self) -> fun() -> - wait_for_node_started(LSock,Tmo,undefined, - Cleanup,TI,Self), + {{ok, _}, _} = wait_for_node_started(LSock,Tmo,undefined, + Cleanup,TI,Self), receive after infinity -> ok end end. @@ -432,7 +432,7 @@ wait_for_node_started(LSock,Timeout,Client,Cleanup,TI,CtrlPid) -> client=Client}); false -> ok end, - gen_tcp:controlling_process(Sock,CtrlPid), + ok = gen_tcp:controlling_process(Sock,CtrlPid), test_server_ctrl:node_started(Nodename), {{ok,Nodename},W} end; diff --git a/lib/common_test/src/test_server_sup.erl b/lib/common_test/src/test_server_sup.erl index fa2bb33c2d..6922e01fcc 100644 --- a/lib/common_test/src/test_server_sup.erl +++ b/lib/common_test/src/test_server_sup.erl @@ -755,7 +755,7 @@ framework_call(FW,_Func,_Args,DefaultReturn) DefaultReturn; framework_call(Callback,Func,Args,DefaultReturn) -> Mod = list_to_atom(Callback), - case code:is_loaded(Mod) of + _ = case code:is_loaded(Mod) of false -> code:load_file(Mod); _ -> ok end, @@ -851,7 +851,8 @@ util_start() -> spawn_link(fun() -> register(?MODULE, self()), util_loop(#util_state{starter=Starter}) - end); + end), + ok; _Pid -> ok end. diff --git a/lib/common_test/src/vts.erl b/lib/common_test/src/vts.erl index e1c16fbda4..f1c5051164 100644 --- a/lib/common_test/src/vts.erl +++ b/lib/common_test/src/vts.erl @@ -64,7 +64,7 @@ %%%----------------------------------------------------------------- %%% User API start() -> - ct_webtool:start(), + {ok, _} = ct_webtool:start(), ct_webtool:start_tools([],"app=vts"). init_data(ConfigFiles,EvHandlers,LogDir,LogOpts,Tests) -> @@ -169,7 +169,7 @@ loop(State) -> NewState = State#state{config=Config,event_handler=EvHandlers, current_log_dir=LogDir, logopts=LogOpts,tests=Tests}, - ct_install(NewState), + _ = ct_install(NewState), return(From,ok), loop(NewState); {start_page,From} -> @@ -192,12 +192,12 @@ loop(State) -> loop(State); {{add_config_file,Input},From} -> {Return,State1} = add_config_file1(Input,State), - ct_install(State1), + _ = ct_install(State1), return(From,Return), loop(State1); {{remove_config_file,Input},From} -> {Return,State1} = remove_config_file1(Input,State), - ct_install(State1), + _ = ct_install(State1), return(From,Return), loop(State1); {run_frame,From} -> @@ -233,7 +233,7 @@ loop(State) -> return(From,result_summary_frame1(State)), loop(State); stop_reload_results -> - file:set_cwd(State#state.start_dir), + ok = file:set_cwd(State#state.start_dir), loop(State#state{reload_results=false}); {no_result_log_frame,From} -> return(From,no_result_log_frame1()), @@ -277,8 +277,8 @@ call(Msg) -> end. return({To,Ref},Result) -> - To ! {Ref, Result}. - + To ! {Ref, Result}, + ok. run_test1(State=#state{tests=Tests,current_log_dir=LogDir, logopts=LogOpts}) -> @@ -311,7 +311,6 @@ run_test1(State=#state{tests=Tests,current_log_dir=LogDir, ct_install(#state{config=Config,event_handler=EvHandlers, current_log_dir=LogDir}) -> ct_run:install([{config,Config},{event_handler,EvHandlers}],LogDir). - %%%----------------------------------------------------------------- %%% HTML start_page1() -> @@ -549,7 +548,7 @@ case_select(Dir,Suite,Case,N) -> end, case MakeResult of ok -> - code:add_pathz(Dir), + true = code:add_pathz(Dir), case catch apply(Suite,all,[]) of {'EXIT',Reason} -> io:format("\n~p\n",[Reason]), @@ -755,7 +754,7 @@ report1(tests_start,{TestName,_N},State) -> end, State#state{testruns=TestRuns}; report1(tests_done,{_Ok,_Fail,_Skip},State) -> - timer:send_after(5000, self(),stop_reload_results), + {ok, _} = timer:send_after(5000, self(),stop_reload_results), State#state{running=State#state.running-1,reload_results=true}; report1(tc_start,{_Suite,_Case},State) -> State; diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile index 1532b6c1f7..b1eddfedd7 100644 --- a/lib/common_test/test/Makefile +++ b/lib/common_test/test/Makefile @@ -69,7 +69,8 @@ MODULES= \ erl2html2_SUITE \ test_server_SUITE \ test_server_test_lib \ - ct_release_test_SUITE + ct_release_test_SUITE \ + ct_log_SUITE ERL_FILES= $(MODULES:%=%.erl) HRL_FILES= test_server_test_lib.hrl diff --git a/lib/common_test/test/ct_gen_conn_SUITE_data/conn_SUITE.erl b/lib/common_test/test/ct_gen_conn_SUITE_data/conn_SUITE.erl index 1404df6410..19eb1211fa 100644 --- a/lib/common_test/test/ct_gen_conn_SUITE_data/conn_SUITE.erl +++ b/lib/common_test/test/ct_gen_conn_SUITE_data/conn_SUITE.erl @@ -73,24 +73,28 @@ handles_to_multi_conn_pids(_Config) -> ConnPid3 = ct_gen_conn:get_conn_pid(Handle3), {true,true} = {is_process_alive(Handle3),is_process_alive(ConnPid3)}, + monitor_procs([Handle1,ConnPid1,Handle2,ConnPid2,Handle3,ConnPid3]), + ok = proto:close(Handle1), - ct:sleep(100), + ok = wait_procs_down([Handle1,ConnPid1]), {false,false} = {is_process_alive(Handle1),is_process_alive(ConnPid1)}, {true,true} = {is_process_alive(Handle2),is_process_alive(ConnPid2)}, ok = proto:kill_conn_proc(Handle2), - ct:sleep(100), + ok = wait_procs_down([ConnPid2]), {true,false} = {is_process_alive(Handle2),is_process_alive(ConnPid2)}, ConnPid2x = ct_gen_conn:get_conn_pid(Handle2), true = is_process_alive(ConnPid2x), + monitor_procs([ConnPid2x]), + ok = proto:close(Handle2), - ct:sleep(100), + ok = wait_procs_down([Handle2,ConnPid2x]), {false,false} = {is_process_alive(Handle2),is_process_alive(ConnPid2x)}, application:set_env(ct_test, reconnect, false), ok = proto:kill_conn_proc(Handle3), - ct:sleep(100), + ok = wait_procs_down([Handle3,ConnPid3]), {false,false} = {is_process_alive(Handle3),is_process_alive(ConnPid3)}, ok. @@ -116,24 +120,28 @@ handles_to_single_conn_pids(_Config) -> {undefined,Handle3,_,_}] = lists:sort(ct_util:get_connections(ConnPid)), ct:pal("CONNS = ~n~p", [Conns]), + monitor_procs([Handle1,Handle2,Handle3,ConnPid]), ok = proto:close(Handle1), - ct:sleep(100), + ok = wait_procs_down([Handle1]), {false,true} = {is_process_alive(Handle1),is_process_alive(ConnPid)}, ok = proto:kill_conn_proc(Handle2), - ct:sleep(100), + ok = wait_procs_down([ConnPid]), NewConnPid = ct_gen_conn:get_conn_pid(Handle2), NewConnPid = ct_gen_conn:get_conn_pid(Handle3), true = is_process_alive(Handle2), true = is_process_alive(Handle3), + false = is_process_alive(ConnPid), + + monitor_procs([NewConnPid]), ok = proto:close(Handle2), - ct:sleep(100), + ok = wait_procs_down([Handle2]), {false,true} = {is_process_alive(Handle2),is_process_alive(NewConnPid)}, application:set_env(ct_test, reconnect, false), ok = proto:kill_conn_proc(Handle3), - ct:sleep(100), + ok = wait_procs_down([Handle3,NewConnPid]), {false,false} = {is_process_alive(Handle3),is_process_alive(NewConnPid)}, ok. @@ -158,30 +166,37 @@ names_to_multi_conn_pids(_Config) -> Handle1 = proto:open(mconn1), + monitor_procs([Handle1,ConnPid1,Handle2,ConnPid2,Handle3,ConnPid3]), + ok = proto:close(mconn1), - ct:sleep(100), + ok = wait_procs_down([Handle1,ConnPid1]), {false,false} = {is_process_alive(Handle1),is_process_alive(ConnPid1)}, ok = proto:kill_conn_proc(Handle2), - ct:sleep(100), + ok = wait_procs_down([ConnPid2]), Handle2 = proto:open(mconn2), % should've been reconnected already {true,false} = {is_process_alive(Handle2),is_process_alive(ConnPid2)}, ConnPid2x = ct_gen_conn:get_conn_pid(Handle2), true = is_process_alive(ConnPid2x), + monitor_procs([ConnPid2x]), + ok = proto:close(mconn2), - ct:sleep(100), + ok = wait_procs_down([Handle2,ConnPid2x]), {false,false} = {is_process_alive(Handle2),is_process_alive(ConnPid2x)}, Handle2y = proto:open(mconn2), ConnPid2y = ct_gen_conn:get_conn_pid(Handle2y), {true,true} = {is_process_alive(Handle2y),is_process_alive(ConnPid2y)}, + + monitor_procs([Handle2y,ConnPid2y]), + ok = proto:close(mconn2), - ct:sleep(100), + ok = wait_procs_down([Handle2y,ConnPid2y]), {false,false} = {is_process_alive(Handle2y),is_process_alive(ConnPid2y)}, application:set_env(ct_test, reconnect, false), ok = proto:kill_conn_proc(Handle3), - ct:sleep(100), + ok = wait_procs_down([Handle3,ConnPid3]), {false,false} = {is_process_alive(Handle3),is_process_alive(ConnPid3)}, ok. @@ -211,16 +226,20 @@ names_to_single_conn_pids(_Config) -> {sconn3,Handle3,_,_}] = lists:sort(ct_util:get_connections(ConnPid)), ct:pal("CONNS on ~p = ~n~p", [ConnPid,Conns]), + monitor_procs([Handle1,Handle2,Handle3,ConnPid]), + ok = proto:close(sconn1), - ct:sleep(100), + ok = wait_procs_down([Handle1]), {false,true} = {is_process_alive(Handle1),is_process_alive(ConnPid)}, ok = proto:kill_conn_proc(Handle2), - ct:sleep(100), + ok = wait_procs_down([ConnPid]), {true,false} = {is_process_alive(Handle2),is_process_alive(ConnPid)}, Handle2 = proto:open(sconn2), % should've been reconnected already NewConnPid = ct_gen_conn:get_conn_pid(Handle2), true = is_process_alive(NewConnPid), + + monitor_procs([NewConnPid]), Conns1 = [{sconn2,Handle2,_,_}, {sconn3,Handle3,_,_}] = @@ -228,14 +247,29 @@ names_to_single_conn_pids(_Config) -> ct:pal("CONNS on ~p = ~n~p", [NewConnPid,Conns1]), ok = proto:close(sconn2), - ct:sleep(100), + ok = wait_procs_down([Handle2]), {false,true} = {is_process_alive(Handle2),is_process_alive(NewConnPid)}, application:set_env(ct_test, reconnect, false), ok = proto:kill_conn_proc(Handle3), - ct:sleep(100), + ok = wait_procs_down([Handle3,NewConnPid]), {false,false} = {is_process_alive(Handle3),is_process_alive(NewConnPid)}, ok. +%%%----------------------------------------------------------------- +monitor_procs(Pids) -> + [erlang:monitor(process,Pid) || Pid <- Pids], + ok. + +wait_procs_down([]) -> + ok; +wait_procs_down(Pids) -> + receive + {'DOWN',_,process,Pid,_} -> + wait_procs_down(lists:delete(Pid,Pids)) + after 2000 -> + timeout + end. + diff --git a/lib/common_test/test/ct_log_SUITE.erl b/lib/common_test/test/ct_log_SUITE.erl new file mode 100644 index 0000000000..9bdd44cbdf --- /dev/null +++ b/lib/common_test/test/ct_log_SUITE.erl @@ -0,0 +1,328 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2009-2016. 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. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%%%------------------------------------------------------------------- +%%% File: ct_log_SUITE +%%% +%%% Description: Test that ct:log, ct:pal and io:format print to +%%% the test case log file as expected, with or without special HTML +%%% characters being escaped. +%%% +%%%------------------------------------------------------------------- +-module(ct_log_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + +-define(eh, ct_test_support_eh). + +%%-------------------------------------------------------------------- +%% TEST SERVER CALLBACK FUNCTIONS +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_testcase(_TestCase, Config) -> + Config. + +end_per_testcase(_TestCase, _Config) -> + ok. + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [{group,print_and_verify}]. + +groups() -> + [{print_and_verify,[sequence],[print,verify]}]. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% TEST CASES +%%-------------------------------------------------------------------- + +%%%----------------------------------------------------------------- +%%% +print(Config) -> + TcLogFile = proplists:get_value(tc_logfile, Config), + Pid = self(), + String = atom_to_list(?MODULE), + + %% START mark + io:format("LOGGING START~n"), + + %% io:format + io:format("1. Printing nothing~n", []), + io:format("2. Printing a string: ~s~n", [String]), + io:format("3. Printing a string: ~p~n", [String]), + io:format("4. Printing a tuple: ~w~n", [{module,?MODULE}]), + io:format("5. Printing a pid: ~w~n", [Pid]), + io:format("6. Printing HTML: <pre>~s</pre>~n", [String]), + + %% --- API --- + %% pal(Format) -> + %% = ct:pal(default, 50, Format, []). + %% pal(X1, X2) -> ok + %% X1 = Category | Importance | Format + %% X2 = Format | FormatArgs + %% pal(X1, X2, X3) -> ok + %% X1 = Category | Importance + %% X2 = Importance | Format + %% X3 = Format | FormatArgs + %% pal(Category, Importance, Format, FormatArgs) -> ok + %% ------ + ct:pal("1. Printing nothing"), + ct:pal("2. Printing nothing", []), + ct:pal("3. Printing a string: ~s", [String]), + ct:pal("4. Printing a string: ~p", [String]), + ct:pal("5. Printing a tuple: ~w", [{module,?MODULE}]), + ct:pal("6. Printing a pid: ~w", [Pid]), + ct:pal("7. Printing HTML: <pre>~s</pre>", [String]), + ct:pal(ct_internal, "8. Printing with category"), + ct:pal(ct_internal, "9. Printing with ~s", ["category"]), + ct:pal(50, "10. Printing with importance"), + ct:pal(50, "11. Printing with ~s", ["importance"]), + ct:pal(ct_internal, 50, "12. Printing with ~s", ["category and importance"]), + + %% --- API --- + %% log(Format) -> ok + %% = ct:log(default, 50, Format, [], []). + %% log(X1, X2) -> ok + %% X1 = Category | Importance | Format + %% X2 = Format | FormatArgs + %% log(X1, X2, X3) -> ok + %% X1 = Category | Importance + %% X2 = Importance | Format + %% X3 = Format | FormatArgs | Opts + %% log(X1, X2, X3, X4) -> ok + %% X1 = Category | Importance + %% X2 = Importance | Format + %% X3 = Format | FormatArgs + %% X4 = FormatArgs | Opts + %% log(Category, Importance, Format, FormatArgs, Opts) -> ok + %% ------ + ct:log("1. Printing nothing"), + ct:log("2. Printing nothing", []), + ct:log("3. Printing a string: ~s", [String]), + ct:log("4. Printing a string: ~p", [String]), + ct:log("5. Printing a tuple: ~w", [{module,?MODULE}]), + ct:log("6. Printing a pid: ~w", [Pid]), + ct:log("7. Printing HTML: <pre>~s</pre>", [String]), + ct:log("8. Printing a pid escaped: ~w", [Pid], [esc_chars]), + ct:log("9. Printing a string escaped: ~p", [String], [esc_chars]), + ct:log("10. Printing HTML escaped: <pre>~s</pre>", [String], [esc_chars]), + ct:log("11. Printing a string, no css: ~s", [String], [no_css]), + ct:log("12. Printing a pid escaped, no css: ~w", [Pid], + [esc_chars, no_css]), + ct:log(ct_internal, "13. Printing with category"), + ct:log(ct_internal, "14. Printing with ~s", ["category"]), + ct:log(ct_internal, "15. Printing with ~s, no_css", ["category"], + [no_css]), + ct:log(50, "16. Printing with importance"), + ct:log(50, "17. Printing with ~s", ["importance"]), + ct:log(50, "18. Printing with ~s, no_css", ["importance"], [no_css]), + ct:log(ct_internal, 50, "19. Printing with category and importance"), + ct:log(ct_internal, 50, "20. Printing with ~s", ["category and importance"]), + ct:log(ct_internal, 50, "21. Printing a pid escaped with ~s, no_css: ~w", + ["category and importance",Pid], [esc_chars,no_css]), + + %% END mark + ct:log("LOGGING END", [], [no_css]), + {save_config,[{the_logfile,TcLogFile},{the_pid,Pid},{the_string,String}]}. + + +verify(Config) -> + {print,SavedCfg} = proplists:get_value(saved_config, Config), + TcLogFile = proplists:get_value(the_logfile, SavedCfg), + Pid = proplists:get_value(the_pid, SavedCfg), + StrPid = lists:flatten(io_lib:format("~p",[Pid])), + EscPid = "<" ++ string:substr(StrPid, 2, length(StrPid)-2) ++ ">", + String = proplists:get_value(the_string, SavedCfg), + ct:log("Read from prev testcase: ~p & ~p", [TcLogFile,Pid]), + {ok,Dev} = file:open(TcLogFile, [read]), + ok = read_until(Dev, "LOGGING START\n"), + + %% io:format + match_line(Dev, "1. Printing nothing", []), + read_nl(Dev), + match_line(Dev, "2. Printing a string: ~s", [String]), + read_nl(Dev), + match_line(Dev, "3. Printing a string: ~p", [String]), + read_nl(Dev), + match_line(Dev, "4. Printing a tuple: ~w", [{module,?MODULE}]), + read_nl(Dev), + match_line(Dev, "5. Printing a pid: ~s", [EscPid]), + read_nl(Dev), + match_line(Dev, "6. Printing HTML: <pre>~s</pre>", [String]), + read_nl(Dev), + %% ct:pal + read_header(Dev), + match_line(Dev, "1. Printing nothing", []), + read_footer(Dev), + read_header(Dev), + match_line(Dev, "2. Printing nothing", []), + read_footer(Dev), + read_header(Dev), + match_line(Dev, "3. Printing a string: ~s", [String]), + read_footer(Dev), + read_header(Dev), + match_line(Dev, "4. Printing a string: ~p", [String]), + read_footer(Dev), + read_header(Dev), + match_line(Dev, "5. Printing a tuple: ~w", [{module,?MODULE}]), + read_footer(Dev), + read_header(Dev), + match_line(Dev, "6. Printing a pid: ~s", [EscPid]), + read_footer(Dev), + read_header(Dev), + match_line(Dev, "7. Printing HTML: <pre>~s</pre>", [String]), + read_footer(Dev), + read_header(Dev, "\"ct_internal\""), + match_line(Dev, "8. Printing with category", []), + read_footer(Dev), + read_header(Dev, "\"ct_internal\""), + match_line(Dev, "9. Printing with ~s", ["category"]), + read_footer(Dev), + read_header(Dev), + match_line(Dev, "10. Printing with importance", []), + read_footer(Dev), + read_header(Dev), + match_line(Dev, "11. Printing with ~s", ["importance"]), + read_footer(Dev), + read_header(Dev, "\"ct_internal\""), + match_line(Dev, "12. Printing with ~s", ["category and importance"]), + read_footer(Dev), + %% ct:log + read_header(Dev), + match_line(Dev, "1. Printing nothing", []), + read_footer(Dev), + read_header(Dev), + match_line(Dev, "2. Printing nothing", []), + read_footer(Dev), + read_header(Dev), + match_line(Dev, "3. Printing a string: ~s", [String]), + read_footer(Dev), + read_header(Dev), + match_line(Dev, "4. Printing a string: ~p", [String]), + read_footer(Dev), + read_header(Dev), + match_line(Dev, "5. Printing a tuple: ~w", [{module,?MODULE}]), + read_footer(Dev), + read_header(Dev), + match_line(Dev, "6. Printing a pid: ~w", [Pid]), + read_footer(Dev), + read_header(Dev), + match_line(Dev, "7. Printing HTML: <pre>~s</pre>", [String]), + read_footer(Dev), + read_header(Dev), + match_line(Dev, "8. Printing a pid escaped: ~s", [EscPid]), + read_footer(Dev), + read_header(Dev), + match_line(Dev, "9. Printing a string escaped: ~p", [String]), + read_footer(Dev), + read_header(Dev), + match_line(Dev, "10. Printing HTML escaped: <pre>~s</pre>", + [String]), + read_footer(Dev), + match_line(Dev, "11. Printing a string, no css: ~s", [String]), + match_line(Dev, "12. Printing a pid escaped, no css: ~s", [EscPid]), + read_header(Dev, "\"ct_internal\""), + match_line(Dev, "13. Printing with category", []), + read_footer(Dev), + read_header(Dev, "\"ct_internal\""), + match_line(Dev, "14. Printing with ~s", ["category"]), + read_footer(Dev), + match_line(Dev, "15. Printing with ~s, no_css", ["category"]), + read_header(Dev), + match_line(Dev, "16. Printing with importance", []), + read_footer(Dev), + read_header(Dev), + match_line(Dev, "17. Printing with ~s", ["importance"]), + read_footer(Dev), + match_line(Dev, "18. Printing with ~s, no_css", ["importance"]), + read_header(Dev, "\"ct_internal\""), + match_line(Dev, "19. Printing with category and importance", []), + read_footer(Dev), + read_header(Dev, "\"ct_internal\""), + match_line(Dev, "20. Printing with ~s", ["category and importance"]), + read_footer(Dev), + match_line(Dev, "21. Printing a pid escaped with ~s, no_css: ~s", + ["category and importance",EscPid]), + + file:close(Dev), + ok. + +%%%----------------------------------------------------------------- +%%% HELP FUNCTIONS +%%%----------------------------------------------------------------- + +read_until(Dev, Pat) -> + case file:read_line(Dev) of + {ok,Pat} -> + file:read_line(Dev), % \n + ok; + eof -> + file:close(Dev), + {error,{not_found,Pat}}; + _ -> + read_until(Dev, Pat) + end. + +match_line(Dev, Format, Args) -> + Pat = lists:flatten(io_lib:format(Format, Args)), + Line = element(2, file:read_line(Dev)), + case re:run(Line, Pat) of + {match,_} -> + ok; + nomatch -> + ct:pal("ERROR! No match for ~p.\nLine = ~p", [Pat,Line]), + file:close(Dev), + ct:fail({mismatch,Pat,Line}) + end. + +read_header(Dev) -> + read_header(Dev, "\"default\""). + +read_header(Dev, Cat) -> + file:read_line(Dev), % \n + "</pre>\n" = element(2, file:read_line(Dev)), + {match,_} = + re:run(element(2, file:read_line(Dev)), "<div class="++Cat++"><pre><b>" + "\\*\\*\\* User \\d{4}-\\d{2}-\\d{2} " + "\\d{2}:\\d{2}:\\d{2}.\\d{1,} \\*\\*\\*</b>"). + +read_footer(Dev) -> + "</pre></div>\n" = element(2, file:read_line(Dev)), + "<pre>\n" = element(2, file:read_line(Dev)). + +read_nl(Dev) -> + file:read_line(Dev). + + diff --git a/lib/common_test/test/ct_netconfc_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE.erl index 03fbc17bd2..2919f01605 100644 --- a/lib/common_test/test/ct_netconfc_SUITE.erl +++ b/lib/common_test/test/ct_netconfc_SUITE.erl @@ -44,16 +44,28 @@ %% there will be clashes with logging processes etc). %%-------------------------------------------------------------------- init_per_suite(Config) -> - case application:load(crypto) of - {error,Reason} when Reason=/={already_loaded,crypto} -> - {skip, Reason}; - _ -> - case application:load(ssh) of - {error,Reason} when Reason=/={already_loaded,ssh} -> - {skip, Reason}; - _ -> - ct_test_support:init_per_suite(Config) - end + case check_crypto_and_ssh() of + ok -> + ct_test_support:init_per_suite(Config); + Skip -> + Skip + end. + +check_crypto_and_ssh() -> + (catch code:load_file(crypto)), + case code:is_loaded(crypto) of + {file,_} -> + case ssh:start() of + Ok when Ok==ok; Ok=={error,{already_started,ssh}} -> + ct:log("ssh started",[]), + ok; + Other -> + ct:log("could not start ssh: ~p",[Other]), + {skip, "SSH could not be started!"} + end; + Other -> + ct:log("could not load crypto: ~p",[Other]), + {skip, "crypto could not be loaded!"} end. end_per_suite(Config) -> 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 f34969683c..2aa6c4d354 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 @@ -124,8 +124,9 @@ end_per_testcase(_Case, _Config) -> ok. init_per_suite(Config) -> - case catch ssh:start() of - Ok when Ok==ok; Ok=={error,{already_started,ssh}} -> + (catch code:load_file(crypto)), + case {ssh:start(),code:is_loaded(crypto)} of + {Ok,{file,_}} when Ok==ok; Ok=={error,{already_started,ssh}} -> ct:log("ssh started",[]), SshDir = filename:join(filename:dirname(code:which(?MODULE)), "ssh_dir"), @@ -133,7 +134,7 @@ init_per_suite(Config) -> ct:log("netconf server started",[]), [{netconf_server,Server},{ssh_dir,SshDir}|Config]; Other -> - ct:log("could not start ssh: ~p",[Other]), + ct:log("could not start ssh or load crypto: ~p",[Other]), {skip, "SSH could not be started!"} end. @@ -360,7 +361,7 @@ get(Config) -> get_a_lot(Config) -> SshDir = ?config(ssh_dir,Config), {ok,Client} = open_success(SshDir), - Descr = lists:append(lists:duplicate(1000,"Description of myserver! ")), + Descr = lists:append(lists:duplicate(100,"Description of myserver! ")), Server = {server,[{xmlns,"myns"}],[{name,[],["myserver"]}, {description,[],[Descr]}]}, Data = lists:duplicate(100,Server), diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc_remote_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc_remote_SUITE.erl index 0a49cdabbb..a65275da43 100644 --- a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc_remote_SUITE.erl +++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc_remote_SUITE.erl @@ -62,14 +62,15 @@ stop_node(Case) -> init_per_suite(Config) -> - case ssh:start() of - Ok when Ok==ok; Ok=={error,{already_started,ssh}} -> + (catch code:load_file(crypto)), + case {ssh:start(),code:is_loaded(crypto)} of + {Ok,{file,_}} when Ok==ok; Ok=={error,{already_started,ssh}} -> ct:log("SSH started locally",[]), SshDir = filename:join(filename:dirname(code:which(?MODULE)), "ssh_dir"), [{ssh_dir,SshDir}|Config]; Other -> - ct:log("could not start ssh locally: ~p",[Other]), + ct:log("could not start ssh or load crypto locally: ~p",[Other]), {skip, "SSH could not be started locally!"} end. @@ -85,15 +86,15 @@ remote_crash(Config) -> {ok,Node} = ct_slave:start(nc_remote_crash), Pa = filename:dirname(code:which(?NS)), true = rpc:call(Node,code,add_patha,[Pa]), - - case rpc:call(Node,ssh,start,[]) of - Ok when Ok==ok; Ok=={error,{already_started,ssh}} -> + rpc:call(Node,code,load_file,[crypto]), + case {rpc:call(Node,ssh,start,[]),rpc:call(Node,code,is_loaded,[crypto])} of + {Ok,{file,_}} when Ok==ok; Ok=={error,{already_started,ssh}} -> ct:log("SSH started remote",[]), ns(Node,start,[?config(ssh_dir,Config)]), ct:log("netconf server started remote",[]), remote_crash(Node,Config); Other -> - ct:log("could not start ssh remote: ~p",[Other]), + ct:log("could not start ssh or load crypto remote: ~p",[Other]), {skip, "SSH could not be started remote!"} end. 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 9fb1fb6547..e62bc617fa 100644 --- a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl +++ b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl @@ -279,7 +279,7 @@ send({CM,Ch},Data) -> %%% Split into many small parts and send to client send_frag({CM,Ch},Data) -> - Sz = rand:uniform(2000), + Sz = rand:uniform(1000), case Data of <<Chunk:Sz/binary,Rest/binary>> -> ssh_connection:send(CM, Ch, Chunk), diff --git a/lib/common_test/test/ct_repeat_testrun_SUITE.erl b/lib/common_test/test/ct_repeat_testrun_SUITE.erl index 632597c214..f8b6a379f6 100644 --- a/lib/common_test/test/ct_repeat_testrun_SUITE.erl +++ b/lib/common_test/test/ct_repeat_testrun_SUITE.erl @@ -66,25 +66,47 @@ %% there will be clashes with logging processes etc). %%-------------------------------------------------------------------- init_per_suite(Config0) -> - Config = ct_test_support:init_per_suite(Config0), - DataDir = ?config(data_dir, Config), - Suite1 = filename:join([DataDir,"a_test","r1_SUITE"]), - Suite2 = filename:join([DataDir,"b_test","r2_SUITE"]), - Opts0 = ct_test_support:get_opts(Config), - Opts1 = Opts0 ++ [{suite,Suite1},{testcase,tc2},{label,timing1}], - Opts2 = Opts0 ++ [{suite,Suite2},{testcase,tc2},{label,timing2}], - - %% Make sure both suites are compiled - {1,0,{0,0}} = ct_test_support:run(ct,run_test,[Opts1],Config), - {1,0,{0,0}} = ct_test_support:run(ct,run_test,[Opts2],Config), - - %% Time the shortest testcase to use for offset - {_T0,{1,0,{0,0}}} = timer:tc(ct_test_support,run,[ct,run_test,[Opts1],Config]), - - %% -2 is to ensure we hit inside the target test case and not after -% T = round(T0/1000000)-2, - T=0, - [{offset,T}|Config]. + TTInfo = {_T,{_Scaled,ScaleVal}} = ct:get_timetrap_info(), + ct:pal("Timetrap info = ~w", [TTInfo]), + if ScaleVal > 1 -> + {skip,"Skip on systems running e.g. cover or debug!"}; + ScaleVal =< 1 -> + Config = ct_test_support:init_per_suite(Config0), + DataDir = ?config(data_dir, Config), + Suite1 = filename:join([DataDir,"a_test","r1_SUITE"]), + Suite2 = filename:join([DataDir,"b_test","r2_SUITE"]), + Opts0 = ct_test_support:get_opts(Config), + Opts1 = Opts0 ++ [{suite,Suite1},{testcase,tc2},{label,timing1}], + Opts2 = Opts0 ++ [{suite,Suite2},{testcase,tc2},{label,timing2}], + + %% Make sure both suites are compiled + {1,0,{0,0}} = ct_test_support:run(ct,run_test,[Opts1],Config), + {1,0,{0,0}} = ct_test_support:run(ct,run_test,[Opts2],Config), + + %% Check if file i/o is too slow for correct measurements + Opts3 = Opts0 ++ [{suite,Suite1},{testcase,tc1},{label,timing3}], + {T,_} = + timer:tc( + fun() -> + {1,0,{0,0}} = ct_test_support:run(ct,run_test, + [Opts3],Config), + {1,0,{0,0}} = ct_test_support:run(ct,run_test, + [Opts3],Config) + end), + %% The time to compare with here must match the timeout value + %% in the test suite. Accept 30% logging overhead (26 sec total). + if T > 26000000 -> + ct:pal("Timing test took ~w sec (< 27 sec expected). " + "Skipping the suite!", + [trunc(T/1000000)]), + ct_test_support:end_per_suite(Config), + {skip,"File I/O too slow for this suite"}; + true -> + ct:pal("Timing test took ~w sec. Proceeding...", + [trunc(T/1000000)]), + [{offset,0}|Config] + end + end. end_per_suite(Config) -> ct_test_support:end_per_suite(Config). diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl index 477fcb8a26..e926abd885 100644 --- a/lib/common_test/test/ct_test_support.erl +++ b/lib/common_test/test/ct_test_support.erl @@ -484,7 +484,8 @@ get_events(_, Config) -> {event_receiver,CTNode} ! {self(),get_events}, Events = receive {event_receiver,Evs} -> Evs end, test_server:format(Level, "Stopping event receiver!~n", []), - {event_receiver,CTNode} ! stop, + {event_receiver,CTNode} ! {self(),stop}, + receive {event_receiver,stopped} -> ok end, Events. er() -> @@ -499,8 +500,9 @@ er_loop(Evs) -> {From,get_events} -> From ! {event_receiver,lists:reverse(Evs)}, er_loop(Evs); - stop -> + {From,stop} -> unregister(event_receiver), + From ! {event_receiver,stopped}, ok end. diff --git a/lib/common_test/test/telnet_server.erl b/lib/common_test/test/telnet_server.erl index 2c33cb268a..65300b0bdf 100644 --- a/lib/common_test/test/telnet_server.erl +++ b/lib/common_test/test/telnet_server.erl @@ -117,38 +117,64 @@ init_client(#state{client=Sock}=State) -> dbg("Server sending: ~p~n",["login: "]), R = case gen_tcp:send(Sock,"login: ") of ok -> - loop(State, 1); + loop(State); Error -> Error end, _ = gen_tcp:close(Sock), R. -loop(State, N) -> +loop(State=#state{client=Sock}) -> receive - {tcp,_,Data} -> + {tcp,Sock,Data} -> try handle_data(Data,State) of {ok,State1} -> - loop(State1, N); + loop(State1); closed -> + _ = flush(State), closed catch throw:Error -> + _ = flush(State), Error end; - {tcp_closed, _} -> + {tcp_closed,Sock} -> closed; - {tcp_error,_,Error} -> + {tcp_error,Sock,Error} -> {error,tcp,Error}; disconnect -> - Sock = State#state.client, dbg("Server closing connection on socket ~p~n", [Sock]), + timer:sleep(1000), ok = gen_tcp:close(Sock), - closed; + _ = flush(State); stop -> + _ = flush(State), stopped end. +flush(State=#state{client=Sock}) -> + receive + {tcp,Sock,Data} = M-> + dbg("Message flushed after close or error: ~p~n", [M]), + try handle_data(Data,State) of + {ok,State1} -> + flush(State1); + closed -> + flush(State) + catch + throw:Error -> + Error + end; + {tcp_closed,Sock} = M -> + dbg("Message flushed after close or error: ~p~n", [M]), + ok; + {tcp_error,Sock,Error} = M -> + dbg("Message flushed after close or error: ~p~n", [M]), + {error,tcp,Error} + after 100 -> + ok + end. + handle_data(Cmd,#state{break=true}=State) -> dbg("Server got data when in break mode: ~p~n",[Cmd]), handle_break_cmd(Cmd,State); diff --git a/lib/debugger/src/dbg_debugged.erl b/lib/debugger/src/dbg_debugged.erl index 5b1469a10e..e142af4ae0 100644 --- a/lib/debugger/src/dbg_debugged.erl +++ b/lib/debugger/src/dbg_debugged.erl @@ -70,7 +70,10 @@ msg_loop(Meta, Mref, SaveStacktrace) -> %% Meta is evaluating a receive, must be done within context %% of real (=this) process {sys, Meta, {'receive',Msg}} -> - receive Msg -> Meta ! {self(), rec_acked} end, + receive Msg -> + Meta ! {self(), rec_acked}, + ok + end, msg_loop(Meta, Mref, SaveStacktrace); %% Meta needs something evaluated within context of real process diff --git a/lib/debugger/src/dbg_icmd.erl b/lib/debugger/src/dbg_icmd.erl index 1b274e20ae..57a3719a50 100644 --- a/lib/debugger/src/dbg_icmd.erl +++ b/lib/debugger/src/dbg_icmd.erl @@ -171,10 +171,10 @@ handle_cmd(Bs, Status, Ieval) -> %% User control of process execution and settings %%==================================================================== -step(Meta) -> Meta ! {user, {cmd, step}}. -next(Meta) -> Meta ! {user, {cmd, next}}. -continue(Meta) -> Meta ! {user, {cmd, continue}}. -finish(Meta) -> Meta ! {user, {cmd, finish}}. +step(Meta) -> Meta ! {user, {cmd, step}}, ok. +next(Meta) -> Meta ! {user, {cmd, next}}, ok. +continue(Meta) -> Meta ! {user, {cmd, continue}}, ok. +finish(Meta) -> Meta ! {user, {cmd, finish}}, ok. skip(Meta) -> Meta ! {user, {cmd, skip}}. timeout(Meta) -> Meta ! {user, timeout}. diff --git a/lib/debugger/src/dbg_iserver.erl b/lib/debugger/src/dbg_iserver.erl index 0ad303d8d9..3561454685 100644 --- a/lib/debugger/src/dbg_iserver.erl +++ b/lib/debugger/src/dbg_iserver.erl @@ -72,17 +72,17 @@ cast(Int, Request) -> gen_server:cast(Int, Request). safe_call(Request) -> - ensure_started(), + {ok, _} = ensure_started(), call(Request). safe_cast(Request) -> - ensure_started(), + {ok, _} = ensure_started(), cast(Request). ensure_started() -> case whereis(?MODULE) of undefined -> start(); - _Pid -> ignore + Pid -> {ok, Pid} end. %%--Module database--------------------------------------------------- @@ -402,8 +402,10 @@ handle_cast({set_status, Meta, Status, Info}, State) -> send_all(subscriber, {new_status, Proc#proc.pid, Status, Info}, State), if Status =:= break -> - auto_attach(break, State#state.auto, Proc); - true -> ignore + _ = auto_attach(break, State#state.auto, Proc), + ok; + true -> + ok end, Proc2 = Proc#proc{status=Status, info=Info}, {noreply, State#state{procs=lists:keyreplace(Meta, #proc.meta, @@ -470,7 +472,7 @@ handle_info({'EXIT',Who,Why}, State) -> [self(),AttPid,Pid,Why,ExitInfo]); undefined -> %% Otherwise, auto attach if necessary - auto_attach(exit, State#state.auto, Pid), + _ = auto_attach(exit, State#state.auto, Pid), Who end, send_all(subscriber, {new_status,Pid,exit,Why}, State), @@ -583,7 +585,8 @@ send_all(Pids, Msg) -> lists:foreach(fun(Pid) -> send(Pid, Msg) end, Pids). send(Pid, Msg) -> - Pid ! {int, Msg}. + Pid ! {int, Msg}, + ok. get_proc({Type, Pid}, Procs) -> Index = case Type of diff --git a/lib/debugger/src/dbg_wx_break_win.erl b/lib/debugger/src/dbg_wx_break_win.erl index cd1e81456f..770681510d 100644 --- a/lib/debugger/src/dbg_wx_break_win.erl +++ b/lib/debugger/src/dbg_wx_break_win.erl @@ -65,18 +65,18 @@ create_win(Parent, Pos, function, Mod, _Line) -> {choices, IntStrs}]), Expand = [{border, 5}, {flag,?wxLEFT bor ?wxRIGHT bor ?wxEXPAND}], - wxSizer:add(MainS, Label, [{border,5}, + _ = wxSizer:add(MainS, Label, [{border,5}, {flag,?wxTOP bor ?wxLEFT bor ?wxRIGHT}]), - wxSizer:add(MainS, Text, Expand), + _ = wxSizer:add(MainS, Text, Expand), FunLabel = wxStaticText:new(Win, ?wxID_ANY, "Function:"), LB = wxListBox:new(Win, ?wxID_ANY, [{size,{-1, 100}},{style,?wxLB_MULTIPLE}]), - wxSizer:add(MainS, FunLabel, Expand), - wxSizer:add(MainS, LB, [{proportion,1}|Expand]), + _ = wxSizer:add(MainS, FunLabel, Expand), + _ = wxSizer:add(MainS, LB, [{proportion,1}|Expand]), wxSizer:setMinSize(MainS, 300, 400), OK = wxDialog:createStdDialogButtonSizer(Win, ?wxOK bor ?wxCANCEL), - wxSizer:add(MainS, OK, [{border,5},{flag,?wxALL}]), + _ = wxSizer:add(MainS, OK, [{border,5},{flag,?wxALL}]), wxDialog:setSizer(Win,MainS), - wxSizer:fit(MainS, Win), + _ = wxSizer:fit(MainS, Win), wxSizer:setSizeHints(MainS,Win), wxComboBox:setFocus(Text), wxDialog:connect(Win, command_button_clicked), @@ -110,11 +110,11 @@ create_win(Parent, Pos, Type, Mod, Line) -> IntStrs = [atom_to_list(M) || M <- Int], ModT = wxComboBox:new(Win, ?wxID_ANY, [{choices,IntStrs}]), ModSz = create_label_of_control(Win, "Module:", ModT, Mod), - wxSizer:add(MainS,ModSz,[{flag, ?wxEXPAND}]), + _ = wxSizer:add(MainS,ModSz,[{flag, ?wxEXPAND}]), %% Create rest of text input fields Add = fun({IType, Label, Def}) -> {Sz, Text} = create_sizer_with_text(Win, Label, Def), - wxSizer:add(MainS, Sz, [{flag, ?wxEXPAND}]), + _ = wxSizer:add(MainS, Sz, [{flag, ?wxEXPAND}]), {Text, IType} end, Inputs = case Type of @@ -129,15 +129,15 @@ create_win(Parent, Pos, Type, Mod, Line) -> Entries = wx:map(Add, Inputs), %% Create and add radio box {TriggerBox,Trigger} = create_trigger_box(Win), - wxSizer:add(MainS, TriggerBox, [{border,5},{flag,?wxALL bor ?wxEXPAND}]), + _ = wxSizer:add(MainS, TriggerBox, [{border,5},{flag,?wxALL bor ?wxEXPAND}]), - wxSizer:addStretchSpacer(MainS), + _ = wxSizer:addStretchSpacer(MainS), %% Put it together OK = wxDialog:createStdDialogButtonSizer(Win, ?wxOK bor ?wxCANCEL), - wxSizer:add(MainS, OK, [{border,5},{flag,?wxALL}]), + _ = wxSizer:add(MainS, OK, [{border,5},{flag,?wxALL}]), wxSizer:setMinSize(MainS, 300, -1), wxDialog:setSizer(Win,MainS), - wxSizer:fit(MainS, Win), + _ = wxSizer:fit(MainS, Win), wxSizer:setSizeHints(MainS,Win), wxComboBox:setFocus(ModT), wxDialog:connect(Win, command_button_clicked), @@ -243,8 +243,8 @@ create_label_of_control(Parent, Label, Control, Def) -> Text = wxStaticText:new(Parent, ?wxID_ANY, Label), Border = {border, 5}, Flag = ?wxRIGHT bor ?wxLEFT bor ?wxALIGN_CENTRE_VERTICAL, - wxSizer:add(Sizer, Text, [{proportion,1}, {flag,Flag}, Border]), - wxSizer:add(Sizer, Control, [{proportion,3}, {flag,Flag bor ?wxEXPAND}, Border]), + _ = wxSizer:add(Sizer, Text, [{proportion,1}, {flag,Flag}, Border]), + _ = wxSizer:add(Sizer, Control, [{proportion,3}, {flag,Flag bor ?wxEXPAND}, Border]), wxControl:setLabel(Control, dbg_wx_win:to_string(Def)), Sizer. @@ -252,11 +252,11 @@ create_trigger_box(Win) -> SBox = wxStaticBox:new(Win, ?wxID_ANY, "Trigger Action:"), SBS = wxStaticBoxSizer:new(SBox, ?wxVERTICAL), Ebtn = wxRadioButton:new(Win, ?wxID_ANY, "Enable"), - wxSizer:add(SBS,Ebtn), + _ = wxSizer:add(SBS,Ebtn), Dibtn = wxRadioButton:new(Win, ?wxID_ANY, "Disable"), - wxSizer:add(SBS,Dibtn), + _ = wxSizer:add(SBS,Dibtn), Debtn = wxRadioButton:new(Win, ?wxID_ANY, "Delete"), - wxSizer:add(SBS,Debtn), + _ = wxSizer:add(SBS,Debtn), wxRadioButton:setValue(Ebtn, true), {SBS, [{Ebtn,enable},{Dibtn,disable},{Debtn,delete}]}. diff --git a/lib/debugger/src/dbg_wx_code.erl b/lib/debugger/src/dbg_wx_code.erl index f8fc331a81..473963500a 100644 --- a/lib/debugger/src/dbg_wx_code.erl +++ b/lib/debugger/src/dbg_wx_code.erl @@ -127,20 +127,22 @@ load_code(Ed, Code) -> %%io:format("~p ~p ~p~n", [Lines, Sz, LW]), ?stc:setMarginWidth(Ed, 0, LW+5), ?stc:setReadOnly(Ed, true), - Ed. + ok. unload_code(Ed) -> ?stc:setReadOnly(Ed, false), ?stc:setTextRaw(Ed, <<0:8>>), ?stc:setReadOnly(Ed, true), - Ed. + ok. add_break_to_code(Ed, Line, active) -> ?stc:markerDelete(Ed, Line-1, 1), - ?stc:markerAdd(Ed, Line-1, 0); + ?stc:markerAdd(Ed, Line-1, 0), + ok; add_break_to_code(Ed, Line, inactive) -> ?stc:markerDelete(Ed, Line-1, 0), - ?stc:markerAdd(Ed, Line-1, 1). + ?stc:markerAdd(Ed, Line-1, 1), + ok. del_break_from_code(Ed,Line) -> ?stc:markerDelete(Ed, Line-1, 0), diff --git a/lib/debugger/src/dbg_wx_filedialog_win.erl b/lib/debugger/src/dbg_wx_filedialog_win.erl index 2103536a04..f7b031dc28 100644 --- a/lib/debugger/src/dbg_wx_filedialog_win.erl +++ b/lib/debugger/src/dbg_wx_filedialog_win.erl @@ -118,9 +118,9 @@ init([Parent, Id, Options0]) -> wxTextCtrl:connect(Dir, char, [{callback, IsTab}]), Top = wxBoxSizer:new(?wxHORIZONTAL), - wxSizer:add(Top, Back, [{border, 2},{flag,?wxALL bor ?wxEXPAND}]), - wxSizer:add(Top, Forw, [{border, 2},{flag,?wxALL bor ?wxEXPAND}]), - wxSizer:add(Top, Up, [{border, 2},{flag,?wxALL bor ?wxEXPAND}]), + _ = wxSizer:add(Top, Back, [{border, 2},{flag,?wxALL bor ?wxEXPAND}]), + _ = wxSizer:add(Top, Forw, [{border, 2},{flag,?wxALL bor ?wxEXPAND}]), + _ = wxSizer:add(Top, Up, [{border, 2},{flag,?wxALL bor ?wxEXPAND}]), %% List Ctrl {Art, IconMap} = create_icons(ExtraIcons), @@ -154,13 +154,13 @@ init([Parent, Id, Options0]) -> %% OK done Box = wxBoxSizer:new(?wxVERTICAL), - wxSizer:add(Box, Top, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]), - wxSizer:add(Box, Dir, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]), - wxSizer:add(Box, LC, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}, {proportion, 1}]), - wxSizer:add(Box, Bott, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]), + _ = wxSizer:add(Box, Top, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]), + _ = wxSizer:add(Box, Dir, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]), + _ = wxSizer:add(Box, LC, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}, {proportion, 1}]), + _ = wxSizer:add(Box, Bott, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]), wxWindow:setSizer(Dlg, Box), - wxSizer:fit(Box, Dlg), + _ = wxSizer:fit(Box, Dlg), wxSizer:setSizeHints(Box,Dlg), State = #state{win=Dlg, back=Back, forward=Forw, up=Up, diff --git a/lib/debugger/src/dbg_wx_mon.erl b/lib/debugger/src/dbg_wx_mon.erl index 345367a911..a32a6894b8 100644 --- a/lib/debugger/src/dbg_wx_mon.erl +++ b/lib/debugger/src/dbg_wx_mon.erl @@ -135,7 +135,7 @@ init2(CallingPid, Mode, SFile, GS) -> %% Start other necessary stuff dbg_wx_win:init(), - dbg_wx_winman:start(), % Debugger window manager + _ = dbg_wx_winman:start(), % Debugger window manager %% Create monitor window Title = "Monitor", @@ -339,7 +339,7 @@ gui_cmd('Delete All Modules', State) -> lists:foreach(fun(Mod) -> int:nn(Mod) end, int:interpreted()), State; gui_cmd({module, Mod, What}, State) -> - case What of + _ = case What of delete -> int:nn(Mod); view -> Window = dbg_wx_mon_win:get_window(State#state.win), diff --git a/lib/debugger/src/dbg_wx_mon_win.erl b/lib/debugger/src/dbg_wx_mon_win.erl index 2e48210f55..9737c9e67f 100644 --- a/lib/debugger/src/dbg_wx_mon_win.erl +++ b/lib/debugger/src/dbg_wx_mon_win.erl @@ -107,31 +107,31 @@ create_win_batch(Title, Menus) -> Hlb = 200, Listbox = wxListBox:new(Panel, ?wxID_ANY, [{size,{?Wf,Hlb}}, {style,?wxLB_SINGLE}]), - wxSizer:add(LeftSz,Listbox,[{proportion,1},{border,3},{flag,?wxEXPAND}]), + _ = wxSizer:add(LeftSz,Listbox,[{proportion,1},{border,3},{flag,?wxEXPAND}]), wxListBox:connect(Listbox, command_listbox_doubleclicked), wxListBox:connect(Listbox, right_down), SBox = wxStaticBox:new(Panel, ?wxID_ANY, "Auto Attach:"), SBS = wxStaticBoxSizer:new(SBox, ?wxVERTICAL), Fbtn = wxCheckBox:new(Panel, ?autoId, "First Call"), - wxSizer:add(SBS,Fbtn), + _ = wxSizer:add(SBS,Fbtn), Bbtn = wxCheckBox:new(Panel, ?autoId, "On Break"), - wxSizer:add(SBS,Bbtn), + _ = wxSizer:add(SBS,Bbtn), Ebtn = wxCheckBox:new(Panel, ?autoId, "On Exit"), - wxSizer:add(SBS,Ebtn), + _ = wxSizer:add(SBS,Ebtn), wxFrame:connect(Panel, command_checkbox_clicked), - wxSizer:add(LeftSz,SBS, [{flag,?wxEXPAND}]), + _ = wxSizer:add(LeftSz,SBS, [{flag,?wxEXPAND}]), SLabel = wxStaticText:new(Panel, ?wxID_ANY, "Stack Trace:\n On (with tail)"), - wxSizer:add(LeftSz,SLabel), + _ = wxSizer:add(LeftSz,SLabel), BLabel = wxStaticText:new(Panel, ?wxID_ANY, "Back Trace Size:\n 50000"), - wxSizer:add(LeftSz,BLabel), + _ = wxSizer:add(LeftSz,BLabel), StringsBox = wxStaticBox:new(Panel, ?wxID_ANY, "Strings:"), StringsBS = wxStaticBoxSizer:new(StringsBox, ?wxVERTICAL), Stringsbtn = wxCheckBox:new(Panel, ?stringsId, ?STRTEXT), - wxSizer:add(StringsBS,Stringsbtn), - wxSizer:add(LeftSz,StringsBS, [{flag,?wxEXPAND}]), + _ = wxSizer:add(StringsBS,Stringsbtn), + _ = wxSizer:add(LeftSz,StringsBS, [{flag,?wxEXPAND}]), %% Create list_crtl / grid Grid = wxListCtrl:new(Panel, [{winid, ?GRID}, @@ -169,12 +169,12 @@ create_win_batch(Title, Menus) -> wxWindow:setFocus(Grid), %% Put it in the window - wxSizer:add(MainSz, LeftSz, [{border, 3}, {flag,?wxALL bor ?wxEXPAND}]), - wxSizer:add(MainSz, Grid, [{border, 3}, {flag,?wxALL bor ?wxEXPAND}, + _ = wxSizer:add(MainSz, LeftSz, [{border, 3}, {flag,?wxALL bor ?wxEXPAND}]), + _ = wxSizer:add(MainSz, Grid, [{border, 3}, {flag,?wxALL bor ?wxEXPAND}, {proportion, 1}]), wxWindow:setSizer(Panel,MainSz), - wxSizer:fit(MainSz, Win), + _ = wxSizer:fit(MainSz, Win), wxSizer:setSizeHints(MainSz,Win), IconFile = dbg_wx_win:find_icon("erlang_bug.png"), diff --git a/lib/debugger/src/dbg_wx_src_view.erl b/lib/debugger/src/dbg_wx_src_view.erl index 571c6b01bb..207c407fbc 100644 --- a/lib/debugger/src/dbg_wx_src_view.erl +++ b/lib/debugger/src/dbg_wx_src_view.erl @@ -56,7 +56,7 @@ code_area(Parent, Sizer) -> end, [SetStyle(Style) || Style <- Styles], ?stc:setKeyWords(Ed, 0, keyWords()), - wxSizer:add(Sizer, Ed, [{proportion,1}, {flag, ?wxEXPAND}]), + _ = wxSizer:add(Sizer, Ed, [{proportion,1}, {flag, ?wxEXPAND}]), Ed. diff --git a/lib/debugger/src/dbg_wx_trace.erl b/lib/debugger/src/dbg_wx_trace.erl index f9c60f9b72..6af19af33b 100644 --- a/lib/debugger/src/dbg_wx_trace.erl +++ b/lib/debugger/src/dbg_wx_trace.erl @@ -321,7 +321,7 @@ gui_cmd('Kill', State) -> exit(State#state.pid, kill), State; gui_cmd('Messages', State) -> - case int:meta(State#state.meta, messages) of + _ = case int:meta(State#state.meta, messages) of [] -> dbg_wx_trace_win:eval_output(State#state.win,"< No Messages!\n", bold); Messages -> diff --git a/lib/debugger/src/dbg_wx_trace_win.erl b/lib/debugger/src/dbg_wx_trace_win.erl index 51687ad4e9..972a917728 100644 --- a/lib/debugger/src/dbg_wx_trace_win.erl +++ b/lib/debugger/src/dbg_wx_trace_win.erl @@ -123,7 +123,8 @@ %% GS = term() %%-------------------------------------------------------------------- init() -> - dbg_wx_win:init(). + _ = dbg_wx_win:init(), + ok. stop(#winInfo{window=Win}) -> (catch wxFrame:destroy(Win)), @@ -149,29 +150,29 @@ create_win(Parent, Title, Windows, Menus) -> Sizer = wxBoxSizer:new(?wxVERTICAL), Code = code_area(Panel), - wxSizer:add(Sizer, Code#sub.win, + _ = wxSizer:add(Sizer, Code#sub.win, [{proportion,1}, {border, 2}, {flag, ?wxEXPAND bor ?wxDOWN}]), wxSizer:setVirtualSizeHints(Sizer, Code#sub.win), ExpandWithBorder = [{border, 3},{flag,?wxEXPAND bor ?wxALL}], Search = search_area(Panel), - wxSizer:add(Sizer, Search#sub.win, ExpandWithBorder), + _ = wxSizer:add(Sizer, Search#sub.win, ExpandWithBorder), Bs = button_area(Panel), - wxSizer:add(Sizer, Bs#sub.win, ExpandWithBorder), + _ = wxSizer:add(Sizer, Bs#sub.win, ExpandWithBorder), InfoArea = wxBoxSizer:new(?wxHORIZONTAL), wxSizer:setMinSize(InfoArea, {100, ?EVAL_H}), Eval = eval_area(Panel), - wxSizer:add(InfoArea, Eval#sub.win, [{proportion,1},{flag,?wxEXPAND}]), + _ = wxSizer:add(InfoArea, Eval#sub.win, [{proportion,1},{flag,?wxEXPAND}]), Bind = bind_area(Panel), - wxSizer:add(InfoArea, Bind#sub.win, + _ = wxSizer:add(InfoArea, Bind#sub.win, [{proportion,1},{border, 2}, {flag,?wxEXPAND bor ?wxLEFT}]), - wxSizer:add(Sizer, InfoArea, ExpandWithBorder), + _ = wxSizer:add(Sizer, InfoArea, ExpandWithBorder), Trace = trace_area(Panel), - wxSizer:add(Sizer, Trace#sub.win, ExpandWithBorder), + _ = wxSizer:add(Sizer, Trace#sub.win, ExpandWithBorder), SB = wxFrame:createStatusBar(Win,[]), %% Note id and lastId to get the event when it dragged is complete @@ -192,7 +193,7 @@ create_win(Parent, Title, Windows, Menus) -> Wi = show_windows(enable_windows(Wi0,Windows)), wxWindow:setSizer(Panel, Sizer), - wxSizer:fit(Sizer, Win), + _ = wxSizer:fit(Sizer, Win), wxSizer:setSizeHints(Sizer,Win), IconFile = dbg_wx_win:find_icon("erlang_bug.png"), @@ -230,11 +231,11 @@ get_window(WinInfo) -> %%-------------------------------------------------------------------- configure(Wi=#winInfo{window=Win,m_szr={Panel,Sizer}}) -> wx:batch(fun() -> - show_windows(Wi), + _ = show_windows(Wi), wxSizer:layout(Sizer), %%wxWindow:setSizerAndFit(Panel,Sizer), wxWindow:setSizer(Panel, Sizer), - wxSizer:fit(Sizer, Win), + _ = wxSizer:fit(Sizer, Win), wxSizer:setSizeHints(Sizer,Win), Wi end). @@ -242,10 +243,10 @@ configure(Wi=#winInfo{window=Win,m_szr={Panel,Sizer}}) -> configure(Wi0=#winInfo{window=Win,m_szr={Panel,Sizer}}, Windows) -> wx:batch(fun() -> Wi = enable_windows(Wi0, Windows), - show_windows(Wi), + _ = show_windows(Wi), wxSizer:layout(Sizer), wxWindow:setSizer(Panel, Sizer), - wxSizer:fit(Sizer, Win), + _ = wxSizer:fit(Sizer, Win), wxSizer:setSizeHints(Sizer,Win), Wi end). @@ -348,7 +349,7 @@ add_break(WinInfo, Menu, {{Mod,Line},[Status|_Options]}=Break) -> case WinInfo#winInfo.editor of {Mod, Editor} -> dbg_wx_code:add_break_to_code(Editor, Line, Status); - _ -> ignore + _ -> ok end, add_break_to_menu(WinInfo, Menu, Break). @@ -372,7 +373,7 @@ update_break(WinInfo, {{Mod,Line},[Status|_Options]}=Break) -> case WinInfo#winInfo.editor of {Mod, Editor} -> dbg_wx_code:add_break_to_code(Editor, Line, Status); - _ -> ignore + _ -> ok end, update_break_in_menu(WinInfo, Break). @@ -929,7 +930,7 @@ button_area(Parent) -> B=wxButton:new(Parent, Button, [{label,dbg_wx_win:to_string(Name)}]), Id = wxWindow:getId(B), - wxSizer:add(Sz,B, []), + _ = wxSizer:add(Sz,B, []), wxButton:connect(B, command_button_clicked, [{id,Id}]) end, buttons()), #sub{name='Button Area', win=Sz}. @@ -938,22 +939,22 @@ button_area(Parent) -> search_area(Parent) -> HSz = wxBoxSizer:new(?wxHORIZONTAL), - wxSizer:add(HSz, wxStaticText:new(Parent, ?wxID_ANY, "Find:"), + _ = wxSizer:add(HSz, wxStaticText:new(Parent, ?wxID_ANY, "Find:"), [{flag,?wxALIGN_CENTER_VERTICAL}]), TC1 = wxTextCtrl:new(Parent, ?SEARCH_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]), - wxSizer:add(HSz, TC1, [{proportion,3}, {flag, ?wxEXPAND}]), + _ = wxSizer:add(HSz, TC1, [{proportion,3}, {flag, ?wxEXPAND}]), Nbtn = wxRadioButton:new(Parent, ?wxID_ANY, "Next"), wxRadioButton:setValue(Nbtn, true), - wxSizer:add(HSz,Nbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]), + _ = wxSizer:add(HSz,Nbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]), Pbtn = wxRadioButton:new(Parent, ?wxID_ANY, "Previous"), - wxSizer:add(HSz,Pbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]), + _ = wxSizer:add(HSz,Pbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]), Cbtn = wxCheckBox:new(Parent, ?wxID_ANY, "Match Case"), - wxSizer:add(HSz,Cbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]), - wxSizer:add(HSz, 15,15, [{proportion,1}, {flag, ?wxEXPAND}]), - wxSizer:add(HSz, wxStaticText:new(Parent, ?wxID_ANY, "Goto Line:"), + _ = wxSizer:add(HSz,Cbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]), + _ = wxSizer:add(HSz, 15,15, [{proportion,1}, {flag, ?wxEXPAND}]), + _ = wxSizer:add(HSz, wxStaticText:new(Parent, ?wxID_ANY, "Goto Line:"), [{flag,?wxALIGN_CENTER_VERTICAL}]), TC2 = wxTextCtrl:new(Parent, ?GOTO_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]), - wxSizer:add(HSz, TC2, [{proportion,0}, {flag, ?wxEXPAND}]), + _ = wxSizer:add(HSz, TC2, [{proportion,0}, {flag, ?wxEXPAND}]), wxTextCtrl:connect(TC1, command_text_updated), wxTextCtrl:connect(TC1, command_text_enter), wxTextCtrl:connect(TC1, kill_focus), @@ -969,14 +970,14 @@ eval_area(Parent) -> VSz = wxBoxSizer:new(?wxVERTICAL), HSz = wxBoxSizer:new(?wxHORIZONTAL), - wxSizer:add(HSz, wxStaticText:new(Parent, ?wxID_ANY, "Evaluator:"), + _ = wxSizer:add(HSz, wxStaticText:new(Parent, ?wxID_ANY, "Evaluator:"), [{flag,?wxALIGN_CENTER_VERTICAL}]), TC = wxTextCtrl:new(Parent, ?EVAL_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]), - wxSizer:add(HSz, TC, [{proportion,1}, {flag, ?wxEXPAND}]), - wxSizer:add(VSz, HSz, [{flag, ?wxEXPAND}]), + _ = wxSizer:add(HSz, TC, [{proportion,1}, {flag, ?wxEXPAND}]), + _ = wxSizer:add(VSz, HSz, [{flag, ?wxEXPAND}]), TL = wxTextCtrl:new(Parent, ?EVAL_LOG, [{style, ?wxTE_DONTWRAP bor ?wxTE_MULTILINE bor ?wxTE_READONLY}]), - wxSizer:add(VSz, TL, [{proportion,5}, {flag, ?wxEXPAND}]), + _ = wxSizer:add(VSz, TL, [{proportion,5}, {flag, ?wxEXPAND}]), wxTextCtrl:connect(TC, command_text_enter), #sub{name='Evaluator Area', win=VSz, in=TC, out=TL}. diff --git a/lib/debugger/src/dbg_wx_win.erl b/lib/debugger/src/dbg_wx_win.erl index 1ff8818bbe..25ffc5054c 100644 --- a/lib/debugger/src/dbg_wx_win.erl +++ b/lib/debugger/src/dbg_wx_win.erl @@ -43,7 +43,8 @@ %% GS = term() %%-------------------------------------------------------------------- init() -> - wx:new(). + _ = wx:new(), + ok. %%-------------------------------------------------------------------- %% create_menus(MenuBar, [Menu]) @@ -80,12 +81,12 @@ create_menus(_MB,[], _Win,Id) -> Id. create_menu_item(Menu, [separator|Is], Win, Id,Connect) -> - wxMenu:appendSeparator(Menu), + _ = wxMenu:appendSeparator(Menu), create_menu_item(Menu,Is,Win,Id+1,Connect); create_menu_item(Menu, [{Name, _N, cascade, Items}|Is], Win, Id0,Connect) -> Sub = wxMenu:new([]), Id = create_menu_item(Sub, Items, Win, Id0, false), - wxMenu:append(Menu, ?wxID_ANY, menu_name(Name,ignore), Sub), + _ = wxMenu:append(Menu, ?wxID_ANY, menu_name(Name,ignore), Sub), %% Simulate GS sub checkBox/RadioBox behaviour Self = self(), Butts = [{MI,get(MI)} || {MI,_,_} <- Items], @@ -99,8 +100,8 @@ create_menu_item(Menu, [{Name, _N, cascade, Items}|Is], Win, Id0,Connect) -> Enabled = lists:foldl(IsChecked, [], Butts), Self ! Ev#wx{userData={Name, Enabled}} end, - wxMenu:connect(Win, command_menu_selected, - [{id,Id0},{lastId, Id-1},{callback,Filter}]), + _ = wxMenu:connect(Win, command_menu_selected, + [{id,Id0},{lastId, Id-1},{callback,Filter}]), create_menu_item(Menu, Is, Win, Id, Connect); create_menu_item(Menu, [{Name,Pos}|Is], Win, Id, Connect) -> MenuId = case lists:member(Name, ['Debugger']) of @@ -168,7 +169,7 @@ add_break(Win, MenuName, Point) -> Delete = wxMenu:appendRadioItem(Trigger, ?wxID_ANY,"Delete"), Add(Delete, {break,Point,{trigger,delete}}), - wxMenu:append(Sub, ?wxID_ANY, "Trigger Action", Trigger), + _ = wxMenu:append(Sub, ?wxID_ANY, "Trigger Action", Trigger), MenuBtn = wxMenu:append(Menu,?wxID_ANY, Label, Sub), #break{mb={Menu,MenuBtn}, diff --git a/lib/debugger/src/dbg_wx_winman.erl b/lib/debugger/src/dbg_wx_winman.erl index efa58ae325..ca858fa4bb 100644 --- a/lib/debugger/src/dbg_wx_winman.erl +++ b/lib/debugger/src/dbg_wx_winman.erl @@ -100,11 +100,11 @@ update_windows_menu(Win, [MonInfo|Infos]) -> OldItems = wxMenu:getMenuItems(Menu), [wxMenu:delete(Menu, Item) || Item <- OldItems], menuitem(Win, Menu,MonInfo, 700), - wxMenu:appendSeparator(Menu), + _ = wxMenu:appendSeparator(Menu), wx:foldl(fun(Info,Acc) -> menuitem(Win,Menu,Info,Acc) end, 701, Infos). menuitem(Window, Menu, {Title, Win}, Id) -> - wxMenu:append(Menu, Id, Title), + _ = wxMenu:append(Menu, Id, Title), wxWindow:connect(Window, command_menu_selected, [{id,Id},{userData,{dbg_ui_winman,Win}}]), Id+1. diff --git a/lib/debugger/src/i.erl b/lib/debugger/src/i.erl index 4ed5265bdf..2da3e77618 100644 --- a/lib/debugger/src/i.erl +++ b/lib/debugger/src/i.erl @@ -108,7 +108,7 @@ ib(Module,Function,Arity) -> ib(Module,Function,Arity,Cond) -> Breaks1 = int:all_breaks(Module), - int:break_in(Module,Function,Arity), + ok = int:break_in(Module,Function,Arity), Breaks2 = int:all_breaks(Module), lists:foreach(fun({Mod,Line}) -> int:test_at_break(Mod,Line,Cond) end, Breaks2--Breaks1). diff --git a/lib/debugger/src/int.erl b/lib/debugger/src/int.erl index 3906c22afd..e5bade9abe 100644 --- a/lib/debugger/src/int.erl +++ b/lib/debugger/src/int.erl @@ -352,10 +352,10 @@ start() -> dbg_iserver:start(). stop() -> lists:foreach( fun(Mod) -> - everywhere(distributed, - fun() -> + _ = everywhere(distributed, + fun() -> erts_debug:breakpoint({Mod,'_','_'}, false) - end) + end) end, interpreted()), dbg_iserver:stop(). @@ -524,21 +524,21 @@ check(Mod) when is_atom(Mod) -> catch check_module(Mod); check(File) when is_list(File) -> catch check_file(File). load({Mod, Src, Beam, BeamBin, Exp, Abst}, Dist) -> - everywhere(Dist, - fun() -> + _ = everywhere(Dist, + fun() -> code:purge(Mod), erts_debug:breakpoint({Mod,'_','_'}, false), {module,Mod} = code:load_binary(Mod, Beam, BeamBin) - end), + end), case erl_prim_loader:get_file(filename:absname(Src)) of {ok, SrcBin, _} -> MD5 = code:module_md5(BeamBin), Bin = term_to_binary({interpreter_module,Exp,Abst,SrcBin,MD5}), {module, Mod} = dbg_iserver:safe_call({load, Mod, Src, Bin}), - everywhere(Dist, - fun() -> + _ = everywhere(Dist, + fun() -> true = erts_debug:breakpoint({Mod,'_','_'}, true) > 0 - end), + end), {module, Mod}; error -> error @@ -738,9 +738,9 @@ del_mod(AbsMod, Dist) -> list_to_atom(filename:basename(AbsMod,".erl")) end, dbg_iserver:safe_cast({delete, Mod}), - everywhere(Dist, - fun() -> + _ = everywhere(Dist, + fun() -> erts_debug:breakpoint({Mod,'_','_'}, false), erlang:yield() - end), + end), ok. diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl index d1ffa07706..272ad10e90 100644 --- a/lib/dialyzer/src/dialyzer_contracts.erl +++ b/lib/dialyzer/src/dialyzer_contracts.erl @@ -591,10 +591,13 @@ remove_uses([{Var, Use}|ToRemove], Constrs0) -> remove_uses(_Var, _Use, []) -> []; remove_uses(Var, Use, [Constr|Constrs]) -> {V, Form} = Constr, - case erl_types:t_var_name(V) =:= Var of - true -> [{V, remove_use(Form, Use)}|Constrs]; - false -> [Constr|remove_uses(Var, Use, Constrs)] - end. + NewConstr = case erl_types:t_var_name(V) =:= Var of + true -> + {V, remove_use(Form, Use)}; + false -> + Constr + end, + [NewConstr|remove_uses(Var, Use, Constrs)]. remove_use({var, L, V}, V) -> {var, L, '_'}; remove_use(T, V) when is_tuple(T) -> diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl index 5ab0c39c04..3349b12932 100644 --- a/lib/dialyzer/src/dialyzer_dataflow.erl +++ b/lib/dialyzer/src/dialyzer_dataflow.erl @@ -430,17 +430,35 @@ handle_apply(Tree, Map, State) -> handle_apply_or_call(FunInfoList, Args, ArgTypes, Map, Tree, State) -> None = t_none(), + %% Call-site analysis may be inaccurate and consider more funs than those that + %% are actually possible. If all of them are incorrect, then warnings can be + %% emitted. If at least one fun is ok, however, then no warning is emitted, + %% just in case the bad ones are not really possible. The last argument is + %% used for this, with the following encoding: + %% Initial value: {none, []} + %% First fun checked: {one, <List of warns>} + %% More funs checked: {many, <List of warns>} + %% A '{one, []}' can only become '{many, []}'. + %% If at any point an fun does not add warnings, then the list is also + %% replaced with an empty list. handle_apply_or_call(FunInfoList, Args, ArgTypes, Map, Tree, State, - [None || _ <- ArgTypes], None, false). + [None || _ <- ArgTypes], None, false, {none, []}). handle_apply_or_call([{local, external}|Left], Args, ArgTypes, Map, Tree, State, - _AccArgTypes, _AccRet, _HadExternal) -> + _AccArgTypes, _AccRet, _HadExternal, Warns) -> + {HowMany, _} = Warns, + NewHowMany = + case HowMany of + none -> one; + _ -> many + end, + NewWarns = {NewHowMany, []}, handle_apply_or_call(Left, Args, ArgTypes, Map, Tree, State, - ArgTypes, t_any(), true); + ArgTypes, t_any(), true, NewWarns); handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left], Args, ArgTypes, Map, Tree, #state{opaques = Opaques} = State, - AccArgTypes, AccRet, HadExternal) -> + AccArgTypes, AccRet, HadExternal, Warns) -> Any = t_any(), AnyArgs = [Any || _ <- Args], GenSig = {AnyArgs, fun(_) -> t_any() end}, @@ -586,16 +604,32 @@ handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left], end, NewAccRet = t_sup(AccRet, TotalRet), ?debug("NewAccRet: ~s\n", [t_to_string(NewAccRet)]), + {NewWarnings, State4} = state__remove_added_warnings(State, State3), + {HowMany, OldWarnings} = Warns, + NewWarns = + case HowMany of + none -> {one, NewWarnings}; + _ -> + case OldWarnings =:= [] of + true -> {many, []}; + false -> + case NewWarnings =:= [] of + true -> {many, []}; + false -> {many, NewWarnings ++ OldWarnings} + end + end + end, handle_apply_or_call(Left, Args, ArgTypes, Map, Tree, - State3, NewAccArgTypes, NewAccRet, HadExternal); + State4, NewAccArgTypes, NewAccRet, HadExternal, NewWarns); handle_apply_or_call([], Args, _ArgTypes, Map, _Tree, State, - AccArgTypes, AccRet, HadExternal) -> + AccArgTypes, AccRet, HadExternal, {_, Warnings}) -> + State1 = state__add_warnings(Warnings, State), case HadExternal of false -> NewMap = enter_type_lists(Args, AccArgTypes, Map), - {State, NewMap, AccRet}; + {State1, NewMap, AccRet}; true -> - {had_external, State} + {had_external, State1} end. apply_fail_reason(FailedSig, FailedBif, FailedContract) -> @@ -3038,6 +3072,14 @@ state__add_warning(#state{warnings = Warnings, warning_mode = true} = State, end end. +state__remove_added_warnings(OldState, NewState) -> + #state{warnings = OldWarnings} = OldState, + #state{warnings = NewWarnings} = NewState, + {NewWarnings -- OldWarnings, NewState#state{warnings = OldWarnings}}. + +state__add_warnings(Warns, #state{warnings = Warnings} = State) -> + State#state{warnings = Warns ++ Warnings}. + -spec state__set_curr_fun(curr_fun(), state()) -> state(). state__set_curr_fun(undefined, State) -> diff --git a/lib/dialyzer/test/map_SUITE_data/results/exact b/lib/dialyzer/test/map_SUITE_data/results/exact index 374ada8869..ea00e61330 100644 --- a/lib/dialyzer/test/map_SUITE_data/results/exact +++ b/lib/dialyzer/test/map_SUITE_data/results/exact @@ -1,3 +1,3 @@ exact.erl:15: Function t2/1 has no local return -exact.erl:19: The variable _ can never match since previous clauses completely covered the type #{'a':=_, ...} +exact.erl:19: The variable _ can never match since previous clauses completely covered the type #{'a':=_, _=>_} diff --git a/lib/dialyzer/test/map_SUITE_data/results/guard_update b/lib/dialyzer/test/map_SUITE_data/results/guard_update index e4bc892195..98df23907f 100644 --- a/lib/dialyzer/test/map_SUITE_data/results/guard_update +++ b/lib/dialyzer/test/map_SUITE_data/results/guard_update @@ -1,5 +1,5 @@ guard_update.erl:5: Function t/0 has no local return -guard_update.erl:6: The call guard_update:f(#{'a':=2}) will never return since it differs in the 1st argument from the success typing arguments: (#{'b':=_, ...}) +guard_update.erl:6: The call guard_update:f(#{'a':=2}) will never return since it differs in the 1st argument from the success typing arguments: (#{'b':=_, _=>_}) guard_update.erl:8: Clause guard cannot succeed. The variable M was matched against the type #{'a':=2} guard_update.erl:8: Function f/1 has no local return diff --git a/lib/dialyzer/test/map_SUITE_data/results/map_in_guard2 b/lib/dialyzer/test/map_SUITE_data/results/map_in_guard2 index 6bc0c010d7..f6fb98a863 100644 --- a/lib/dialyzer/test/map_SUITE_data/results/map_in_guard2 +++ b/lib/dialyzer/test/map_SUITE_data/results/map_in_guard2 @@ -1,7 +1,7 @@ map_in_guard2.erl:10: The call map_in_guard2:assoc_guard_clause('not_a_map') will never return since it differs in the 1st argument from the success typing arguments: (map()) map_in_guard2.erl:12: The pattern 'true' can never match the type 'false' -map_in_guard2.erl:14: The call map_in_guard2:exact_guard_clause(#{}) will never return since it differs in the 1st argument from the success typing arguments: (#{'a':=_, ...}) +map_in_guard2.erl:14: The call map_in_guard2:exact_guard_clause(#{}) will never return since it differs in the 1st argument from the success typing arguments: (#{'a':=_, _=>_}) map_in_guard2.erl:17: Clause guard cannot succeed. The variable M was matched against the type 'not_a_map' map_in_guard2.erl:20: Function assoc_update/1 has no local return map_in_guard2.erl:20: Guard test is_map(M::'not_a_map') can never succeed diff --git a/lib/dialyzer/test/map_SUITE_data/results/typeflow b/lib/dialyzer/test/map_SUITE_data/results/typeflow index e3378a24bb..acfb7f551e 100644 --- a/lib/dialyzer/test/map_SUITE_data/results/typeflow +++ b/lib/dialyzer/test/map_SUITE_data/results/typeflow @@ -1,4 +1,4 @@ typeflow.erl:14: Function t2/1 has no local return typeflow.erl:16: The call lists:sort(integer()) will never return since it differs in the 1st argument from the success typing arguments: ([any()]) -typeflow.erl:9: The variable _ can never match since previous clauses completely covered the type #{'a':=integer(), ...} +typeflow.erl:9: The variable _ can never match since previous clauses completely covered the type #{'a':=integer(), _=>_} diff --git a/lib/dialyzer/test/map_SUITE_data/results/typesig b/lib/dialyzer/test/map_SUITE_data/results/typesig index 3049402860..fb2f851a7d 100644 --- a/lib/dialyzer/test/map_SUITE_data/results/typesig +++ b/lib/dialyzer/test/map_SUITE_data/results/typesig @@ -1,5 +1,5 @@ typesig.erl:5: Function t1/0 has no local return -typesig.erl:5: The call typesig:test(#{'a':=1}) will never return since it differs in the 1st argument from the success typing arguments: (#{'a':={number()}, ...}) +typesig.erl:5: The call typesig:test(#{'a':=1}) will never return since it differs in the 1st argument from the success typing arguments: (#{'a':={number()}, _=>_}) typesig.erl:6: Function t2/0 has no local return -typesig.erl:6: The call typesig:test(#{'a':={'b'}}) will never return since it differs in the 1st argument from the success typing arguments: (#{'a':={number()}, ...}) +typesig.erl:6: The call typesig:test(#{'a':={'b'}}) will never return since it differs in the 1st argument from the success typing arguments: (#{'a':={number()}, _=>_}) diff --git a/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy b/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy index 7ce440a60d..11b9ecade6 100644 --- a/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy +++ b/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy @@ -1,4 +1,3 @@ -higher_order_discrepancy.erl:11: The call higher_order_discrepancy:g('foo') will never return since it differs in the 1st argument from the success typing arguments: ('bar') -higher_order_discrepancy.erl:14: Function g/1 has no local return -higher_order_discrepancy.erl:14: The pattern 'bar' can never match the type 'foo' +higher_order_discrepancy.erl:19: Function g/1 has no local return +higher_order_discrepancy.erl:19: The pattern 'bar' can never match the type 'foo' diff --git a/lib/dialyzer/test/small_SUITE_data/results/maps1 b/lib/dialyzer/test/small_SUITE_data/results/maps1 index a178e96b20..f36f7f4926 100644 --- a/lib/dialyzer/test/small_SUITE_data/results/maps1 +++ b/lib/dialyzer/test/small_SUITE_data/results/maps1 @@ -1,4 +1,4 @@ maps1.erl:43: Function t3/0 has no local return -maps1.erl:44: The call maps1:foo(#{'greger'=>3, #{'arne'=>'anka'}=>45},1) will never return since it differs in the 1st and 2nd argument from the success typing arguments: (#{'beta':=_, ...},'b') +maps1.erl:44: The call maps1:foo(#{'greger'=>3, #{'arne'=>'anka'}=>45},1) will never return since it differs in the 1st and 2nd argument from the success typing arguments: (#{'beta':=_, _=>_},'b') maps1.erl:52: The variable Mod can never match since previous clauses completely covered the type #{} diff --git a/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl b/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl index ff5ee6bac4..f9547d4929 100644 --- a/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl +++ b/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl @@ -1,3 +1,8 @@ +%% With the patch introduced to avoid false warnings in +%% user_SUITE_data/src/wpc_hlines.erl we can unfortunately no longer precisely +%% catch problems like this one... The refinement procedure is still enough to +%% keep some of the details, nevertheless. + -module(higher_order_discrepancy). -export([test/1]). diff --git a/lib/dialyzer/test/small_SUITE_data/src/loopy.erl b/lib/dialyzer/test/small_SUITE_data/src/loopy.erl new file mode 100644 index 0000000000..28125ec3d9 --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/loopy.erl @@ -0,0 +1,17 @@ +%% ERL-157, OTP-13653. +%% Would cause Dialyzer to go into an infinite loop. + +-module(loopy). + +-export([loop/1]). + + +-spec loop(Args) -> ok when + Args :: [{Module, Args}], + Module :: module(), + Args :: any(). +loop([{Module, Args} | Rest]) -> + Module:init(Args), + loop(Rest); +loop([]) -> + ok. diff --git a/lib/dialyzer/test/user_SUITE_data/results/wpc_hlines b/lib/dialyzer/test/user_SUITE_data/results/wpc_hlines new file mode 100644 index 0000000000..d6e3f29ab9 --- /dev/null +++ b/lib/dialyzer/test/user_SUITE_data/results/wpc_hlines @@ -0,0 +1,3 @@ + +wpc_hlines.erl:22: Function bad/1 has no local return +wpc_hlines.erl:22: The pattern 'false' can never match the type 'true' diff --git a/lib/dialyzer/test/user_SUITE_data/src/wpc_hlines.erl b/lib/dialyzer/test/user_SUITE_data/src/wpc_hlines.erl new file mode 100644 index 0000000000..8c205a8247 --- /dev/null +++ b/lib/dialyzer/test/user_SUITE_data/src/wpc_hlines.erl @@ -0,0 +1,22 @@ +%% Bug reported by Dan Gudmundsson, test shrunk down by Magnus LÃ¥ng. + +%% The problem is that dialyzer_dep generates edges from the fun +%% application to both of the functions, and then during the warning pass +%% dialyzer_dataflow:handle_apply_or_call generates warnings for any such +%% edge that won't return. + +%% Since dialyzer_dep is currently supposed to overapproximate rather than +%% underapproximate, the fix was to modify handle_apply_or_call to not generate +%% warnings if some of the possible funs can succeed. + +-module(wpc_hlines). + +-export([do_export/0]). + +do_export() -> + {Proj, _} = % The culprit seems to be putting the funs in a tuple + {fun good/1, fun bad/1}, + Proj(true). + +good(_) -> ok. +bad(false) -> ok. diff --git a/lib/edoc/priv/edoc.dtd b/lib/edoc/priv/edoc.dtd index 4278a9e643..89058f5d85 100644 --- a/lib/edoc/priv/edoc.dtd +++ b/lib/edoc/priv/edoc.dtd @@ -103,7 +103,7 @@ <!ATTLIST type name CDATA #IMPLIED> <!ELEMENT union (typevar | atom | integer | float | nil | list | tuple | - fun | record | abstype)+> + fun | record | map | abstype)+> <!ELEMENT typevar EMPTY> <!ATTLIST typevar name CDATA #REQUIRED> @@ -129,6 +129,10 @@ <!ELEMENT field (atom, type)> +<!ELEMENT map (map_field)*> + +<!ELEMENT map_field (type, type)> + <!ELEMENT abstype (erlangName, type*)> <!ATTLIST abstype href CDATA #IMPLIED> diff --git a/lib/edoc/src/edoc_layout.erl b/lib/edoc/src/edoc_layout.erl index f723cd8373..ef57b7b084 100644 --- a/lib/edoc/src/edoc_layout.erl +++ b/lib/edoc/src/edoc_layout.erl @@ -898,8 +898,14 @@ t_map(Es) -> Fs = get_elem(map_field, Es), ["#{"] ++ seq(fun t_map_field/1, Fs, ["}"]). -t_map_field(#xmlElement{content = [K,V]}) -> - t_utype_elem(K) ++ [" => "] ++ t_utype_elem(V). +t_map_field(#xmlElement{content = [K,V]}=E) -> + KElem = t_utype_elem(K), + VElem = t_utype_elem(V), + AS = case get_attrval(assoc_type, E) of + "assoc" -> " => "; + "exact" -> " := " + end, + KElem ++ [AS] ++ VElem. t_record(E, Es) -> Name = ["#"] ++ t_type(get_elem(atom, Es)), @@ -1133,8 +1139,12 @@ ot_tuple(Es) -> ot_map(Es) -> {type,0,map,[ot_map_field(E) || E <- get_elem(map_field,Es)]}. -ot_map_field(#xmlElement{content=[K,V]}) -> - {type,0,map_field_assoc,ot_utype_elem(K), ot_utype_elem(V)}. +ot_map_field(#xmlElement{content=[K,V]}=E) -> + A = case get_attrval(assoc_type, E) of + "assoc" -> map_field_assoc; + "exact" -> map_field_exact + end, + {type,0,A,[ot_utype_elem(K), ot_utype_elem(V)]}. ot_fun(Es) -> Range = ot_utype(get_elem(type, Es)), diff --git a/lib/edoc/src/edoc_parser.yrl b/lib/edoc/src/edoc_parser.yrl index 835e7ccaa6..68a3439f10 100644 --- a/lib/edoc/src/edoc_parser.yrl +++ b/lib/edoc/src/edoc_parser.yrl @@ -36,8 +36,8 @@ Terminals atom float integer var an_var string start_spec start_typedef start_throws start_ref -'(' ')' ',' '.' '=>' '->' '{' '}' '[' ']' '|' '+' ':' '::' '=' '/' '//' '*' -'#' 'where' '<<' '>>' '..' '...'. +'(' ')' ',' '.' '=>' ':=' '->' '{' '}' '[' ']' '|' '+' ':' '::' '=' '/' '//' +'*' '#' 'where' '<<' '>>' '..' '...'. Rootsymbol start. @@ -76,7 +76,12 @@ utype_map_fields -> '$empty' : []. utype_map_fields -> utype_map_field : ['$1']. utype_map_fields -> utype_map_fields ',' utype_map_field : ['$3' | '$1']. -utype_map_field -> utype '=>' utype : #t_map_field{ k_type = '$1', v_type = '$3'}. +utype_map_field -> utype '=>' utype : #t_map_field{assoc_type = assoc, + k_type = '$1', + v_type = '$3'}. +utype_map_field -> utype ':=' utype : #t_map_field{assoc_type = exact, + k_type = '$1', + v_type = '$3'}. utype_tuple -> '{' utypes '}' : lists:reverse('$2'). diff --git a/lib/edoc/src/edoc_scanner.erl b/lib/edoc/src/edoc_scanner.erl index 36423d63f8..f1d5e1d4b9 100644 --- a/lib/edoc/src/edoc_scanner.erl +++ b/lib/edoc/src/edoc_scanner.erl @@ -146,6 +146,8 @@ scan1([$>,$>|Cs], Toks, Pos) -> scan1(Cs, [{'>>',Pos}|Toks], Pos); scan1([$-,$>|Cs], Toks, Pos) -> scan1(Cs, [{'->',Pos}|Toks], Pos); +scan1([$:,$=|Cs], Toks, Pos) -> + scan1(Cs, [{':=',Pos}|Toks], Pos); scan1([$:,$:|Cs], Toks, Pos) -> scan1(Cs, [{'::',Pos}|Toks], Pos); scan1([$/,$/|Cs], Toks, Pos) -> diff --git a/lib/edoc/src/edoc_specs.erl b/lib/edoc/src/edoc_specs.erl index faee8adf7b..c15dfd328f 100644 --- a/lib/edoc/src/edoc_specs.erl +++ b/lib/edoc/src/edoc_specs.erl @@ -369,11 +369,11 @@ d2e({type,_,map,any}, _Prec) -> d2e({type,_,map,Es}, _Prec) -> #t_map{types = d2e(Es) }; d2e({type,_,map_field_assoc,[K,V]}, Prec) -> - T = #t_map_field{k_type = d2e(K), v_type=d2e(V) }, + T = #t_map_field{assoc_type = assoc, k_type = d2e(K), v_type=d2e(V) }, {P,_R} = erl_parse:type_preop_prec('#'), maybe_paren(P, Prec, T); -d2e({type,_,map_field_exact,K,V}, Prec) -> - T = #t_map_field{k_type = d2e(K), v_type=d2e(V) }, +d2e({type,_,map_field_exact,[K,V]}, Prec) -> + T = #t_map_field{assoc_type = exact, k_type = d2e(K), v_type=d2e(V) }, {P,_R} = erl_parse:type_preop_prec('#'), maybe_paren(P, Prec, T); d2e({type,_,tuple,Ts0}, _Prec) -> diff --git a/lib/edoc/src/edoc_types.erl b/lib/edoc/src/edoc_types.erl index 65fba61a72..5bb68e79fb 100644 --- a/lib/edoc/src/edoc_types.erl +++ b/lib/edoc/src/edoc_types.erl @@ -89,8 +89,8 @@ to_xml(#t_fun{args = As, range = T}, Env) -> wrap_utype(T, Env)]}; to_xml(#t_map{ types = Ts}, Env) -> {map, map(fun to_xml/2, Ts, Env)}; -to_xml(#t_map_field{ k_type=K, v_type=V}, Env) -> - {map_field, [wrap_utype(K,Env), wrap_utype(V, Env)]}; +to_xml(#t_map_field{assoc_type = AT, k_type=K, v_type=V}, Env) -> + {map_field, [{assoc_type, AT}], [wrap_utype(K,Env), wrap_utype(V, Env)]}; to_xml(#t_tuple{types = Ts}, Env) -> {tuple, map(fun wrap_utype/2, Ts, Env)}; to_xml(#t_list{type = T}, Env) -> diff --git a/lib/edoc/src/edoc_types.hrl b/lib/edoc/src/edoc_types.hrl index 7fec10d936..3e5e91484f 100644 --- a/lib/edoc/src/edoc_types.hrl +++ b/lib/edoc/src/edoc_types.hrl @@ -157,5 +157,5 @@ -record(t_paren, {a=[], type}). % parentheses -record(t_map, {a=[], types=[]}). --record(t_map_field, {a=[], k_type, v_type}). +-record(t_map_field, {a=[], assoc_type, k_type, v_type}). diff --git a/lib/erl_docgen/src/docgen_otp_specs.erl b/lib/erl_docgen/src/docgen_otp_specs.erl index e154323f07..6c41147e27 100644 --- a/lib/erl_docgen/src/docgen_otp_specs.erl +++ b/lib/erl_docgen/src/docgen_otp_specs.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2015. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. 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. @@ -389,10 +389,10 @@ t_type([#xmlElement{name = list, content = Es}]) -> t_list(Es); t_type([#xmlElement{name = nonempty_list, content = Es}]) -> t_nonempty_list(Es); -t_type([#xmlElement{name = tuple, content = Es}]) -> - t_tuple(Es); t_type([#xmlElement{name = map, content = Es}]) -> t_map(Es); +t_type([#xmlElement{name = tuple, content = Es}]) -> + t_tuple(Es); t_type([#xmlElement{name = 'fun', content = Es}]) -> ["fun("] ++ t_fun(Es) ++ [")"]; t_type([E = #xmlElement{name = record, content = Es}]) -> @@ -435,16 +435,22 @@ t_nonempty_list(Es) -> t_tuple(Es) -> ["{"] ++ seq(fun t_utype_elem/1, Es, ["}"]). +t_fun(Es) -> + ["("] ++ seq(fun t_utype_elem/1, get_content(argtypes, Es), + [") -> "] ++ t_utype(get_elem(type, Es))). + t_map(Es) -> Fs = get_elem(map_field, Es), ["#{"] ++ seq(fun t_map_field/1, Fs, ["}"]). -t_map_field(#xmlElement{content = [K,V]}) -> - [t_utype_elem(K) ++ " => " ++ t_utype_elem(V)]. - -t_fun(Es) -> - ["("] ++ seq(fun t_utype_elem/1, get_content(argtypes, Es), - [") -> "] ++ t_utype(get_elem(type, Es))). +t_map_field(#xmlElement{content = [K,V]}=E) -> + KElem = t_utype_elem(K), + VElem = t_utype_elem(V), + AS = case get_attrval(assoc_type, E) of + "assoc" -> " => "; + "exact" -> " := " + end, + KElem ++ [AS] ++ VElem. t_record(E, Es) -> Name = ["#"] ++ t_type(get_elem(atom, Es)), @@ -618,8 +624,12 @@ ot_tuple(Es) -> ot_map(Es) -> {type,0,map,[ot_map_field(E) || E <- get_elem(map_field,Es)]}. -ot_map_field(#xmlElement{content=[K,V]}) -> - {type,0,map_field_assoc,[ot_utype_elem(K),ot_utype_elem(V)]}. +ot_map_field(#xmlElement{content=[K,V]}=E) -> + A = case get_attrval(assoc_type, E) of + "assoc" -> map_field_assoc; + "exact" -> map_field_exact + end, + {type,0,A,[ot_utype_elem(K), ot_utype_elem(V)]}. ot_fun(Es) -> Range = ot_utype(get_elem(type, Es)), diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl index c383541020..705fc73613 100644 --- a/lib/hipe/cerl/erl_types.erl +++ b/lib/hipe/cerl/erl_types.erl @@ -4302,7 +4302,6 @@ t_to_string(?map(Pairs0,DefK,DefV), RecDict) -> {Pairs, ExtraEl} = case {DefK, DefV} of {?none, ?none} -> {Pairs0, []}; - {?any, ?any} -> {Pairs0, ["..."]}; _ -> {Pairs0 ++ [{DefK,?opt,DefV}], []} end, Tos = fun(T) -> case T of diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 42772923e4..932567ec55 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -2080,7 +2080,7 @@ run_clients(NumClients, ServerPort, SeqNumServer) -> end end), MRef = erlang:monitor(process, Pid), - timer:sleep(10 + random:uniform(1334)), + timer:sleep(10 + rand:uniform(1334)), {Id, Pid, MRef} end, lists:seq(1, NumClients)). @@ -2169,7 +2169,7 @@ slowly_send_response(CSock, Answer) -> [length(Answer), Answer])), lists:foreach( fun(Char) -> - timer:sleep(random:uniform(500)), + timer:sleep(rand:uniform(500)), gen_tcp:send(CSock, <<Char>>) end, Response). @@ -2189,9 +2189,8 @@ parse_connection_type(Request) -> set_random_seed() -> Unique = erlang:unique_integer(), - A = erlang:phash2([make_ref(), self(), Unique]), - random:seed(A, A, A). + rand:seed(exsplus, {A, A, A}). otp_8739(doc) -> diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml index b75d42d198..88135ea43d 100644 --- a/lib/kernel/doc/src/gen_tcp.xml +++ b/lib/kernel/doc/src/gen_tcp.xml @@ -153,17 +153,17 @@ do_recv(Sock, Bs) -> <c><anno>Address</anno></c> can be a hostname or an IP address.</p> <p>The following options are available:</p> <taglist> - <tag><c>{ip, ip_address()}</c></tag> + <tag><c>{ip, Address}</c></tag> <item><p>If the host has many network interfaces, this option specifies which one to use.</p></item> - <tag><c>{ifaddr, ip_address()}</c></tag> - <item><p>Same as <c>{ip, ip_address()}</c>. If the host has many + <tag><c>{ifaddr, Address}</c></tag> + <item><p>Same as <c>{ip, Address}</c>. If the host has many network interfaces, this option specifies which one to use.</p> </item> <tag><c>{fd, integer() >= 0}</c></tag> <item><p>If a socket has somehow been connected without using <c>gen_tcp</c>, use this option to pass the file descriptor - for it. If <c>{ip, ip_address()}</c> and/or + for it. If <c>{ip, Address}</c> and/or <c>{port, port_number()}</c> is combined with this option, the <c>fd</c> is bound to the specified interface and port before connecting. If these options are not specified, it is assumed that @@ -175,9 +175,10 @@ do_recv(Sock, Bs) -> <tag><c>local</c></tag> <item> <p> - Sets up the socket for local address family. This option is only - valid together with <c>{fd, integer()}</c> when the file descriptor - is of local address family (e.g. a Unix Domain Socket) + Sets up a Unix Domain Socket. See + <seealso marker="inet#type-local_address"> + <c>inet:local_address()</c> + </seealso> </p> </item> <tag><c>{port, Port}</c></tag> @@ -254,7 +255,7 @@ do_recv(Sock, Bs) -> <item><p><c>B</c> is an integer >= <c>0</c>. The backlog value defines the maximum length that the queue of pending connections can grow to. Defaults to <c>5</c>.</p></item> - <tag><c>{ip, ip_address()}</c></tag> + <tag><c>{ip, Address}</c></tag> <item><p>If the host has many network interfaces, this option specifies which one to listen on.</p></item> <tag><c>{port, Port}</c></tag> @@ -263,8 +264,8 @@ do_recv(Sock, Bs) -> <item><p>If a socket has somehow been connected without using <c>gen_tcp</c>, use this option to pass the file descriptor for it.</p></item> - <tag><c>{ifaddr, ip_address()}</c></tag> - <item><p>Same as <c>{ip, ip_address()}</c>. If the host has many + <tag><c>{ifaddr, Address}</c></tag> + <item><p>Same as <c>{ip, Address}</c>. If the host has many network interfaces, this option specifies which one to use.</p> </item> <tag><c>inet6</c></tag> diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml index ca9d9c978c..3f88a0272d 100644 --- a/lib/kernel/doc/src/gen_udp.xml +++ b/lib/kernel/doc/src/gen_udp.xml @@ -85,11 +85,11 @@ <item><p>Received <c>Packet</c> is delivered as a list.</p></item> <tag><c>binary</c></tag> <item><p>Received <c>Packet</c> is delivered as a binary.</p></item> - <tag><c>{ip, ip_address()}</c></tag> + <tag><c>{ip, Address}</c></tag> <item><p>If the host has many network interfaces, this option specifies which one to use.</p></item> - <tag><c>{ifaddr, ip_address()}</c></tag> - <item><p>Same as <c>{ip, ip_address()}</c>. If the host has many + <tag><c>{ifaddr, Address}</c></tag> + <item><p>Same as <c>{ip, Address}</c>. If the host has many network interfaces, this option specifies which one to use.</p></item> <tag><c>{fd, integer() >= 0}</c></tag> @@ -107,9 +107,10 @@ <tag><c>local</c></tag> <item> <p> - Sets up the socket for local address family. This option is only - valid together with <c>{fd, integer()}</c> when the file descriptor - is of local address family (e.g. a Unix Domain Socket) + Sets up a Unix Domain Socket. See + <seealso marker="inet#type-local_address"> + <c>inet:local_address()</c> + </seealso> </p> </item> <tag><c>{udp_module, module()}</c></tag> @@ -184,8 +185,10 @@ <name name="send" arity="4"/> <fsummary>Send a packet.</fsummary> <desc> - <p>Sends a packet to the specified address and port. Argument - <c><anno>Address</anno></c> can be a hostname or an IP address.</p> + <p> + Sends a packet to the specified address and port. Argument + <c><anno>Address</anno></c> can be a hostname or a socket address. + </p> </desc> </func> </funcs> diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index 5ff167bcb3..c0dce2f50c 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -118,6 +118,59 @@ fe80::204:acff:fe17:bf38 <name name="port_number"/> </datatype> <datatype> + <name name="local_address"/> + <desc> + <p> + This address family only works on Unix-like systems. + </p> + <p> + <c><anno>File</anno></c> is normally a file pathname + in a local filesystem. It is limited in length by the + operating system, traditionally to 108 bytes. + </p> + <p> + A <c>binary()</c> is passed as is to the operating system, + but a <c>string()</c> is encoded according to the + <seealso marker="file#native_name_encoding/0"> + system filename encoding mode. + </seealso> + </p> + <p> + Other addresses are possible, for example Linux implements + "Abstract Addresses". See the documentation for + Unix Domain Sockets on your system, + normally <c>unix</c> in manual section 7. + </p> + <p> + In most API functions where you can use + this address family the port number must be <c>0</c>. + </p> + </desc> + </datatype> + <datatype> + <name name="socket_address"/> + </datatype> + <datatype> + <name name="returned_non_ip_address"/> + <desc> + <p> + Addresses besides + <seealso marker="#type-ip_address"> + <c>ip_address()</c> + </seealso> + ones that are returned from socket API functions. + See in particular + <seealso marker="#type-local_address"> + <c>local_address()</c>. + </seealso> + The <c>unspec</c> family corresponds to AF_UNSPEC and can + occur if the other side has no socket address. + The <c>undefined</c> family can only occur in the unlikely + event of an address family that the VM does not recognize. + </p> + </desc> + </datatype> + <datatype> <name name="posix"/> <desc> <p>An atom that is named from the POSIX error codes used in Unix, diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl index 2b3afcd44c..1a21541b7c 100644 --- a/lib/kernel/src/gen_tcp.erl +++ b/lib/kernel/src/gen_tcp.erl @@ -96,17 +96,17 @@ tos | ipv6_v6only. -type connect_option() :: - {ip, inet:ip_address()} | + {ip, inet:socket_address()} | {fd, Fd :: non_neg_integer()} | - {ifaddr, inet:ip_address()} | + {ifaddr, inet:socket_address()} | inet:address_family() | {port, inet:port_number()} | {tcp_module, module()} | option(). -type listen_option() :: - {ip, inet:ip_address()} | + {ip, inet:socket_address()} | {fd, Fd :: non_neg_integer()} | - {ifaddr, inet:ip_address()} | + {ifaddr, inet:socket_address()} | inet:address_family() | {port, inet:port_number()} | {backlog, B :: non_neg_integer()} | @@ -122,7 +122,7 @@ %% -spec connect(Address, Port, Options) -> {ok, Socket} | {error, Reason} when - Address :: inet:ip_address() | inet:hostname(), + Address :: inet:socket_address() | inet:hostname(), Port :: inet:port_number(), Options :: [connect_option()], Socket :: socket(), @@ -133,7 +133,7 @@ connect(Address, Port, Opts) -> -spec connect(Address, Port, Options, Timeout) -> {ok, Socket} | {error, Reason} when - Address :: inet:ip_address() | inet:hostname(), + Address :: inet:socket_address() | inet:hostname(), Port :: inet:port_number(), Options :: [connect_option()], Timeout :: timeout(), diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl index 2227bb3562..98d2f0bcfb 100644 --- a/lib/kernel/src/gen_udp.erl +++ b/lib/kernel/src/gen_udp.erl @@ -92,9 +92,9 @@ open(Port) -> -spec open(Port, Opts) -> {ok, Socket} | {error, Reason} when Port :: inet:port_number(), Opts :: [Option], - Option :: {ip, inet:ip_address()} + Option :: {ip, inet:socket_address()} | {fd, non_neg_integer()} - | {ifaddr, inet:ip_address()} + | {ifaddr, inet:socket_address()} | inet:address_family() | {port, inet:port_number()} | option(), @@ -114,7 +114,7 @@ close(S) -> -spec send(Socket, Address, Port, Packet) -> ok | {error, Reason} when Socket :: socket(), - Address :: inet:ip_address() | inet:hostname(), + Address :: inet:socket_address() | inet:hostname(), Port :: inet:port_number(), Packet :: iodata(), Reason :: not_owner | inet:posix(). @@ -148,7 +148,7 @@ send(S, Packet) when is_port(S) -> {ok, {Address, Port, Packet}} | {error, Reason} when Socket :: socket(), Length :: non_neg_integer(), - Address :: inet:ip_address(), + Address :: inet:ip_address() | inet:returned_non_ip_address(), Port :: inet:port_number(), Packet :: string() | binary(), Reason :: not_owner | inet:posix(). @@ -166,7 +166,7 @@ recv(S,Len) when is_port(S), is_integer(Len) -> Socket :: socket(), Length :: non_neg_integer(), Timeout :: timeout(), - Address :: inet:ip_address(), + Address :: inet:ip_address() | inet:returned_non_ip_address(), Port :: inet:port_number(), Packet :: string() | binary(), Reason :: not_owner | inet:posix(). diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index de43ea792b..9fc685e728 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -73,9 +73,9 @@ -export([start_timer/1, timeout/1, timeout/2, stop_timer/1]). -export_type([address_family/0, hostent/0, hostname/0, ip4_address/0, - ip6_address/0, ip_address/0, posix/0, socket/0, - port_number/0]). - + ip6_address/0, ip_address/0, port_number/0, + local_address/0, socket_address/0, returned_non_ip_address/0, + posix/0, socket/0, stat_option/0]). %% imports -import(lists, [append/1, duplicate/2, filter/2, foldl/3]). @@ -98,6 +98,11 @@ 0..65535,0..65535,0..65535,0..65535}. -type ip_address() :: ip4_address() | ip6_address(). -type port_number() :: 0..65535. +-type local_address() :: {local, File :: binary() | string()}. +-type returned_non_ip_address() :: + {local, binary()} | + {unspec, <<>>} | + {undefined, any()}. -type posix() :: exbadport | exbadseq | file:posix(). -type socket() :: port(). @@ -138,7 +143,7 @@ -type socket_protocol() :: 'tcp' | 'udp' | 'sctp'. -type socket_type() :: 'stream' | 'dgram' | 'seqpacket'. -type socket_address() :: - ip_address() | {address_family(), any()} | 'any' | 'loopback'. + ip_address() | 'any' | 'loopback' | local_address(). -type stat_option() :: 'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' | 'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'. @@ -163,26 +168,33 @@ close(Socket) -> end. --spec peername(Socket) -> {ok, {Address, Port}} | {error, posix()} when - Socket :: socket(), - Address :: ip_address(), - Port :: non_neg_integer(). +-spec peername(Socket :: socket()) -> + {ok, + {ip_address(), port_number()} | + returned_non_ip_address()} | + {error, posix()}. peername(Socket) -> prim_inet:peername(Socket). --spec setpeername(Socket :: socket(), Address :: {ip_address(), port_number()}) -> - 'ok' | {'error', any()}. +-spec setpeername( + Socket :: socket(), + Address :: + {ip_address() | 'any' | 'loopback', + port_number()} | + socket_address()) -> + 'ok' | {'error', any()}. setpeername(Socket, {IP,Port}) -> prim_inet:setpeername(Socket, {IP,Port}); setpeername(Socket, undefined) -> prim_inet:setpeername(Socket, undefined). --spec peernames(Socket) -> {ok, [{Address, Port}]} | {error, posix()} when - Socket :: socket(), - Address :: ip_address(), - Port :: non_neg_integer(). +-spec peernames(Socket :: socket()) -> + {ok, + [{ip_address(), port_number()} | + returned_non_ip_address()]} | + {error, posix()}. peernames(Socket) -> prim_inet:peernames(Socket). @@ -198,15 +210,21 @@ peernames(Socket, Assoc) -> prim_inet:peernames(Socket, Assoc). --spec sockname(Socket) -> {ok, {Address, Port}} | {error, posix()} when - Socket :: socket(), - Address :: ip_address(), - Port :: non_neg_integer(). +-spec sockname(Socket :: socket()) -> + {ok, + {ip_address(), port_number()} | + returned_non_ip_address()} | + {error, posix()}. sockname(Socket) -> prim_inet:sockname(Socket). --spec setsockname(Socket :: socket(), Address :: {ip_address(), port_number()}) -> +-spec setsockname( + Socket :: socket(), + Address :: + {ip_address() | 'any' | 'loopback', + port_number()} | + socket_address()) -> 'ok' | {'error', any()}. setsockname(Socket, {IP,Port}) -> @@ -214,10 +232,11 @@ setsockname(Socket, {IP,Port}) -> setsockname(Socket, undefined) -> prim_inet:setsockname(Socket, undefined). --spec socknames(Socket) -> {ok, [{Address, Port}]} | {error, posix()} when - Socket :: socket(), - Address :: ip_address(), - Port :: non_neg_integer(). +-spec socknames(Socket :: socket()) -> + {ok, + [{ip_address(), port_number()} | + returned_non_ip_address()]} | + {error, posix()}. socknames(Socket) -> prim_inet:socknames(Socket). @@ -1296,7 +1315,17 @@ gethostbyaddr_tm_native(Addr, Timer, Opts) -> end. -spec open(Fd_or_OpenOpts :: integer() | list(), - Addr :: socket_address(), + Addr :: + socket_address() | + {ip_address() | 'any' | 'loopback', % Unofficial + port_number()} | + {inet, % Unofficial + {ip4_address() | 'any' | 'loopback', + port_number()}} | + {inet6, % Unofficial + {ip6_address() | 'any' | 'loopback', + port_number()}} | + undefined, % Internal - no bind() Port :: port_number(), Opts :: [socket_setopt()], Protocol :: socket_protocol(), @@ -1316,11 +1345,16 @@ open(FdO, Addr, Port, Opts, Protocol, Family, Type, Module) {ok,S} -> case prim_inet:setopts(S, Opts) of ok -> - case if is_list(Addr) -> - bindx(S, Addr, Port); - true -> - prim_inet:bind(S, Addr, Port) - end of + case + case Addr of + undefined -> + {ok, undefined}; + _ when is_list(Addr) -> + bindx(S, Addr, Port); + _ -> + prim_inet:bind(S, Addr, Port) + end + of {ok, _} -> inet_db:register_socket(S, Module), {ok,S}; diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index 32d09fb63c..c8a8962e78 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -25,6 +25,7 @@ %% %% family codes to open +-define(INET_AF_UNSPEC, 0). -define(INET_AF_INET, 1). -define(INET_AF_INET6, 2). -define(INET_AF_ANY, 3). % Fake for ANY in any address family diff --git a/lib/kernel/src/local_tcp.erl b/lib/kernel/src/local_tcp.erl index 64085ec42e..e3c67dfbb7 100644 --- a/lib/kernel/src/local_tcp.erl +++ b/lib/kernel/src/local_tcp.erl @@ -107,8 +107,14 @@ do_connect(Addr = {?FAMILY, _}, 0, Opts, Time) -> when tuple_size(BAddr) =:= 2, element(1, BAddr) =:= ?FAMILY; BAddr =:= any -> case inet:open( - Fd, BAddr, 0, SockOpts, - ?PROTO, ?FAMILY, ?TYPE, ?MODULE) of + Fd, + case BAddr of + any -> + undefined; + _ -> + BAddr + end, + 0, SockOpts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE) of {ok, S} -> case prim_inet:connect(S, Addr, 0, Time) of ok -> {ok,S}; diff --git a/lib/kernel/src/local_udp.erl b/lib/kernel/src/local_udp.erl index ebb4d2b33f..481a8c4910 100644 --- a/lib/kernel/src/local_udp.erl +++ b/lib/kernel/src/local_udp.erl @@ -59,7 +59,14 @@ open(0, Opts) -> when tuple_size(BAddr) =:= 2, element(1, BAddr) =:= ?FAMILY; BAddr =:= any -> inet:open( - Fd, BAddr, 0, SockOpts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE); + Fd, + case BAddr of + any -> + undefined; + _ -> + BAddr + end, + 0, SockOpts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE); {ok, _} -> exit(badarg) end. diff --git a/lib/observer/src/crashdump_viewer.erl b/lib/observer/src/crashdump_viewer.erl index de52e2a995..9268dac180 100644 --- a/lib/observer/src/crashdump_viewer.erl +++ b/lib/observer/src/crashdump_viewer.erl @@ -1491,6 +1491,9 @@ get_portinfo(Fd,Port) -> "Port controls linked-in driver" -> Str = lists:flatten(["Linked in driver: " | val(Fd)]), get_portinfo(Fd,Port#port{controls=Str}); + "Port controls forker process" -> + Str = lists:flatten(["Forker process: " | val(Fd)]), + get_portinfo(Fd,Port#port{controls=Str}); "Port controls external process" -> Str = lists:flatten(["External proc: " | val(Fd)]), get_portinfo(Fd,Port#port{controls=Str}); diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl index fe2aa11450..620979dcc9 100644 --- a/lib/observer/src/observer_procinfo.erl +++ b/lib/observer/src/observer_procinfo.erl @@ -317,7 +317,7 @@ fetch_state_info2(Pid, M) -> of {status, _, {module, _}, [_PDict, _SysState, _Parent, _Dbg, - [Header,{data, First},{data, Second}]]} -> + [Header,{data, First},{data, Second}|_]]} -> [{"Behaviour", B}, Header] ++ First ++ Second; {status, _, {module, _}, [_PDict, _SysState, _Parent, _Dbg, diff --git a/lib/runtime_tools/c_src/dyntrace_lttng.h b/lib/runtime_tools/c_src/dyntrace_lttng.h index 2a3224e191..5e838892d6 100644 --- a/lib/runtime_tools/c_src/dyntrace_lttng.h +++ b/lib/runtime_tools/c_src/dyntrace_lttng.h @@ -19,7 +19,7 @@ */ #undef TRACEPOINT_PROVIDER -#define TRACEPOINT_PROVIDER com_ericsson_dyntrace +#define TRACEPOINT_PROVIDER org_erlang_dyntrace #if !defined(DYNTRACE_LTTNG_H) || defined(TRACEPOINT_HEADER_MULTI_READ) #define DYNTRACE_LTTNG_H @@ -27,22 +27,22 @@ #include <lttng/tracepoint.h> #define LTTNG1(Name, Arg1) \ - tracepoint(com_ericsson_dyntrace, Name, (Arg1)) + tracepoint(org_erlang_dyntrace, Name, (Arg1)) #define LTTNG2(Name, Arg1, Arg2) \ - tracepoint(com_ericsson_dyntrace, Name, (Arg1), (Arg2)) + tracepoint(org_erlang_dyntrace, Name, (Arg1), (Arg2)) #define LTTNG3(Name, Arg1, Arg2, Arg3) \ - tracepoint(com_ericsson_dyntrace, Name, (Arg1), (Arg2), (Arg3)) + tracepoint(org_erlang_dyntrace, Name, (Arg1), (Arg2), (Arg3)) #define LTTNG4(Name, Arg1, Arg2, Arg3, Arg4) \ - tracepoint(com_ericsson_dyntrace, Name, (Arg1), (Arg2), (Arg3), (Arg4)) + tracepoint(org_erlang_dyntrace, Name, (Arg1), (Arg2), (Arg3), (Arg4)) #define LTTNG5(Name, Arg1, Arg2, Arg3, Arg4, Arg5) \ - tracepoint(com_ericsson_dyntrace, Name, (Arg1), (Arg2), (Arg3), (Arg4), (Arg5)) + tracepoint(org_erlang_dyntrace, Name, (Arg1), (Arg2), (Arg3), (Arg4), (Arg5)) #define LTTNG_ENABLED(Name) \ - tracepoint_enabled(com_ericsson_dyntrace, Name) + tracepoint_enabled(org_erlang_dyntrace, Name) #define LTTNG_BUFFER_SZ (256) #define LTTNG_PROC_BUFFER_SZ (16) @@ -76,7 +76,7 @@ /* Process scheduling */ TRACEPOINT_EVENT( - com_ericsson_dyntrace, + org_erlang_dyntrace, process_spawn, TP_ARGS( char*, p, @@ -91,7 +91,7 @@ TRACEPOINT_EVENT( ) TRACEPOINT_EVENT( - com_ericsson_dyntrace, + org_erlang_dyntrace, process_link, TP_ARGS( char*, from, @@ -106,7 +106,7 @@ TRACEPOINT_EVENT( ) TRACEPOINT_EVENT( - com_ericsson_dyntrace, + org_erlang_dyntrace, process_exit, TP_ARGS( char*, p, @@ -119,7 +119,7 @@ TRACEPOINT_EVENT( ) TRACEPOINT_EVENT( - com_ericsson_dyntrace, + org_erlang_dyntrace, process_register, TP_ARGS( char*, pid, @@ -136,7 +136,7 @@ TRACEPOINT_EVENT( /* Scheduled */ TRACEPOINT_EVENT( - com_ericsson_dyntrace, + org_erlang_dyntrace, process_scheduled, TP_ARGS( char*, p, @@ -154,7 +154,7 @@ TRACEPOINT_EVENT( TRACEPOINT_EVENT( - com_ericsson_dyntrace, + org_erlang_dyntrace, port_open, TP_ARGS( char*, pid, @@ -169,7 +169,7 @@ TRACEPOINT_EVENT( ) TRACEPOINT_EVENT( - com_ericsson_dyntrace, + org_erlang_dyntrace, port_exit, TP_ARGS( char*, port, @@ -182,7 +182,7 @@ TRACEPOINT_EVENT( ) TRACEPOINT_EVENT( - com_ericsson_dyntrace, + org_erlang_dyntrace, port_link, TP_ARGS( char*, from, @@ -197,7 +197,7 @@ TRACEPOINT_EVENT( ) TRACEPOINT_EVENT( - com_ericsson_dyntrace, + org_erlang_dyntrace, port_scheduled, TP_ARGS( char*, p, @@ -214,7 +214,7 @@ TRACEPOINT_EVENT( /* Call tracing */ TRACEPOINT_EVENT( - com_ericsson_dyntrace, + org_erlang_dyntrace, function_call, TP_ARGS( char*, pid, @@ -229,7 +229,7 @@ TRACEPOINT_EVENT( ) TRACEPOINT_EVENT( - com_ericsson_dyntrace, + org_erlang_dyntrace, function_return, TP_ARGS( char*, pid, @@ -244,7 +244,7 @@ TRACEPOINT_EVENT( ) TRACEPOINT_EVENT( - com_ericsson_dyntrace, + org_erlang_dyntrace, function_exception, TP_ARGS( char*, pid, @@ -261,7 +261,7 @@ TRACEPOINT_EVENT( /* Process messages */ TRACEPOINT_EVENT( - com_ericsson_dyntrace, + org_erlang_dyntrace, message_send, TP_ARGS( char*, sender, @@ -276,7 +276,7 @@ TRACEPOINT_EVENT( ) TRACEPOINT_EVENT( - com_ericsson_dyntrace, + org_erlang_dyntrace, message_receive, TP_ARGS( char*, receiver, @@ -291,7 +291,7 @@ TRACEPOINT_EVENT( /* Process Memory */ TRACEPOINT_EVENT( - com_ericsson_dyntrace, + org_erlang_dyntrace, gc_minor_start, TP_ARGS( char*, p, @@ -308,7 +308,7 @@ TRACEPOINT_EVENT( ) TRACEPOINT_EVENT( - com_ericsson_dyntrace, + org_erlang_dyntrace, gc_minor_end, TP_ARGS( char*, p, @@ -325,7 +325,7 @@ TRACEPOINT_EVENT( ) TRACEPOINT_EVENT( - com_ericsson_dyntrace, + org_erlang_dyntrace, gc_major_start, TP_ARGS( char*, p, @@ -342,7 +342,7 @@ TRACEPOINT_EVENT( ) TRACEPOINT_EVENT( - com_ericsson_dyntrace, + org_erlang_dyntrace, gc_major_end, TP_ARGS( char*, p, diff --git a/lib/runtime_tools/doc/src/LTTng.xml b/lib/runtime_tools/doc/src/LTTng.xml index 9b490a27a0..82a4c79379 100644 --- a/lib/runtime_tools/doc/src/LTTng.xml +++ b/lib/runtime_tools/doc/src/LTTng.xml @@ -66,7 +66,7 @@ $ make </code> <section> <title>Dyntrace Tracepoints</title> - <p>All tracepoints are in the domain of <c>com_ericsson_dyntrace</c></p> + <p>All tracepoints are in the domain of <c>org_erlang_dyntrace</c></p> <p>All Erlang types are the string equivalent in LTTng.</p> <p><em>process_spawn</em></p> @@ -310,7 +310,7 @@ $ make </code> <section> <title>BEAM Tracepoints</title> - <p>All tracepoints are in the domain of <c>com_ericsson_otp</c></p> + <p>All tracepoints are in the domain of <c>org_erlang_otp</c></p> <p>All Erlang types are the string equivalent in LTTng.</p> <p><em>scheduler_poll</em></p> @@ -550,8 +550,8 @@ Eshell V8.0 (abort with ^G) <p>Enable the process_register LTTng tracepoint for Erlang.</p> - <pre>$ lttng enable-event -u com_ericsson_dyntrace:process_register -UST event com_ericsson_dyntrace:process_register created in channel channel0</pre> + <pre>$ lttng enable-event -u org_erlang_dyntrace:process_register +UST event org_erlang_dyntrace:process_register created in channel channel0</pre> <p>Enable process tracing for new processes and use <c>dyntrace</c> as tracer backend.</p> @@ -573,23 +573,23 @@ Tracing started for session erlang-demo</pre> <pre>$ lttng stop Tracing stopped for session erlang-demo $ lttng view -[17:20:42.561168759] (+?.?????????) elxd1168lx9 com_ericsson_dyntrace:process_register: \ +[17:20:42.561168759] (+?.?????????) elxd1168lx9 org_erlang_dyntrace:process_register: \ { cpu_id = 5 }, { pid = "<0.66.0>", name = "sasl_sup", type = "register" } -[17:20:42.561215519] (+0.000046760) elxd1168lx9 com_ericsson_dyntrace:process_register: \ +[17:20:42.561215519] (+0.000046760) elxd1168lx9 org_erlang_dyntrace:process_register: \ { cpu_id = 5 }, { pid = "<0.67.0>", name = "sasl_safe_sup", type = "register" } -[17:20:42.562149024] (+0.000933505) elxd1168lx9 com_ericsson_dyntrace:process_register: \ +[17:20:42.562149024] (+0.000933505) elxd1168lx9 org_erlang_dyntrace:process_register: \ { cpu_id = 5 }, { pid = "<0.68.0>", name = "alarm_handler", type = "register" } -[17:20:42.571035803] (+0.008886779) elxd1168lx9 com_ericsson_dyntrace:process_register: \ +[17:20:42.571035803] (+0.008886779) elxd1168lx9 org_erlang_dyntrace:process_register: \ { cpu_id = 5 }, { pid = "<0.69.0>", name = "release_handler", type = "register" } -[17:20:42.574939868] (+0.003904065) elxd1168lx9 com_ericsson_dyntrace:process_register: \ +[17:20:42.574939868] (+0.003904065) elxd1168lx9 org_erlang_dyntrace:process_register: \ { cpu_id = 5 }, { pid = "<0.74.0>", name = "os_mon_sup", type = "register" } -[17:20:42.576818712] (+0.001878844) elxd1168lx9 com_ericsson_dyntrace:process_register: \ +[17:20:42.576818712] (+0.001878844) elxd1168lx9 org_erlang_dyntrace:process_register: \ { cpu_id = 5 }, { pid = "<0.75.0>", name = "disksup", type = "register" } -[17:20:42.580032013] (+0.003213301) elxd1168lx9 com_ericsson_dyntrace:process_register: \ +[17:20:42.580032013] (+0.003213301) elxd1168lx9 org_erlang_dyntrace:process_register: \ { cpu_id = 5 }, { pid = "<0.76.0>", name = "memsup", type = "register" } -[17:20:42.583046339] (+0.003014326) elxd1168lx9 com_ericsson_dyntrace:process_register: \ +[17:20:42.583046339] (+0.003014326) elxd1168lx9 org_erlang_dyntrace:process_register: \ { cpu_id = 5 }, { pid = "<0.78.0>", name = "cpu_sup", type = "register" } -[17:20:42.586206242] (+0.003159903) elxd1168lx9 com_ericsson_dyntrace:process_register: \ +[17:20:42.586206242] (+0.003159903) elxd1168lx9 org_erlang_dyntrace:process_register: \ { cpu_id = 5 }, { pid = "<0.82.0>", name = "timer_server", type = "register" }</pre> </section> </chapter> diff --git a/lib/runtime_tools/test/dyntrace_lttng_SUITE.erl b/lib/runtime_tools/test/dyntrace_lttng_SUITE.erl index 07707c6a12..a98ac6e99c 100644 --- a/lib/runtime_tools/test/dyntrace_lttng_SUITE.erl +++ b/lib/runtime_tools/test/dyntrace_lttng_SUITE.erl @@ -84,25 +84,25 @@ end_per_testcase(Case, _Config) -> %% tracepoints %% -%% com_ericsson_dyntrace:gc_major_end -%% com_ericsson_dyntrace:gc_major_start -%% com_ericsson_dyntrace:gc_minor_end -%% com_ericsson_dyntrace:gc_minor_start -%% com_ericsson_dyntrace:message_receive -%% com_ericsson_dyntrace:message_send -%% -com_ericsson_dyntrace:message_queued -%% com_ericsson_dyntrace:function_exception -%% com_ericsson_dyntrace:function_return -%% com_ericsson_dyntrace:function_call -%% com_ericsson_dyntrace:port_link -%% com_ericsson_dyntrace:port_exit -%% com_ericsson_dyntrace:port_open -%% com_ericsson_dyntrace:port_scheduled -%% com_ericsson_dyntrace:process_scheduled -%% com_ericsson_dyntrace:process_register -%% com_ericsson_dyntrace:process_exit -%% com_ericsson_dyntrace:process_link -%% com_ericsson_dyntrace:process_spawn +%% org_erlang_dyntrace:gc_major_end +%% org_erlang_dyntrace:gc_major_start +%% org_erlang_dyntrace:gc_minor_end +%% org_erlang_dyntrace:gc_minor_start +%% org_erlang_dyntrace:message_receive +%% org_erlang_dyntrace:message_send +%% -org_erlang_dyntrace:message_queued +%% org_erlang_dyntrace:function_exception +%% org_erlang_dyntrace:function_return +%% org_erlang_dyntrace:function_call +%% org_erlang_dyntrace:port_link +%% org_erlang_dyntrace:port_exit +%% org_erlang_dyntrace:port_open +%% org_erlang_dyntrace:port_scheduled +%% org_erlang_dyntrace:process_scheduled +%% org_erlang_dyntrace:process_register +%% org_erlang_dyntrace:process_exit +%% org_erlang_dyntrace:process_link +%% org_erlang_dyntrace:process_spawn %% %% Testcases %% @@ -112,7 +112,7 @@ t_lttng_list(_Config) -> ok. t_procs(Config) when is_list(Config) -> - ok = lttng_start_event("com_ericsson_dyntrace:process_*", Config), + ok = lttng_start_event("org_erlang_dyntrace:process_*", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []},procs]), Pid = spawn_link(fun() -> waiter() end), @@ -122,27 +122,27 @@ t_procs(Config) when is_list(Config) -> _ = erlang:trace(all, false, [procs]), Res = lttng_stop_and_view(Config), - ok = check_tracepoint("com_ericsson_dyntrace:process_spawn", Res), - ok = check_tracepoint("com_ericsson_dyntrace:process_link", Res), - ok = check_tracepoint("com_ericsson_dyntrace:process_exit", Res), - ok = check_tracepoint("com_ericsson_dyntrace:process_register", Res), + ok = check_tracepoint("org_erlang_dyntrace:process_spawn", Res), + ok = check_tracepoint("org_erlang_dyntrace:process_link", Res), + ok = check_tracepoint("org_erlang_dyntrace:process_exit", Res), + ok = check_tracepoint("org_erlang_dyntrace:process_register", Res), ok. t_ports(Config) when is_list(Config) -> - ok = lttng_start_event("com_ericsson_dyntrace:port_*", Config), + ok = lttng_start_event("org_erlang_dyntrace:port_*", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []},ports]), _ = os:cmd("ls"), _ = erlang:trace(all, false, [{tracer, dyntrace, []},ports]), Res = lttng_stop_and_view(Config), - ok = check_tracepoint("com_ericsson_dyntrace:port_open", Res), - ok = check_tracepoint("com_ericsson_dyntrace:port_link", Res), - ok = check_tracepoint("com_ericsson_dyntrace:port_exit", Res), + ok = check_tracepoint("org_erlang_dyntrace:port_open", Res), + ok = check_tracepoint("org_erlang_dyntrace:port_link", Res), + ok = check_tracepoint("org_erlang_dyntrace:port_exit", Res), ok. t_running_process(Config) when is_list(Config) -> - ok = lttng_start_event("com_ericsson_dyntrace:process_scheduled", Config), + ok = lttng_start_event("org_erlang_dyntrace:process_scheduled", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []},running]), Pid = spawn_link(fun() -> waiter() end), @@ -152,11 +152,11 @@ t_running_process(Config) when is_list(Config) -> _ = erlang:trace(all, false, [running]), Res = lttng_stop_and_view(Config), - ok = check_tracepoint("com_ericsson_dyntrace:process_scheduled", Res), + ok = check_tracepoint("org_erlang_dyntrace:process_scheduled", Res), ok. t_running_port(Config) when is_list(Config) -> - ok = lttng_start_event("com_ericsson_dyntrace:port_scheduled", Config), + ok = lttng_start_event("org_erlang_dyntrace:port_scheduled", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []},running_ports]), _ = os:cmd("ls"), @@ -164,12 +164,12 @@ t_running_port(Config) when is_list(Config) -> _ = erlang:trace(all, false, [running_ports]), Res = lttng_stop_and_view(Config), - ok = check_tracepoint("com_ericsson_dyntrace:port_scheduled", Res), + ok = check_tracepoint("org_erlang_dyntrace:port_scheduled", Res), ok. t_call(Config) when is_list(Config) -> - ok = lttng_start_event("com_ericsson_dyntrace:function_*", Config), + ok = lttng_start_event("org_erlang_dyntrace:function_*", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []}, call]), _ = erlang:trace_pattern({?MODULE, '_', '_'}, [{'_',[],[{exception_trace}]}], [local]), @@ -184,13 +184,13 @@ t_call(Config) when is_list(Config) -> _ = erlang:trace_pattern({?MODULE, '_', '_'}, false, [local]), _ = erlang:trace(all, false, [call]), Res = lttng_stop_and_view(Config), - ok = check_tracepoint("com_ericsson_dyntrace:function_call", Res), - ok = check_tracepoint("com_ericsson_dyntrace:function_return", Res), - ok = check_tracepoint("com_ericsson_dyntrace:function_exception", Res), + ok = check_tracepoint("org_erlang_dyntrace:function_call", Res), + ok = check_tracepoint("org_erlang_dyntrace:function_return", Res), + ok = check_tracepoint("org_erlang_dyntrace:function_exception", Res), ok. t_send(Config) when is_list(Config) -> - ok = lttng_start_event("com_ericsson_dyntrace:message_send", Config), + ok = lttng_start_event("org_erlang_dyntrace:message_send", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []},send]), Pid = spawn_link(fun() -> waiter() end), @@ -201,11 +201,11 @@ t_send(Config) when is_list(Config) -> _ = erlang:trace(all, false, [send]), Res = lttng_stop_and_view(Config), - ok = check_tracepoint("com_ericsson_dyntrace:message_send", Res), + ok = check_tracepoint("org_erlang_dyntrace:message_send", Res), ok. t_call_return_to(Config) when is_list(Config) -> - ok = lttng_start_event("com_ericsson_dyntrace:function_*", Config), + ok = lttng_start_event("org_erlang_dyntrace:function_*", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []}, call, return_to]), _ = erlang:trace_pattern({lists, '_', '_'}, true, [local]), _ = erlang:trace_pattern({?MODULE, '_', '_'}, true, [local]), @@ -219,11 +219,11 @@ t_call_return_to(Config) when is_list(Config) -> _ = erlang:trace_pattern({lists, '_', '_'}, false, [local]), _ = erlang:trace(all, false, [call,return_to]), Res = lttng_stop_and_view(Config), - ok = check_tracepoint("com_ericsson_dyntrace:function_call", Res), + ok = check_tracepoint("org_erlang_dyntrace:function_call", Res), ok. t_call_silent(Config) when is_list(Config) -> - ok = lttng_start_event("com_ericsson_dyntrace:function_*", Config), + ok = lttng_start_event("org_erlang_dyntrace:function_*", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []}, call, silent]), _ = erlang:trace_pattern({?MODULE, '_', '_'}, [{'_',[],[{exception_trace}]}], [local]), @@ -238,14 +238,14 @@ t_call_silent(Config) when is_list(Config) -> _ = erlang:trace_pattern({?MODULE, '_', '_'}, false, [local]), _ = erlang:trace(all, false, [call]), Res = lttng_stop_and_view(Config), - notfound = check_tracepoint("com_ericsson_dyntrace:function_call", Res), - notfound = check_tracepoint("com_ericsson_dyntrace:function_return", Res), - notfound = check_tracepoint("com_ericsson_dyntrace:function_exception", Res), + notfound = check_tracepoint("org_erlang_dyntrace:function_call", Res), + notfound = check_tracepoint("org_erlang_dyntrace:function_return", Res), + notfound = check_tracepoint("org_erlang_dyntrace:function_exception", Res), ok. t_receive(Config) when is_list(Config) -> - ok = lttng_start_event("com_ericsson_dyntrace:message_receive", Config), + ok = lttng_start_event("org_erlang_dyntrace:message_receive", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []},'receive']), timer:sleep(20), @@ -260,11 +260,11 @@ t_receive(Config) when is_list(Config) -> timer:sleep(10), _ = erlang:trace(all, false, ['receive']), Res = lttng_stop_and_view(Config), - ok = check_tracepoint("com_ericsson_dyntrace:message_receive", Res), + ok = check_tracepoint("org_erlang_dyntrace:message_receive", Res), ok. t_garbage_collection(Config) when is_list(Config) -> - ok = lttng_start_event("com_ericsson_dyntrace:gc_*", Config), + ok = lttng_start_event("org_erlang_dyntrace:gc_*", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []},garbage_collection]), Pid = spawn_link(fun() -> gcfier() end), @@ -273,14 +273,14 @@ t_garbage_collection(Config) when is_list(Config) -> timer:sleep(10), _ = erlang:trace(all, false, [garbage_collection]), Res = lttng_stop_and_view(Config), - ok = check_tracepoint("com_ericsson_dyntrace:gc_major_start", Res), - ok = check_tracepoint("com_ericsson_dyntrace:gc_major_end", Res), - ok = check_tracepoint("com_ericsson_dyntrace:gc_minor_start", Res), - ok = check_tracepoint("com_ericsson_dyntrace:gc_minor_end", Res), + ok = check_tracepoint("org_erlang_dyntrace:gc_major_start", Res), + ok = check_tracepoint("org_erlang_dyntrace:gc_major_end", Res), + ok = check_tracepoint("org_erlang_dyntrace:gc_minor_start", Res), + ok = check_tracepoint("org_erlang_dyntrace:gc_minor_end", Res), ok. t_all(Config) when is_list(Config) -> - ok = lttng_start_event("com_ericsson_dyntrace:*", Config), + ok = lttng_start_event("org_erlang_dyntrace:*", Config), _ = erlang:trace(new, true, [{tracer, dyntrace, []},all]), Pid1 = spawn_link(fun() -> waiter() end), @@ -297,21 +297,21 @@ t_all(Config) when is_list(Config) -> _ = erlang:trace(all, false, [all]), Res = lttng_stop_and_view(Config), - ok = check_tracepoint("com_ericsson_dyntrace:process_spawn", Res), - ok = check_tracepoint("com_ericsson_dyntrace:process_link", Res), - ok = check_tracepoint("com_ericsson_dyntrace:process_exit", Res), - ok = check_tracepoint("com_ericsson_dyntrace:process_register", Res), - ok = check_tracepoint("com_ericsson_dyntrace:port_open", Res), - ok = check_tracepoint("com_ericsson_dyntrace:port_link", Res), - ok = check_tracepoint("com_ericsson_dyntrace:port_exit", Res), - ok = check_tracepoint("com_ericsson_dyntrace:process_scheduled", Res), - ok = check_tracepoint("com_ericsson_dyntrace:port_scheduled", Res), - ok = check_tracepoint("com_ericsson_dyntrace:message_send", Res), - ok = check_tracepoint("com_ericsson_dyntrace:message_receive", Res), - ok = check_tracepoint("com_ericsson_dyntrace:gc_major_start", Res), - ok = check_tracepoint("com_ericsson_dyntrace:gc_major_end", Res), - ok = check_tracepoint("com_ericsson_dyntrace:gc_minor_start", Res), - ok = check_tracepoint("com_ericsson_dyntrace:gc_minor_end", Res), + ok = check_tracepoint("org_erlang_dyntrace:process_spawn", Res), + ok = check_tracepoint("org_erlang_dyntrace:process_link", Res), + ok = check_tracepoint("org_erlang_dyntrace:process_exit", Res), + ok = check_tracepoint("org_erlang_dyntrace:process_register", Res), + ok = check_tracepoint("org_erlang_dyntrace:port_open", Res), + ok = check_tracepoint("org_erlang_dyntrace:port_link", Res), + ok = check_tracepoint("org_erlang_dyntrace:port_exit", Res), + ok = check_tracepoint("org_erlang_dyntrace:process_scheduled", Res), + ok = check_tracepoint("org_erlang_dyntrace:port_scheduled", Res), + ok = check_tracepoint("org_erlang_dyntrace:message_send", Res), + ok = check_tracepoint("org_erlang_dyntrace:message_receive", Res), + ok = check_tracepoint("org_erlang_dyntrace:gc_major_start", Res), + ok = check_tracepoint("org_erlang_dyntrace:gc_major_end", Res), + ok = check_tracepoint("org_erlang_dyntrace:gc_minor_start", Res), + ok = check_tracepoint("org_erlang_dyntrace:gc_minor_end", Res), ok. diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl index 4dcaec03a7..8134e02221 100644 --- a/lib/sasl/test/release_handler_SUITE.erl +++ b/lib/sasl/test/release_handler_SUITE.erl @@ -1366,7 +1366,7 @@ upgrade_supervisor(Conf) when is_list(Conf) -> ASupBeam2 = rpc:call(Node, code, which, [a_sup]), %% Check that the restart strategy and child spec is updated - {status, _, {module, _}, [_, _, _, _, [_,_,{data,[{"State",State}]}]]} = + {status, _, {module, _}, [_, _, _, _, [_,_,{data,[{"State",State}]}|_]]} = rpc:call(Node,sys,get_status,[a_sup]), {state,_,RestartStrategy,[Child],_,_,_,_,_,_,_} = State, one_for_all = RestartStrategy, % changed from one_for_one diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl index ed9e7aacaa..0f68130a05 100644 --- a/lib/ssh/test/ssh_algorithms_SUITE.erl +++ b/lib/ssh/test/ssh_algorithms_SUITE.erl @@ -24,6 +24,7 @@ -include_lib("common_test/include/ct.hrl"). -include_lib("ssh/src/ssh_transport.hrl"). +-include("ssh_test_lib.hrl"). %% Note: This directive should only be used in test suites. -compile(export_all). @@ -70,32 +71,39 @@ two_way_tags() -> [cipher,mac,compression]. %%-------------------------------------------------------------------- init_per_suite(Config) -> - ct:log("~n" - "Environment:~n============~n" - "os:getenv(\"HOME\") = ~p~n" - "init:get_argument(home) = ~p~n~n~n" - "OS ssh:~n=======~n~p~n~n~n" - "Erl ssh:~n========~n~p~n~n~n" - "Installed ssh client:~n=====================~n~p~n~n~n" - "Installed ssh server:~n=====================~n~p~n~n~n" - "Misc values:~n============~n" - " -- Default dh group exchange parameters ({min,def,max}): ~p~n" - " -- dh_default_groups: ~p~n" - " -- Max num algorithms: ~p~n" - ,[os:getenv("HOME"), - init:get_argument(home), - os:cmd("ssh -V"), - ssh:default_algorithms(), - ssh_test_lib:default_algorithms(sshc), - ssh_test_lib:default_algorithms(sshd), - {?DEFAULT_DH_GROUP_MIN,?DEFAULT_DH_GROUP_NBITS,?DEFAULT_DH_GROUP_MAX}, - public_key:dh_gex_group_sizes(), - ?MAX_NUM_ALGORITHMS - ]), - ct:log("all() ->~n ~p.~n~ngroups()->~n ~p.~n",[all(),groups()]), - ssh:start(), - [{std_simple_sftp_size,25000} % Sftp transferred data size - | setup_pubkey(Config)]. + ?CHECK_CRYPTO( + begin + ct:log("~n" + "Environment:~n============~n" + "os:getenv(\"HOME\") = ~p~n" + "init:get_argument(home) = ~p~n~n~n" + "OS ssh:~n=======~n~p~n~n~n" + "Erl ssh:~n========~n~p~n~n~n" + "crypto:info_lib():~n========~n~p~n~n~n" + "Installed ssh client:~n=====================~n~p~n~n~n" + "Installed ssh server:~n=====================~n~p~n~n~n" + "Misc values:~n============~n" + " -- Default dh group exchange parameters ({min,def,max}): ~p~n" + " -- dh_default_groups: ~p~n" + " -- Max num algorithms: ~p~n" + ,[os:getenv("HOME"), + init:get_argument(home), + os:cmd("ssh -V"), + ssh:default_algorithms(), + crypto:info_lib(), + ssh_test_lib:default_algorithms(sshc), + ssh_test_lib:default_algorithms(sshd), + {?DEFAULT_DH_GROUP_MIN,?DEFAULT_DH_GROUP_NBITS,?DEFAULT_DH_GROUP_MAX}, + public_key:dh_gex_group_sizes(), + ?MAX_NUM_ALGORITHMS + ]), + ct:log("all() ->~n ~p.~n~ngroups()->~n ~p.~n",[all(),groups()]), + ssh:start(), + [{std_simple_sftp_size,25000} % Sftp transferred data size + | setup_pubkey(Config)] + end + ). + end_per_suite(_Config) -> ssh:stop(). diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl index 4991816850..733414e23a 100644 --- a/lib/ssh/test/ssh_basic_SUITE.erl +++ b/lib/ssh/test/ssh_basic_SUITE.erl @@ -25,6 +25,7 @@ -include_lib("common_test/include/ct.hrl"). -include_lib("kernel/include/inet.hrl"). -include_lib("kernel/include/file.hrl"). +-include("ssh_test_lib.hrl"). %% Note: This directive should only be used in test suites. %%-compile(export_all). @@ -130,7 +131,7 @@ basic_tests() -> %%-------------------------------------------------------------------- init_per_suite(Config) -> - Config. + ?CHECK_CRYPTO(Config). end_per_suite(_Config) -> ssh:stop(). diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl index a52633a269..bcf3b01824 100644 --- a/lib/ssh/test/ssh_connection_SUITE.erl +++ b/lib/ssh/test/ssh_connection_SUITE.erl @@ -43,6 +43,7 @@ suite() -> all() -> [ {group, openssh}, + small_interrupted_send, interrupted_send, start_shell, start_shell_exec, @@ -81,7 +82,7 @@ sock() -> %%-------------------------------------------------------------------- init_per_suite(Config) -> - Config. + ?CHECK_CRYPTO(Config). end_per_suite(Config) -> Config. @@ -124,7 +125,7 @@ simple_exec(Config) when is_list(Config) -> do_simple_exec(ConnectionRef). -simple_exec_sock(Config) -> +simple_exec_sock(_Config) -> {ok, Sock} = gen_tcp:connect("localhost", ?SSH_DEFAULT_PORT, [{active,false}]), {ok, ConnectionRef} = ssh:connect(Sock, [{silently_accept_hosts, true}, {user_interaction, false}]), @@ -361,44 +362,96 @@ ptty_alloc_pixel(Config) when is_list(Config) -> ssh:close(ConnectionRef). %%-------------------------------------------------------------------- +small_interrupted_send(Config) -> + K = 1024, + M = K*K, + do_interrupted_send(Config, 10*M, 4*K). interrupted_send(Config) -> + M = 1024*1024, + do_interrupted_send(Config, 10*M, 4*M). + +do_interrupted_send(Config, SendSize, EchoSize) -> PrivDir = proplists:get_value(priv_dir, Config), UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth file:make_dir(UserDir), SysDir = proplists:get_value(data_dir, Config), + EchoSS_spec = {ssh_echo_server, [EchoSize,[{dbg,true}]]}, {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, {user_dir, UserDir}, {password, "morot"}, - {subsystems, [{"echo_n", {ssh_echo_server, [4000000]}}]}]), - + {subsystems, [{"echo_n",EchoSS_spec}]}]), + + ct:log("connect", []), ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, {user, "foo"}, {password, "morot"}, {user_interaction, false}, {user_dir, UserDir}]), - - {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity), - - success = ssh_connection:subsystem(ConnectionRef, ChannelId, "echo_n", infinity), - - %% build 10MB binary - Data = << <<X:32>> || X <- lists:seq(1,2500000)>>, - - %% expect remote end to send us 4MB back - <<ExpectedData:4000000/binary, _/binary>> = Data, - - %% pre-adjust receive window so the other end doesn't block - ssh_connection:adjust_window(ConnectionRef, ChannelId, size(ExpectedData) + 1), - - case ssh_connection:send(ConnectionRef, ChannelId, Data, 10000) of - {error, closed} -> - ok; - Msg -> - ct:fail({expected,{error,closed}, got, Msg}) - end, - receive_data(ExpectedData, ConnectionRef, ChannelId), - ssh:close(ConnectionRef), - ssh:stop_daemon(Pid). + ct:log("connected", []), + + %% build big binary + Data = << <<X:32>> || X <- lists:seq(1,SendSize div 4)>>, + + %% expect remote end to send us EchoSize back + <<ExpectedData:EchoSize/binary, _/binary>> = Data, + + %% Spawn listener. Otherwise we could get a deadlock due to filled buffers + Parent = self(), + ResultPid = spawn( + fun() -> + ct:log("open channel",[]), + {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity), + ct:log("start subsystem", []), + case ssh_connection:subsystem(ConnectionRef, ChannelId, "echo_n", infinity) of + success -> + Parent ! {self(), channelId, ChannelId}, + + Result = + try collect_data(ConnectionRef, ChannelId) + of + ExpectedData -> + ok; + _ -> + {fail,"unexpected result"} + catch + Class:Exception -> + {fail, io_lib:format("Exception ~p:~p",[Class,Exception])} + end, + Parent ! {self(), Result}; + Other -> + Parent ! {self(), channelId, error, Other} + end + end), + + receive + {ResultPid, channelId, ChannelId} -> + %% pre-adjust receive window so the other end doesn't block + ct:log("adjust window", []), + ssh_connection:adjust_window(ConnectionRef, ChannelId, size(ExpectedData) + 1), + + ct:log("going to send ~p bytes", [size(Data)]), + case ssh_connection:send(ConnectionRef, ChannelId, Data, 30000) of + {error, closed} -> + ct:log("{error,closed} - That's what we expect :)", []), + ok; + Msg -> + ct:log("Got ~p - that's bad, very bad indeed",[Msg]), + ct:fail({expected,{error,closed}, got, Msg}) + end, + ct:log("going to check the result (if it is available)", []), + receive + {ResultPid, Result} -> + ct:log("Got result: ~p", [Result]), + ssh:close(ConnectionRef), + ssh:stop_daemon(Pid), + Result + end; + + {ResultPid, channelId, error, Other} -> + ssh:close(ConnectionRef), + ssh:stop_daemon(Pid), + {fail, io_lib:format("ssh_connection:subsystem: ~p",[Other])} + end. %%-------------------------------------------------------------------- start_shell() -> @@ -549,10 +602,10 @@ start_shell_sock_daemon_exec(Config) -> spawn_link(fun() -> {ok,Ss} = gen_tcp:connect("localhost", Port, [{active,false}]), - {ok, Pid} = ssh:daemon(Ss, [{system_dir, SysDir}, - {user_dir, UserDir}, - {password, "morot"}, - {exec, fun ssh_exec/1}]) + {ok, _Pid} = ssh:daemon(Ss, [{system_dir, SysDir}, + {user_dir, UserDir}, + {password, "morot"}, + {exec, fun ssh_exec/1}]) end), {ok,Sc} = gen_tcp:accept(Sl), {ok,ConnectionRef} = ssh:connect(Sc, [{silently_accept_hosts, true}, @@ -856,20 +909,36 @@ big_cat_rx(ConnectionRef, ChannelId, Acc) -> timeout end. -receive_data(ExpectedData, ConnectionRef, ChannelId) -> - ExpectedData = collect_data(ConnectionRef, ChannelId). - collect_data(ConnectionRef, ChannelId) -> - collect_data(ConnectionRef, ChannelId, []). + ct:log("Listener ~p running! ConnectionRef=~p, ChannelId=~p",[self(),ConnectionRef,ChannelId]), + collect_data(ConnectionRef, ChannelId, [], 0). -collect_data(ConnectionRef, ChannelId, Acc) -> +collect_data(ConnectionRef, ChannelId, Acc, Sum) -> + TO = 5000, receive - {ssh_cm, ConnectionRef, {data, ChannelId, 0, Data}} -> - collect_data(ConnectionRef, ChannelId, [Data | Acc]); + {ssh_cm, ConnectionRef, {data, ChannelId, 0, Data}} when is_binary(Data) -> + ct:log("collect_data: received ~p bytes. total ~p bytes",[size(Data),Sum+size(Data)]), + collect_data(ConnectionRef, ChannelId, [Data | Acc], Sum+size(Data)); {ssh_cm, ConnectionRef, {eof, ChannelId}} -> - iolist_to_binary(lists:reverse(Acc)) - after 5000 -> - timeout + try + iolist_to_binary(lists:reverse(Acc)) + of + Bin -> + ct:log("collect_data: received eof.~nGot in total ~p bytes",[size(Bin)]), + Bin + catch + C:E -> + ct:log("collect_data: received eof.~nAcc is strange...~nException=~p:~p~nAcc=~p", + [C,E,Acc]), + {error,{C,E}} + end; + Msg -> + ct:log("collect_data: ***** unexpected message *****~n~p",[Msg]), + collect_data(ConnectionRef, ChannelId, Acc, Sum) + + after TO -> + ct:log("collect_data: ----- Nothing received for ~p seconds -----~n",[]), + collect_data(ConnectionRef, ChannelId, Acc, Sum) end. %%%------------------------------------------------------------------- diff --git a/lib/ssh/test/ssh_echo_server.erl b/lib/ssh/test/ssh_echo_server.erl index ed9bbe1b67..5387d21efd 100644 --- a/lib/ssh/test/ssh_echo_server.erl +++ b/lib/ssh/test/ssh_echo_server.erl @@ -26,15 +26,29 @@ -record(state, { n, id, - cm + cm, + dbg = false }). -export([init/1, handle_msg/2, handle_ssh_msg/2, terminate/2]). +-define(DBG(State,Fmt,Args), + case State#state.dbg of + true -> ct:log("~p:~p ~p "++Fmt, [?MODULE,?LINE,self()|Args]); + false -> ok + end). + + init([N]) -> - ct:pal("Echo server: ~p",[self()]), - {ok, #state{n = N}}. + {ok, #state{n = N}}; +init([N,Opts]) -> + State = #state{n = N, + dbg = proplists:get_value(dbg,Opts,false) + }, + ?DBG(State, "init([~p])",[N]), + {ok, State}. handle_msg({ssh_channel_up, ChannelId, ConnectionManager}, State) -> + ?DBG(State, "ssh_channel_up Cid=~p ConnMngr=~p",[ChannelId,ConnectionManager]), {ok, State#state{id = ChannelId, cm = ConnectionManager}}. @@ -42,32 +56,39 @@ handle_ssh_msg({ssh_cm, CM, {data, ChannelId, 0, Data}}, #state{n = N} = State) M = N - size(Data), case M > 0 of true -> + ?DBG(State, "ssh_cm data Cid=~p size(Data)=~p M=~p",[ChannelId,size(Data),M]), ssh_connection:send(CM, ChannelId, Data), {ok, State#state{n = M}}; false -> <<SendData:N/binary, _/binary>> = Data, + ?DBG(State, "ssh_cm data Cid=~p size(Data)=~p M=~p size(SendData)=~p~nSend eof",[ChannelId,size(Data),M,size(SendData)]), ssh_connection:send(CM, ChannelId, SendData), ssh_connection:send_eof(CM, ChannelId), {stop, ChannelId, State} end; handle_ssh_msg({ssh_cm, _ConnectionManager, {data, _ChannelId, 1, Data}}, State) -> + ?DBG(State, "stderr: ~p",[Data]), error_logger:format(standard_error, " ~p~n", [binary_to_list(Data)]), {ok, State}; handle_ssh_msg({ssh_cm, _ConnectionManager, {eof, _ChannelId}}, State) -> + ?DBG(State, "{eof ~p}",[_ChannelId]), {ok, State}; -handle_ssh_msg({ssh_cm, _, {signal, _, _}}, State) -> +handle_ssh_msg({ssh_cm, _, _Sig={signal, _, _}}, State) -> %% Ignore signals according to RFC 4254 section 6.9. + ?DBG(State, "~p",[_Sig]), {ok, State}; -handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, _, _Error, _}}, - State) -> +handle_ssh_msg({ssh_cm, _, _Sig={exit_signal, ChannelId, _, _Error, _}}, State) -> + ?DBG(State, "~p",[_Sig]), {stop, ChannelId, State}; -handle_ssh_msg({ssh_cm, _, {exit_status, ChannelId, _Status}}, State) -> +handle_ssh_msg({ssh_cm, _, _Sig={exit_status, ChannelId, _Status}}, State) -> + ?DBG(State, "~p",[_Sig]), {stop, ChannelId, State}. terminate(_Reason, _State) -> + ?DBG(_State, "terminate ~p",[_Reason]), ok. diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl index d1e3d6cb0e..61883c0647 100644 --- a/lib/ssh/test/ssh_options_SUITE.erl +++ b/lib/ssh/test/ssh_options_SUITE.erl @@ -27,7 +27,7 @@ -include_lib("common_test/include/ct.hrl"). -include_lib("kernel/include/file.hrl"). - +-include("ssh_test_lib.hrl"). %%% Test cases -export([connectfun_disconnectfun_client/1, @@ -126,7 +126,7 @@ groups() -> %%-------------------------------------------------------------------- init_per_suite(Config) -> - Config. + ?CHECK_CRYPTO(Config). end_per_suite(_Config) -> ssh:stop(). diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl index 41faf951e1..4fac1f718a 100644 --- a/lib/ssh/test/ssh_protocol_SUITE.erl +++ b/lib/ssh/test/ssh_protocol_SUITE.erl @@ -26,6 +26,7 @@ -include_lib("ssh/src/ssh.hrl"). % ?UINT32, ?BYTE, #ssh{} ... -include_lib("ssh/src/ssh_transport.hrl"). -include_lib("ssh/src/ssh_auth.hrl"). +-include("ssh_test_lib.hrl"). %% Note: This directive should only be used in test suites. -compile(export_all). @@ -87,7 +88,7 @@ groups() -> init_per_suite(Config) -> - start_std_daemon( setup_dirs( start_apps(Config))). + ?CHECK_CRYPTO(start_std_daemon( setup_dirs( start_apps(Config)))). end_per_suite(Config) -> stop_apps(Config). diff --git a/lib/ssh/test/ssh_renegotiate_SUITE.erl b/lib/ssh/test/ssh_renegotiate_SUITE.erl index 300816276a..b10ec3707f 100644 --- a/lib/ssh/test/ssh_renegotiate_SUITE.erl +++ b/lib/ssh/test/ssh_renegotiate_SUITE.erl @@ -21,6 +21,7 @@ -module(ssh_renegotiate_SUITE). -include_lib("common_test/include/ct.hrl"). +-include("ssh_test_lib.hrl"). %% Note: This directive should only be used in test suites. -compile(export_all). @@ -45,7 +46,7 @@ tests() -> [rekey, rekey_limit, renegotiate1, renegotiate2]. %%-------------------------------------------------------------------- init_per_suite(Config) -> - Config. + ?CHECK_CRYPTO(Config). end_per_suite(_Config) -> ssh:stop(). diff --git a/lib/ssh/test/ssh_sftp_SUITE.erl b/lib/ssh/test/ssh_sftp_SUITE.erl index 19cf6d446e..19ad81e7da 100644 --- a/lib/ssh/test/ssh_sftp_SUITE.erl +++ b/lib/ssh/test/ssh_sftp_SUITE.erl @@ -26,7 +26,7 @@ -include_lib("common_test/include/ct.hrl"). -include_lib("kernel/include/file.hrl"). - +-include("ssh_test_lib.hrl"). % Default timetrap timeout -define(default_timeout, ?t:minutes(1)). @@ -45,10 +45,13 @@ all() -> init_per_suite(Config) -> - ct:log("file:native_name_encoding() = ~p,~nio:getopts() = ~p", - [file:native_name_encoding(),io:getopts()]), - ssh:start(), - Config. + ?CHECK_CRYPTO( + begin + ct:log("file:native_name_encoding() = ~p,~nio:getopts() = ~p", + [file:native_name_encoding(),io:getopts()]), + ssh:start(), + Config + end). end_per_suite(_onfig) -> ssh:stop(). diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl index 4a69fd36b3..52a26110c4 100644 --- a/lib/ssh/test/ssh_sftpd_SUITE.erl +++ b/lib/ssh/test/ssh_sftpd_SUITE.erl @@ -28,6 +28,7 @@ -include_lib("kernel/include/file.hrl"). -include("ssh_xfer.hrl"). -include("ssh.hrl"). +-include("ssh_test_lib.hrl"). -define(USER, "Alladin"). -define(PASSWD, "Sesame"). @@ -72,14 +73,17 @@ groups() -> %%-------------------------------------------------------------------- init_per_suite(Config) -> - DataDir = proplists:get_value(data_dir, Config), - PrivDir = proplists:get_value(priv_dir, Config), - ssh_test_lib:setup_dsa(DataDir, PrivDir), - %% to make sure we don't use public-key-auth - %% this should be tested by other test suites - UserDir = filename:join(proplists:get_value(priv_dir, Config), nopubkey), - file:make_dir(UserDir), - Config. + ?CHECK_CRYPTO( + begin + DataDir = proplists:get_value(data_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), + ssh_test_lib:setup_dsa(DataDir, PrivDir), + %% to make sure we don't use public-key-auth + %% this should be tested by other test suites + UserDir = filename:join(proplists:get_value(priv_dir, Config), nopubkey), + file:make_dir(UserDir), + Config + end). end_per_suite(Config) -> SysDir = proplists:get_value(priv_dir, Config), diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl index 75b5090c2b..56a33d6349 100644 --- a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl +++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl @@ -26,6 +26,7 @@ -include_lib("common_test/include/ct.hrl"). -include_lib("kernel/include/file.hrl"). +-include("ssh_test_lib.hrl"). -define(USER, "Alladin"). -define(PASSWD, "Sesame"). @@ -53,17 +54,20 @@ groups() -> %%-------------------------------------------------------------------- init_per_suite(Config) -> - catch ssh:stop(), - DataDir = proplists:get_value(data_dir, Config), - PrivDir = proplists:get_value(priv_dir, Config), - FileAlt = filename:join(DataDir, "ssh_sftpd_file_alt.erl"), - c:c(FileAlt), - FileName = filename:join(DataDir, "test.txt"), - {ok, FileInfo} = file:read_file_info(FileName), - ok = file:write_file_info(FileName, - FileInfo#file_info{mode = 8#400}), - ssh_test_lib:setup_dsa(DataDir, PrivDir), - Config. + ?CHECK_CRYPTO( + begin + catch ssh:stop(), + DataDir = proplists:get_value(data_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), + FileAlt = filename:join(DataDir, "ssh_sftpd_file_alt.erl"), + c:c(FileAlt), + FileName = filename:join(DataDir, "test.txt"), + {ok, FileInfo} = file:read_file_info(FileName), + ok = file:write_file_info(FileName, + FileInfo#file_info{mode = 8#400}), + ssh_test_lib:setup_dsa(DataDir, PrivDir), + Config + end). end_per_suite(Config) -> UserDir = filename:join(proplists:get_value(priv_dir, Config), nopubkey), diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl index 574564f6e9..ff53e1c4c6 100644 --- a/lib/ssh/test/ssh_sup_SUITE.erl +++ b/lib/ssh/test/ssh_sup_SUITE.erl @@ -53,11 +53,14 @@ end_per_group(_GroupName, Config) -> Config. init_per_suite(Config) -> - Port = ssh_test_lib:inet_port(node()), - PrivDir = proplists:get_value(priv_dir, Config), - UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth - file:make_dir(UserDir), - [{userdir, UserDir},{port, Port}, {host, "localhost"}, {host_ip, any} | Config]. + ?CHECK_CRYPTO( + begin + Port = ssh_test_lib:inet_port(node()), + PrivDir = proplists:get_value(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + [{userdir, UserDir},{port, Port}, {host, "localhost"}, {host_ip, any} | Config] + end). end_per_suite(_) -> ok. diff --git a/lib/ssh/test/ssh_test_lib.hrl b/lib/ssh/test/ssh_test_lib.hrl index 7cb7edeaa8..54c93b7e87 100644 --- a/lib/ssh/test/ssh_test_lib.hrl +++ b/lib/ssh/test/ssh_test_lib.hrl @@ -1,4 +1,14 @@ %%------------------------------------------------------------------------- +%% Check for usable crypt +%%------------------------------------------------------------------------- +-define(CHECK_CRYPTO(Available), + try crypto:start() + of _ -> Available + catch _:_ -> {skip, "Can't start crypto"} + end + ). + +%%------------------------------------------------------------------------- %% Help macro %%------------------------------------------------------------------------- -define(wait_match(Pattern, FunctionCall, Bind, Timeout, Ntries), diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl index f96a2cc62b..a914938c41 100644 --- a/lib/ssh/test/ssh_to_openssh_SUITE.erl +++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl @@ -22,6 +22,7 @@ -module(ssh_to_openssh_SUITE). -include_lib("common_test/include/ct.hrl"). +-include("ssh_test_lib.hrl"). %% Note: This directive should only be used in test suites. -compile(export_all). @@ -62,12 +63,14 @@ groups() -> ]. init_per_suite(Config) -> - case gen_tcp:connect("localhost", 22, []) of - {error,econnrefused} -> - {skip,"No openssh deamon"}; - _ -> - ssh_test_lib:openssh_sanity_check(Config) - end. + ?CHECK_CRYPTO( + case gen_tcp:connect("localhost", 22, []) of + {error,econnrefused} -> + {skip,"No openssh deamon"}; + _ -> + ssh_test_lib:openssh_sanity_check(Config) + end + ). end_per_suite(_Config) -> ok. diff --git a/lib/ssh/test/ssh_upgrade_SUITE.erl b/lib/ssh/test/ssh_upgrade_SUITE.erl index 9d9b2b78fb..b5b27c369a 100644 --- a/lib/ssh/test/ssh_upgrade_SUITE.erl +++ b/lib/ssh/test/ssh_upgrade_SUITE.erl @@ -23,6 +23,7 @@ -compile(export_all). -include_lib("common_test/include/ct.hrl"). +-include("ssh_test_lib.hrl"). -record(state, { config, @@ -48,13 +49,15 @@ all() -> ]. init_per_suite(Config0) -> - case ct_release_test:init(Config0) of - {skip, Reason} -> - {skip, Reason}; - Config -> - ssh:start(), - Config - end. + ?CHECK_CRYPTO( + case ct_release_test:init(Config0) of + {skip, Reason} -> + {skip, Reason}; + Config -> + ssh:start(), + Config + end + ). end_per_suite(Config) -> ct_release_test:cleanup(Config), diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index 62f6263e9e..bed82cdb91 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -901,6 +901,23 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> + <name>getstat(Socket) -> + {ok, OptionValues} | {error, inet:posix()}</name> + <name>getstat(Socket, OptionNames) -> + {ok, OptionValues} | {error, inet:posix()}</name> + <fsummary>Get one or more statistic options for a socket</fsummary> + <type> + <v>Socket = sslsocket()</v> + <v>OptionNames = [atom()]</v> + <v>OptionValues = [{inet:stat_option(), integer()}]</v> + </type> + <desc> + <p>Gets one or more statistic options for the underlying TCP socket.</p> + <p>See inet:getstat/2 for statistic options description.</p> + </desc> + </func> + + <func> <name>listen(Port, Options) -> {ok, ListenSocket} | {error, Reason}</name> <fsummary>Creates an SSL listen socket.</fsummary> diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 0058e5ec9a..d2aeb3258f 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -34,7 +34,8 @@ listen/2, transport_accept/1, transport_accept/2, ssl_accept/1, ssl_accept/2, ssl_accept/3, controlling_process/2, peername/1, peercert/1, sockname/1, - close/1, close/2, shutdown/2, recv/2, recv/3, send/2, getopts/2, setopts/2 + close/1, close/2, shutdown/2, recv/2, recv/3, send/2, + getopts/2, setopts/2, getstat/1, getstat/2 ]). %% SSL/TLS protocol handling -export([cipher_suites/0, cipher_suites/1, @@ -469,6 +470,32 @@ setopts(#sslsocket{}, Options) -> {error, {options,{not_a_proplist, Options}}}. %%--------------------------------------------------------------- +-spec getstat(Socket) -> + {ok, OptionValues} | {error, inet:posix()} when + Socket :: #sslsocket{}, + OptionValues :: [{inet:stat_option(), integer()}]. +%% +%% Description: Get all statistic options for a socket. +%%-------------------------------------------------------------------- +getstat(Socket) -> + getstat(Socket, inet:stats()). + +%%--------------------------------------------------------------- +-spec getstat(Socket, Options) -> + {ok, OptionValues} | {error, inet:posix()} when + Socket :: #sslsocket{}, + Options :: [inet:stat_option()], + OptionValues :: [{inet:stat_option(), integer()}]. +%% +%% Description: Get one or more statistic options for a socket. +%%-------------------------------------------------------------------- +getstat(#sslsocket{pid = {Listen, #config{transport_info = {Transport, _, _, _}}}}, Options) when is_port(Listen), is_list(Options) -> + ssl_socket:getstat(Transport, Listen, Options); + +getstat(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}, Options) when is_pid(Pid), is_list(Options) -> + ssl_socket:getstat(Transport, Socket, Options). + +%%--------------------------------------------------------------- -spec shutdown(#sslsocket{}, read | write | read_write) -> ok | {error, reason()}. %% %% Description: Same as gen_tcp:shutdown/2 diff --git a/lib/ssl/src/ssl_crl.erl b/lib/ssl/src/ssl_crl.erl index faf5007b16..d9f21e04ac 100644 --- a/lib/ssl/src/ssl_crl.erl +++ b/lib/ssl/src/ssl_crl.erl @@ -39,13 +39,12 @@ trusted_cert_and_path(CRL, {SerialNumber, Issuer},{Db, DbRef} = DbHandle) -> end; trusted_cert_and_path(CRL, issuer_not_found, {Db, DbRef} = DbHandle) -> - try find_issuer(CRL, DbHandle) of - OtpCert -> + case find_issuer(CRL, DbHandle) of + {ok, OtpCert} -> {ok, Root, Chain} = ssl_certificate:certificate_chain(OtpCert, Db, DbRef), - {ok, Root, lists:reverse(Chain)} - catch - throw:_ -> - {error, issuer_not_found} + {ok, Root, lists:reverse(Chain)}; + {error, issuer_not_found} -> + {ok, unknown_crl_ca, []} end. find_issuer(CRL, {Db,_}) -> @@ -61,11 +60,10 @@ find_issuer(CRL, {Db,_}) -> issuer_not_found -> {error, issuer_not_found} catch - {ok, IssuerCert} -> - IssuerCert + {ok, _} = Result -> + Result end. - verify_crl_issuer(CRL, ErlCertCandidate, Issuer, NotIssuer) -> TBSCert = ErlCertCandidate#'OTPCertificate'.tbsCertificate, case public_key:pkix_normalize_name(TBSCert#'OTPTBSCertificate'.subject) of diff --git a/lib/ssl/src/ssl_socket.erl b/lib/ssl/src/ssl_socket.erl index 95a70a4602..b2aea2ba9c 100644 --- a/lib/ssl/src/ssl_socket.erl +++ b/lib/ssl/src/ssl_socket.erl @@ -24,7 +24,7 @@ -include("ssl_internal.hrl"). -include("ssl_api.hrl"). --export([socket/5, setopts/3, getopts/3, peername/2, sockname/2, port/2]). +-export([socket/5, setopts/3, getopts/3, getstat/3, peername/2, sockname/2, port/2]). -export([emulated_options/0, internal_inet_values/0, default_inet_values/0, init/1, start_link/3, terminate/2, inherit_tracker/3, get_emulated_opts/1, set_emulated_opts/2, get_all_opts/1, handle_call/3, handle_cast/2, @@ -74,6 +74,11 @@ getopts(gen_tcp, Socket, Options) -> getopts(Transport, Socket, Options) -> Transport:getopts(Socket, Options). +getstat(gen_tcp, Socket, Options) -> + inet:getstat(Socket, Options); +getstat(Transport, Socket, Options) -> + Transport:getstat(Socket, Options). + peername(gen_tcp, Socket) -> inet:peername(Socket); peername(Transport, Socket) -> diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index efe996e57c..93b6ae66dc 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -150,6 +150,7 @@ api_tests() -> sockname, versions, controlling_process, + getstat, close_with_timeout, hibernate, hibernate_right_away, @@ -691,6 +692,75 @@ controlling_process(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- +getstat() -> + [{doc,"Test API function getstat/2"}]. + +getstat(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server1 = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result, []}}, + {options, [{active, false} | ServerOpts]}]), + Port1 = ssl_test_lib:inet_port(Server1), + Server2 = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result, []}}, + {options, [{active, false} | ServerOpts]}]), + Port2 = ssl_test_lib:inet_port(Server2), + {ok, ActiveC} = rpc:call(ClientNode, ssl, connect, + [Hostname,Port1,[{active, once}|ClientOpts]]), + {ok, PassiveC} = rpc:call(ClientNode, ssl, connect, + [Hostname,Port2,[{active, false}|ClientOpts]]), + + ct:log("Testcase ~p, Client ~p Servers ~p, ~p ~n", + [self(), self(), Server1, Server2]), + + %% We only check that the values are non-zero initially + %% (due to the handshake), and that sending more changes the values. + + %% Passive socket. + + {ok, InitialStats} = ssl:getstat(PassiveC), + ct:pal("InitialStats ~p~n", [InitialStats]), + [true] = lists:usort([0 =/= proplists:get_value(Name, InitialStats) + || Name <- [recv_cnt, recv_oct, recv_avg, recv_max, send_cnt, send_oct, send_avg, send_max]]), + + ok = ssl:send(PassiveC, "Hello world"), + wait_for_send(PassiveC), + {ok, SStats} = ssl:getstat(PassiveC, [send_cnt, send_oct]), + ct:pal("SStats ~p~n", [SStats]), + [true] = lists:usort([proplists:get_value(Name, SStats) =/= proplists:get_value(Name, InitialStats) + || Name <- [send_cnt, send_oct]]), + + %% Active socket. + + {ok, InitialAStats} = ssl:getstat(ActiveC), + ct:pal("InitialAStats ~p~n", [InitialAStats]), + [true] = lists:usort([0 =/= proplists:get_value(Name, InitialAStats) + || Name <- [recv_cnt, recv_oct, recv_avg, recv_max, send_cnt, send_oct, send_avg, send_max]]), + + _ = receive + {ssl, ActiveC, _} -> + ok + after + ?SLEEP -> + exit(timeout) + end, + + ok = ssl:send(ActiveC, "Hello world"), + wait_for_send(ActiveC), + {ok, ASStats} = ssl:getstat(ActiveC, [send_cnt, send_oct]), + ct:pal("ASStats ~p~n", [ASStats]), + [true] = lists:usort([proplists:get_value(Name, ASStats) =/= proplists:get_value(Name, InitialAStats) + || Name <- [send_cnt, send_oct]]), + + ok. + +%%-------------------------------------------------------------------- controller_dies() -> [{doc,"Test that the socket is closed after controlling process dies"}]. controller_dies(Config) when is_list(Config) -> @@ -4592,4 +4662,6 @@ first_rsa_suite([{rsa, _, _, _} = Suite| _]) -> first_rsa_suite([_ | Rest]) -> first_rsa_suite(Rest). - +wait_for_send(Socket) -> + %% Make sure TLS process processed send message event + _ = ssl:connection_information(Socket). diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index a896de4f1c..1de09aae62 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -170,9 +170,6 @@ fun_type -> '(' top_types ')' '->' top_type : {type, ?anno('$1'), 'fun', [{type, ?anno('$1'), product, '$2'},'$5']}. -map_pair_types -> '...' : [{type, ?anno('$1'), map_field_assoc, - [{type, ?anno('$1'), any, []}, - {type, ?anno('$1'), any, []}]}]. map_pair_types -> map_pair_type : ['$1']. map_pair_types -> map_pair_type ',' map_pair_types : ['$1'|'$3']. diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl index ca764675fc..4009300a32 100644 --- a/lib/stdlib/src/erl_pp.erl +++ b/lib/stdlib/src/erl_pp.erl @@ -344,27 +344,9 @@ binary_type(I1, I2) -> map_type(Fs) -> {first,[$#],map_pair_types(Fs)}. -map_pair_types(Fs0) -> - Fs = replace_any_map(Fs0), +map_pair_types(Fs) -> tuple_type(Fs, fun map_pair_type/2). -replace_any_map([{type,Line,map_field_assoc,[KType,VType]}]=Fs) -> - IsAny = fun({type,_,any,[]}) -> true; - %% ({var,_,'_'}) -> true; - (_) -> false - end, - case IsAny(KType) andalso IsAny(VType) of - true -> - [{type,Line,map_field_assoc,any}]; - false -> - Fs - end; -replace_any_map([F|Fs]) -> - [F|replace_any_map(Fs)]; -replace_any_map([]) -> []. - -map_pair_type({type,_Line,map_field_assoc,any}, _Prec) -> - leaf("..."); map_pair_type({type,_Line,map_field_assoc,[KType,VType]}, Prec) -> {list,[{cstep,[ltype(KType, Prec),leaf(" =>")],ltype(VType, Prec)}]}; map_pair_type({type,_Line,map_field_exact,[KType,VType]}, Prec) -> diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl index a594c66fa7..c81e72689c 100644 --- a/lib/stdlib/src/supervisor.erl +++ b/lib/stdlib/src/supervisor.erl @@ -30,7 +30,7 @@ %% Internal exports -export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). + terminate/2, code_change/3, format_status/2]). -export([try_again_restart/2]). %% For release_handler only @@ -264,8 +264,13 @@ cast(Supervisor, Req) -> get_callback_module(Pid) -> {status, _Pid, {module, _Mod}, [_PDict, _SysState, _Parent, _Dbg, Misc]} = sys:get_status(Pid), - [_Header, _Data, {data, [{"State", State}]}] = Misc, - State#state.module. + case lists:keyfind(supervisor, 1, Misc) of + {supervisor, [{"Callback", Mod}]} -> + Mod; + _ -> + [_Header, _Data, {data, [{"State", State}]} | _] = Misc, + State#state.module + end. %%% --------------------------------------------------- %%% @@ -1450,3 +1455,9 @@ report_progress(Child, SupName) -> Progress = [{supervisor, SupName}, {started, extract_child(Child)}], error_logger:info_report(progress, Progress). + +format_status(terminate, [_PDict, State]) -> + State; +format_status(_, [_PDict, State]) -> + [{data, [{"State", State}]}, + {supervisor, [{"Callback", State#state.module}]}]. diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl index a48ba7b5b7..951a17d3eb 100644 --- a/lib/stdlib/test/erl_pp_SUITE.erl +++ b/lib/stdlib/test/erl_pp_SUITE.erl @@ -1112,15 +1112,14 @@ pr_1014(Config) -> ok = pp_forms(<<"-type t() :: #{any() => _}. ">>), ok = pp_forms(<<"-type t() :: #{_ => any()}. ">>), ok = pp_forms(<<"-type t() :: #{any() => any()}. ">>), - ok = pp_forms(<<"-type t() :: #{...}. ">>), - ok = pp_forms(<<"-type t() :: #{atom() := integer(), ...}. ">>), + ok = pp_forms(<<"-type t() :: #{atom() := integer(), any() => any()}. ">>), FileName = filename('pr_1014.erl', Config), C = <<"-module pr_1014.\n" "-compile export_all.\n" "-type m() :: #{..., a := integer()}.\n">>, ok = file:write_file(FileName, C), - {error,[{_,[{3,erl_parse,["syntax error before: ","','"]}]}],_} = + {error,[{_,[{3,erl_parse,["syntax error before: ","'...'"]}]}],_} = compile:file(FileName, [return]), ok. diff --git a/lib/stdlib/test/id_transform_SUITE.erl b/lib/stdlib/test/id_transform_SUITE.erl index 54f452825f..3d4ae1a189 100644 --- a/lib/stdlib/test/id_transform_SUITE.erl +++ b/lib/stdlib/test/id_transform_SUITE.erl @@ -61,13 +61,8 @@ id_transform(Config) when is_list(Config) -> "erl_id_trans.erl"]), {ok,erl_id_trans,Bin} = compile:file(File,[binary]), {module,erl_id_trans} = code:load_binary(erl_id_trans, File, Bin), - case test_server:purify_is_running() of - false -> - ct:timetrap({hours,1}), - run_in_test_suite(); - true -> - {skip,"Valgrind (too slow)"} - end. + ct:timetrap({hours,1}), + run_in_test_suite(). run_in_test_suite() -> SuperDir = filename:dirname(filename:dirname(code:which(?MODULE))), diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl index 3f1aa0e7a3..cd2c6b0cbb 100644 --- a/lib/stdlib/test/supervisor_SUITE.erl +++ b/lib/stdlib/test/supervisor_SUITE.erl @@ -66,7 +66,7 @@ %% Misc tests -export([child_unlink/1, tree/1, count_children/1, - count_restarting_children/1, + count_restarting_children/1, get_callback_module/1, do_not_save_start_parameters_for_temporary_children/1, do_not_save_child_specs_for_temporary_children/1, simple_one_for_one_scale_many_temporary_children/1, @@ -91,7 +91,7 @@ all() -> {group, normal_termination}, {group, shutdown_termination}, {group, abnormal_termination}, child_unlink, tree, - count_children, count_restarting_children, + count_children, count_restarting_children, get_callback_module, do_not_save_start_parameters_for_temporary_children, do_not_save_child_specs_for_temporary_children, simple_one_for_one_scale_many_temporary_children, temporary_bystander, @@ -1507,6 +1507,14 @@ count_restarting_children(Config) when is_list(Config) -> [1,0,0,0] = get_child_counts(SupPid). %%------------------------------------------------------------------------- +%% Test get_callback_module +get_callback_module(Config) when is_list(Config) -> + Child = {child, {supervisor_1, start_child, []}, temporary, 1000, + worker, []}, + {ok, SupPid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child]}}), + supervisor_SUITE = supervisor:get_callback_module(SupPid). + +%%------------------------------------------------------------------------- %% Temporary children shall not be restarted so they should not save %% start parameters, as it potentially can take up a huge amount of %% memory for no purpose. diff --git a/lib/syntax_tools/src/erl_prettypr.erl b/lib/syntax_tools/src/erl_prettypr.erl index 119d375746..f1615b2610 100644 --- a/lib/syntax_tools/src/erl_prettypr.erl +++ b/lib/syntax_tools/src/erl_prettypr.erl @@ -1130,13 +1130,14 @@ lay_2(Node, Ctxt) -> any_size -> text("map()"); Fs -> - {Prec, _PrecR} = type_preop_prec('#'), - Es = lay_map_fields(Fs, - floating(text(",")), - reset_prec(Ctxt)), + Ctxt1 = reset_prec(Ctxt), + Es = seq(Fs, + floating(text(",")), Ctxt1, + fun lay/2), D = beside(floating(text("#{")), beside(par(Es), floating(text("}")))), + {Prec, _PrecR} = type_preop_prec('#'), maybe_parentheses(D, Prec, Ctxt) end; @@ -1400,36 +1401,6 @@ lay_error_info(T, Ctxt) -> lay_concrete(T, Ctxt) -> lay(erl_syntax:abstract(T), Ctxt). -lay_map_fields([H | T], Separator, Ctxt) -> - case T of - [] -> - [case erl_syntax:type(H) of - map_type_assoc -> - lay_last_type_assoc(H, Ctxt); - _ -> - lay(H, Ctxt) - end]; - _ -> - [maybe_append(Separator, lay(H, Ctxt)) - | lay_map_fields(T, Separator, Ctxt)] - end; -lay_map_fields([], _, _) -> - [empty()]. - -lay_last_type_assoc(Node, Ctxt) -> - Name = erl_syntax:map_type_assoc_name(Node), - Value = erl_syntax:map_type_assoc_value(Node), - IsAny = fun({type,_,any,[]}) -> true; - %% ({var,_,'_'}) -> true; - (_) -> false - end, - case IsAny(Name) andalso IsAny(Value) of - true -> - text("..."); - false -> - lay_type_assoc(Name, Value, Ctxt) - end. - lay_type_assoc(Name, Value, Ctxt) -> Ctxt1 = reset_prec(Ctxt), D1 = lay(Name, Ctxt1), diff --git a/lib/syntax_tools/test/syntax_tools_SUITE_data/type_specs.erl b/lib/syntax_tools/test/syntax_tools_SUITE_data/type_specs.erl index 5621d3a293..e4f8a1c3de 100644 --- a/lib/syntax_tools/test/syntax_tools_SUITE_data/type_specs.erl +++ b/lib/syntax_tools/test/syntax_tools_SUITE_data/type_specs.erl @@ -49,9 +49,12 @@ -type m1() :: #{} | map(). -type m2() :: #{a := m1(), b => #{} | fy:m2()}. --type m3() :: #{...}. --type m4() :: #{_ => _, ...}. --type m5() :: #{any() => any(), ...}. % Currently printed as `#{..., ...}'. +%-type m3() :: #{...}. +%-type m4() :: #{_ => _, ...}. +%-type m5() :: #{any() => any(), ...}. +-type m3() :: #{any() => any()}. +-type m4() :: #{_ => _, any() => any()}. +-type m5() :: #{any() => any(), any() => any()}. -type b1() :: B1 :: binary() | (BitString :: bitstring()). -define(PAIR(A, B), {(A), (B)}). diff --git a/lib/tools/src/xref_base.erl b/lib/tools/src/xref_base.erl index 4322943c59..bb9815f9b0 100644 --- a/lib/tools/src/xref_base.erl +++ b/lib/tools/src/xref_base.erl @@ -669,16 +669,45 @@ do_add_directory(Dir, AppName, Bui, Rec, Ver, War, State) -> warnings(War, unreadable, Unreadable), case Errors of [] -> - do_add_modules(FileNames, AppName, Bui, Ver, War, State, []); + do_add_modules(FileNames, AppName, Bui, Ver, War, State); [Error | _] -> throw(Error) end. -do_add_modules([], _AppName, _OB, _OV, _OW, State, Modules) -> +do_add_modules(Files, AppName, OB, OV, OW, State0) -> + NFiles = length(Files), + Reader = fun(SplitName, State) -> + _Pid = read_module(SplitName, AppName, OB, OV, OW, State) + end, + N = parallelism(), + Files1 = start_readers(Files, Reader, State0, N), + %% Increase the number of readers towards the end to decrease the + %% waiting time for the collecting process: + Nx = N, + add_mods(Files1, Reader, State0, [], NFiles, Nx). + +add_mods(_, _ReaderFun, State, Modules, 0, _Nx) -> {ok, sort(Modules), State}; -do_add_modules([File | Files], AppName, OB, OV, OW, State, Modules) -> - {ok, M, NewState} = do_add_module(File, AppName, OB, OV, OW, State), - do_add_modules(Files, AppName, OB, OV, OW, NewState, M ++ Modules). +add_mods(Files, ReaderFun, State, Modules, N, Nx) -> + {I, Nx1} = case Nx > 0 of + false -> {1, Nx}; + true -> {2, Nx - 1} + end, + Files1 = start_readers(Files, ReaderFun, State, I), + {ok, M, NewState} = process_module(State), + add_mods(Files1, ReaderFun, NewState, M ++ Modules, N - 1, Nx1). + +start_readers([SplitName|Files], ReaderFun, State, N) when N > 0 -> + _Pid = ReaderFun(SplitName, State), + start_readers(Files, ReaderFun, State, N - 1); +start_readers(Files, _ReaderFun, _State, _) -> + Files. + +parallelism() -> + case erlang:system_info(multi_scheduling) of + enabled -> erlang:system_info(schedulers_online); + _ -> 1 + end. %% -> {ok, Module, State} | throw(Error) do_add_a_module(File, AppName, Builtins, Verbose, Warnings, State) -> @@ -692,50 +721,75 @@ do_add_a_module(File, AppName, Builtins, Verbose, Warnings, State) -> %% -> {ok, Module, State} | throw(Error) %% Options: verbose, warnings, builtins -do_add_module({Dir, Basename}, AppName, Builtins, Verbose, Warnings, State) -> - File = filename:join(Dir, Basename), - {ok, M, Bad, NewState} = - do_add_module1(Dir, File, AppName, Builtins, Verbose, Warnings, State), - _ = filter(fun({Tag,B}) -> warnings(Warnings, Tag, [[File,B]]) end, Bad), - {ok, M, NewState}. - -do_add_module1(Dir, File, AppName, Builtins, Verbose, Warnings, State) -> - message(Verbose, reading_beam, [File]), - Mode = State#xref.mode, +do_add_module(SplitName, AppName, Builtins, Verbose, Warnings, State) -> + _Pid = read_module(SplitName, AppName, Builtins, Verbose, Warnings, State), + process_module(State). + +read_module(SplitName, AppName, Builtins, Verbose, Warnings, State) -> Me = self(), - Fun = fun() -> Me ! {self(), abst(File, Builtins, Mode)} end, - case xref_utils:subprocess(Fun, [link, {min_heap_size,100000}]) of + #xref{mode = Mode} = State, + Fun = + fun() -> + Me ! {?MODULE, + read_a_module(SplitName, AppName, Builtins, Verbose, + Warnings, Mode)} + end, + spawn_opt(Fun, [link, {min_heap_size, 1000000}, {priority, high}]). + +read_a_module({Dir, BaseName}, AppName, Builtins, Verbose, Warnings, Mode) -> + File = filename:join(Dir, BaseName), + case abst(File, Builtins, Mode) of {ok, _M, no_abstract_code} when Verbose -> - message(Verbose, skipped_beam, []), - {ok, [], [], State}; + message(Verbose, no_debug_info, [File]), + no; {ok, _M, no_abstract_code} when not Verbose -> message(Warnings, no_debug_info, [File]), - {ok, [], [], State}; + no; {ok, M, Data, UnresCalls0} -> - %% Remove duplicates. Identical unresolved calls on the - %% same line are counted as _one_ unresolved call. - UnresCalls = usort(UnresCalls0), - message(Verbose, done, []), - NoUnresCalls = length(UnresCalls), - case NoUnresCalls of - 0 -> ok; - 1 -> warnings(Warnings, unresolved_summary1, [[M]]); - N -> warnings(Warnings, unresolved_summary, [[M, N]]) - end, - T = case xref_utils:file_info(File) of - {ok, {_, _, _, Time}} -> Time; - Error -> throw(Error) - end, - XMod = #xref_mod{name = M, app_name = AppName, dir = Dir, - mtime = T, builtins = Builtins, - no_unresolved = NoUnresCalls}, - do_add_module(State, XMod, UnresCalls, Data); + message(Verbose, done, [File]), + %% Remove duplicates. Identical unresolved calls on the + %% same line are counted as _one_ unresolved call. + UnresCalls = usort(UnresCalls0), + NoUnresCalls = length(UnresCalls), + case NoUnresCalls of + 0 -> ok; + 1 -> warnings(Warnings, unresolved_summary1, [[M]]); + N -> warnings(Warnings, unresolved_summary, [[M, N]]) + end, + case xref_utils:file_info(File) of + {ok, {_, _, _, Time}} -> + XMod = #xref_mod{name = M, app_name = AppName, + dir = Dir, mtime = Time, + builtins = Builtins, + no_unresolved = NoUnresCalls}, + {ok, PrepMod, Bad} = + prepare_module(Mode, XMod, UnresCalls, Data), + foreach(fun({Tag,B}) -> + warnings(Warnings, Tag, + [[File,B]]) + end, Bad), + {ok, PrepMod}; + Error -> Error + end; Error -> message(Verbose, error, []), - throw(Error) + Error end. -abst(File, Builtins, Mode) when Mode =:= functions -> +process_module(State) -> + receive + {?MODULE, Reply} -> + case Reply of + no -> + {ok, [], State}; + {ok, PrepMod} -> + finish_module(PrepMod, State); + Error -> + throw(Error) + end + end. + +abst(File, Builtins, _Mode = functions) -> case beam_lib:chunks(File, [abstract_code, exports, attributes]) of {ok, {M,[{abstract_code,NoA},_X,_A]}} when NoA =:= no_abstract_code -> {ok, M, NoA}; @@ -762,7 +816,7 @@ abst(File, Builtins, Mode) when Mode =:= functions -> Error when element(1, Error) =:= error -> Error end; -abst(File, Builtins, Mode) when Mode =:= modules -> +abst(File, Builtins, _Mode = modules) -> case beam_lib:chunks(File, [exports, imports, attributes]) of {ok, {Mod, [{exports,X0}, {imports,I0}, {attributes,At}]}} -> X1 = mfa_exports(X0, At, Mod), @@ -856,19 +910,13 @@ deprecated_flag(_) -> undefined. %% dom CallAt = LC U XC %% Attrs is collected from the attribute 'xref' (experimental). do_add_module(S, XMod, Unres, Data) -> - M = XMod#xref_mod.name, - case dict:find(M, S#xref.modules) of - {ok, OldXMod} -> - BF2 = module_file(XMod), - BF1 = module_file(OldXMod), - throw_error({module_clash, {M, BF1, BF2}}); - error -> - do_add_module(S, M, XMod, Unres, Data) - end. + #xref{mode = Mode} = S, + Mode = S#xref.mode, + {ok, PrepMod, Bad} = prepare_module(Mode, XMod, Unres, Data), + {ok, Ms, NS} = finish_module(PrepMod, S), + {ok, Ms, Bad, NS}. -%%do_add_module(S, M, _XMod, _Unres, Data)-> -%% {ok, M, [], S}; -do_add_module(S, M, XMod, Unres0, Data) when S#xref.mode =:= functions -> +prepare_module(_Mode = functions, XMod, Unres0, Data) -> {DefAt0, LPreCAt0, XPreCAt0, LC0, XC0, X0, Attrs, Depr} = Data, %% Bad is a list of bad values of 'xref' attributes. {ALC0,AXC0,Bad0} = Attrs, @@ -904,26 +952,27 @@ do_add_module(S, M, XMod, Unres0, Data) when S#xref.mode =:= functions -> LC = union(LC1, ALC), {DF1,DF_11,DF_21,DF_31,DBad} = depr_mod(Depr, X), + {EE, ECallAt} = inter_graph(X, L, LC, XC, CallAt), + {ok, {functions, XMod, [DefAt,L,X,LCallAt,XCallAt,CallAt,LC,XC,EE,ECallAt, + DF1,DF_11,DF_21,DF_31], NoCalls, Unres}, + DBad++Bad}; +prepare_module(_Mode = modules, XMod, _Unres, Data) -> + {X0, I0, Depr} = Data, + X1 = xref_utils:xset(X0, [tspec(func)]), + I1 = xref_utils:xset(I0, [tspec(func)]), + {DF1,DF_11,DF_21,DF_31,DBad} = depr_mod(Depr, X1), + {ok, {modules, XMod, [X1,I1,DF1,DF_11,DF_21,DF_31]}, DBad}. - %% {EE, ECallAt} = inter_graph(X, L, LC, XC, LCallAt, XCallAt), - Self = self(), - Fun = fun() -> inter_graph(Self, X, L, LC, XC, CallAt) end, - {EE, ECallAt} = - xref_utils:subprocess(Fun, [link, {min_heap_size,100000}]), - +finish_module({functions, XMod, List, NoCalls, Unres}, S) -> + ok = check_module(XMod, S), [DefAt2,L2,X2,LCallAt2,XCallAt2,CallAt2,LC2,XC2,EE2,ECallAt2, - DF2,DF_12,DF_22,DF_32] = - pack([DefAt,L,X,LCallAt,XCallAt,CallAt,LC,XC,EE,ECallAt, - DF1,DF_11,DF_21,DF_31]), - - %% Foo = [DefAt2,L2,X2,LCallAt2,XCallAt2,CallAt2,LC2,XC2,EE2,ECallAt2, - %% DF2,DF_12,DF_22,DF_32], - %% io:format("{~p, ~p, ~p},~n", [M, pack:lsize(Foo), pack:usize(Foo)]), + DF2,DF_12,DF_22,DF_32] = pack(List), LU = range(LC2), LPredefined = predefined_funs(LU), + M = XMod#xref_mod.name, MS = xref_utils:xset(M, atom), T = from_sets({MS,DefAt2,L2,X2,LCallAt2,XCallAt2,CallAt2, LC2,XC2,LU,EE2,ECallAt2,Unres,LPredefined, @@ -934,19 +983,28 @@ do_add_module(S, M, XMod, Unres0, Data) when S#xref.mode =:= functions -> XMod1 = XMod#xref_mod{data = T, info = Info}, S1 = S#xref{modules = dict:store(M, XMod1, S#xref.modules)}, - {ok, [M], DBad++Bad, take_down(S1)}; -do_add_module(S, M, XMod, _Unres, Data) when S#xref.mode =:= modules -> - {X0, I0, Depr} = Data, - X1 = xref_utils:xset(X0, [tspec(func)]), - I1 = xref_utils:xset(I0, [tspec(func)]), - {DF1,DF_11,DF_21,DF_31,DBad} = depr_mod(Depr, X1), - [X2,I2,DF2,DF_12,DF_22,DF_32] = pack([X1,I1,DF1,DF_11,DF_21,DF_31]), + {ok, [M], take_down(S1)}; +finish_module({modules, XMod, List}, S) -> + ok = check_module(XMod, S), + [X2,I2,DF2,DF_12,DF_22,DF_32] = pack(List), + M = XMod#xref_mod.name, MS = xref_utils:xset(M, atom), T = from_sets({MS, X2, I2, DF2, DF_12, DF_22, DF_32}), Info = [], XMod1 = XMod#xref_mod{data = T, info = Info}, S1 = S#xref{modules = dict:store(M, XMod1, S#xref.modules)}, - {ok, [M], DBad, take_down(S1)}. + {ok, [M], take_down(S1)}. + +check_module(XMod, State) -> + M = XMod#xref_mod.name, + case dict:find(M, State#xref.modules) of + {ok, OldXMod} -> + BF2 = module_file(XMod), + BF1 = module_file(OldXMod), + throw_error({module_clash, {M, BF1, BF2}}); + error -> + ok + end. depr_mod({Depr,Bad0}, X) -> %% Bad0 are badly formed deprecated attributes. @@ -992,9 +1050,6 @@ no_info(X, L, LC, XC, EE, Unres, NoCalls, NoUnresCalls) -> %% Note: this is overwritten in do_set_up(): {no_inter_function_calls, no_elements(EE)}]. -inter_graph(Pid, X, L, LC, XC, CallAt) -> - Pid ! {self(), inter_graph(X, L, LC, XC, CallAt)}. - %% Inter Call Graph. %inter_graph(_X, _L, _LC, _XC, _CallAt) -> % {empty_set(), empty_set()}; @@ -1766,10 +1821,6 @@ tpack(T, I, L) -> message(true, What, Arg) -> case What of - reading_beam -> - io:format("~ts... ", Arg); - skipped_beam -> - io:format("skipped (no debug information)~n", Arg); no_debug_info -> io:format("Skipping ~ts (no debug information)~n", Arg); unresolved_summary1 -> @@ -1791,7 +1842,7 @@ message(true, What, Arg) -> set_up -> io:format("Setting up...", Arg); done -> - io:format("done~n", Arg); + io:format("done reading ~ts~n", Arg); error -> io:format("error~n", Arg); Else -> diff --git a/lib/tools/src/xref_utils.erl b/lib/tools/src/xref_utils.erl index f69aa70244..b0c168e018 100644 --- a/lib/tools/src/xref_utils.erl +++ b/lib/tools/src/xref_utils.erl @@ -47,8 +47,6 @@ -export([options/2]). --export([subprocess/2]). - -export([format_error/1]). -import(lists, [append/1, delete/2, filter/2, foldl/3, foreach/2, @@ -512,12 +510,6 @@ find_beam(Culprit) -> options(Options, Valid) -> split_options(Options, [], [], [], Valid). -subprocess(Fun, Opts) -> - Pid = spawn_opt(Fun, Opts), - receive - {Pid, Reply} -> Reply - end. - format_error({error, Module, Error}) -> Module:format_error(Error); format_error({file_error, FileName, Reason}) -> |