diff options
Diffstat (limited to 'lib/kernel/test')
21 files changed, 1629 insertions, 659 deletions
diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile index cb11d4e899..f1b8a105ed 100644 --- a/lib/kernel/test/Makefile +++ b/lib/kernel/test/Makefile @@ -145,7 +145,7 @@ release_tests_spec: make_emakefile $(INSTALL_DIR) "$(RELSYSDIR)" $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)" $(INSTALL_DATA) $(APP_FILES) "$(RELSYSDIR)" - $(INSTALL_DATA) kernel.spec $(EMAKEFILE)\ + $(INSTALL_DATA) kernel.spec kernel_smoke.spec $(EMAKEFILE)\ $(COVERFILE) "$(RELSYSDIR)" chmod -R u+w "$(RELSYSDIR)" @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -) diff --git a/lib/kernel/test/application_SUITE.erl b/lib/kernel/test/application_SUITE.erl index 1ff291be54..c6cbd1a0ef 100644 --- a/lib/kernel/test/application_SUITE.erl +++ b/lib/kernel/test/application_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -33,10 +33,10 @@ permit_false_start_local/1, permit_false_start_dist/1, script_start/1, nodedown_start/1, init2973/0, loop2973/0, loop5606/1]). --export([config_change/1, +-export([config_change/1, persistent_env/1, distr_changed_tc1/1, distr_changed_tc2/1, - ensure_started/1, - shutdown_func/1, do_shutdown/1, shutdown_timeout/1]). + ensure_started/1, ensure_all_started/1, + shutdown_func/1, do_shutdown/1, shutdown_timeout/1, shutdown_deadlock/1]). -define(TESTCASE, testcase_name). -define(testcase, ?config(?TESTCASE, Config)). @@ -52,8 +52,10 @@ all() -> [failover, failover_comp, permissions, load, load_use_cache, ensure_started, {group, reported_bugs}, start_phases, script_start, nodedown_start, permit_false_start_local, - permit_false_start_dist, get_key, get_env, - {group, distr_changed}, config_change, shutdown_func, shutdown_timeout]. + permit_false_start_dist, get_key, get_env, ensure_all_started, + {group, distr_changed}, config_change, shutdown_func, shutdown_timeout, + shutdown_deadlock, + persistent_env]. groups() -> [{reported_bugs, [], @@ -960,7 +962,7 @@ nodedown_start(Conf) when is_list(Conf) -> ensure_started(suite) -> []; ensure_started(doc) -> ["Test application:ensure_started/1."]; -ensure_started(Conf) -> +ensure_started(_Conf) -> {ok, Fd} = file:open("app1.app", [write]), w_app1(Fd), @@ -978,6 +980,85 @@ ensure_started(Conf) -> ok = application:unload(app1), ok. +ensure_all_started(suite) -> []; +ensure_all_started(doc) -> ["Test application:ensure_all_started/1-2."]; +ensure_all_started(_Conf) -> + + {ok, Fd1} = file:open("app1.app", [write]), + w_app1(Fd1), + file:close(Fd1), + {ok, Fd9} = file:open("app9.app", [write]), + w_app9(Fd9), + file:close(Fd9), + {ok, Fd10} = file:open("app10.app", [write]), + w_app10_dep9(Fd10), + file:close(Fd10), + {ok, FdErr} = file:open("app_chain_error.app", [write]), + w_app(FdErr, app_chain_error()), + file:close(FdErr), + {ok, FdErr2} = file:open("app_chain_error2.app", [write]), + w_app(FdErr2, app_chain_error2()), + file:close(FdErr2), + + %% Single app start/stop + false = lists:keyfind(app1, 1, application:which_applications()), + {ok, [app1]} = application:ensure_all_started(app1), % app1 started + {app1, _, _} = lists:keyfind(app1, 1, application:which_applications()), + {ok, []} = application:ensure_all_started(app1), % no start needed + ok = application:stop(app1), + false = lists:keyfind(app1, 1, application:which_applications()), + ok = application:unload(app1), + + %% App or dependency not found. + Name = hopefully_not_an_existing_app_file, + {error,{Name, {"no such file or directory", _ }}} = + application:ensure_all_started(Name), + + %% Start dependencies. + {error, {not_started, app9}} = application:start(app10), + {ok, [app9,app10]} = application:ensure_all_started(app10, temporary), + {app9, _, _} = lists:keyfind(app9, 1, application:which_applications()), + {app10, _, _} = lists:keyfind(app10, 1, application:which_applications()), + %% Only report apps/dependencies that actually needed to start + ok = application:stop(app10), + ok = application:unload(app10), + {ok, [app10]} = application:ensure_all_started(app10, temporary), + ok = application:stop(app9), + ok = application:unload(app9), + ok = application:stop(app10), + ok = application:unload(app10), + + %% Deeper failure chain. We have the following dependencies: + %% app_chain_error -> app_chain_error2 + %% app_chain_error2 -> app10 + %% app_chain_error2 -> hopefully_not_an_existing_app + %% app10 -> app 9 + %% First we have none running and we expect to have neither app9 + %% nor app10 running after failing to start + %% hopefully_not_an_existing_app + {error, {hopefully_not_an_existing_app, {"no such file or directory", _}}}= + application:ensure_all_started(app_chain_error), + false = lists:keyfind(app9, 1, application:which_applications()), + false = lists:keyfind(app10, 1, application:which_applications()), + false = lists:keyfind(app_chain_error2,1,application:which_applications()), + false = lists:keyfind(app_chain_error, 1, application:which_applications()), + %% Here we will have app9 already running, and app10 should be + %% able to boot fine. + %% In this dependency failing, we expect app9 to still be running, but + %% not app10 after failing to start hopefully_not_an_existing_app + {ok, [app9]} = application:ensure_all_started(app9, temporary), + {error, {hopefully_not_an_existing_app, {"no such file or directory", _}}}= + application:ensure_all_started(app_chain_error), + {app9, _, _} = lists:keyfind(app9, 1, application:which_applications()), + false = lists:keyfind(app10, 1, application:which_applications()), + false = lists:keyfind(app_chain_error2,1,application:which_applications()), + false = lists:keyfind(app_chain_error, 1, application:which_applications()), + ok = application:stop(app9), + ok = application:unload(app9), + ok = application:unload(app10), + ok = application:unload(app_chain_error2), + ok = application:unload(app_chain_error), + ok. %%%----------------------------------------------------------------- %%% Testing of reported bugs and other tickets. @@ -1908,6 +1989,50 @@ get_appls([_ | T], Res) -> get_appls([], Res) -> Res. +persistent_env(suite) -> + []; +persistent_env(doc) -> + ["Test set_env/4 and unset_env/3 with persistent true"]; +persistent_env(Conf) when is_list(Conf) -> + ok = application:set_env(appinc, own2, persist, [{persistent, true}]), + ok = application:set_env(appinc, key1, persist, [{persistent, true}]), + + %% own_env1 and own2 are set in appinc + ok = application:load(appinc()), + {ok, value1} = application:get_env(appinc, own_env1), + {ok, persist} = application:get_env(appinc, own2), + {ok, persist} = application:get_env(appinc, key1), + + %% Changing the environment after loaded reflects and should persist + ok = application:set_env(appinc, own_env1, persist, [{persistent, true}]), + {ok, persist} = application:get_env(appinc, own_env1), + {ok, persist} = application:get_env(appinc, own2), + {ok, persist} = application:get_env(appinc, key1), + + %% On reload, own_env1, own2 and key1 should all persist + ok = application:unload(appinc), + ok = application:load(appinc()), + {ok, persist} = application:get_env(appinc, own_env1), + {ok, persist} = application:get_env(appinc, own2), + {ok, persist} = application:get_env(appinc, key1), + + %% Unset own_env1 and key1, own2 should still persist + ok = application:unset_env(appinc, own_env1, [{persistent, true}]), + ok = application:unset_env(appinc, key1, [{persistent, true}]), + undefined = application:get_env(appinc, own_env1), + {ok, persist} = application:get_env(appinc, own2), + undefined = application:get_env(appinc, key1), + + %% own_env1 should be back to its application value on reload + ok = application:unload(appinc), + ok = application:load(appinc()), + {ok, value1} = application:get_env(appinc, own_env1), + {ok, persist} = application:get_env(appinc, own2), + undefined = application:get_env(appinc, key1), + + %% Clean up + ok = application:unload(appinc). + %%%----------------------------------------------------------------- %%% Tests the 'shutdown_func' kernel config parameter %%%----------------------------------------------------------------- @@ -1972,7 +2097,32 @@ shutdown_timeout(Config) when is_list(Config) -> end, ok. +%%%----------------------------------------------------------------- +%%% Provokes a (previous) application shutdown deadlock +%%%----------------------------------------------------------------- +shutdown_deadlock(Config) when is_list(Config) -> + DataDir = ?config(data_dir,Config), + code:add_path(filename:join([DataDir,deadlock])), + %% ok = rpc:call(Cp1, application, start, [sasl]), + ok = application:start(deadlock), + Tester = self(), + application:set_env(deadlock, fail_stop, Tester), + spawn(fun() -> Tester ! {stop, application:stop(deadlock)} end), + receive + {deadlock, Server} -> + spawn(fun() -> + Master = application_controller:get_master(deadlock), + Child = application_master:get_child(Master), + Tester ! {child, Child} + end), + timer:sleep(100), + erlang:display({self(), "Sending Continue", Server}), + Server ! continue + end, + [_|_] = application:which_applications(), + application:unload(deadlock), % clean up! + ok. %%----------------------------------------------------------------- @@ -2125,6 +2275,24 @@ app_start_error() -> {applications, [kernel]}, {mod, {app_start_error, []}}]}. +app_chain_error() -> + {application, app_chain_error, + [{description, "ERTS CXC 138 ce"}, + {vsn, "2.0"}, + {modules, []}, + {registered, []}, + {applications, [kernel, app_chain_error2]}, + {mod, {ch_sup, {app_chain_error, 20,20}}}]}. + +app_chain_error2() -> + {application, app_chain_error2, + [{description, "ERTS CXC 138 ce2"}, + {vsn, "2.0"}, + {modules, []}, + {registered, []}, + {applications, [kernel, app10, hopefully_not_an_existing_app]}, + {mod, {ch_sup, {app_chain_error2, 21,21}}}]}. + app_group_leader() -> {application, group_leader, [{description, "GROUP_LEADER CXC 138 11"}, @@ -2374,6 +2542,12 @@ w_app7(Fd) -> w_app8(Fd) -> io:format(Fd, "~p.\n", [app8()]). +w_app9(Fd) -> + io:format(Fd, "~p.\n", [app9()]). + +w_app10_dep9(Fd) -> + io:format(Fd, "~p.\n", [app10_dep9()]). + w_app_start_error(Fd) -> io:format(Fd, "~p.\n", [app_start_error()]). diff --git a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app index 0c1001bed6..233c7a3f76 100644 --- a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app +++ b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app @@ -4,5 +4,5 @@ {applications, [kernel, stdlib, sasl]}, {modules, [deadlock]}, {mod, {deadlock, []}}, - {env, [{fail_start, false}]} + {env, [{fail_start, false}, {fail_stop, false}]} ]}. diff --git a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl index 5f68bf9078..3ef6105371 100644 --- a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl +++ b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl @@ -21,7 +21,7 @@ init([sup]) -> {ok, {{one_for_one, 5, 10}, [ { sasl_syslog_dm, {?MODULE, start_link, []}, - permanent, brutal_kill, worker, + permanent, 25000, worker, [deadlock] } ]}}; @@ -32,6 +32,8 @@ init([sup]) -> init([child]) -> case application:get_env(deadlock, fail_start) of {ok, false} -> + process_flag(trap_exit, true), + io:format("~p: Traps exit~n",[?MODULE]), %% we must not fail on the first init, otherwise supervisor %% terminates immediately {ok, []}; @@ -50,6 +52,14 @@ handle_info(_Msg, State) -> {noreply, State}. terminate(_Reason, _State) -> + case application:get_env(deadlock, fail_stop) of + {ok, false} -> ok; + {ok, Tester} -> + Tester ! {deadlock, self()}, + io:format("~p: Waiting in terminate (~p)~n",[?MODULE,Tester]), + receive continue -> ok end + end, + io:format("~p: terminates~n", [?MODULE]), ok. code_change(_OldVsn, State, _Extra) -> diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index fc17db2745..42b81d16b3 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -23,7 +23,8 @@ -export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2]). -export([set_path/1, get_path/1, add_path/1, add_paths/1, del_path/1, replace_path/1, load_file/1, load_abs/1, ensure_loaded/1, - delete/1, purge/1, soft_purge/1, is_loaded/1, all_loaded/1, + delete/1, purge/1, purge_many_exits/1, soft_purge/1, is_loaded/1, + all_loaded/1, load_binary/1, dir_req/1, object_code/1, set_path_file/1, upgrade/1, sticky_dir/1, pa_pz_option/1, add_del_path/1, @@ -35,7 +36,7 @@ on_load_embedded/1, on_load_errors/1, big_boot_embedded/1, native_early_modules/1, get_mode/1]). --export([init_per_testcase/2, end_per_testcase/2, +-export([init_per_testcase/2, end_per_testcase/2, init_per_suite/1, end_per_suite/1, sticky_compiler/1]). @@ -48,10 +49,10 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. -all() -> +all() -> [set_path, get_path, add_path, add_paths, del_path, replace_path, load_file, load_abs, ensure_loaded, - delete, purge, soft_purge, is_loaded, all_loaded, + delete, purge, purge_many_exits, soft_purge, is_loaded, all_loaded, load_binary, dir_req, object_code, set_path_file, upgrade, pa_pz_option, add_del_path, dir_disappeared, @@ -62,7 +63,7 @@ all() -> on_load_binary, on_load_embedded, on_load_errors, big_boot_embedded, native_early_modules, get_mode]. -groups() -> +groups() -> []. init_per_group(_GroupName, Config) -> @@ -76,10 +77,10 @@ init_per_suite(Config) -> %% the module name does not match the filename, so %% we must compile to a binary and write the Beam file %% ourselves. - ?line Dir = filename:dirname(code:which(?MODULE)), - ?line File = filename:join(Dir, "code_a_test"), - ?line {ok,code_b_test,Code} = compile:file(File, [binary]), - ?line ok = file:write_file(File++".beam", Code), + Dir = filename:dirname(code:which(?MODULE)), + File = filename:join(Dir, "code_a_test"), + {ok,code_b_test,Code} = compile:file(File, [binary]), + ok = file:write_file(File++".beam", Code), Config. end_per_suite(Config) -> @@ -98,7 +99,7 @@ init_per_testcase(_Func, Config) -> P=code:get_path(), [{watchdog, Dog}, {code_path, P}|Config]. -end_per_testcase(TC, Config) when TC == mult_lib_roots; +end_per_testcase(TC, Config) when TC == mult_lib_roots; TC == big_boot_embedded -> {ok, HostName} = inet:gethostname(), NodeName = list_to_atom(atom_to_list(TC)++"@"++HostName), @@ -121,51 +122,49 @@ set_path(doc) -> []; set_path(Config) when is_list(Config) -> P = code:get_path(), NonExDir = filename:join(?config(priv_dir, Config), ?t:temp_name("hej")), - ?line {'EXIT',_} = (catch code:set_path({a})), - ?line {error, bad_directory} = (catch code:set_path([{a}])), - ?line {error, bad_directory} = code:set_path(NonExDir), - ?line P = code:get_path(), % still the same path. - ?line true = code:set_path(P), % set the same path again. - ?line P = code:get_path(), % still the same path. + {'EXIT',_} = (catch code:set_path({a})), + {error, bad_directory} = (catch code:set_path([{a}])), + {error, bad_directory} = code:set_path(NonExDir), + P = code:get_path(), % still the same path. + true = code:set_path(P), % set the same path again. + P = code:get_path(), % still the same path. LibDir = code:lib_dir(), - ?line true = code:set_path([LibDir | P]), - ?line [LibDir | P] = code:get_path(), - ?line true = code:set_path([LibDir]), - ?line [LibDir] = code:get_path(), + true = code:set_path([LibDir | P]), + [LibDir | P] = code:get_path(), + true = code:set_path([LibDir]), + [LibDir] = code:get_path(), ok. get_path(suite) -> []; get_path(doc) -> []; get_path(Config) when is_list(Config) -> - ?line P = code:get_path(), + P = code:get_path(), % test that all directories are strings (lists). - ?line [] = lists:filter(fun(Dir) when is_list(Dir) -> - false; - (_) -> - true - end, - P), + [] = lists:filter(fun + (Dir) when is_list(Dir) -> false; + (_) -> true + end, P), ok. add_path(suite) -> []; add_path(doc) -> []; add_path(Config) when is_list(Config) -> P = code:get_path(), - ?line {'EXIT',_} = (catch code:add_path({})), - ?line {'EXIT',_} = (catch code:add_patha({})), - ?line {'EXIT',_} = (catch code:add_pathz({})), - ?line {error, bad_directory} = code:add_path("xyz"), - ?line {error, bad_directory} = code:add_patha("xyz"), - ?line {error, bad_directory} = code:add_pathz("xyz"), + {'EXIT',_} = (catch code:add_path({})), + {'EXIT',_} = (catch code:add_patha({})), + {'EXIT',_} = (catch code:add_pathz({})), + {error, bad_directory} = code:add_path("xyz"), + {error, bad_directory} = code:add_patha("xyz"), + {error, bad_directory} = code:add_pathz("xyz"), LibDir = code:lib_dir(), - ?line true = code:add_path(LibDir), - ?line LibDir = lists:last(code:get_path()), + true = code:add_path(LibDir), + LibDir = lists:last(code:get_path()), code:set_path(P), - ?line true = code:add_pathz(LibDir), - ?line LibDir = lists:last(code:get_path()), + true = code:add_pathz(LibDir), + LibDir = lists:last(code:get_path()), code:set_path(P), - ?line true = code:add_patha(LibDir), - ?line [LibDir|_] = code:get_path(), + true = code:add_patha(LibDir), + [LibDir|_] = code:get_path(), code:set_path(P), ok. @@ -173,134 +172,134 @@ add_paths(suite) -> []; add_paths(doc) -> []; add_paths(Config) when is_list(Config) -> P = code:get_path(), - ?line ok = code:add_paths([{}]), - ?line ok = code:add_pathsa([{}]), - ?line ok = code:add_pathsz([{}]), - ?line ok = code:add_paths(["xyz"]), - ?line ok = code:add_pathsa(["xyz"]), - ?line ok = code:add_pathsz(["xyz"]), + ok = code:add_paths([{}]), + ok = code:add_pathsa([{}]), + ok = code:add_pathsz([{}]), + ok = code:add_paths(["xyz"]), + ok = code:add_pathsa(["xyz"]), + ok = code:add_pathsz(["xyz"]), P = code:get_path(), % check that no directory is added. LibDir = code:lib_dir(), - ?line ok = code:add_paths([LibDir]), - ?line LibDir = lists:last(code:get_path()), + ok = code:add_paths([LibDir]), + LibDir = lists:last(code:get_path()), code:set_path(P), - ?line ok = code:add_pathsz([LibDir]), - ?line LibDir = lists:last(code:get_path()), + ok = code:add_pathsz([LibDir]), + LibDir = lists:last(code:get_path()), code:set_path(P), - ?line ok = code:add_pathsa([LibDir]), - ?line [LibDir|P] = code:get_path(), + ok = code:add_pathsa([LibDir]), + [LibDir|P] = code:get_path(), code:set_path(P), RootDir = code:root_dir(), Res = P ++ [LibDir, RootDir], - ?line ok = code:add_paths([LibDir, RootDir]), - ?line Res = code:get_path(), + ok = code:add_paths([LibDir, RootDir]), + Res = code:get_path(), code:set_path(P), - ?line ok = code:add_pathsz([LibDir, RootDir]), - ?line Res = code:get_path(), + ok = code:add_pathsz([LibDir, RootDir]), + Res = code:get_path(), code:set_path(P), - ?line ok = code:add_pathsa([LibDir, RootDir]), - ?line [RootDir, LibDir|P] = code:get_path(), + ok = code:add_pathsa([LibDir, RootDir]), + [RootDir, LibDir|P] = code:get_path(), code:set_path(P), - ?line ok = code:add_paths([LibDir, "xyz"]), + ok = code:add_paths([LibDir, "xyz"]), Res1 = P ++ [LibDir], - ?line Res1 = code:get_path(), + Res1 = code:get_path(), code:set_path(P), - ?line ok = code:add_pathsz([LibDir, "xyz"]), - ?line Res1 = code:get_path(), + ok = code:add_pathsz([LibDir, "xyz"]), + Res1 = code:get_path(), code:set_path(P), - ?line ok = code:add_pathsa([LibDir, "xyz"]), - ?line [LibDir|P] = code:get_path(), + ok = code:add_pathsa([LibDir, "xyz"]), + [LibDir|P] = code:get_path(), code:set_path(P), ok. del_path(suite) -> []; del_path(doc) -> []; del_path(Config) when is_list(Config) -> - ?line P = code:get_path(), + P = code:get_path(), test_server:format("Initial code:get_path()=~p~n",[P]), - ?line {'EXIT',_} = (catch code:del_path(3)), - ?line false = code:del_path(my_dummy_name), - ?line false = code:del_path("/kdlk/my_dummy_dir"), + {'EXIT',_} = (catch code:del_path(3)), + false = code:del_path(my_dummy_name), + false = code:del_path("/kdlk/my_dummy_dir"), Dir = filename:join([code:lib_dir(kernel),"ebin"]), test_server:format("kernel dir: ~p~n",[Dir]), - ?line true = code:del_path(kernel), + true = code:del_path(kernel), NewP = code:get_path(), test_server:format("Path after removing 'kernel':~p~n",[NewP]), ReferenceP = lists:delete(Dir,P), test_server:format("Reference path:~p~n",[ReferenceP]), - ?line NewP = ReferenceP, % check that dir is deleted + NewP = ReferenceP, % check that dir is deleted code:set_path(P), - ?line true = code:del_path(Dir), + true = code:del_path(Dir), NewP1 = code:get_path(), - ?line NewP1 = lists:delete(Dir,P), % check that dir is deleted + NewP1 = lists:delete(Dir,P), % check that dir is deleted code:set_path(P), ok. replace_path(suite) -> []; replace_path(doc) -> []; replace_path(Config) when is_list(Config) -> - ?line PrivDir = ?config(priv_dir, Config), - ?line P = code:get_path(), - ?line {'EXIT',_} = (catch code:replace_path(3,"")), - ?line {error, bad_name} = code:replace_path(dummy_name,""), - ?line {error, bad_name} = code:replace_path(kernel, + PrivDir = ?config(priv_dir, Config), + P = code:get_path(), + {'EXIT',_} = (catch code:replace_path(3,"")), + {error, bad_name} = code:replace_path(dummy_name,""), + {error, bad_name} = code:replace_path(kernel, "/kdlk/my_dummy_dir"), - ?line {error, bad_directory} = code:replace_path(kernel, + {error, bad_directory} = code:replace_path(kernel, "/kdlk/kernel-1.2"), - ?line P = code:get_path(), % Check that path is not changed. + P = code:get_path(), % Check that path is not changed. - ?line ok = file:set_cwd(PrivDir), + ok = file:set_cwd(PrivDir), %% Replace an existing application. file:make_dir("./kernel-2.11"), {ok, Cwd} = file:get_cwd(), NewDir = Cwd ++ "/kernel-2.11", - ?line true = code:replace_path(kernel, NewDir), - ?line NewDir = code:lib_dir(kernel), - ?line true = code:set_path(P), %Reset path - ?line ok = file:del_dir("./kernel-2.11"), + true = code:replace_path(kernel, NewDir), + NewDir = code:lib_dir(kernel), + true = code:set_path(P), %Reset path + ok = file:del_dir("./kernel-2.11"), %% Add a completly new application. NewAppName = 'blurf_blarfer', - ?line NewAppDir = filename:join(Cwd, atom_to_list(NewAppName) ++ "-6.33.1"), - ?line ok = file:make_dir(NewAppDir), - ?line true = code:replace_path(NewAppName, NewAppDir), - ?line NewAppDir = code:lib_dir(NewAppName), - ?line NewAppDir = lists:last(code:get_path()), - ?line true = code:set_path(P), %Reset path - ?line ok = file:del_dir(NewAppDir), + NewAppDir = filename:join(Cwd, atom_to_list(NewAppName) ++ "-6.33.1"), + ok = file:make_dir(NewAppDir), + true = code:replace_path(NewAppName, NewAppDir), + NewAppDir = code:lib_dir(NewAppName), + NewAppDir = lists:last(code:get_path()), + true = code:set_path(P), %Reset path + ok = file:del_dir(NewAppDir), ok. dir_disappeared(suite) -> []; dir_disappeared(doc) -> ["OTP-3977"]; dir_disappeared(Config) when is_list(Config) -> - ?line PrivDir = ?config(priv_dir, Config), - ?line Dir = filename:join(PrivDir, "temp"), - ?line ok = file:make_dir(Dir), - ?line true = code:add_path(Dir), - ?line ok = file:del_dir(Dir), - ?line non_existing = code:which(bubbelskrammel), + PrivDir = ?config(priv_dir, Config), + Dir = filename:join(PrivDir, "temp"), + ok = file:make_dir(Dir), + true = code:add_path(Dir), + ok = file:del_dir(Dir), + non_existing = code:which(bubbelskrammel), ok. load_file(suite) -> []; load_file(doc) -> []; load_file(Config) when is_list(Config) -> - ?line {error, nofile} = code:load_file(duuuumy_mod), - ?line {error, badfile} = code:load_file(code_a_test), - ?line {'EXIT', _} = (catch code:load_file(123)), - ?line {module, code_b_test} = code:load_file(code_b_test), + {error, nofile} = code:load_file(duuuumy_mod), + {error, badfile} = code:load_file(code_a_test), + {'EXIT', _} = (catch code:load_file(123)), + {module, code_b_test} = code:load_file(code_b_test), TestDir = test_dir(), code:stick_dir(TestDir), - ?line {error, sticky_directory} = code:load_file(code_b_test), + {error, sticky_directory} = code:load_file(code_b_test), code:unstick_dir(TestDir), ok. @@ -311,30 +310,30 @@ load_abs(suite) -> []; load_abs(doc) -> []; load_abs(Config) when is_list(Config) -> TestDir = test_dir(), - ?line {error, nofile} = code:load_abs(TestDir ++ "/duuuumy_mod"), - ?line {error, badfile} = code:load_abs(TestDir ++ "/code_a_test"), - ?line {'EXIT', _} = (catch code:load_abs({})), - ?line {module, code_b_test} = code:load_abs(TestDir ++ "/code_b_test"), + {error, nofile} = code:load_abs(TestDir ++ "/duuuumy_mod"), + {error, badfile} = code:load_abs(TestDir ++ "/code_a_test"), + {'EXIT', _} = (catch code:load_abs({})), + {module, code_b_test} = code:load_abs(TestDir ++ "/code_b_test"), code:stick_dir(TestDir), - ?line {error, sticky_directory} = code:load_abs(TestDir ++ "/code_b_test"), + {error, sticky_directory} = code:load_abs(TestDir ++ "/code_b_test"), code:unstick_dir(TestDir), ok. ensure_loaded(suite) -> []; ensure_loaded(doc) -> []; ensure_loaded(Config) when is_list(Config) -> - ?line {module, lists} = code:ensure_loaded(lists), + {module, lists} = code:ensure_loaded(lists), case init:get_argument(mode) of {ok, [["embedded"]]} -> - ?line {error, embedded} = code:ensure_loaded(code_b_test), - ?line {error, badarg} = code:ensure_loaded(34), + {error, embedded} = code:ensure_loaded(code_b_test), + {error, badarg} = code:ensure_loaded(34), ok; _ -> - ?line {error, nofile} = code:ensure_loaded(duuuumy_mod), - ?line {error, badfile} = code:ensure_loaded(code_a_test), - ?line {'EXIT', _} = (catch code:ensure_loaded(34)), - ?line {module, code_b_test} = code:ensure_loaded(code_b_test), - ?line {module, code_b_test} = code:ensure_loaded(code_b_test), + {error, nofile} = code:ensure_loaded(duuuumy_mod), + {error, badfile} = code:ensure_loaded(code_a_test), + {'EXIT', _} = (catch code:ensure_loaded(34)), + {module, code_b_test} = code:ensure_loaded(code_b_test), + {module, code_b_test} = code:ensure_loaded(code_b_test), ok end. @@ -343,15 +342,15 @@ delete(doc) -> []; delete(Config) when is_list(Config) -> OldFlag = process_flag(trap_exit, true), code:purge(code_b_test), - ?line Pid = code_b_test:do_spawn(), - ?line true = code:delete(code_b_test), - ?line {'EXIT',_} = (catch code:delete(122)), - ?line false = code_b_test:check_exit(Pid), - ?line false = code:delete(code_b_test), - ?line false = code_b_test:check_exit(Pid), + Pid = code_b_test:do_spawn(), + true = code:delete(code_b_test), + {'EXIT',_} = (catch code:delete(122)), + false = code_b_test:check_exit(Pid), + false = code:delete(code_b_test), + false = code_b_test:check_exit(Pid), exit(Pid,kill), - ?line true = code_b_test:check_exit(Pid), - ?line false = code:delete(code_b_test), + true = code_b_test:check_exit(Pid), + false = code:delete(code_b_test), code:purge(code_b_test), process_flag(trap_exit, OldFlag), ok. @@ -361,31 +360,67 @@ purge(doc) -> []; purge(Config) when is_list(Config) -> OldFlag = process_flag(trap_exit, true), code:purge(code_b_test), - ?line {'EXIT',_} = (catch code:purge({})), - ?line false = code:purge(code_b_test), - ?line Pid = code_b_test:do_spawn(), - ?line true = code:delete(code_b_test), - ?line false = code_b_test:check_exit(Pid), - ?line true = code:purge(code_b_test), - ?line true = code_b_test:check_exit(Pid), + {'EXIT',_} = (catch code:purge({})), + false = code:purge(code_b_test), + Pid = code_b_test:do_spawn(), + true = code:delete(code_b_test), + false = code_b_test:check_exit(Pid), + true = code:purge(code_b_test), + true = code_b_test:check_exit(Pid), process_flag(trap_exit, OldFlag), ok. +purge_many_exits(Config) when is_list(Config) -> + OldFlag = process_flag(trap_exit, true), + code:purge(code_b_test), + {'EXIT',_} = (catch code:purge({})), + false = code:purge(code_b_test), + TPids = lists:map(fun (_) -> + {code_b_test:do_spawn(), + spawn_link(fun () -> + receive + after infinity -> ok + end + end)} + end, + lists:seq(1, 1000)), + % Give them time to start... + receive after 1000 -> ok end, + true = code:delete(code_b_test), + lists:foreach(fun ({Pid1, Pid2}) -> + true = erlang:is_process_alive(Pid1), + false = code_b_test:check_exit(Pid1), + true = erlang:is_process_alive(Pid2) + end, TPids), + true = code:purge(code_b_test), + lists:foreach(fun ({Pid1, Pid2}) -> + false = erlang:is_process_alive(Pid1), + true = code_b_test:check_exit(Pid1), + true = erlang:is_process_alive(Pid2), + exit(Pid2, kill) + end, TPids), + lists:foreach(fun ({_Pid1, Pid2}) -> + receive {'EXIT', Pid2, _} -> ok end + end, TPids), + process_flag(trap_exit, OldFlag), + ok. + + soft_purge(suite) -> []; soft_purge(doc) -> []; soft_purge(Config) when is_list(Config) -> OldFlag = process_flag(trap_exit, true), code:purge(code_b_test), - ?line {'EXIT',_} = (catch code:soft_purge(23)), - ?line true = code:soft_purge(code_b_test), - ?line Pid = code_b_test:do_spawn(), - ?line true = code:delete(code_b_test), - ?line false = code_b_test:check_exit(Pid), - ?line false = code:soft_purge(code_b_test), - ?line false = code_b_test:check_exit(Pid), + {'EXIT',_} = (catch code:soft_purge(23)), + true = code:soft_purge(code_b_test), + Pid = code_b_test:do_spawn(), + true = code:delete(code_b_test), + false = code_b_test:check_exit(Pid), + false = code:soft_purge(code_b_test), + false = code_b_test:check_exit(Pid), exit(Pid,kill), - ?line true = code_b_test:check_exit(Pid), - ?line true = code:soft_purge(code_b_test), + true = code_b_test:check_exit(Pid), + true = code:soft_purge(code_b_test), process_flag(trap_exit, OldFlag), ok. @@ -394,12 +429,12 @@ is_loaded(doc) -> []; is_loaded(Config) when is_list(Config) -> code:purge(code_b_test), code:delete(code_b_test), - ?line false = code:is_loaded(duuuuuumy_mod), - ?line {'EXIT',_} = (catch code:is_loaded(23)), - ?line {file, preloaded} = code:is_loaded(init), + false = code:is_loaded(duuuuuumy_mod), + {'EXIT',_} = (catch code:is_loaded(23)), + {file, preloaded} = code:is_loaded(init), TestDir = test_dir(), - ?line {module, code_b_test} = code:load_abs(TestDir ++ "/code_b_test"), - ?line {file, _Loaded} = code:is_loaded(code_b_test), + {module, code_b_test} = code:load_abs(TestDir ++ "/code_b_test"), + {file, _Loaded} = code:is_loaded(code_b_test), code:purge(code_b_test), code:delete(code_b_test), ok. @@ -413,21 +448,19 @@ all_loaded(Config) when is_list(Config) -> end. all_loaded_1() -> - ?line Preloaded = [{M,preloaded} || M <- lists:sort(erlang:pre_loaded())], + Preloaded = [{M,preloaded} || M <- lists:sort(erlang:pre_loaded())], - ?line Loaded0 = lists:sort(code:all_loaded()), - ?line all_unique(Loaded0), - ?line Loaded1 = lists:keysort(2, Loaded0), - ?line Loaded2 = match_and_remove(Preloaded, Loaded1), + Loaded0 = lists:sort(code:all_loaded()), + all_unique(Loaded0), + Loaded1 = lists:keysort(2, Loaded0), + Loaded2 = match_and_remove(Preloaded, Loaded1), ObjExt = code:objfile_extension(), - ?line [] = lists:filter(fun({Mod,AbsName}) when is_atom(Mod), - is_list(AbsName) -> - Mod =/= list_to_atom(filename:basename(AbsName, - ObjExt)); - (_) -> true - end, - Loaded2), + [] = lists:filter(fun + ({Mod,AbsName}) when is_atom(Mod), is_list(AbsName) -> + Mod =/= list_to_atom(filename:basename(AbsName, ObjExt)); + (_) -> true + end, Loaded2), ok. match_and_remove([], List) -> List; @@ -442,19 +475,19 @@ load_binary(doc) -> []; load_binary(Config) when is_list(Config) -> TestDir = test_dir(), File = TestDir ++ "/code_b_test" ++ code:objfile_extension(), - ?line {ok,Bin} = file:read_file(File), - ?line {'EXIT',_} = (catch code:load_binary(12, File, Bin)), - ?line {'EXIT',_} = (catch code:load_binary(code_b_test, 12, Bin)), - ?line {'EXIT',_} = (catch code:load_binary(code_b_test, File, 12)), - ?line {module, code_b_test} = code:load_binary(code_b_test, File, Bin), + {ok,Bin} = file:read_file(File), + {'EXIT',_} = (catch code:load_binary(12, File, Bin)), + {'EXIT',_} = (catch code:load_binary(code_b_test, 12, Bin)), + {'EXIT',_} = (catch code:load_binary(code_b_test, File, 12)), + {module, code_b_test} = code:load_binary(code_b_test, File, Bin), code:stick_dir(TestDir), - ?line {error, sticky_directory} = code:load_binary(code_b_test, File, Bin), + {error, sticky_directory} = code:load_binary(code_b_test, File, Bin), code:unstick_dir(TestDir), code:purge(code_b_test), code:delete(code_b_test), ok. -upgrade(Config) -> +upgrade(Config) -> DataDir = ?config(data_dir, Config), %%T = [beam, hipe], @@ -462,28 +495,28 @@ upgrade(Config) -> [upgrade_do(DataDir, Client, U1, U2, O1, O2) || Client<-T, U1<-T, U2<-T, O1<-T, O2<-T], - + ok. upgrade_do(DataDir, Client, U1, U2, O1, O2) -> - compile_load(upgrade_client, DataDir, undefined, Client), + compile_load(upgrade_client, DataDir, undefined, Client), upgrade_client:run(DataDir, U1, U2, O1, O2), ok. compile_load(Mod, Dir, Ver, CodeType) -> Version = case Ver of - undefined -> - io:format("Compiling '~p' as ~p\n", [Mod, CodeType]), - []; - _ -> - io:format("Compiling version ~p of '~p' as ~p\n", - [Ver, Mod, CodeType]), - [{d,list_to_atom("VERSION_" ++ integer_to_list(Ver))}] - end, + undefined -> + io:format("Compiling '~p' as ~p\n", [Mod, CodeType]), + []; + _ -> + io:format("Compiling version ~p of '~p' as ~p\n", + [Ver, Mod, CodeType]), + [{d,list_to_atom("VERSION_" ++ integer_to_list(Ver))}] + end, Target = case CodeType of - beam -> []; - hipe -> [native] - end, + beam -> []; + hipe -> [native] + end, CompOpts = [binary, report] ++ Target ++ Version, Src = filename:join(Dir, atom_to_list(Mod) ++ ".erl"), @@ -497,17 +530,17 @@ compile_load(Mod, Dir, Ver, CodeType) -> dir_req(suite) -> []; dir_req(doc) -> []; dir_req(Config) when is_list(Config) -> - ?line {ok,[[Root0]]} = init:get_argument(root), - ?line Root = filename:join([Root0]), % Normalised form. - ?line Root = code:root_dir(), + {ok,[[Root0]]} = init:get_argument(root), + Root = filename:join([Root0]), % Normalised form. + Root = code:root_dir(), LibDir = Root ++ "/lib", - ?line LibDir = code:lib_dir(), - ?line code:compiler_dir(), - ?line {error, bad_name} = code:lib_dir(duuumy), - ?line KernLib = code:lib_dir(kernel), - ?line Priv = KernLib ++ "/priv", - ?line Priv = code:priv_dir(kernel), - ?line {error, bad_name} = code:priv_dir(duuumy), + LibDir = code:lib_dir(), + code:compiler_dir(), + {error, bad_name} = code:lib_dir(duuumy), + KernLib = code:lib_dir(kernel), + Priv = KernLib ++ "/priv", + Priv = code:priv_dir(kernel), + {error, bad_name} = code:priv_dir(duuumy), ok. object_code(suite) -> []; @@ -517,19 +550,19 @@ object_code(Config) when is_list(Config) -> P = code:get_path(), P = code:get_path(), code:add_path(TestDir), - ?line {module, code_b_test} = code:load_abs(TestDir ++ "/code_b_test"), + {module, code_b_test} = code:load_abs(TestDir ++ "/code_b_test"), LoadedFile = filename:absname(TestDir ++ "/code_b_test" ++ code:objfile_extension()), - ?line case code:get_object_code(code_b_test) of + case code:get_object_code(code_b_test) of {code_b_test,Bin,LoadedFile} when is_binary(Bin) -> ok end, code:purge(code_b_test), code:delete(code_b_test), - ?line error = code:get_object_code(dddddddduuuuuuumy), - ?line {'EXIT',_} = (catch code:get_object_code(23)), - ?line code:set_path(P), - ?line P=code:get_path(), + error = code:get_object_code(dddddddduuuuuuumy), + {'EXIT',_} = (catch code:get_object_code(23)), + code:set_path(P), + P=code:get_path(), ok. set_path_file(suite) -> []; @@ -537,17 +570,17 @@ set_path_file(doc) -> ["Test that set_path does not accept ", "files as pathnames (known previous bug)"]; set_path_file(Config) when is_list(Config) -> File=filename:join(?config(priv_dir, Config), "testfil"), - ?line ok=file:write_file(File, list_to_binary("lite data")), - ?line {error, bad_directory}=code:set_path([File]). + ok=file:write_file(File, list_to_binary("lite data")), + {error, bad_directory}=code:set_path([File]). sticky_dir(suite) -> []; sticky_dir(doc) -> ["Test that a module with the same name as a module in ", "a sticky directory cannot be loaded."]; sticky_dir(Config) when is_list(Config) -> MyDir=filename:dirname(code:which(?MODULE)), - ?line {ok, Node}=?t:start_node(sticky_dir, slave,[{args, "-pa \""++MyDir++"\""}]), + {ok, Node}=?t:start_node(sticky_dir, slave,[{args, "-pa \""++MyDir++"\""}]), File=filename:join([?config(data_dir, Config), "calendar"]), - ?line Ret=rpc:call(Node, ?MODULE, sticky_compiler, [File]), + Ret=rpc:call(Node, ?MODULE, sticky_compiler, [File]), case Ret of fail -> ?t:fail("c:c allowed a sticky module to be compiled and loaded."); @@ -607,70 +640,70 @@ add_del_path(Config) when is_list(Config) -> Dir1 = filename:join(DDir,"dummy_app-1.0/ebin"), Dir2 = filename:join(DDir,"dummy_app-2.0/ebin"), code:add_patha(Dir1), - ?line PrivDir1 = filename:join(DDir,"dummy_app-1.0/priv"), - ?line PrivDir1 = code:priv_dir(dummy_app), - ?line code:add_path(Dir2), % put last in path - ?line PrivDir1 = code:priv_dir(dummy_app), - ?line code:del_path(Dir2), - ?line PrivDir1 = code:priv_dir(dummy_app), + PrivDir1 = filename:join(DDir,"dummy_app-1.0/priv"), + PrivDir1 = code:priv_dir(dummy_app), + code:add_path(Dir2), % put last in path + PrivDir1 = code:priv_dir(dummy_app), + code:del_path(Dir2), + PrivDir1 = code:priv_dir(dummy_app), ok. clash(Config) when is_list(Config) -> DDir = ?config(data_dir,Config)++"clash/", P = code:get_path(), - [TestServerPath|_] = [Path || Path <- code:get_path(), - re:run(Path,"test_server/?$",[]) /= nomatch], + [TestServerPath|_] = [Path || Path <- code:get_path(), + re:run(Path,"test_server/?$",[unicode]) /= nomatch], %% test non-clashing entries %% remove TestServerPath to prevent clash with test-server path - ?line true = code:del_path(TestServerPath), - ?line true = code:add_path(DDir++"foobar-0.1/ebin"), - ?line true = code:add_path(DDir++"zork-0.8/ebin"), + true = code:del_path(TestServerPath), + true = code:add_path(DDir++"foobar-0.1/ebin"), + true = code:add_path(DDir++"zork-0.8/ebin"), test_server:capture_start(), - ?line ok = code:clash(), + ok = code:clash(), test_server:capture_stop(), - ?line [OKMsg|_] = test_server:capture_get(), - ?line true = lists:prefix("** Found 0 name clashes", OKMsg), - ?line true = code:set_path(P), + [OKMsg|_] = test_server:capture_get(), + true = lists:prefix("** Found 0 name clashes", OKMsg), + true = code:set_path(P), %% test clashing entries %% remove TestServerPath to prevent clash with test-server path - ?line true = code:del_path(TestServerPath), - ?line true = code:add_path(DDir++"foobar-0.1/ebin"), - ?line true = code:add_path(DDir++"foobar-0.1.ez/foobar-0.1/ebin"), + true = code:del_path(TestServerPath), + true = code:add_path(DDir++"foobar-0.1/ebin"), + true = code:add_path(DDir++"foobar-0.1.ez/foobar-0.1/ebin"), test_server:capture_start(), - ?line ok = code:clash(), + ok = code:clash(), test_server:capture_stop(), - ?line [ClashMsg|_] = test_server:capture_get(), - ?line {match, [" hides "]} = re:run(ClashMsg, "\\*\\* .*( hides ).*", + [ClashMsg|_] = test_server:capture_get(), + {match, [" hides "]} = re:run(ClashMsg, "\\*\\* .*( hides ).*", [{capture,all_but_first,list}]), - ?line true = code:set_path(P), + true = code:set_path(P), %% test "Bad path can't read" %% remove TestServerPath to prevent clash with test-server path Priv = ?config(priv_dir, Config), - ?line true = code:del_path(TestServerPath), + true = code:del_path(TestServerPath), TmpEzFile = Priv++"foobar-0.tmp.ez", - ?line {ok, _} = file:copy(DDir++"foobar-0.1.ez", TmpEzFile), - ?line true = code:add_path(TmpEzFile++"/foobar-0.1/ebin"), + {ok, _} = file:copy(DDir++"foobar-0.1.ez", TmpEzFile), + true = code:add_path(TmpEzFile++"/foobar-0.1/ebin"), case os:type() of {win32,_} -> - %% The file wont be deleted on windows until it's closed, why we + %% The file wont be deleted on windows until it's closed, why we %% need to rename instead. - ?line ok = file:rename(TmpEzFile,TmpEzFile++".moved"); + ok = file:rename(TmpEzFile,TmpEzFile++".moved"); _ -> - ?line ok = file:delete(TmpEzFile) + ok = file:delete(TmpEzFile) end, test_server:capture_start(), - ?line ok = code:clash(), + ok = code:clash(), test_server:capture_stop(), - ?line [BadPathMsg|_] = test_server:capture_get(), - ?line true = lists:prefix("** Bad path can't read", BadPathMsg), - ?line true = code:set_path(P), + [BadPathMsg|_] = test_server:capture_get(), + true = lists:prefix("** Bad path can't read", BadPathMsg), + true = code:set_path(P), file:delete(TmpEzFile++".moved"), %% Only effect on windows ok. @@ -687,7 +720,7 @@ ext_mod_dep(Config) when is_list(Config) -> xref:add_directory(s, filename:join(code:lib_dir(kernel),"ebin")), xref:add_directory(s, filename:join(code:lib_dir(stdlib),"ebin")), case catch ext_mod_dep2() of - {'EXIT', Reason} -> + {'EXIT', Reason} -> xref:stop(s), exit(Reason); Else -> @@ -699,7 +732,7 @@ ext_mod_dep(Config) when is_list(Config) -> end. ext_mod_dep2() -> - Exports0 = code_server:module_info(exports) -- + Exports0 = code_server:module_info(exports) -- [{module_info,0},{module_info,1}], Exports = [{code_server,M,A} || {M,A} <- Exports0], case analyse(Exports, [], [], 0) of @@ -709,17 +742,17 @@ ext_mod_dep2() -> {not_verified,ErrCnt} end. -analyse([], [], Visited, ErrCnt) -> +analyse([], [], Visited, ErrCnt) -> {Visited,ErrCnt}; analyse([], [This={M,F,A}|Path], Visited, ErrCnt0) -> %% The code_server has been granted to use the following modules, - %% These modules should be loaded by code.erl before + %% These modules should be loaded by code.erl before %% the code_server is started. OK = [erlang, os, prim_file, erl_prim_loader, init, ets, code_server, lists, lists_sort, unicode, binary, filename, gb_sets, gb_trees, hipe_unified_loader, hipe_bifs, prim_zip, zlib], - ErrCnt1 = + ErrCnt1 = case lists:member(M, OK) or erlang:is_builtin(M,F,A) of true -> 0; @@ -729,7 +762,7 @@ analyse([], [This={M,F,A}|Path], Visited, ErrCnt0) -> {Visited, ErrCnt1+ErrCnt0}; analyse([MFA|R], Path, Visited0, ErrCnt0) -> case lists:member(MFA,Visited0) of - false -> + false -> {Visited,ErrCnt1} = analyse2(MFA, Path, Visited0), analyse(R, Path, Visited, ErrCnt1+ErrCnt0); true -> @@ -814,7 +847,7 @@ check_funs({'$M_EXPR','$F_EXPR',_}, {code_server,start_link,1}]) -> 0; check_funs({'$M_EXPR','$F_EXPR',_}, [{erlang,spawn_link,1},{code_server,start_link,1}]) -> 0; -check_funs({'$M_EXPR',module_info,1}, +check_funs({'$M_EXPR',module_info,1}, [{hipe_unified_loader,patch_to_emu_step1,1} | _]) -> 0; check_funs({'$M_EXPR','$F_EXPR',2}, [{lists,foldl,3}, @@ -829,7 +862,7 @@ check_funs({'$M_EXPR','$F_EXPR',1}, check_funs({'$M_EXPR',warning_msg,2}, [{code_server,finish_on_load_report,2} | _]) -> 0; %% This is cheating! /raimo -%% +%% %% check_funs(This = {M,_,_}, Path) -> %% case catch atom_to_list(M) of %% [$h,$i,$p,$e | _] -> @@ -861,9 +894,9 @@ load_cached(suite) -> load_cached(doc) -> []; load_cached(Config) when is_list(Config) -> - ?line Priv = ?config(priv_dir, Config), - ?line WD = filename:dirname(code:which(?MODULE)), - ?line {ok,Node} = + Priv = ?config(priv_dir, Config), + WD = filename:dirname(code:which(?MODULE)), + {ok,Node} = ?t:start_node(code_cache_node, peer, [{args, "-pa \"" ++ WD ++ "\""}, {erl, [this]}]), @@ -873,7 +906,7 @@ load_cached(Config) when is_list(Config) -> _ -> false end end, - ?line Tabs = rpc:call(Node, ets, all, []), + Tabs = rpc:call(Node, ets, all, []), case rpc:call(Node, lists, any, [CCTabCreated,Tabs]) of true -> ?t:stop_node(Node), @@ -881,25 +914,25 @@ load_cached(Config) when is_list(Config) -> false -> ok end, - ?line rpc:call(Node, code, del_path, [Priv]), - ?line rpc:call(Node, code, add_pathz, [Priv]), + rpc:call(Node, code, del_path, [Priv]), + rpc:call(Node, code, add_pathz, [Priv]), FullModName = Priv ++ "/code_cache_test", - ?line {ok,Dev} = file:open(FullModName ++ ".erl", [write]), - ?line io:format(Dev, "-module(code_cache_test). -export([a/0]). a() -> ok.~n", []), - ?line ok = file:close(Dev), - ?line {ok,code_cache_test} = compile:file(FullModName, [{outdir,Priv}]), + {ok,Dev} = file:open(FullModName ++ ".erl", [write]), + io:format(Dev, "-module(code_cache_test). -export([a/0]). a() -> ok.~n", []), + ok = file:close(Dev), + {ok,code_cache_test} = compile:file(FullModName, [{outdir,Priv}]), F = fun load_loop/2, N = 1000, - ?line {T0,T1} = rpc:call(Node, erlang, apply, [F, [N,code_cache_test]]), + {T0,T1} = rpc:call(Node, erlang, apply, [F, [N,code_cache_test]]), TNoCache = now_diff(T1, T0), - ?line rpc:call(Node, code, rehash, []), - ?line {T2,T3} = rpc:call(Node, erlang, apply, [F, [N,code_cache_test]]), - ?line TCache = now_diff(T3, T2), + rpc:call(Node, code, rehash, []), + {T2,T3} = rpc:call(Node, erlang, apply, [F, [N,code_cache_test]]), + TCache = now_diff(T3, T2), AvgNoCache = TNoCache/N, AvgCache = TCache/N, - ?line io:format("Avg. load time (no_cache/cache): ~w/~w~n", [AvgNoCache,AvgCache]), + io:format("Avg. load time (no_cache/cache): ~w/~w~n", [AvgNoCache,AvgCache]), ?t:stop_node(Node), if AvgNoCache =< AvgCache -> ?t:fail("Cache not working properly."); @@ -916,7 +949,7 @@ load_loop(N, M, T0) -> code:delete(M), code:purge(M), load_loop(N-1, M, T0). - + now_diff({A2, B2, C2}, {A1, B1, C1}) -> ((A2-A1)*1000000 + B2-B1)*1000000 + C2-C1. @@ -925,30 +958,30 @@ start_node_with_cache(suite) -> start_node_with_cache(doc) -> []; start_node_with_cache(Config) when is_list(Config) -> - ?line {ok,Node} = - ?t:start_node(code_cache_node, peer, [{args, + {ok,Node} = + ?t:start_node(code_cache_node, peer, [{args, "-code_path_cache"}, {erl, [this]}]), - ?line Tabs = rpc:call(Node, ets, all, []), + Tabs = rpc:call(Node, ets, all, []), io:format("Tabs: ~w~n", [Tabs]), CCTabCreated = fun(Tab) -> case rpc:call(Node, ets, info, [Tab,name]) of code_cache -> true; _ -> false end - end, - ?line true = lists:any(CCTabCreated, Tabs), + end, + true = lists:any(CCTabCreated, Tabs), ?t:stop_node(Node), ok. - + add_and_rehash(suite) -> []; add_and_rehash(doc) -> []; add_and_rehash(Config) when is_list(Config) -> - ?line Priv = ?config(priv_dir, Config), - ?line WD = filename:dirname(code:which(?MODULE)), - ?line {ok,Node} = + Priv = ?config(priv_dir, Config), + WD = filename:dirname(code:which(?MODULE)), + {ok,Node} = ?t:start_node(code_cache_node, peer, [{args, "-pa \"" ++ WD ++ "\""}, {erl, [this]}]), @@ -958,7 +991,7 @@ add_and_rehash(Config) when is_list(Config) -> _ -> false end end, - ?line Tabs0 = rpc:call(Node, ets, all, []), + Tabs0 = rpc:call(Node, ets, all, []), case rpc:call(Node, lists, any, [CCTabCreated,Tabs0]) of true -> ?t:stop_node(Node), @@ -966,36 +999,36 @@ add_and_rehash(Config) when is_list(Config) -> false -> ok end, - ?line ok = rpc:call(Node, code, rehash, []), % create cache - ?line Tabs1 = rpc:call(Node, ets, all, []), - ?line true = rpc:call(Node, lists, any, [CCTabCreated,Tabs1]), % cache table created - ?line ok = rpc:call(Node, code, rehash, []), + ok = rpc:call(Node, code, rehash, []), % create cache + Tabs1 = rpc:call(Node, ets, all, []), + true = rpc:call(Node, lists, any, [CCTabCreated,Tabs1]), % cache table created + ok = rpc:call(Node, code, rehash, []), OkDir = filename:join(Priv, ""), BadDir = filename:join(Priv, "guggemuffsussiputt"), - ?line CP = [OkDir | rpc:call(Node, code, get_path, [])], - ?line true = rpc:call(Node, code, set_path, [CP]), + CP = [OkDir | rpc:call(Node, code, get_path, [])], + true = rpc:call(Node, code, set_path, [CP]), CP1 = [BadDir | CP], - ?line {error,_} = rpc:call(Node, code, set_path, [CP1]), - ?line true = rpc:call(Node, code, del_path, [OkDir]), - ?line true = rpc:call(Node, code, add_path, [OkDir]), - ?line true = rpc:call(Node, code, add_path, [OkDir]), - ?line {error,_} = rpc:call(Node, code, add_path, [BadDir]), - ?line ok = rpc:call(Node, code, rehash, []), + {error,_} = rpc:call(Node, code, set_path, [CP1]), + true = rpc:call(Node, code, del_path, [OkDir]), + true = rpc:call(Node, code, add_path, [OkDir]), + true = rpc:call(Node, code, add_path, [OkDir]), + {error,_} = rpc:call(Node, code, add_path, [BadDir]), + ok = rpc:call(Node, code, rehash, []), ?t:stop_node(Node), ok. - + where_is_file_no_cache(suite) -> []; where_is_file_no_cache(doc) -> []; where_is_file_no_cache(Config) when is_list(Config) -> - ?line {T,KernelBeamFile} = timer:tc(code, where_is_file, ["kernel.beam"]), + {T,KernelBeamFile} = timer:tc(code, where_is_file, ["kernel.beam"]), io:format("Load time: ~w ms~n", [T]), - ?line KernelEbinDir = filename:dirname(KernelBeamFile), - ?line AppFile = filename:join(KernelEbinDir, "kernel.app"), - ?line AppFile = code:where_is_file("kernel.app"), - ?line non_existing = code:where_is_file("kernel"), % no such file + KernelEbinDir = filename:dirname(KernelBeamFile), + AppFile = filename:join(KernelEbinDir, "kernel.app"), + AppFile = code:where_is_file("kernel.app"), + non_existing = code:where_is_file("kernel"), % no such file ok. where_is_file_cached(suite) -> @@ -1003,97 +1036,97 @@ where_is_file_cached(suite) -> where_is_file_cached(doc) -> []; where_is_file_cached(Config) when is_list(Config) -> - ?line {ok,Node} = - ?t:start_node(code_cache_node, peer, [{args, + {ok,Node} = + ?t:start_node(code_cache_node, peer, [{args, "-code_path_cache"}, {erl, [this]}]), - ?line Tabs = rpc:call(Node, ets, all, []), + Tabs = rpc:call(Node, ets, all, []), io:format("Tabs: ~w~n", [Tabs]), CCTabCreated = fun(Tab) -> case rpc:call(Node, ets, info, [Tab,name]) of code_cache -> true; _ -> false end - end, - ?line true = lists:any(CCTabCreated, Tabs), - ?line KernelBeamFile = rpc:call(Node, code, where_is_file, ["kernel.beam"]), - ?line {T,KernelBeamFile} = rpc:call(Node, timer, tc, [code,where_is_file,["kernel.beam"]]), + end, + true = lists:any(CCTabCreated, Tabs), + KernelBeamFile = rpc:call(Node, code, where_is_file, ["kernel.beam"]), + {T,KernelBeamFile} = rpc:call(Node, timer, tc, [code,where_is_file,["kernel.beam"]]), io:format("Load time: ~w ms~n", [T]), - ?line KernelEbinDir = rpc:call(Node, filename, dirname, [KernelBeamFile]), - ?line AppFile = rpc:call(Node, filename, join, [KernelEbinDir,"kernel.app"]), - ?line AppFile = rpc:call(Node, code, where_is_file, ["kernel.app"]), - ?line non_existing = rpc:call(Node, code, where_is_file, ["kernel"]), % no such file + KernelEbinDir = rpc:call(Node, filename, dirname, [KernelBeamFile]), + AppFile = rpc:call(Node, filename, join, [KernelEbinDir,"kernel.app"]), + AppFile = rpc:call(Node, code, where_is_file, ["kernel.app"]), + non_existing = rpc:call(Node, code, where_is_file, ["kernel"]), % no such file ?t:stop_node(Node), ok. - + purge_stacktrace(suite) -> []; purge_stacktrace(doc) -> ["Test that stacktrace is deleted when purging a referred module"]; purge_stacktrace(Config) when is_list(Config) -> - ?line code:purge(code_b_test), + code:purge(code_b_test), try code_b_test:call(fun(b) -> ok end, a) catch error:function_clause -> - ?line code:load_file(code_b_test), - ?line case erlang:get_stacktrace() of + code:load_file(code_b_test), + case erlang:get_stacktrace() of [{?MODULE,_,[a],_}, {code_b_test,call,2,_}, {?MODULE,purge_stacktrace,1,_}|_] -> - ?line false = code:purge(code_b_test), - ?line [] = erlang:get_stacktrace() + false = code:purge(code_b_test), + [] = erlang:get_stacktrace() end end, try code_b_test:call(nofun, 2) catch error:function_clause -> - ?line code:load_file(code_b_test), - ?line case erlang:get_stacktrace() of + code:load_file(code_b_test), + case erlang:get_stacktrace() of [{code_b_test,call,[nofun,2],_}, {?MODULE,purge_stacktrace,1,_}|_] -> - ?line false = code:purge(code_b_test), - ?line [] = erlang:get_stacktrace() + false = code:purge(code_b_test), + [] = erlang:get_stacktrace() end end, Args = [erlang,error,[badarg]], try code_b_test:call(erlang, error, [badarg,Args]) catch error:badarg -> - ?line code:load_file(code_b_test), - ?line case erlang:get_stacktrace() of + code:load_file(code_b_test), + case erlang:get_stacktrace() of [{code_b_test,call,Args,_}, {?MODULE,purge_stacktrace,1,_}|_] -> - ?line false = code:purge(code_b_test), - ?line [] = erlang:get_stacktrace() + false = code:purge(code_b_test), + [] = erlang:get_stacktrace() end end, ok. mult_lib_roots(Config) when is_list(Config) -> - ?line DataDir = filename:join(?config(data_dir, Config), "mult_lib_roots"), - ?line mult_lib_compile(DataDir, "my_dummy_app-b/ebin/lists"), - ?line mult_lib_compile(DataDir, + DataDir = filename:join(?config(data_dir, Config), "mult_lib_roots"), + mult_lib_compile(DataDir, "my_dummy_app-b/ebin/lists"), + mult_lib_compile(DataDir, "my_dummy_app-c/ebin/code_SUITE_mult_root_module"), %% Set up ERL_LIBS and start a slave node. ErlLibs = filename:join(DataDir, "first_root") ++ mult_lib_sep() ++ filename:join(DataDir, "second_root"), - ?line {ok,Node} = + {ok,Node} = ?t:start_node(mult_lib_roots, slave, [{args,"-env ERL_LIBS "++ErlLibs}]), - ?line TSPath = filename:dirname(code:which(test_server)), - ?line Path0 = rpc:call(Node, code, get_path, []), - ?line [TSPath,"."|Path1] = Path0, - ?line [Kernel|Path2] = Path1, - ?line [Stdlib|Path3] = Path2, - ?line mult_lib_verify_lib(Kernel, "kernel"), - ?line mult_lib_verify_lib(Stdlib, "stdlib"), - ?line [Lib1,Lib2,Lib3,Lib4,Lib5|Path] = Path3, + TSPath = filename:dirname(code:which(test_server)), + Path0 = rpc:call(Node, code, get_path, []), + [TSPath,"."|Path1] = Path0, + [Kernel|Path2] = Path1, + [Stdlib|Path3] = Path2, + mult_lib_verify_lib(Kernel, "kernel"), + mult_lib_verify_lib(Stdlib, "stdlib"), + [Lib1,Lib2,Lib3,Lib4,Lib5|Path] = Path3, + - ["first_root/my_dummy_app-a/ebin", "first_root/my_dummy_app-b/ebin", "first_root/my_dummy_app-c/ebin", @@ -1103,7 +1136,7 @@ mult_lib_roots(Config) when is_list(Config) -> E <- lists:sort([Lib1,Lib2,Lib3,Lib4,Lib5])], io:format("~p\n", [Path]), - ?line true = rpc:call(Node, code_SUITE_mult_root_module, works_fine, []), + true = rpc:call(Node, code_SUITE_mult_root_module, works_fine, []), ok. @@ -1113,7 +1146,7 @@ mult_lib_compile(Root, Last) -> Dir = filename:dirname(Name), {ok,Mod} = compile:file(Name, [report,{outdir,Dir}]), ok. - + mult_lib_sep() -> case os:type() of {win32,_} -> ";"; @@ -1123,23 +1156,23 @@ mult_lib_sep() -> mult_lib_verify_lib(Path, Expected) -> Dir = filename:basename(filename:dirname(Path)), true = lists:prefix(Expected, Dir). - + mult_lib_remove_prefix([H|T1], [H|T2]) -> mult_lib_remove_prefix(T1, T2); mult_lib_remove_prefix([$/|T], []) -> T. bad_erl_libs(Config) when is_list(Config) -> - ?line {ok,Node} = + {ok,Node} = ?t:start_node(mult_lib_roots, slave, [{args,"-env ERL_LIBS "}]), - ?line ?t:stop_node(Node), + ?t:stop_node(Node), - ?line {ok,Node2} = + {ok,Node2} = ?t:start_node(mult_lib_roots, slave, [{args,"-env ERL_LIBS /no/such/dir"}]), - ?line ?t:stop_node(Node2), + ?t:stop_node(Node2), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1158,55 +1191,55 @@ do_code_archive(Config, Root, StripVsn) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), App = code_archive_dict, VsnBase = atom_to_list(App) ++ "-1.0", - Base = + Base = case StripVsn of true -> atom_to_list(App); false -> VsnBase end, Ext = init:archive_extension(), RootDir = filename:join([PrivDir, Root]), - ?line ok = file:make_dir(RootDir), + ok = file:make_dir(RootDir), Archive = filename:join([RootDir, VsnBase ++ Ext]), - ?line {ok, _} = zip:create(Archive, [VsnBase], + {ok, _} = zip:create(Archive, [VsnBase], [{compress, []}, {cwd, DataDir}]), - ?line {ok, _} = zip:extract(Archive, [{cwd, PrivDir}]), + {ok, _} = zip:extract(Archive, [{cwd, PrivDir}]), case StripVsn of true -> - ?line ok = file:rename(filename:join([PrivDir, VsnBase]), + ok = file:rename(filename:join([PrivDir, VsnBase]), filename:join([PrivDir, Base])); false -> ok end, - + io:format("DEBUG: ~p\n", [?LINE]), %% Compile the code - ?line ok = compile_app(PrivDir, Base), - + ok = compile_app(PrivDir, Base), + %% Create the archive - ?line ok = file:delete(Archive), - ?line {ok, _} = zip:create(Archive, [Base], + ok = file:delete(Archive), + {ok, _} = zip:create(Archive, [Base], [{compress, []}, {cwd, PrivDir}]), %% Set up ERL_LIBS and start a slave node. - ?line {ok, Node} = + {ok, Node} = ?t:start_node(code_archive, slave, [{args,"-env ERL_LIBS " ++ RootDir}]), - ?line CodePath = rpc:call(Node, code, get_path, []), + CodePath = rpc:call(Node, code, get_path, []), AppEbin = filename:join([Archive, Base, "ebin"]), io:format("AppEbin: ~p\n", [AppEbin]), io:format("CodePath: ~p\n", [CodePath]), io:format("Archive: ~p\n", [erl_prim_loader:read_file_info(Archive)]), - ?line true = lists:member(AppEbin, CodePath), + true = lists:member(AppEbin, CodePath), %% Start the app - ?line ok = rpc:call(Node, application, start, [App]), - + ok = rpc:call(Node, application, start, [App]), + %% Access the app priv dir AppPrivDir = rpc:call(Node, code, priv_dir, [App]), - ?line AppPrivFile = filename:join([AppPrivDir, "code_archive.txt"]), + AppPrivFile = filename:join([AppPrivDir, "code_archive.txt"]), io:format("AppPrivFile: ~p\n", [AppPrivFile]), - ?line {ok, _Bin, _Path} = + {ok, _Bin, _Path} = rpc:call(Node, erl_prim_loader, get_file, [AppPrivFile]), %% Use the app @@ -1221,14 +1254,14 @@ do_code_archive(Config, Root, StripVsn) when is_list(Config) -> error = rpc:call(Node, App, find, [Tab, Key]), ok = rpc:call(Node, App, erase, [Tab]), - ?line ?t:stop_node(Node), + ?t:stop_node(Node), ok. compile_app(TopDir, AppName) -> AppDir = filename:join([TopDir, AppName]), SrcDir = filename:join([AppDir, "src"]), OutDir = filename:join([AppDir, "ebin"]), - ?line {ok, Files} = file:list_dir(SrcDir), + {ok, Files} = file:list_dir(SrcDir), compile_files(Files, SrcDir, OutDir). compile_files([File | Files], SrcDir, OutDir) -> @@ -1253,27 +1286,27 @@ big_boot_embedded(doc) -> ["Test that a boot file with (almost) all of OTP can be used to start an" " embeddedd system."]; big_boot_embedded(Config) when is_list(Config) -> - ?line {BootArg,AppsInBoot} = create_big_boot(Config), - ?line {ok, Node} = + {BootArg,AppsInBoot} = create_big_boot(Config), + {ok, Node} = ?t:start_node(big_boot_embedded, slave, [{args,"-boot "++BootArg++" -mode embedded"}]), - ?line RemoteNodeApps = - [ {X,Y} || {X,_,Y} <- + RemoteNodeApps = + [ {X,Y} || {X,_,Y} <- rpc:call(Node,application,loaded_applications,[]) ], - ?line true = lists:sort(AppsInBoot) =:= lists:sort(RemoteNodeApps), + true = lists:sort(AppsInBoot) =:= lists:sort(RemoteNodeApps), ok. on_load(Config) when is_list(Config) -> Master = on_load_test_case_process, - ?line Data = filename:join([?config(data_dir, Config),"on_load"]), - ?line ok = file:set_cwd(Data), - ?line up_to_date = make:all([{d,'MASTER',Master}]), + Data = filename:join([?config(data_dir, Config),"on_load"]), + ok = file:set_cwd(Data), + up_to_date = make:all([{d,'MASTER',Master}]), %% Register a name for this process. - ?line register(Master, self()), - - ?line {_,Ref} = spawn_monitor(fun() -> + register(Master, self()), + + {_,Ref} = spawn_monitor(fun() -> exit(on_load_a:data()) end), receive @@ -1285,8 +1318,8 @@ on_load(Config) when is_list(Config) -> receive {on_load_c,PidC} -> ok end, - - ?line Refs = on_load_massive_spawn(lists:seq(1, 50)), + + Refs = on_load_massive_spawn(lists:seq(1, 50)), receive after 7 -> ok end, PidC ! go, @@ -1304,13 +1337,13 @@ on_load(Config) when is_list(Config) -> receive {'DOWN',Ref,process,_,Res} -> - ?line [a,b,c] = Res + [a,b,c] = Res end, on_load_wait_for_all(Refs), receive Any -> - ?line ?t:fail({unexpected,Any}) + ?t:fail({unexpected,Any}) after 10 -> ok end. @@ -1377,13 +1410,13 @@ on_load_embedded(Config) when is_list(Config) -> end. on_load_embedded_1(Config) -> - ?line DataDir = ?config(data_dir, Config), + DataDir = ?config(data_dir, Config), %% Link the on_load_app application into the lib directory. - ?line LibRoot = code:lib_dir(), - ?line LinkName = filename:join(LibRoot, "on_load_app-1.0"), - ?line OnLoadApp = filename:join(DataDir, "on_load_app-1.0"), - ?line del_link(LinkName), + LibRoot = code:lib_dir(), + LinkName = filename:join(LibRoot, "on_load_app-1.0"), + OnLoadApp = filename:join(DataDir, "on_load_app-1.0"), + del_link(LinkName), io:format("LinkName :~p, OnLoadApp: ~p~n",[LinkName,OnLoadApp]), case file:make_symlink(OnLoadApp, LinkName) of {error,enotsup} -> @@ -1392,28 +1425,28 @@ on_load_embedded_1(Config) -> end, %% Compile the code. - ?line OnLoadAppEbin = filename:join(LinkName, "ebin"), - ?line {ok,_ } = compile:file(filename:join([OnLoadApp,"src", + OnLoadAppEbin = filename:join(LinkName, "ebin"), + {ok,_ } = compile:file(filename:join([OnLoadApp,"src", "on_load_embedded"]), [{outdir,OnLoadAppEbin}]), %% Create and compile a boot file. - ?line true = code:add_pathz(OnLoadAppEbin), + true = code:add_pathz(OnLoadAppEbin), Options = case is_source_dir() of true -> [local]; false -> [] end, - ?line BootScript = create_boot(Config, Options), - ?line true = code:del_path(OnLoadAppEbin), + BootScript = create_boot(Config, Options), + true = code:del_path(OnLoadAppEbin), %% Start the node and check that the on_load function was run. - ?line {ok,Node} = start_node(on_load_embedded, + {ok,Node} = start_node(on_load_embedded, "-mode embedded -boot " ++ BootScript), ok = rpc:call(Node, on_load_embedded, status, []), %% Clean up. - ?line stop_node(Node), - ?line ok = del_link(LinkName). + stop_node(Node), + ok = del_link(LinkName). del_link(LinkName) -> case file:delete(LinkName) of @@ -1421,100 +1454,94 @@ del_link(LinkName) -> file:del_dir(LinkName); Other -> Other - end. + end. create_boot(Config, Options) -> - ?line {ok, OldDir} = file:get_cwd(), - ?line {LatestDir,LatestName} = create_script(Config), - ?line ok = file:set_cwd(LatestDir), - ?line ok = systools:make_script(LatestName, Options), - ?line ok = file:set_cwd(OldDir), + {ok, OldDir} = file:get_cwd(), + {LatestDir,LatestName} = create_script(Config), + ok = file:set_cwd(LatestDir), + ok = systools:make_script(LatestName, Options), + ok = file:set_cwd(OldDir), filename:join(LatestDir, LatestName). create_script(Config) -> - ?line PrivDir = ?config(priv_dir, Config), - ?line Name = PrivDir ++ "on_load_test", - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel, 1, Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib, 1, Apps), - ?line {ok,Fd} = file:open(Name ++ ".rel", [write]), - ?line io:format(Fd, + PrivDir = ?config(priv_dir, Config), + Name = PrivDir ++ "on_load_test", + Apps = application_controller:which_applications(), + {value,{_,_,KernelVer}} = lists:keysearch(kernel, 1, Apps), + {value,{_,_,StdlibVer}} = lists:keysearch(stdlib, 1, Apps), + {ok,Fd} = file:open(Name ++ ".rel", [write]), + io:format(Fd, "{release, {\"Test release 3\", \"P2A\"}, \n" " {erts, \"9.42\"}, \n" " [{kernel, \"~s\"}, {stdlib, \"~s\"}," " {on_load_app, \"1.0\"}]}.\n", [KernelVer,StdlibVer]), - ?line file:close(Fd), + file:close(Fd), {filename:dirname(Name),filename:basename(Name)}. create_big_boot(Config) -> - ?line {ok, OldDir} = file:get_cwd(), - ?line {Options,Local} = case is_source_dir() of - true -> {[no_module_tests,local],true}; - _ -> {[no_module_tests],false} + {ok, OldDir} = file:get_cwd(), + {Options,Local} = case is_source_dir() of + true -> {[no_module_tests,local],true}; + _ -> {[no_module_tests],false} end, - ?line {LatestDir,LatestName,Apps} = create_big_script(Config,Local), - ?line ok = file:set_cwd(LatestDir), - ?line ok = systools:make_script(LatestName, Options), - ?line ok = file:set_cwd(OldDir), + {LatestDir,LatestName,Apps} = create_big_script(Config,Local), + ok = file:set_cwd(LatestDir), + ok = systools:make_script(LatestName, Options), + ok = file:set_cwd(OldDir), {filename:join(LatestDir, LatestName),Apps}. -% The following apps cannot be loaded +% The following apps cannot be loaded % hipe .app references (or can reference) files that have no % corresponding beam file (if hipe is not enabled) -filter_app("hipe",_) -> - false; +filter_app("hipe",_) -> false; % Dialyzer and typer depends on hipe -filter_app("dialyzer",_) -> - false; -filter_app("typer",_) -> - false; +filter_app("dialyzer",_) -> false; +filter_app("typer",_) -> false; % Orber requires explicit configuration -filter_app("orber",_) -> - false; +filter_app("orber",_) -> false; % cos* depends on orber -filter_app("cos"++_,_) -> - false; +filter_app("cos"++_,_) -> false; % ic has a mod instruction in the app file but no corresponding start function -filter_app("ic",_) -> - false; +filter_app("ic",_) -> false; % Netconf has some dependency that I really do not understand (maybe like orber) -filter_app("netconf",_) -> - false; +filter_app("netconf",_) -> false; % Safe has the same kind of error in the .app file as ic -filter_app("safe",_) -> - false; +filter_app("safe",_) -> false; % Comte cannot be started in the "usual" way -filter_app("comte",_) -> - false; +filter_app("comte",_) -> false; % OS_mon does not find it's port program when running cerl -filter_app("os_mon",true) -> - false; +filter_app("os_mon",true) -> false; +% erts is not a "real" app either =/ +filter_app("erts",_) -> false; % Other apps should be OK. -filter_app(_,_) -> - true. +filter_app(_,_) -> true. create_big_script(Config,Local) -> - ?line PrivDir = ?config(priv_dir, Config), - ?line Name = filename:join(PrivDir,"full_script_test"), - ?line InitialApplications=application:loaded_applications(), + PrivDir = ?config(priv_dir, Config), + Name = filename:join(PrivDir,"full_script_test"), + InitialApplications=application:loaded_applications(), %% Applications left loaded by the application suite, unload them! - ?line UnloadFix=[app0,app1,app2,group_leader,app_start_error], - ?line [application:unload(Leftover) || + UnloadFix=[app0,app1,app2,group_leader,app_start_error], + [application:unload(Leftover) || Leftover <- UnloadFix, lists:keymember(Leftover,1,InitialApplications) ], %% Now we should have only "real" applications... - ?line [application:load(list_to_atom(Y)) || {match,[Y]} <- [ re:run(X,code:lib_dir()++"/"++"([^/-]*).*/ebin",[{capture,[1],list}]) || X <- code:get_path()],filter_app(Y,Local)], - ?line Apps = [ {N,V} || {N,_,V} <- application:loaded_applications()], - ?line {ok,Fd} = file:open(Name ++ ".rel", [write]), - ?line io:format(Fd, + [application:load(list_to_atom(Y)) + || {match,[Y]} <- [re:run(X,code:lib_dir()++"/"++"([^/-]*).*/ebin", + [{capture,[1],list},unicode]) || + X <- code:get_path()],filter_app(Y,Local)], + Apps = [ {N,V} || {N,_,V} <- application:loaded_applications()], + {ok,Fd} = file:open(Name ++ ".rel", [write]), + io:format(Fd, "{release, {\"Test release 3\", \"P2A\"}, \n" " {erts, \"9.42\"}, \n" " ~p}.\n", [Apps]), - ?line file:close(Fd), - ?line NewlyLoaded = + file:close(Fd), + NewlyLoaded = application:loaded_applications() -- InitialApplications, - ?line [ application:unload(N) || {N,_,_} <- NewlyLoaded], + [ application:unload(N) || {N,_,_} <- NewlyLoaded], {filename:dirname(Name),filename:basename(Name),Apps}. is_source_dir() -> @@ -1523,35 +1550,35 @@ is_source_dir() -> on_load_errors(Config) when is_list(Config) -> Master = on_load_error_test_case_process, - ?line register(Master, self()), + register(Master, self()), - ?line Data = filename:join([?config(data_dir, Config),"on_load_errors"]), - ?line ok = file:set_cwd(Data), - ?line up_to_date = make:all([{d,'MASTER',Master}]), + Data = filename:join([?config(data_dir, Config),"on_load_errors"]), + ok = file:set_cwd(Data), + up_to_date = make:all([{d,'MASTER',Master}]), - ?line do_on_load_error(an_atom), + do_on_load_error(an_atom), - ?line error_logger:add_report_handler(?MODULE, self()), + error_logger:add_report_handler(?MODULE, self()), - ?line do_on_load_error({something,terrible,is,wrong}), + do_on_load_error({something,terrible,is,wrong}), receive Any1 -> - ?line {_, "The on_load function"++_, + {_, "The on_load function"++_, [on_load_error, {something,terrible,is,wrong},_]} = Any1 end, - ?line do_on_load_error(fail), %Cause exception. + do_on_load_error(fail), %Cause exception. receive Any2 -> - ?line {_, "The on_load function"++_, + {_, "The on_load function"++_, [on_load_error,{failed,[_|_]},_]} = Any2 end, %% There should be no more messages. receive Unexpected -> - ?line ?t:fail({unexpected,Unexpected}) + ?t:fail({unexpected,Unexpected}) after 10 -> ok end, @@ -1559,14 +1586,14 @@ on_load_errors(Config) when is_list(Config) -> ok. do_on_load_error(ReturnValue) -> - ?line {_,Ref} = spawn_monitor(fun() -> + {_,Ref} = spawn_monitor(fun() -> exit(on_load_error:main()) end), receive {on_load_error,ErrorPid} -> ok end, - ?line ErrorPid ! ReturnValue, + ErrorPid ! ReturnValue, receive {'DOWN',Ref,process,_,Exit} -> - ?line {undef,[{on_load_error,main,[],_}|_]} = Exit + {undef,[{on_load_error,main,[],_}|_]} = Exit end. native_early_modules(suite) -> []; @@ -1580,10 +1607,10 @@ native_early_modules(Config) when is_list(Config) -> end. native_early_modules_1(Architecture) -> - ?line {lists, ListsBinary, _ListsFilename} = code:get_object_code(lists), - ?line ChunkName = hipe_unified_loader:chunk_name(Architecture), - ?line NativeChunk = beam_lib:chunks(ListsBinary, [ChunkName]), - ?line IsHipeCompiled = case NativeChunk of + {lists, ListsBinary, _ListsFilename} = code:get_object_code(lists), + ChunkName = hipe_unified_loader:chunk_name(Architecture), + NativeChunk = beam_lib:chunks(ListsBinary, [ChunkName]), + IsHipeCompiled = case NativeChunk of {ok,{_,[{_,Bin}]}} when is_binary(Bin) -> true; {error, beam_lib, _} -> false end, @@ -1591,10 +1618,10 @@ native_early_modules_1(Architecture) -> false -> {skip,"OTP apparently not configured with --enable-native-libs"}; true -> - ?line true = lists:all(fun code:is_module_native/1, - [ets,file,filename,gb_sets,gb_trees, - %%hipe_unified_loader, no_native as workaround - lists,os]), + true = lists:all(fun code:is_module_native/1, + [ets,file,filename,gb_sets,gb_trees, + %%hipe_unified_loader, no_native as workaround + lists,os]), ok end. diff --git a/lib/kernel/test/erl_prim_loader_SUITE.erl b/lib/kernel/test/erl_prim_loader_SUITE.erl index 35502a1d27..b2ca3bdbc2 100644 --- a/lib/kernel/test/erl_prim_loader_SUITE.erl +++ b/lib/kernel/test/erl_prim_loader_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2012. All Rights Reserved. +%% Copyright Ericsson AB 1996-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -24,7 +24,7 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2]). --export([get_path/1, set_path/1, get_file/1, +-export([get_path/1, set_path/1, get_file/1, normalize_and_backslash/1, inet_existing/1, inet_coming_up/1, inet_disconnects/1, multiple_slaves/1, file_requests/1, local_archive/1, remote_archive/1, @@ -39,7 +39,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [get_path, set_path, get_file, inet_existing, + [get_path, set_path, get_file, + normalize_and_backslash, inet_existing, inet_coming_up, inet_disconnects, multiple_slaves, file_requests, local_archive, remote_archive, primary_archive, virtual_dir_in_archive]. @@ -107,6 +108,26 @@ get_file(Config) when is_list(Config) -> ?line error = erl_prim_loader:get_file({dummy}), ok. +normalize_and_backslash(Config) -> + %% Test OTP-11170 + case os:type() of + {win32,_} -> + {skip, "not on windows"}; + _ -> + test_normalize_and_backslash(Config) + end. +test_normalize_and_backslash(Config) -> + PrivDir = ?config(priv_dir,Config), + Dir = filename:join(PrivDir,"\\"), + File = filename:join(Dir,"file-OTP-11170"), + ok = file:make_dir(Dir), + ok = file:write_file(File,"a file to test OTP-11170"), + {ok,["file-OTP-11170"]} = file:list_dir(Dir), + {ok,["file-OTP-11170"]} = erl_prim_loader:list_dir(Dir), + ok = file:delete(File), + ok = file:del_dir(Dir), + ok. + inet_existing(doc) -> ["Start a node using the 'inet' loading method, ", "from an already started boot server."]; inet_existing(Config) when is_list(Config) -> diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl index e4c8f0ffaf..c75639ae7e 100644 --- a/lib/kernel/test/file_SUITE.erl +++ b/lib/kernel/test/file_SUITE.erl @@ -805,6 +805,20 @@ new_modes(Config) when is_list(Config) -> ?line {ok, [$\[]} = ?FILE_MODULE:read(Fd6, 1), ?line ok = ?FILE_MODULE:close(Fd6), + %% write and sync + case ?FILE_MODULE:open(Name1, [write, sync]) of + {ok, Fd7} -> + ok = io:write(Fd7, Marker), + ok = io:put_chars(Fd7, ".\n"), + ok = ?FILE_MODULE:close(Fd7), + {ok, Fd8} = ?FILE_MODULE:open(Name1, [read]), + {ok, Marker} = io:read(Fd8, prompt), + ok = ?FILE_MODULE:close(Fd8); + {error, enotsup} -> + %% for platforms that don't support the sync option + ok + end, + ?line [] = flush(), ?line test_server:timetrap_cancel(Dog), ok. diff --git a/lib/kernel/test/file_name_SUITE.erl b/lib/kernel/test/file_name_SUITE.erl index 0c8082026a..9354af2e41 100644 --- a/lib/kernel/test/file_name_SUITE.erl +++ b/lib/kernel/test/file_name_SUITE.erl @@ -1,5 +1,4 @@ -module(file_name_SUITE). -%% -*- coding: utf-8 -*- %% %% %CopyrightBegin% %% diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index e89cb44797..881aaed429 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -1,4 +1,4 @@ -%% +%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2007-2013. All Rights Reserved. @@ -35,8 +35,11 @@ open_unihoming_ipv6_socket/1, open_multihoming_ipv6_socket/1, open_multihoming_ipv4_and_ipv6_socket/1, - basic_stream/1, xfer_stream_min/1, peeloff_active_once/1, - peeloff_active_true/1, buffers/1]). + basic_stream/1, xfer_stream_min/1, active_n/1, + peeloff_active_once/1, peeloff_active_true/1, peeloff_active_n/1, + buffers/1, + names_unihoming_ipv4/1, names_unihoming_ipv6/1, + names_multihoming_ipv4/1, names_multihoming_ipv6/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -46,9 +49,11 @@ all() -> open_multihoming_ipv4_socket, open_unihoming_ipv6_socket, open_multihoming_ipv6_socket, - open_multihoming_ipv4_and_ipv6_socket, + open_multihoming_ipv4_and_ipv6_socket, active_n, basic_stream, xfer_stream_min, peeloff_active_once, - peeloff_active_true, buffers]. + peeloff_active_true, peeloff_active_n, buffers, + names_unihoming_ipv4, names_unihoming_ipv6, + names_multihoming_ipv4, names_multihoming_ipv6]. groups() -> []. @@ -107,7 +112,7 @@ xfer_min(Config) when is_list(Config) -> ?line {ok,Sb} = gen_sctp:open([{type,seqpacket}]), ?line {ok,Pb} = inet:port(Sb), ?line ok = gen_sctp:listen(Sb, true), - + ?line {ok,Sa} = gen_sctp:open(), ?line {ok,Pa} = inet:port(Sa), ?line {ok,#sctp_assoc_change{state=comm_up, @@ -118,18 +123,18 @@ xfer_min(Config) when is_list(Config) -> gen_sctp:connect(Sa, Loopback, Pb, []), ?line {SbAssocId,SaOutboundStreams,SaInboundStreams} = case recv_event(log_ok(gen_sctp:recv(Sb, infinity))) of - {Loopback,Pa, - #sctp_assoc_change{state=comm_up, - error=0, - outbound_streams=SbOutboundStreams, - inbound_streams=SbInboundStreams, - assoc_id=AssocId}} -> - {AssocId,SbInboundStreams,SbOutboundStreams}; - {Loopback,Pa, - #sctp_paddr_change{state=addr_confirmed, - addr={Loopback,Pa}, - error=0, - assoc_id=AssocId}} -> + {Loopback,Pa, + #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=SbOutboundStreams, + inbound_streams=SbInboundStreams, + assoc_id=AssocId}} -> + {AssocId,SbInboundStreams,SbOutboundStreams}; + {Loopback,Pa, + #sctp_paddr_change{state=addr_confirmed, + addr={Loopback,Pa}, + error=0, + assoc_id=AssocId}} -> {Loopback,Pa, #sctp_assoc_change{state=comm_up, error=0, @@ -148,17 +153,20 @@ xfer_min(Config) when is_list(Config) -> assoc_id=SbAssocId}], Data} -> ok; Event1 -> - {Loopback,Pa, - #sctp_paddr_change{addr = {Loopback,_}, - state = addr_available, - error = 0, - assoc_id = SbAssocId}} = - recv_event(Event1), - {ok,{Loopback, - Pa, - [#sctp_sndrcvinfo{stream=Stream, - assoc_id=SbAssocId}], - Data}} = gen_sctp:recv(Sb, infinity) + case recv_event(Event1) of + {Loopback,Pa, + #sctp_paddr_change{addr = {Loopback,_}, + state = State, + error = 0, + assoc_id = SbAssocId}} + when State =:= addr_available; + State =:= addr_confirmed -> + {Loopback, + Pa, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SbAssocId}], + Data} = log_ok(gen_sctp:recv(Sb, infinity)) + end end, ?line ok = gen_sctp:send(Sb, SbAssocId, 0, Data), ?line case log_ok(gen_sctp:recv(Sa, infinity)) of @@ -197,7 +205,7 @@ xfer_min(Config) when is_list(Config) -> recv_event(log_ok(gen_sctp:recv(Sb, infinity))), ?line ok = gen_sctp:close(Sa), ?line ok = gen_sctp:close(Sb), - + ?line receive Msg -> test_server:fail({received,Msg}) after 17 -> ok @@ -216,7 +224,7 @@ xfer_active(Config) when is_list(Config) -> ?line {ok,Sb} = gen_sctp:open([{active,true}]), ?line {ok,Pb} = inet:port(Sb), ?line ok = gen_sctp:listen(Sb, true), - + ?line {ok,Sa} = gen_sctp:open([{active,true}]), ?line {ok,Pa} = inet:port(Sa), ?line ok = gen_sctp:connect_init(Sa, Loopback, Pb, []), @@ -348,7 +356,7 @@ def_sndrcvinfo(Config) when is_list(Config) -> %% ?line S1 = log_ok(gen_sctp:open( - 0, [{sctp_default_send_param,#sctp_sndrcvinfo{ppid=17}}])), + 0, [{sctp_default_send_param,#sctp_sndrcvinfo{ppid=17}}])), ?LOGVAR(S1), ?line P1 = log_ok(inet:port(S1)), @@ -455,18 +463,22 @@ def_sndrcvinfo(Config) when is_list(Config) -> stream=1, ppid=0, context=0, assoc_id=S1AssocId}], <<"3: ",Data/binary>>} -> ok; Event2 -> - {Loopback,P2, - #sctp_paddr_change{ - addr={Loopback,_}, state=addr_available, - error=0, assoc_id=S1AssocId}} = - recv_event(Event2), - ?line case log_ok(gen_sctp:recv(S1)) of - {Loopback,P2, - [#sctp_sndrcvinfo{ - stream=1, ppid=0, context=0, - assoc_id=S1AssocId}], - <<"3: ",Data/binary>>} -> ok - end + case recv_event(Event2) of + {Loopback,P2, + #sctp_paddr_change{ + addr={Loopback,_}, + state=State, + error=0, assoc_id=S1AssocId}} + when State =:= addr_available; + State =:= addr_confirmed -> + ?line case log_ok(gen_sctp:recv(S1)) of + {Loopback,P2, + [#sctp_sndrcvinfo{ + stream=1, ppid=0, context=0, + assoc_id=S1AssocId}], + <<"3: ",Data/binary>>} -> ok + end + end end, ?line ok = do_from_other_process( @@ -509,6 +521,13 @@ log_ok(X) -> log(ok(X)). ok({ok,X}) -> X. +err([], Result) -> + erlang:error(Result); +err([Reason|_], {error,Reason}) -> + ok; +err([_|Reasons], Result) -> + err(Reasons, Result). + log(X) -> io:format("LOG[~w]: ~p~n", [self(),X]), X. @@ -529,57 +548,57 @@ api_open_close(Config) when is_list(Config) -> ?line {ok,S1} = gen_sctp:open(0), ?line {ok,P} = inet:port(S1), ?line ok = gen_sctp:close(S1), - + ?line {ok,S2} = gen_sctp:open(P), ?line {ok,P} = inet:port(S2), ?line ok = gen_sctp:close(S2), - + ?line {ok,S3} = gen_sctp:open([{port,P}]), ?line {ok,P} = inet:port(S3), ?line ok = gen_sctp:close(S3), - + ?line {ok,S4} = gen_sctp:open(P, []), ?line {ok,P} = inet:port(S4), ?line ok = gen_sctp:close(S4), - + ?line {ok,S5} = gen_sctp:open(P, [{ifaddr,any}]), ?line {ok,P} = inet:port(S5), ?line ok = gen_sctp:close(S5), ?line ok = gen_sctp:close(S5), - + ?line try gen_sctp:close(0) catch error:badarg -> ok end, - + ?line try gen_sctp:open({}) catch error:badarg -> ok end, - + ?line try gen_sctp:open(-1) catch error:badarg -> ok end, - + ?line try gen_sctp:open(65536) catch error:badarg -> ok end, - + ?line try gen_sctp:open(make_ref(), []) catch error:badarg -> ok end, - + ?line try gen_sctp:open(0, {}) catch error:badarg -> ok end, - + ?line try gen_sctp:open(0, [make_ref()]) catch error:badarg -> ok end, - + ?line try gen_sctp:open([{invalid_option,0}]) catch error:badarg -> ok end, - + ?line try gen_sctp:open(0, [{mode,invalid_mode}]) catch error:badarg -> ok end, @@ -591,11 +610,11 @@ api_listen(suite) -> []; api_listen(Config) when is_list(Config) -> ?line Localhost = {127,0,0,1}, - + ?line try gen_sctp:listen(0, true) catch error:badarg -> ok end, - + ?line {ok,S} = gen_sctp:open(), ?line {ok,Pb} = inet:port(S), ?line try gen_sctp:listen(S, not_allowed_for_listen) @@ -603,7 +622,7 @@ api_listen(Config) when is_list(Config) -> end, ?line ok = gen_sctp:close(S), ?line {error,closed} = gen_sctp:listen(S, true), - + ?line {ok,Sb} = gen_sctp:open(Pb), ?line {ok,Sa} = gen_sctp:open(), ?line case gen_sctp:connect(Sa, localhost, Pb, []) of @@ -615,8 +634,8 @@ api_listen(Config) when is_list(Config) -> gen_sctp:recv(Sa, infinity); {error,#sctp_assoc_change{state=cant_assoc}} -> ok%; - %% {error,{Localhost,Pb,_,#sctp_assoc_change{state=cant_assoc}}} -> - %% ok + %% {error,{Localhost,Pb,_,#sctp_assoc_change{state=cant_assoc}}} -> + %% ok end, ?line ok = gen_sctp:listen(Sb, true), ?line {ok,#sctp_assoc_change{state=comm_up, @@ -767,6 +786,106 @@ implicit_inet6(S1, Addr) -> end, ?line ok = gen_sctp:close(S2). +active_n(doc) -> + "Verify {active,N} socket management"; +active_n(suite) -> + []; +active_n(Config) when is_list(Config) -> + N = 3, + S1 = ok(gen_sctp:open([{active,N}])), + [{active,N}] = ok(inet:getopts(S1, [active])), + ok = inet:setopts(S1, [{active,-N}]), + receive + {sctp_passive, S1} -> ok + after + 5000 -> + exit({error,sctp_passive_failure}) + end, + [{active,false}] = ok(inet:getopts(S1, [active])), + ok = inet:setopts(S1, [{active,0}]), + receive + {sctp_passive, S1} -> ok + after + 5000 -> + exit({error,sctp_passive_failure}) + end, + ok = inet:setopts(S1, [{active,32767}]), + {error,einval} = inet:setopts(S1, [{active,1}]), + {error,einval} = inet:setopts(S1, [{active,-32769}]), + ok = inet:setopts(S1, [{active,-32768}]), + receive + {sctp_passive, S1} -> ok + after + 5000 -> + exit({error,sctp_passive_failure}) + end, + [{active,false}] = ok(inet:getopts(S1, [active])), + ok = inet:setopts(S1, [{active,N}]), + ok = inet:setopts(S1, [{active,true}]), + [{active,true}] = ok(inet:getopts(S1, [active])), + receive + _ -> exit({error,active_n}) + after + 0 -> + ok + end, + ok = inet:setopts(S1, [{active,N}]), + ok = inet:setopts(S1, [{active,once}]), + [{active,once}] = ok(inet:getopts(S1, [active])), + receive + _ -> exit({error,active_n}) + after + 0 -> + ok + end, + {error,einval} = inet:setopts(S1, [{active,32768}]), + ok = inet:setopts(S1, [{active,false}]), + [{active,false}] = ok(inet:getopts(S1, [active])), + ok = gen_sctp:listen(S1, true), + S1Port = ok(inet:port(S1)), + S2 = ok(gen_sctp:open(0, [{active,false}])), + Assoc = ok(gen_sctp:connect(S2, "localhost", S1Port, [])), + ok = inet:setopts(S1, [{active,N}]), + [{active,N}] = ok(inet:getopts(S1, [active])), + LoopFun = fun(Count, Count, _Fn) -> + receive + {sctp_passive,S1} -> + ok + after + 5000 -> + exit({error,timeout}) + end; + (I, Count, Fn) -> + Msg = list_to_binary("message "++integer_to_list(I)), + ok = gen_sctp:send(S2, Assoc, 0, Msg), + receive + {sctp,S1,_,_,{[SR],Msg}} when is_record(SR, sctp_sndrcvinfo) -> + Fn(I+1, Count, Fn); + {sctp,S1,_,_,_} -> + %% ignore non-data messages + ok = inet:setopts(S1, [{active,1}]), + Fn(I, Count, Fn); + Other -> + exit({unexpected, Other}) + after + 5000 -> + exit({error,timeout}) + end + end, + ok = LoopFun(1, N, LoopFun), + S3 = ok(gen_sctp:open([{active,0}])), + receive + {sctp_passive,S3} -> + [{active,false}] = ok(inet:getopts(S3, [active])) + after + 5000 -> + exit({error,udp_passive}) + end, + ok = gen_sctp:close(S3), + ok = gen_sctp:close(S2), + ok = gen_sctp:close(S1), + ok. + basic_stream(doc) -> "Hello world stream socket"; basic_stream(suite) -> @@ -840,23 +959,36 @@ xfer_stream_min(Config) when is_list(Config) -> ?line SbOutboundStreams = SaInboundStreams, ?line ?LOGVAR(SbOutboundStreams), ?line ok = gen_sctp:send(Sa, SaAssocId, 0, Data), - ?line case gen_sctp:recv(Sb, infinity) of - {ok,{Loopback, + ?line case log_ok(gen_sctp:recv(Sb, infinity)) of + {Loopback, + Pa, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SbAssocId}], + Data} -> ok; + {Loopback, + Pa,[], + #sctp_paddr_change{addr = {Loopback,_}, + state = addr_available, + error = 0, + assoc_id = SbAssocId}} -> + {Loopback, Pa, [#sctp_sndrcvinfo{stream=Stream, assoc_id=SbAssocId}], - Data}} -> ok; - {ok,{Loopback, - Pa,[], - #sctp_paddr_change{addr = {Loopback,_}, - state = addr_available, - error = 0, - assoc_id = SbAssocId}}} -> - {ok,{Loopback, - Pa, - [#sctp_sndrcvinfo{stream=Stream, - assoc_id=SbAssocId}], - Data}} = gen_sctp:recv(Sb, infinity) + Data} = log_ok(gen_sctp:recv(Sb, infinity)); + {Loopback, + Pa, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SbAssocId}], + #sctp_paddr_change{addr = {Loopback,_}, + state = addr_confirmed, + error = 0, + assoc_id = SbAssocId}} -> + {Loopback, + Pa, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SbAssocId}], + Data} = log_ok(gen_sctp:recv(Sb, infinity)) end, ?line ok = do_from_other_process( @@ -941,6 +1073,14 @@ peeloff_active_true(suite) -> peeloff_active_true(Config) -> peeloff(Config, [{active,true}]). +peeloff_active_n(doc) -> + "Peel off an SCTP stream socket ({active,N})"; +peeloff_active_n(suite) -> + []; + +peeloff_active_n(Config) -> + peeloff(Config, [{active,1}]). + peeloff(Config, SockOpts) when is_list(Config) -> ?line Addr = {127,0,0,1}, ?line Stream = 0, @@ -972,10 +1112,10 @@ peeloff(Config, SockOpts) when is_list(Config) -> ?line ?LOGVAR(S2Ai), ?line S1Ai = receive - {S1,{Addr,P2, - #sctp_assoc_change{ - state=comm_up, - assoc_id=AssocId1}}} -> AssocId1 + {S1,{Addr,P2, + #sctp_assoc_change{ + state=comm_up, + assoc_id=AssocId1}}} -> AssocId1 after Timeout -> socket_bailout([S1,S2]) end, @@ -1003,8 +1143,8 @@ peeloff(Config, SockOpts) when is_list(Config) -> ?line P3 = case P3_X of 0 -> P1; _ -> P3_X end, ?line [{_,#sctp_paddrinfo{assoc_id=S3Ai,state=active}}] = socket_call(S3, - {getopts,[{sctp_get_peer_addr_info, - #sctp_paddrinfo{address={Addr,P2}}}]}), + {getopts,[{sctp_get_peer_addr_info, + #sctp_paddrinfo{address={Addr,P2}}}]}), %%?line S3Ai = S1Ai, ?line ?LOGVAR(S3Ai), %% @@ -1087,9 +1227,9 @@ buffers(Config) when is_list(Config) -> %% ?line socket_call(S1, {setopts,[{recbuf,Limit}]}), ?line Recbuf = - case socket_call(S1, {getopts,[recbuf]}) of - [{recbuf,RB1}] when RB1 >= Limit -> RB1 - end, + case socket_call(S1, {getopts,[recbuf]}) of + [{recbuf,RB1}] when RB1 >= Limit -> RB1 + end, ?line Data = mk_data(Recbuf+Limit), ?line socket_call(S2, {setopts,[{sndbuf,Recbuf+Limit}]}), ?line socket_call(S2, {send,S2Ai,Stream,Data}), @@ -1190,6 +1330,93 @@ open_multihoming_ipv4_and_ipv6_socket(Config) when is_list(Config) -> {skip, Reason} end. +names_unihoming_ipv4(doc) -> + "Test inet:socknames/peernames on unihoming IPv4 sockets"; +names_unihoming_ipv4(suite) -> + []; +names_unihoming_ipv4(Config) when is_list(Config) -> + ?line do_names(Config, inet, 1). + +names_unihoming_ipv6(doc) -> + "Test inet:socknames/peernames on unihoming IPv6 sockets"; +names_unihoming_ipv6(suite) -> + []; +names_unihoming_ipv6(Config) when is_list(Config) -> + ?line do_names(Config, inet6, 1). + +names_multihoming_ipv4(doc) -> + "Test inet:socknames/peernames on multihoming IPv4 sockets"; +names_multihoming_ipv4(suite) -> + []; +names_multihoming_ipv4(Config) when is_list(Config) -> + ?line do_names(Config, inet, 2). + +names_multihoming_ipv6(doc) -> + "Test inet:socknames/peernames on multihoming IPv6 sockets"; +names_multihoming_ipv6(suite) -> + []; +names_multihoming_ipv6(Config) when is_list(Config) -> + ?line do_names(Config, inet6, 2). + + + +do_names(_, FamilySpec, AddressCount) -> + Fun = + fun (ServerSocket, _, ServerAssoc, ClientSocket, _, ClientAssoc) -> + ?line ServerSocknamesNoassoc = + lists:sort(ok(inet:socknames(ServerSocket))), + ?line ?LOGVAR(ServerSocknamesNoassoc), + ?line ServerSocknames = + lists:sort(ok(inet:socknames(ServerSocket, ServerAssoc))), + ?line ?LOGVAR(ServerSocknames), + ?line [_|_] = + ordsets:intersection + (ServerSocknamesNoassoc, ServerSocknames), + ?line ClientSocknamesNoassoc = + lists:sort(ok(inet:socknames(ClientSocket))), + ?line ?LOGVAR(ClientSocknamesNoassoc), + ?line ClientSocknames = + lists:sort(ok(inet:socknames(ClientSocket, ClientAssoc))), + ?line ?LOGVAR(ClientSocknames), + ?line [_|_] = + ordsets:intersection + (ClientSocknamesNoassoc, ClientSocknames), + ?line err([einval,enotconn], inet:peernames(ServerSocket)), + ?line ServerPeernames = + lists:sort(ok(inet:peernames(ServerSocket, ServerAssoc))), + ?line ?LOGVAR(ServerPeernames), + ?line err([einval,enotconn], inet:peernames(ClientSocket)), + ?line ClientPeernames = + lists:sort(ok(inet:peernames(ClientSocket, ClientAssoc))), + ?line ?LOGVAR(ClientPeernames), + ?line ServerSocknames = ClientPeernames, + ?line ClientSocknames = ServerPeernames, + ?line {ok,Socket} = + gen_sctp:peeloff(ServerSocket, ServerAssoc), + ?line SocknamesNoassoc = + lists:sort(ok(inet:socknames(Socket))), + ?line ?LOGVAR(SocknamesNoassoc), + ?line Socknames = + lists:sort(ok(inet:socknames(Socket, ServerAssoc))), + ?line ?LOGVAR(Socknames), + ?line true = + ordsets:is_subset(SocknamesNoassoc, Socknames), + ?line Peernames = + lists:sort(ok(inet:peernames(Socket, ServerAssoc))), + ?line ?LOGVAR(Peernames), + ?line ok = gen_sctp:close(Socket), + ?line Socknames = ClientPeernames, + ?line ClientSocknames = Peernames, + ok + end, + ?line case get_addrs_by_family(FamilySpec, AddressCount) of + {ok, Addresses} when length(Addresses) =:= AddressCount -> + ?line do_open_and_connect(Addresses, hd(Addresses), Fun); + {error, Reason} -> + {skip, Reason} + end. + + get_addrs_by_family(Family, NumAddrs) -> case os:type() of @@ -1274,6 +1501,10 @@ f(F, A) -> lists:flatten(io_lib:format(F, A)). do_open_and_connect(ServerAddresses, AddressToConnectTo) -> + ?line Fun = fun (_, _, _, _, _, _) -> ok end, + ?line do_open_and_connect(ServerAddresses, AddressToConnectTo, Fun). +%% +do_open_and_connect(ServerAddresses, AddressToConnectTo, Fun) -> ?line ServerFamily = get_family_by_addrs(ServerAddresses), ?line io:format("Serving ~p addresses: ~p~n", [ServerFamily, ServerAddresses]), @@ -1284,14 +1515,26 @@ do_open_and_connect(ServerAddresses, AddressToConnectTo) -> ?line ClientFamily = get_family_by_addr(AddressToConnectTo), ?line io:format("Connecting to ~p ~p~n", [ClientFamily, AddressToConnectTo]), - ?line S2 = ok(gen_sctp:open(0, [ClientFamily])), + ?line ClientOpts = + [ClientFamily | + case ClientFamily of + inet6 -> + [{ipv6_v6only,true}]; + _ -> + [] + end], + ?line S2 = ok(gen_sctp:open(0, ClientOpts)), + log(open), %% Verify client can connect - ?line #sctp_assoc_change{state=comm_up} = + ?line #sctp_assoc_change{state=comm_up} = S2Assoc = ok(gen_sctp:connect(S2, AddressToConnectTo, P1, [])), + log(comm_up), %% verify server side also receives comm_up from client - ?line recv_comm_up_eventually(S1), + ?line S1Assoc = recv_comm_up_eventually(S1), + ?line Result = Fun(S1, ServerFamily, S1Assoc, S2, ClientFamily, S2Assoc), ?line ok = gen_sctp:close(S2), - ?line ok = gen_sctp:close(S1). + ?line ok = gen_sctp:close(S1), + Result. %% If at least one of the addresses is an ipv6 address, return inet6, else inet. get_family_by_addrs(Addresses) -> @@ -1306,9 +1549,11 @@ get_family_by_addr(Addr) when tuple_size(Addr) =:= 8 -> inet6. recv_comm_up_eventually(S) -> ?line case ok(gen_sctp:recv(S)) of - {_Addr, _Port, _Info, #sctp_assoc_change{state=comm_up}} -> - ok; - {_Addr, _Port, _Info, _OtherSctpMsg} -> + {_Addr, _Port, _Info, + #sctp_assoc_change{state=comm_up} = Assoc} -> + Assoc; + {_Addr, _Port, _Info, _OtherSctpMsg} = Msg -> + ?line log({unexpected,Msg}), ?line recv_comm_up_eventually(S) end. @@ -1367,10 +1612,10 @@ socket_bailout([]) -> socket_history({State,Flush}) -> {lists:keysort( - 2, - lists:flatten( - [[{Key,Val} || Val <- Vals] - || {Key,Vals} <- gb_trees:to_list(State)])), + 2, + lists:flatten( + [[{Key,Val} || Val <- Vals] + || {Key,Vals} <- gb_trees:to_list(State)])), Flush}. s_handler(Socket) -> @@ -1453,7 +1698,7 @@ s_loop(Socket, Timeout, Parent, Handler, State) -> #sctp_assoc_change{ state=comm_up, inbound_streams=Is}}}|_] - when 0 =< Stream, Stream < Is-> ok; + when 0 =< Stream, Stream < Is-> ok; [] -> ok end, Key = {msg,AssocId,Stream}, @@ -1473,7 +1718,7 @@ s_loop(Socket, Timeout, Parent, Handler, State) -> case {gb_get(Key, State),St} of {[],_} -> ok; {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_],_} - when St =:= comm_lost; St =:= shutdown_comp -> ok + when St =:= comm_lost; St =:= shutdown_comp -> ok end, NewState = gb_push(Key, Val, State), Parent ! {self(),{Addr,Port,SAC}}, @@ -1489,8 +1734,9 @@ s_loop(Socket, Timeout, Parent, Handler, State) -> [] -> ok end, case {gb_get({assoc_change,AssocId}, State),St} of - {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_], - addr_available} -> ok; + {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_],_} + when St =:= addr_available; + St =:= addr_confirmed -> ok; {[],addr_confirmed} -> ok end, Key = {paddr_change,AssocId}, @@ -1519,7 +1765,13 @@ s_loop(Socket, Timeout, Parent, Handler, State) -> end. again(Socket) -> - inet:setopts(Socket, [{active,once}]). + receive + {sctp_passive,Socket} -> + [{active, false}] = ok(inet:getopts(Socket, [active])), + ok = inet:setopts(Socket,[{active,1}]) + after 0 -> + ok = inet:setopts(Socket, [{active,once}]) + end. gb_push(Key, Val, GBT) -> case gb_trees:lookup(Key, GBT) of diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index ee271fbdfa..ee8bfcceb1 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -25,7 +25,7 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, controlling_process/1, controlling_process_self/1, - no_accept/1, close_with_pending_output/1, + no_accept/1, close_with_pending_output/1, active_n/1, data_before_close/1, iter_max_socks/1, get_status/1, passive_sockets/1, accept_closed_by_other_process/1, init_per_testcase/2, end_per_testcase/2, @@ -70,7 +70,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [controlling_process, controlling_process_self, no_accept, close_with_pending_output, data_before_close, - iter_max_socks, passive_sockets, + iter_max_socks, passive_sockets, active_n, accept_closed_by_other_process, otp_3924, closed_socket, shutdown_active, shutdown_passive, shutdown_pending, default_options, http_bad_packet, busy_send, @@ -407,6 +407,114 @@ send_loop(Sock, Data, Left) -> ok = gen_tcp:send(Sock, Data), send_loop(Sock, Data, Left-1). +%% Test {active,N} option +active_n(doc) -> + ["Verify operation of the {active,N} option."]; +active_n(suite) -> []; +active_n(Config) when is_list(Config) -> + N = 3, + LS = ok(gen_tcp:listen(0, [{active,N}])), + [{active,N}] = ok(inet:getopts(LS, [active])), + ok = inet:setopts(LS, [{active,-N}]), + receive + {tcp_passive, LS} -> ok + after + 5000 -> + exit({error,tcp_passive_failure}) + end, + [{active,false}] = ok(inet:getopts(LS, [active])), + ok = inet:setopts(LS, [{active,0}]), + receive + {tcp_passive, LS} -> ok + after + 5000 -> + exit({error,tcp_passive_failure}) + end, + ok = inet:setopts(LS, [{active,32767}]), + {error,einval} = inet:setopts(LS, [{active,1}]), + {error,einval} = inet:setopts(LS, [{active,-32769}]), + ok = inet:setopts(LS, [{active,-32768}]), + receive + {tcp_passive, LS} -> ok + after + 5000 -> + exit({error,tcp_passive_failure}) + end, + [{active,false}] = ok(inet:getopts(LS, [active])), + ok = inet:setopts(LS, [{active,N}]), + ok = inet:setopts(LS, [{active,true}]), + [{active,true}] = ok(inet:getopts(LS, [active])), + receive + _ -> exit({error,active_n}) + after + 0 -> + ok + end, + ok = inet:setopts(LS, [{active,N}]), + ok = inet:setopts(LS, [{active,once}]), + [{active,once}] = ok(inet:getopts(LS, [active])), + receive + _ -> exit({error,active_n}) + after + 0 -> + ok + end, + {error,einval} = inet:setopts(LS, [{active,32768}]), + ok = inet:setopts(LS, [{active,false}]), + [{active,false}] = ok(inet:getopts(LS, [active])), + Port = ok(inet:port(LS)), + C = ok(gen_tcp:connect("localhost", Port, [{active,N}])), + [{active,N}] = ok(inet:getopts(C, [active])), + S = ok(gen_tcp:accept(LS)), + ok = inet:setopts(S, [{active,N}]), + [{active,N}] = ok(inet:getopts(S, [active])), + repeat(3, + fun(I) -> + Msg = "message "++integer_to_list(I), + ok = gen_tcp:send(C, Msg), + receive + {tcp,S,Msg} -> + ok = gen_tcp:send(S, Msg) + after + 5000 -> + exit({error,timeout}) + end, + receive + {tcp,C,Msg} -> + ok + after + 5000 -> + exit({error,timeout}) + end + end), + receive + {tcp_passive,S} -> + [{active,false}] = ok(inet:getopts(S, [active])) + after + 5000 -> + exit({error,tcp_passive}) + end, + receive + {tcp_passive,C} -> + [{active,false}] = ok(inet:getopts(C, [active])) + after + 5000 -> + exit({error,tcp_passive}) + end, + LS2 = ok(gen_tcp:listen(0, [{active,0}])), + receive + {tcp_passive,LS2} -> + [{active,false}] = ok(inet:getopts(LS2, [active])) + after + 5000 -> + exit({error,tcp_passive}) + end, + ok = gen_tcp:close(LS2), + ok = gen_tcp:close(C), + ok = gen_tcp:close(S), + ok = gen_tcp:close(LS), + ok. + -define(OTP_3924_MAX_DELAY, 100). %% Taken out of the blue, but on intra host connections %% I expect propagation of a close to be quite fast @@ -2659,3 +2767,5 @@ oct_aloop(S,X,Times) -> gen_tcp:close(S), closed end. + +ok({ok,V}) -> V. diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl index cd768813cf..6bb41999c5 100644 --- a/lib/kernel/test/gen_udp_SUITE.erl +++ b/lib/kernel/test/gen_udp_SUITE.erl @@ -1,8 +1,7 @@ -%% -*- coding: utf-8 -*- %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2012. All Rights Reserved. +%% Copyright Ericsson AB 1998-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -34,7 +33,7 @@ init_per_group/2,end_per_group/2]). -export([init_per_testcase/2, end_per_testcase/2]). --export([send_to_closed/1, +-export([send_to_closed/1, active_n/1, buffer_size/1, binary_passive_recv/1, bad_address/1, read_packets/1, open_fd/1, connect/1, implicit_inet6/1]). @@ -43,7 +42,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [send_to_closed, buffer_size, binary_passive_recv, bad_address, read_packets, open_fd, connect, - implicit_inet6]. + implicit_inet6, active_n]. groups() -> []. @@ -466,6 +465,108 @@ open_fd(Config) when is_list(Config) -> ?t:fail(io_lib:format("~w", [flush()])) end. +active_n(Config) when is_list(Config) -> + N = 3, + S1 = ok(gen_udp:open(0, [{active,N}])), + [{active,N}] = ok(inet:getopts(S1, [active])), + ok = inet:setopts(S1, [{active,-N}]), + receive + {udp_passive, S1} -> ok + after + 5000 -> + exit({error,udp_passive_failure}) + end, + [{active,false}] = ok(inet:getopts(S1, [active])), + ok = inet:setopts(S1, [{active,0}]), + receive + {udp_passive, S1} -> ok + after + 5000 -> + exit({error,udp_passive_failure}) + end, + ok = inet:setopts(S1, [{active,32767}]), + {error,einval} = inet:setopts(S1, [{active,1}]), + {error,einval} = inet:setopts(S1, [{active,-32769}]), + ok = inet:setopts(S1, [{active,-32768}]), + receive + {udp_passive, S1} -> ok + after + 5000 -> + exit({error,udp_passive_failure}) + end, + [{active,false}] = ok(inet:getopts(S1, [active])), + ok = inet:setopts(S1, [{active,N}]), + ok = inet:setopts(S1, [{active,true}]), + [{active,true}] = ok(inet:getopts(S1, [active])), + receive + _ -> exit({error,active_n}) + after + 0 -> + ok + end, + ok = inet:setopts(S1, [{active,N}]), + ok = inet:setopts(S1, [{active,once}]), + [{active,once}] = ok(inet:getopts(S1, [active])), + receive + _ -> exit({error,active_n}) + after + 0 -> + ok + end, + {error,einval} = inet:setopts(S1, [{active,32768}]), + ok = inet:setopts(S1, [{active,false}]), + [{active,false}] = ok(inet:getopts(S1, [active])), + S1Port = ok(inet:port(S1)), + S2 = ok(gen_udp:open(0, [{active,N}])), + S2Port = ok(inet:port(S2)), + [{active,N}] = ok(inet:getopts(S2, [active])), + ok = inet:setopts(S1, [{active,N}]), + [{active,N}] = ok(inet:getopts(S1, [active])), + lists:foreach( + fun(I) -> + Msg = "message "++integer_to_list(I), + ok = gen_udp:send(S2, "localhost", S1Port, Msg), + receive + {udp,S1,_,S2Port,Msg} -> + ok = gen_udp:send(S1, "localhost", S2Port, Msg) + after + 5000 -> + exit({error,timeout}) + end, + receive + {udp,S2,_,S1Port,Msg} -> + ok + after + 5000 -> + exit({error,timeout}) + end + end, lists:seq(1,N)), + receive + {udp_passive,S1} -> + [{active,false}] = ok(inet:getopts(S1, [active])) + after + 5000 -> + exit({error,udp_passive}) + end, + receive + {udp_passive,S2} -> + [{active,false}] = ok(inet:getopts(S2, [active])) + after + 5000 -> + exit({error,udp_passive}) + end, + S3 = ok(gen_udp:open(0, [{active,0}])), + receive + {udp_passive,S3} -> + [{active,false}] = ok(inet:getopts(S3, [active])) + after + 5000 -> + exit({error,udp_passive}) + end, + ok = gen_udp:close(S3), + ok = gen_udp:close(S2), + ok = gen_udp:close(S1), + ok. % % Utils diff --git a/lib/kernel/test/global_SUITE_data/global_trace.erl b/lib/kernel/test/global_SUITE_data/global_trace.erl index 00bacf8f54..1396d86c79 100644 --- a/lib/kernel/test/global_SUITE_data/global_trace.erl +++ b/lib/kernel/test/global_SUITE_data/global_trace.erl @@ -1,4 +1,3 @@ -%% -*- coding: utf-8 -*- %% %% %CopyrightBegin% %% diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index 62ba95e1a3..ed43749cc0 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -38,10 +38,10 @@ gethostnative_debug_level/0, gethostnative_debug_level/1, getif/1, getif_ifr_name_overflow/1,getservbyname_overflow/1, getifaddrs/1, - parse_strict_address/1]). + parse_strict_address/1, simple_netns/1]). -export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1, parse_address/1, - kill_gethost/0, parallell_gethost/0]). + kill_gethost/0, parallell_gethost/0, test_netns/0]). -export([init_per_testcase/2, end_per_testcase/2]). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -53,7 +53,7 @@ all() -> t_gethostnative, gethostnative_parallell, cname_loop, gethostnative_debug_level, gethostnative_soft_restart, getif, getif_ifr_name_overflow, getservbyname_overflow, - getifaddrs, parse_strict_address]. + getifaddrs, parse_strict_address, simple_netns]. groups() -> [{parse, [], [parse_hosts, parse_address]}]. @@ -226,7 +226,7 @@ t_gethostbyname_v6(Config) when is_list(Config) -> h_addr_list = [IP4]} = HEnt4, {ok,IP46} = inet_parse:ipv6_address( - "::ffff:" ++ inet_parse:ntoa(IP4)), + "::ffff:" ++ inet:ntoa(IP4)), check_elems( [{HEnt#hostent.h_name,[Name,FullName]}]) end, @@ -246,7 +246,7 @@ t_gethostbyname_v6(Config) when is_list(Config) -> h_addr_list = [IP4F]} = HEnt4F, {ok,IP46F} = inet_parse:ipv6_address( - "::ffff:" ++ inet_parse:ntoa(IP4F)), + "::ffff:" ++ inet:ntoa(IP4F)), check_elems( [{HEntF#hostent.h_name,[Name,FullName]}]) end; @@ -1099,3 +1099,96 @@ toupper([C|Cs]) when is_integer(C) -> end; toupper([]) -> []. + + +simple_netns(Config) when is_list(Config) -> + {ok,U} = gen_udp:open(0), + case inet:setopts(U, [{netns,""}]) of + ok -> + jog_netns_opt(U), + ok = gen_udp:close(U), + %% + {ok,L} = gen_tcp:listen(0, []), + jog_netns_opt(L), + ok = gen_tcp:close(L), + %% + {ok,S} = gen_sctp:open(), + jog_netns_opt(S), + ok = gen_sctp:close(S); + {error,einval} -> + {skip,"setns() not supported"} + end. + +jog_netns_opt(S) -> + %% This is just jogging the option mechanics + ok = inet:setopts(S, [{netns,""}]), + {ok,[{netns,""}]} = inet:getopts(S, [netns]), + ok = inet:setopts(S, [{netns,"/proc/self/ns/net"}]), + {ok,[{netns,"/proc/self/ns/net"}]} = inet:getopts(S, [netns]), + ok. + + +%% Manual test to be run outside test_server in an emulator +%% started by root, in a machine with setns() support... +test_netns() -> + DefaultIF = v1, + DefaultIP = {192,168,1,17}, + Namespace = "test", + NamespaceIF = v2, + NamespaceIP = {192,168,1,18}, + %% + DefaultIPString = inet_parse:ntoa(DefaultIP), + NamespaceIPString = inet_parse:ntoa(NamespaceIP), + cmd("ip netns add ~s", + [Namespace]), + cmd("ip link add name ~w type veth peer name ~w netns ~s", + [DefaultIF,NamespaceIF,Namespace]), + cmd("ip netns exec ~s ip addr add ~s/30 dev ~w", + [Namespace,NamespaceIPString,NamespaceIF]), + cmd("ip netns exec ~s ip link set ~w up", + [Namespace,NamespaceIF]), + cmd("ip addr add ~s/30 dev ~w", + [DefaultIPString,DefaultIF]), + cmd("ip link set ~w up", + [DefaultIF]), + try test_netns( + {DefaultIF,DefaultIP}, + filename:join("/var/run/netns/", Namespace), + {NamespaceIF,NamespaceIP}) of + Result -> + io:put_chars(["#### Test done",io_lib:nl()]), + Result + after + cmd("ip link delete ~w type veth", + [DefaultIF]), + cmd("ip netns delete ~s", + [Namespace]) + end. + +test_netns({DefaultIF,DefaultIP}, Namespace, {NamespaceIF,NamespaceIP}) -> + {ok,ListenSocket} = gen_tcp:listen(0, [{active,false}]), + {ok,[{addr,DefaultIP}]} = inet:ifget(ListenSocket, DefaultIF, [addr]), + {ok,ListenPort} = inet:port(ListenSocket), + {ok,ConnectSocket} = + gen_tcp:connect( + DefaultIP, ListenPort, [{active,false},{netns,Namespace}], 3000), + {ok,[{addr,NamespaceIP}]} = inet:ifget(ConnectSocket, NamespaceIF, [addr]), + {ok,ConnectPort} = inet:port(ConnectSocket), + {ok,AcceptSocket} = gen_tcp:accept(ListenSocket, 0), + {ok,AcceptPort} = inet:port(AcceptSocket), + {ok,{NamespaceIP,ConnectPort}} = inet:peername(AcceptSocket), + {ok,{DefaultIP,AcceptPort}} = inet:peername(ConnectSocket), + ok = gen_tcp:send(ConnectSocket, "data"), + ok = gen_tcp:close(ConnectSocket), + {ok,"data"} = gen_tcp:recv(AcceptSocket, 4, 1000), + {error,closed} = gen_tcp:recv(AcceptSocket, 1, 1000), + ok = gen_tcp:close(AcceptSocket), + ok = gen_tcp:close(ListenSocket). + +cmd(Cmd, Args) -> + cmd(io_lib:format(Cmd, Args)). +%% +cmd(CmdString) -> + io:put_chars(["# ",CmdString,io_lib:nl()]), + io:put_chars([os:cmd(CmdString++" ; echo ' =>' $?")]), + ok. diff --git a/lib/kernel/test/interactive_shell_SUITE.erl b/lib/kernel/test/interactive_shell_SUITE.erl index d7d9434b1f..a375adceea 100644 --- a/lib/kernel/test/interactive_shell_SUITE.erl +++ b/lib/kernel/test/interactive_shell_SUITE.erl @@ -22,7 +22,7 @@ init_per_group/2,end_per_group/2, get_columns_and_rows/1, exit_initial/1, job_control_local/1, job_control_remote/1, - job_control_remote_noshell/1]). + job_control_remote_noshell/1,ctrl_keys/1]). -export([init_per_testcase/2, end_per_testcase/2]). %% For spawn @@ -41,7 +41,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [get_columns_and_rows, exit_initial, job_control_local, - job_control_remote, job_control_remote_noshell]. + job_control_remote, job_control_remote_noshell, + ctrl_keys]. groups() -> []. @@ -289,7 +290,51 @@ job_control_remote_noshell(Config) when is_list(Config) -> ?line stop_noshell_node(NSNode), ?line Res end. - + +ctrl_keys(suite) -> []; +ctrl_keys(doc) -> ["Tests various control keys"]; +ctrl_keys(_Conf) when is_list(_Conf) -> + Cu=[$\^u], + Cw=[$\^w], + Home=[27,$O,$H], + End=[27,$O,$F], + rtnode([{putline,""}, + {putline,"2."}, + {getline,"2"}, + {putline,"\"hello "++Cw++"world\"."}, % test <CTRL>+W + {getline,"\"world\""}, + {putline,"\"hello "++Cu++"\"world\"."}, % test <CTRL>+U + {getline,"\"world\""}, + {putline,"world\"."++Home++"\"hello "}, % test <HOME> + {getline,"\"hello world\""}, + {putline,"world"++Home++"\"hello "++End++"\"."}, % test <END> + {getline,"\"hello world\""}] + ++wordLeft()++wordRight(),[]). + + +wordLeft() -> + L1=[27,27,$[,$D], + L2=[27]++"[5D", + L3=[27]++"[1;5D", + wordLeft(L1)++wordLeft(L2)++wordLeft(L3). + +wordLeft(Chars) -> + End=[27,$O,$F], + [{putline,"\"world\""++Chars++"hello "++End++"."}, + {getline,"\"hello world\""}]. + +wordRight() -> + R1=[27,27,$[,$C], + R2=[27]++"[5C", + R3=[27]++"[1;5C", + wordRight(R1)++wordRight(R2)++wordRight(R3). + +wordRight(Chars) -> + Home=[27,$O,$H], + [{putline,"world"++Home++"\"hello "++Chars++"\"."}, + {getline,"\"hello world\""}]. + + rtnode(C,N) -> rtnode(C,N,[]). rtnode(Commands,Nodename,ErlPrefix) -> diff --git a/lib/kernel/test/kernel_SUITE.erl b/lib/kernel/test/kernel_SUITE.erl index 0f29d895e5..78f5e93fc3 100644 --- a/lib/kernel/test/kernel_SUITE.erl +++ b/lib/kernel/test/kernel_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2014. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -23,9 +23,6 @@ -include_lib("test_server/include/test_server.hrl"). -% Default timetrap timeout (set in init_per_testcase). --define(default_timeout, ?t:minutes(1)). - % Test server specific exports -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2]). @@ -59,11 +56,8 @@ end_per_group(_GroupName, Config) -> init_per_testcase(_Case, Config) -> - ?line Dog=test_server:timetrap(?default_timeout), - [{watchdog, Dog}|Config]. -end_per_testcase(_Case, Config) -> - Dog=?config(watchdog, Config), - test_server:timetrap_cancel(Dog), + Config. +end_per_testcase(_Case, _Config) -> ok. % @@ -78,56 +72,80 @@ app_test(Config) when is_list(Config) -> ok. -%% Test that appup allows upgrade from/downgrade to a maximum of two -%% major releases back. +%% Test that appup allows upgrade from/downgrade to a maximum of one +%% major release back. appup_test(_Config) -> - application:load(kernel), - {_,_,Vsn} = lists:keyfind(kernel,1,application:loaded_applications()), - AppupFile = filename:join([code:lib_dir(kernel),ebin,"kernel.appup"]), + appup_tests(kernel,create_test_vsns(kernel)). + +appup_tests(_App,{[],[]}) -> + {skip,"no previous releases available"}; +appup_tests(App,{OkVsns,NokVsns}) -> + application:load(App), + {_,_,Vsn} = lists:keyfind(App,1,application:loaded_applications()), + AppupFileName = atom_to_list(App) ++ ".appup", + AppupFile = filename:join([code:lib_dir(App),ebin,AppupFileName]), {ok,[{Vsn,UpFrom,DownTo}=AppupScript]} = file:consult(AppupFile), ct:log("~p~n",[AppupScript]), - {OkVsns,NokVsns} = create_test_vsns(Vsn), + ct:log("Testing ok versions: ~p~n",[OkVsns]), check_appup(OkVsns,UpFrom,{ok,[restart_new_emulator]}), check_appup(OkVsns,DownTo,{ok,[restart_new_emulator]}), + ct:log("Testing not ok versions: ~p~n",[NokVsns]), check_appup(NokVsns,UpFrom,error), check_appup(NokVsns,DownTo,error), ok. -create_test_vsns(Current) -> - [XStr,YStr|Rest] = string:tokens(Current,"."), - X = list_to_integer(XStr), - Y = list_to_integer(YStr), - SecondMajor = vsn(X,Y-2), - SecondMinor = SecondMajor ++ ".1.3", - FirstMajor = vsn(X,Y-1), - FirstMinor = FirstMajor ++ ".57", - ThisMajor = vsn(X,Y), - This = - case Rest of - [] -> - []; - ["1"] -> - [ThisMajor]; - _ -> - ThisMinor = ThisMajor ++ ".1", - [ThisMajor,ThisMinor] +create_test_vsns(App) -> + This = erlang:system_info(otp_release), + FirstMajor = previous_major(This), + SecondMajor = previous_major(FirstMajor), + Ok = app_vsn(App,[FirstMajor]), + Nok0 = app_vsn(App,[SecondMajor]), + Nok = case Ok of + [Ok1|_] -> + [Ok1 ++ ",1" | Nok0]; % illegal + _ -> + Nok0 + end, + {Ok,Nok}. + +previous_major("17") -> + "r16"; +previous_major("r"++Rel) -> + "r"++previous_major(Rel); +previous_major(Rel) -> + integer_to_list(list_to_integer(Rel)-1). + +app_vsn(App,[R|Rs]) -> + OldRel = + case test_server:is_release_available(R) of + true -> + {release,R}; + false -> + case ct:get_config({otp_releases,list_to_atom(R)}) of + undefined -> + false; + Prog0 -> + case os:find_executable(Prog0) of + false -> + false; + Prog -> + {prog,Prog} + end + end end, - OkVsns = This ++ [FirstMajor, FirstMinor, SecondMajor, SecondMinor], - - ThirdMajor = vsn(X,Y-3), - ThirdMinor = ThirdMajor ++ ".10.12", - Illegal = ThisMajor ++ ",1", - Newer1Major = vsn(X,Y+1), - Newer1Minor = Newer1Major ++ ".1", - Newer2Major = ThisMajor ++ "1", - NokVsns = [ThirdMajor,ThirdMinor, - Illegal, - Newer1Major,Newer1Minor, - Newer2Major], - {OkVsns,NokVsns}. - -vsn(X,Y) -> - integer_to_list(X) ++ "." ++ integer_to_list(Y). + case OldRel of + false -> + app_vsn(App,Rs); + _ -> + {ok,N} = test_server:start_node(prevrel,peer,[{erl,[OldRel]}]), + _ = rpc:call(N,application,load,[App]), + As = rpc:call(N,application,loaded_applications,[]), + {_,_,V} = lists:keyfind(App,1,As), + test_server:stop_node(N), + [V|app_vsn(App,Rs)] + end; +app_vsn(_App,[]) -> + []. check_appup([Vsn|Vsns],Instrs,Expected) -> case systools_relup:appup_search_for_version(Vsn, Instrs) of diff --git a/lib/kernel/test/kernel_smoke.spec b/lib/kernel/test/kernel_smoke.spec new file mode 100644 index 0000000000..e5d8273c56 --- /dev/null +++ b/lib/kernel/test/kernel_smoke.spec @@ -0,0 +1,9 @@ +{config, "../test_server/ts.config"}. +{config, "../test_server/ts.unix.config"}. + +{cases,"../kernel_test", inet_SUITE,[t_gethostbyaddr,t_gethostbyname, + t_gethostbyaddr_v6,t_gethostbyname_v6,t_gethostnative,getifaddrs]}. +{cases,"../kernel_test", inet_res_SUITE,[gethostbyaddr,gethostbyname, + gethostbyaddr_v6,gethostbyname_v6,basic]}. +{cases,"../kernel_test", gen_tcp_echo_SUITE,[active_echo]}. +{cases,"../kernel_test", heart_SUITE,[reboot]}. diff --git a/lib/kernel/test/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl index 73ed704ae3..9b474c4cdf 100644 --- a/lib/kernel/test/os_SUITE.erl +++ b/lib/kernel/test/os_SUITE.erl @@ -20,7 +20,7 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2]). --export([space_in_cwd/1, quoting/1, space_in_name/1, bad_command/1, +-export([space_in_cwd/1, quoting/1, cmd_unicode/1, space_in_name/1, bad_command/1, find_executable/1, unix_comment_in_command/1, deep_list_command/1, evil/1]). -include_lib("test_server/include/test_server.hrl"). @@ -28,9 +28,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [space_in_cwd, quoting, space_in_name, bad_command, - find_executable, unix_comment_in_command, deep_list_command, - evil]. + [space_in_cwd, quoting, cmd_unicode, space_in_name, bad_command, + find_executable, unix_comment_in_command, deep_list_command, evil]. groups() -> []. @@ -95,6 +94,21 @@ quoting(Config) when is_list(Config) -> ?line [] = receive_all(), ok. + +cmd_unicode(doc) -> "Test that unicode arguments work."; +cmd_unicode(suite) -> []; +cmd_unicode(Config) when is_list(Config) -> + ?line DataDir = ?config(data_dir, Config), + ?line Echo = filename:join(DataDir, "my_echo"), + + ?line comp("one", os:cmd(Echo ++ " one")), + ?line comp("one::two", os:cmd(Echo ++ " one two")), + ?line comp("åäö::ϼΩ", os:cmd(Echo ++ " åäö " ++ [1020, 937])), + ?t:sleep(5), + ?line [] = receive_all(), + ok. + + space_in_name(doc) -> "Test that program with a space in its name can be executed."; space_in_name(suite) -> []; @@ -302,8 +316,8 @@ comp(Expected, Got) -> Expected -> ok; Other -> - ok = io:format("Expected: ~s\n", [Expected]), - ok = io:format("Got: ~s\n", [Other]), + ok = io:format("Expected: ~ts\n", [Expected]), + ok = io:format("Got: ~ts\n", [Other]), test_server:fail() end. diff --git a/lib/kernel/test/os_SUITE_data/my_echo.c b/lib/kernel/test/os_SUITE_data/my_echo.c index 2127511dd1..712c828bb5 100644 --- a/lib/kernel/test/os_SUITE_data/my_echo.c +++ b/lib/kernel/test/os_SUITE_data/my_echo.c @@ -1,3 +1,30 @@ +#ifdef __WIN32__ +#include <windows.h> + +int wmain(int argc, wchar_t **argv) +{ + char* sep = ""; + int len; + + /* + * Echo all arguments separated with '::', so that we can check that + * quotes are interpreted correctly. + */ + + while (argc-- > 1) { + char *utf8; + len = WideCharToMultiByte(CP_UTF8, 0, argv[1], -1, NULL, 0, NULL, NULL); + utf8 = malloc(len*sizeof(char)); + WideCharToMultiByte(CP_UTF8, 0, argv++[1], -1, utf8, len, NULL, NULL); + printf("%s%s", sep, utf8); + free(utf8); + sep = "::"; + } + putchar('\n'); + return 0; +} +#else + #include <stdio.h> int @@ -17,3 +44,4 @@ main(int argc, char** argv) putchar('\n'); return 0; } +#endif diff --git a/lib/kernel/test/ram_file_SUITE.erl b/lib/kernel/test/ram_file_SUITE.erl index 5c4437d4d3..615251a257 100644 --- a/lib/kernel/test/ram_file_SUITE.erl +++ b/lib/kernel/test/ram_file_SUITE.erl @@ -1,8 +1,7 @@ -%% -*- coding: utf-8 -*- %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2012. All Rights Reserved. +%% Copyright Ericsson AB 2001-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/kernel/test/sendfile_SUITE.erl b/lib/kernel/test/sendfile_SUITE.erl index 4cf4c6489d..2c741232c4 100644 --- a/lib/kernel/test/sendfile_SUITE.erl +++ b/lib/kernel/test/sendfile_SUITE.erl @@ -24,7 +24,14 @@ -compile(export_all). -all() -> +all() -> [{group,async_threads}, + {group,no_async_threads}]. + +groups() -> + [{async_threads,[],tcs()}, + {no_async_threads,[],tcs()}]. + +tcs() -> [t_sendfile_small ,t_sendfile_big_all ,t_sendfile_big_size @@ -33,6 +40,7 @@ all() -> ,t_sendfile_offset ,t_sendfile_sendafter ,t_sendfile_recvafter + ,t_sendfile_recvafter_remoteclose ,t_sendfile_sendduring ,t_sendfile_recvduring ,t_sendfile_closeduring @@ -63,6 +71,14 @@ init_per_suite(Config) -> end_per_suite(Config) -> file:delete(proplists:get_value(big_file, Config)). +init_per_group(async_threads,Config) -> + [{sendfile_opts,[{use_threads,true}]}|Config]; +init_per_group(no_async_threads,Config) -> + [{sendfile_opts,[{use_threads,false}]}|Config]. + +end_per_group(_,_Config) -> + ok. + init_per_testcase(TC,Config) when TC == t_sendfile_recvduring; TC == t_sendfile_sendduring -> Filename = proplists:get_value(small_file, Config), @@ -71,7 +87,7 @@ init_per_testcase(TC,Config) when TC == t_sendfile_recvduring; {_Size, Data} = sendfile_file_info(Filename), {ok,D} = file:open(Filename, [raw,binary,read]), prim_file:sendfile(D, Sock, 0, 0, 0, - [],[],false,false,false), + [],[],[]), Data end, @@ -92,6 +108,7 @@ t_sendfile_small(Config) when is_list(Config) -> Send = fun(Sock) -> {Size, Data} = sendfile_file_info(Filename), + %% Here we make sure to test the sendfile/2 api {ok, Size} = file:sendfile(Filename, Sock), Data end, @@ -101,6 +118,7 @@ t_sendfile_small(Config) when is_list(Config) -> t_sendfile_many_small(Config) when is_list(Config) -> Filename = proplists:get_value(small_file, Config), FileOpts = proplists:get_value(file_opts, Config, []), + SendfileOpts = proplists:get_value(sendfile_opts, Config), error_logger:add_report_handler(?MODULE,[self()]), @@ -109,7 +127,7 @@ t_sendfile_many_small(Config) when is_list(Config) -> N = 10000, {ok,D} = file:open(Filename,[read|FileOpts]), [begin - {ok,Size} = file:sendfile(D,Sock,0,0,[]) + {ok,Size} = file:sendfile(D,Sock,0,0,SendfileOpts) end || _I <- lists:seq(1,N)], file:close(D), Size*N @@ -127,11 +145,12 @@ t_sendfile_many_small(Config) when is_list(Config) -> t_sendfile_big_all(Config) when is_list(Config) -> Filename = proplists:get_value(big_file, Config), + SendfileOpts = proplists:get_value(sendfile_opts, Config), Send = fun(Sock) -> {ok, #file_info{size = Size}} = file:read_file_info(Filename), - {ok, Size} = file:sendfile(Filename, Sock), + {ok, Size} = sendfile(Filename, Sock, SendfileOpts), Size end, @@ -140,12 +159,13 @@ t_sendfile_big_all(Config) when is_list(Config) -> t_sendfile_big_size(Config) -> Filename = proplists:get_value(big_file, Config), FileOpts = proplists:get_value(file_opts, Config, []), + SendfileOpts = proplists:get_value(sendfile_opts, Config), SendAll = fun(Sock) -> {ok, #file_info{size = Size}} = file:read_file_info(Filename), {ok,D} = file:open(Filename,[read|FileOpts]), - {ok, Size} = file:sendfile(D, Sock,0,Size,[]), + {ok, Size} = file:sendfile(D, Sock,0,Size,SendfileOpts), Size end, @@ -154,12 +174,13 @@ t_sendfile_big_size(Config) -> t_sendfile_partial(Config) -> Filename = proplists:get_value(small_file, Config), FileOpts = proplists:get_value(file_opts, Config, []), + SendfileOpts = proplists:get_value(sendfile_opts, Config), SendSingle = fun(Sock) -> {_Size, <<Data:5/binary,_/binary>>} = sendfile_file_info(Filename), {ok,D} = file:open(Filename,[read|FileOpts]), - {ok,5} = file:sendfile(D,Sock,0,5,[]), + {ok,5} = file:sendfile(D,Sock,0,5,SendfileOpts), file:close(D), Data end, @@ -170,14 +191,14 @@ t_sendfile_partial(Config) -> {ok,D} = file:open(Filename,[read|FileOpts]), {ok, <<FData/binary>>} = file:read(D,5), FSend = fun(Sock) -> - {ok,5} = file:sendfile(D,Sock,0,5,[]), + {ok,5} = file:sendfile(D,Sock,0,5,SendfileOpts), FData end, ok = sendfile_send(FSend), SSend = fun(Sock) -> - {ok,3} = file:sendfile(D,Sock,5,3,[]), + {ok,3} = file:sendfile(D,Sock,5,3,SendfileOpts), SData end, @@ -190,12 +211,13 @@ t_sendfile_partial(Config) -> t_sendfile_offset(Config) -> Filename = proplists:get_value(small_file, Config), FileOpts = proplists:get_value(file_opts, Config, []), + SendfileOpts = proplists:get_value(sendfile_opts, Config), Send = fun(Sock) -> {_Size, <<_:5/binary,Data:3/binary,_/binary>> = AllData} = sendfile_file_info(Filename), {ok,D} = file:open(Filename,[read|FileOpts]), - {ok,3} = file:sendfile(D,Sock,5,3,[]), + {ok,3} = file:sendfile(D,Sock,5,3,SendfileOpts), {ok, AllData} = file:read(D,100), file:close(D), Data @@ -205,10 +227,11 @@ t_sendfile_offset(Config) -> t_sendfile_sendafter(Config) -> Filename = proplists:get_value(small_file, Config), + SendfileOpts = proplists:get_value(sendfile_opts, Config), Send = fun(Sock) -> {Size, Data} = sendfile_file_info(Filename), - {ok, Size} = file:sendfile(Filename, Sock), + {ok, Size} = sendfile(Filename, Sock, SendfileOpts), ok = gen_tcp:send(Sock, <<2>>), <<Data/binary,2>> end, @@ -217,10 +240,11 @@ t_sendfile_sendafter(Config) -> t_sendfile_recvafter(Config) -> Filename = proplists:get_value(small_file, Config), + SendfileOpts = proplists:get_value(sendfile_opts, Config), Send = fun(Sock) -> {Size, Data} = sendfile_file_info(Filename), - {ok, Size} = file:sendfile(Filename, Sock), + {ok, Size} = sendfile(Filename, Sock, SendfileOpts), ok = gen_tcp:send(Sock, <<1>>), {ok,<<1>>} = gen_tcp:recv(Sock, 1), <<Data/binary,1>> @@ -228,8 +252,28 @@ t_sendfile_recvafter(Config) -> ok = sendfile_send(Send). +%% This tests specifically for a bug fixed in 17.0 +t_sendfile_recvafter_remoteclose(Config) -> + Filename = proplists:get_value(small_file, Config), + + Send = fun(Sock, SFServer) -> + {Size, _Data} = sendfile_file_info(Filename), + {ok, Size} = file:sendfile(Filename, Sock), + + %% Make sure the remote end has been closed + SFServer ! stop, + timer:sleep(100), + + %% In the bug this returned {error,ebadf} + {error,closed} = gen_tcp:recv(Sock, 1), + -1 + end, + + ok = sendfile_send({127,0,0,1},Send,0). + t_sendfile_sendduring(Config) -> Filename = proplists:get_value(big_file, Config), + SendfileOpts = proplists:get_value(sendfile_opts, Config), Send = fun(Sock) -> {ok, #file_info{size = Size}} = @@ -238,7 +282,7 @@ t_sendfile_sendduring(Config) -> timer:sleep(50), ok = gen_tcp:send(Sock, <<2>>) end), - {ok, Size} = file:sendfile(Filename, Sock), + {ok, Size} = sendfile(Filename, Sock, SendfileOpts), Size+1 end, @@ -246,6 +290,7 @@ t_sendfile_sendduring(Config) -> t_sendfile_recvduring(Config) -> Filename = proplists:get_value(big_file, Config), + SendfileOpts = proplists:get_value(sendfile_opts, Config), Send = fun(Sock) -> {ok, #file_info{size = Size}} = @@ -255,7 +300,7 @@ t_sendfile_recvduring(Config) -> ok = gen_tcp:send(Sock, <<1>>), {ok,<<1>>} = gen_tcp:recv(Sock, 1) end), - {ok, Size} = file:sendfile(Filename, Sock), + {ok, Size} = sendfile(Filename, Sock, SendfileOpts), timer:sleep(1000), Size+1 end, @@ -264,6 +309,7 @@ t_sendfile_recvduring(Config) -> t_sendfile_closeduring(Config) -> Filename = proplists:get_value(big_file, Config), + SendfileOpts = proplists:get_value(sendfile_opts, Config), Send = fun(Sock,SFServPid) -> spawn_link(fun() -> @@ -272,13 +318,14 @@ t_sendfile_closeduring(Config) -> end), case erlang:system_info(thread_pool_size) of 0 -> - {error, closed} = file:sendfile(Filename, Sock); + {error, closed} = sendfile(Filename, Sock, + SendfileOpts); _Else -> %% This can return how much has been sent or %% {error,closed} depending on OS. %% How much is sent impossible to know as %% the socket was closed mid sendfile - case file:sendfile(Filename, Sock) of + case sendfile(Filename, Sock, SendfileOpts) of {error, closed} -> ok; {ok, Size} when is_integer(Size) -> @@ -292,6 +339,7 @@ t_sendfile_closeduring(Config) -> t_sendfile_crashduring(Config) -> Filename = proplists:get_value(big_file, Config), + SendfileOpts = proplists:get_value(sendfile_opts, Config), error_logger:add_report_handler(?MODULE,[self()]), @@ -300,7 +348,7 @@ t_sendfile_crashduring(Config) -> timer:sleep(50), exit(die) end), - {error, closed} = file:sendfile(Filename, Sock), + {error, closed} = sendfile(Filename, Sock, SendfileOpts), -1 end, process_flag(trap_exit,true), @@ -395,6 +443,16 @@ sendfile_file_info(File) -> {ok, Data} = file:read_file(File), {Size, Data}. +sendfile(Filename,Sock,Opts) -> + case file:open(Filename, [read, raw, binary]) of + {error, Reason} -> + {error, Reason}; + {ok, Fd} -> + Res = file:sendfile(Fd, Sock, 0, 0, Opts), + _ = file:close(Fd), + Res + end. + %% Error handler diff --git a/lib/kernel/test/zlib_SUITE.erl b/lib/kernel/test/zlib_SUITE.erl index bd237cb513..3be6f39d95 100644 --- a/lib/kernel/test/zlib_SUITE.erl +++ b/lib/kernel/test/zlib_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2012. All Rights Reserved. +%% Copyright Ericsson AB 2005-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -178,7 +178,7 @@ api_deflateInit(Config) when is_list(Config) -> ?m(ok,zlib:close(Z)) end, lists:seq(1,8)), - Strategies = [filtered,huffman_only,default], + Strategies = [filtered,huffman_only,rle,default], lists:foreach(fun(Strategy) -> ?line Z = zlib:open(), ?m(ok, zlib:deflateInit(Z,best_speed,deflated,-15,8,Strategy)), @@ -220,7 +220,6 @@ api_deflateParams(Config) when is_list(Config) -> ?m(_, zlib:deflate(Z1, <<1,1,1,1,1,1,1,1,1>>, none)), ?m(ok, zlib:deflateParams(Z1, best_compression, huffman_only)), ?m(_, zlib:deflate(Z1, <<1,1,1,1,1,1,1,1,1>>, sync)), - ?m({'EXIT',_}, zlib:deflateParams(Z1,best_speed, filtered)), ?m(ok, zlib:close(Z1)). api_deflate(doc) -> "Test deflate"; @@ -565,8 +564,8 @@ intro(Config) when is_list(Config) -> large_deflate(doc) -> "Test deflate large file, which had a bug reported on erlang-bugs"; large_deflate(suite) -> []; large_deflate(Config) when is_list(Config) -> - large_deflate(). -large_deflate() -> + large_deflate_do(). +large_deflate_do() -> ?line Z = zlib:open(), ?line Plain = rand_bytes(zlib:getBufSize(Z)*5), ?line ok = zlib:deflateInit(Z), @@ -899,7 +898,7 @@ worker(Seed, FnATpl, Parent) -> Parent ! self(). worker_loop(0, _FnATpl) -> - large_deflate(), % the time consuming one as finale + large_deflate_do(), % the time consuming one as finale ok; worker_loop(N, FnATpl) -> {F,A} = element(random:uniform(size(FnATpl)),FnATpl), |