aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/test
diff options
context:
space:
mode:
authorSverker Eriksson <[email protected]>2017-08-30 21:00:35 +0200
committerSverker Eriksson <[email protected]>2017-08-30 21:00:35 +0200
commit44a83c8860bbd00878c720a7b9d940b4630bab8a (patch)
tree101b3c52ec505a94f56c8f70e078ecb8a2e8c6cd /lib/kernel/test
parent7c67bbddb53c364086f66260701bc54a61c9659c (diff)
parent040bdce67f88d833bfb59adae130a4ffb4c180f0 (diff)
downloadotp-44a83c8860bbd00878c720a7b9d940b4630bab8a.tar.gz
otp-44a83c8860bbd00878c720a7b9d940b4630bab8a.tar.bz2
otp-44a83c8860bbd00878c720a7b9d940b4630bab8a.zip
Merge tag 'OTP-20.0' into sverker/20/binary_to_atom-utf8-crash/ERL-474/OTP-14590
Diffstat (limited to 'lib/kernel/test')
-rw-r--r--lib/kernel/test/application_SUITE.erl4
-rw-r--r--lib/kernel/test/code_SUITE.erl394
-rw-r--r--lib/kernel/test/code_SUITE_data/upgrade_client.erl93
-rw-r--r--lib/kernel/test/code_SUITE_data/upgradee.erl12
-rw-r--r--lib/kernel/test/disk_log_SUITE.erl33
-rw-r--r--lib/kernel/test/erl_distribution_SUITE.erl278
-rw-r--r--lib/kernel/test/erl_distribution_wb_SUITE.erl10
-rw-r--r--lib/kernel/test/error_logger_SUITE.erl15
-rw-r--r--lib/kernel/test/file_SUITE.erl60
-rw-r--r--lib/kernel/test/file_SUITE_data/realmen.html4
-rw-r--r--lib/kernel/test/file_name_SUITE.erl4
-rw-r--r--lib/kernel/test/gen_sctp_SUITE.erl148
-rw-r--r--lib/kernel/test/gen_tcp_api_SUITE.erl27
-rw-r--r--lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c2
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl2
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl6
-rw-r--r--lib/kernel/test/inet_SUITE.erl230
-rw-r--r--lib/kernel/test/inet_sockopt_SUITE.erl4
-rw-r--r--lib/kernel/test/init_SUITE.erl61
-rw-r--r--lib/kernel/test/interactive_shell_SUITE.erl2
-rw-r--r--lib/kernel/test/multi_load_SUITE.erl10
-rw-r--r--lib/kernel/test/os_SUITE.erl100
-rw-r--r--lib/kernel/test/os_SUITE_data/Makefile.src8
-rw-r--r--lib/kernel/test/os_SUITE_data/my_fds.c9
-rw-r--r--lib/kernel/test/pdict_SUITE.erl60
-rw-r--r--lib/kernel/test/pg2_SUITE.erl29
-rw-r--r--lib/kernel/test/prim_file_SUITE.erl49
-rw-r--r--lib/kernel/test/rpc_SUITE.erl14
-rw-r--r--lib/kernel/test/sendfile_SUITE.erl6
-rw-r--r--lib/kernel/test/zlib_SUITE.erl38
30 files changed, 1410 insertions, 302 deletions
diff --git a/lib/kernel/test/application_SUITE.erl b/lib/kernel/test/application_SUITE.erl
index 81407e9d96..866043cfb4 100644
--- a/lib/kernel/test/application_SUITE.erl
+++ b/lib/kernel/test/application_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1498,7 +1498,7 @@ otp_5363(Conf) when is_list(Conf) ->
%% Ticket: OTP-5606
%% Slogan: Problems with starting a distributed application
%%-----------------------------------------------------------------
-%% Test of several processes simultanously starting the same
+%% Test of several processes simultaneously starting the same
%% distributed application.
otp_5606(Conf) when is_list(Conf) ->
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 8da67c89f8..6f8e949aac 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -36,7 +36,9 @@
code_archive/1, code_archive2/1, on_load/1, on_load_binary/1,
on_load_embedded/1, on_load_errors/1, on_load_update/1,
on_load_purge/1, on_load_self_call/1, on_load_pending/1,
+ on_load_deleted/1,
big_boot_embedded/1,
+ module_status/1,
native_early_modules/1, get_mode/1,
normalized_paths/1]).
@@ -66,6 +68,8 @@ all() ->
bad_erl_libs, code_archive, code_archive2, on_load,
on_load_binary, on_load_embedded, on_load_errors, on_load_update,
on_load_purge, on_load_self_call, on_load_pending,
+ on_load_deleted,
+ module_status,
big_boot_embedded, native_early_modules, get_mode, normalized_paths].
groups() ->
@@ -91,6 +95,11 @@ init_per_suite(Config) ->
end_per_suite(Config) ->
Config.
+-define(TESTMOD, test_dummy).
+-define(TESTMODSTR, "test_dummy").
+-define(TESTMODSRC, ?TESTMODSTR ".erl").
+-define(TESTMODOBJ, ?TESTMODSTR ".beam").
+
init_per_testcase(big_boot_embedded, Config) ->
case catch crypto:start() of
ok ->
@@ -98,16 +107,36 @@ init_per_testcase(big_boot_embedded, Config) ->
_Else ->
{skip, "Needs crypto!"}
end;
+init_per_testcase(on_load_embedded, Config0) ->
+ LibRoot = code:lib_dir(),
+ LinkName = filename:join(LibRoot, "on_load_app-1.0"),
+ Config = [{link_name,LinkName}|Config0],
+ init_per_testcase(Config);
init_per_testcase(_Func, Config) ->
+ init_per_testcase(Config).
+
+init_per_testcase(Config) ->
P = code:get_path(),
[{code_path, P}|Config].
+
+end_per_testcase(module_status, Config) ->
+ code:purge(?TESTMOD),
+ code:delete(?TESTMOD),
+ code:purge(?TESTMOD),
+ file:delete(?TESTMODOBJ),
+ file:delete(?TESTMODSRC),
+ end_per_testcase(Config);
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),
test_server:stop_node(NodeName),
end_per_testcase(Config);
+end_per_testcase(on_load_embedded, Config) ->
+ LinkName = proplists:get_value(link_name, Config),
+ _ = del_link(LinkName),
+ end_per_testcase(Config);
end_per_testcase(_Func, Config) ->
end_per_testcase(Config).
@@ -307,7 +336,7 @@ load_abs(Config) when is_list(Config) ->
{error, nofile} = code:load_abs(TestDir ++ "/duuuumy_mod"),
{error, badfile} = code:load_abs(TestDir ++ "/code_a_test"),
{'EXIT', _} = (catch code:load_abs({})),
- {'EXIT', _} = (catch code:load_abs("Non-latin-имя-файла")),
+ {error, nofile} = code:load_abs("Non-latin-имя-файла"),
{module, code_b_test} = code:load_abs(TestDir ++ "/code_b_test"),
code:stick_dir(TestDir),
{error, sticky_directory} = code:load_abs(TestDir ++ "/code_b_test"),
@@ -481,23 +510,35 @@ load_binary(Config) when is_list(Config) ->
code:delete(code_b_test),
ok.
+
upgrade(Config) ->
DataDir = proplists:get_value(data_dir, Config),
- %%T = [beam, hipe],
- T = [beam],
-
- [upgrade_do(DataDir, Client, U1, U2, O1, O2)
- || Client<-T, U1<-T, U2<-T, O1<-T, O2<-T],
-
+ case erlang:system_info(hipe_architecture) of
+ undefined ->
+ upgrade_do(DataDir, beam, [beam]);
+
+ _ ->
+ T = [beam, hipe],
+ [upgrade_do(DataDir, Client, T) || Client <- T],
+
+ case hipe:llvm_support_available() of
+ false -> ok;
+ true ->
+ T2 = [beam, hipe_llvm],
+ [upgrade_do(DataDir, Client, T2) || Client <- T2]
+ end
+ end,
ok.
-upgrade_do(DataDir, Client, U1, U2, O1, O2) ->
+upgrade_do(DataDir, Client, T) ->
compile_load(upgrade_client, DataDir, undefined, Client),
- upgrade_client:run(DataDir, U1, U2, O1, O2),
+ [upgrade_client:run(DataDir, U1, U2, O1, O2)
+ || U1<-T, U2<-T, O1<-T, O2<-T],
ok.
compile_load(Mod, Dir, Ver, CodeType) ->
+ %%erlang:display({"{{{{{{{{{{{{{{{{Loading",Mod,Ver,CodeType}),
Version = case Ver of
undefined ->
io:format("Compiling '~p' as ~p\n", [Mod, CodeType]),
@@ -509,14 +550,21 @@ compile_load(Mod, Dir, Ver, CodeType) ->
end,
Target = case CodeType of
beam -> [];
- hipe -> [native]
+ hipe -> [native];
+ hipe_llvm -> [native,{hipe,[to_llvm]}]
end,
CompOpts = [binary, report] ++ Target ++ Version,
Src = filename:join(Dir, atom_to_list(Mod) ++ ".erl"),
+ T1 = erlang:now(),
{ok,Mod,Code} = compile:file(Src, CompOpts),
+ T2 = erlang:now(),
ObjFile = filename:basename(Src,".erl") ++ ".beam",
{module,Mod} = code:load_binary(Mod, ObjFile, Code),
+ T3 = erlang:now(),
+ io:format("Compile time ~p ms, Load time ~p ms\n",
+ [timer:now_diff(T2,T1) div 1000, timer:now_diff(T3,T2) div 1000]),
+ %%erlang:display({"}}}}}}}}}}}}}}}Loaded",Mod,Ver,CodeType}),
ok.
dir_req(Config) when is_list(Config) ->
@@ -586,20 +634,28 @@ sticky_compiler(Files, PrivDir) ->
[R || R <- Rets, R =/= ok].
do_sticky_compile(Mod, Dir) ->
- %% Make sure that the module is loaded. A module being sticky
- %% only prevents it from begin reloaded, not from being loaded
- %% from the wrong place to begin with.
- Mod = Mod:module_info(module),
- File = filename:append(Dir, atom_to_list(Mod)),
- Src = io_lib:format("-module(~s).\n"
- "-export([test/1]).\n"
- "test(me) -> fail.\n", [Mod]),
- ok = file:write_file(File++".erl", Src),
- case c:c(File, [{outdir,Dir}]) of
- {ok,Module} ->
- Module:test(me);
- {error,sticky_directory} ->
- ok
+ case code:is_sticky(Mod) of
+ true ->
+ %% Make sure that the module is loaded. A module being sticky
+ %% only prevents it from begin reloaded, not from being loaded
+ %% from the wrong place to begin with.
+ Mod = Mod:module_info(module),
+ File = filename:append(Dir, atom_to_list(Mod)),
+ Src = io_lib:format("-module(~s).\n"
+ "-export([test/1]).\n"
+ "test(me) -> fail.\n", [Mod]),
+ ok = file:write_file(File++".erl", Src),
+ case c:c(File, [{outdir,Dir}]) of
+ {ok,Module} ->
+ Module:test(me);
+ {error,sticky_directory} ->
+ ok
+ end;
+ false ->
+ %% For some reason the module is not sticky
+ %% could be that the .erlang file has
+ %% unstuck it?
+ {Mod, is_not_sticky}
end.
%% Test that the -pa and -pz options work as expected.
@@ -808,8 +864,6 @@ 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},
- [{hipe_unified_loader,patch_to_emu_step1,1} | _]) -> 0;
check_funs({'$M_EXPR','$F_EXPR',2},
[{hipe_unified_loader,write_words,3} | _]) -> 0;
check_funs({'$M_EXPR','$F_EXPR',2},
@@ -821,11 +875,7 @@ check_funs({'$M_EXPR','$F_EXPR',2},
{hipe_unified_loader,sort_and_write,5} | _]) -> 0;
check_funs({'$M_EXPR','$F_EXPR',1},
[{lists,foreach,2},
- {hipe_unified_loader,patch_consts,3} | _]) -> 0;
-check_funs({'$M_EXPR','$F_EXPR',1},
- [{lists,foreach,2},
- {hipe_unified_loader,mark_referred_from,1},
- {hipe_unified_loader,get_refs_from,2}| _]) -> 0;
+ {hipe_unified_loader,patch_consts,4} | _]) -> 0;
check_funs({'$M_EXPR',warning_msg,2},
[{code_server,finish_on_load_report,2} | _]) -> 0;
check_funs({'$M_EXPR','$F_EXPR',1},
@@ -1234,10 +1284,9 @@ on_load_embedded(Config) when is_list(Config) ->
on_load_embedded_1(Config) ->
DataDir = proplists:get_value(data_dir, Config),
+ LinkName = proplists:get_value(link_name, Config),
%% Link the on_load_app application into the lib directory.
- 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]),
@@ -1271,8 +1320,7 @@ on_load_embedded_1(Config) ->
ok = rpc:call(Node, on_load_embedded, status, []),
%% Clean up.
- stop_node(Node),
- ok = del_link(LinkName).
+ stop_node(Node).
del_link(LinkName) ->
case file:delete(LinkName) of
@@ -1323,9 +1371,8 @@ create_big_boot(Config) ->
%% corresponding beam file (if hipe is not enabled).
filter_app("hipe",_) -> false;
-%% Dialyzer and typer depends on hipe
+%% Dialyzer depends on hipe
filter_app("dialyzer",_) -> false;
-filter_app("typer",_) -> false;
%% Orber requires explicit configuration
filter_app("orber",_) -> false;
@@ -1602,6 +1649,98 @@ on_load_pending(_Config) ->
ok = Mod:t(),
ok.
+on_load_deleted(_Config) ->
+ Mod = ?FUNCTION_NAME,
+
+ R0 = fun() ->
+ Tree = ?Q(["-module('@Mod@').\n",
+ "-on_load(f/0).\n",
+ "f() -> ok.\n"]),
+ merl:print(Tree),
+ {ok,Mod,Code} = merl:compile(Tree),
+ {module,Mod} = code:load_binary(Mod, "", Code)
+ end,
+ delete_before_reload(Mod, R0),
+ delete_before_reload(Mod, R0),
+
+ R1 = fun() ->
+ Tree = ?Q(["-module('@Mod@').\n",
+ "-on_load(f/0).\n",
+ "f() -> fail.\n"]),
+ merl:print(Tree),
+ {ok,Mod,Code} = merl:compile(Tree),
+ {error,on_load_failure} = code:load_binary(Mod, "", Code)
+ end,
+ delete_before_reload(Mod, R1),
+ delete_before_reload(Mod, R1),
+
+ OtherMod = list_to_atom(lists:concat([Mod,"_42"])),
+ OtherTree = ?Q(["-module('@OtherMod@').\n"]),
+ merl:print(OtherTree),
+ {ok,OtherMod,OtherCode} = merl:compile(OtherTree),
+
+ R2 = fun() ->
+ RegName = 'on_load__registered_name',
+ Tree = ?Q(["-module('@Mod@').\n",
+ "-on_load(f/0).\n",
+ "f() ->\n",
+ " register('@RegName@', self()),\n",
+ " receive _ -> ok end.\n"]),
+ merl:print(Tree),
+ {ok,Mod,Code} = merl:compile(Tree),
+ spawn(fun() ->
+ {module,Mod} = code:load_binary(Mod, "", Code)
+ end),
+ receive after 1 -> ok end,
+ {module,OtherMod} = code:load_binary(OtherMod, "",
+ OtherCode),
+ RegName ! stop
+ end,
+ delete_before_reload(Mod, R2),
+
+ ok.
+
+delete_before_reload(Mod, Reload) ->
+ false = check_old_code(Mod),
+
+ Tree1 = ?Q(["-module('@Mod@').\n",
+ "-export([f/1]).\n",
+ "f(Parent) ->\n",
+ " register('@Mod@', self()),\n",
+ " Parent ! started,\n",
+ " receive _ -> ok end.\n"]),
+ merl:print(Tree1),
+ {ok,Mod,Code1} = merl:compile(Tree1),
+
+ Self = self(),
+ spawn(fun() ->
+ {module,Mod} = code:load_binary(Mod, "", Code1),
+ Mod:f(Self)
+ end),
+ receive started -> ok end,
+
+ true = code:delete(Mod),
+ true = check_old_code(Mod),
+
+ Reload(),
+
+ %% When loading the the module with the -on_load() function,
+ %% the reference to the old code would be lost. Make sure that
+ %% the old code is remembered and is still preventing the
+ %% purge.
+ false = code:soft_purge(Mod),
+
+ %% Get rid of the old code.
+ Mod ! stop,
+ receive after 1 -> ok end,
+ true = code:soft_purge(Mod),
+
+ %% Unload the version of the module with the -on_load() function.
+ true = code:delete(Mod),
+ true = code:soft_purge(Mod),
+
+ ok.
+
%% Test that the native code of early loaded modules is loaded.
native_early_modules(Config) when is_list(Config) ->
@@ -1650,6 +1789,185 @@ do_normalized_paths([M|Ms]) ->
do_normalized_paths([]) ->
ok.
+%% Test that module_status/1 behaves as expected
+module_status(_Config) ->
+ case test_server:is_cover() of
+ true ->
+ module_status();
+ false ->
+ %% Make sure that we terminate the cover server.
+ try
+ module_status()
+ after
+ cover:stop()
+ end
+ end.
+
+module_status() ->
+ %% basics
+ not_loaded = code:module_status(fubar), % nonexisting
+ {file, preloaded} = code:is_loaded(erlang),
+ loaded = code:module_status(erlang), % preloaded
+ loaded = code:module_status(?MODULE), % normal known loaded
+
+ non_existing = code:which(?TESTMOD), % verify dummy name not in path
+ code:purge(?TESTMOD), % ensure no previous version in memory
+ code:delete(?TESTMOD),
+ code:purge(?TESTMOD),
+
+ %% generated code is detected as such
+ {ok,?TESTMOD,Bin} = compile:forms(dummy_ast(), []),
+ {module,?TESTMOD} = code:load_binary(?TESTMOD,"",Bin), % no source file
+ ok = ?TESTMOD:f(),
+ "" = code:which(?TESTMOD), % verify empty string for source file
+ loaded = code:module_status(?TESTMOD),
+
+ %% deleting generated code
+ true = code:delete(?TESTMOD),
+ non_existing = code:which(?TESTMOD), % verify still not in path
+ not_loaded = code:module_status(?TESTMOD),
+
+ %% beam file exists but not loaded
+ make_source_file(<<"0">>),
+ compile_beam(0),
+ true = (non_existing =/= code:which(?TESTMOD)), % verify in path
+ not_loaded = code:module_status(?TESTMOD),
+
+ %% loading code from disk makes it loaded
+ load_code(),
+ loaded = code:module_status(?TESTMOD), % loaded
+
+ %% cover compiling a module
+ {ok,?TESTMOD} = cover:compile(?TESTMOD),
+ {file, cover_compiled} = code:is_loaded(?TESTMOD), % verify cover compiled
+ modified = code:module_status(?TESTMOD), % loaded cover code but file exists
+ remove_code(),
+ removed = code:module_status(?TESTMOD), % removed
+ compile_beam(0),
+ modified = code:module_status(?TESTMOD), % recreated
+ load_code(),
+ loaded = code:module_status(?TESTMOD), % loading removes cover status
+ code:purge(?TESTMOD),
+ true = code:delete(?TESTMOD),
+ not_loaded = code:module_status(?TESTMOD), % deleted
+
+ %% recompilation ignores timestamps, only md5 matters
+ load_code(),
+ compile_beam(1100),
+ loaded = code:module_status(?TESTMOD),
+
+ %% modifying module detects different md5
+ make_source_file(<<"1">>),
+ compile_beam(0),
+ modified = code:module_status(?TESTMOD),
+
+ %% loading the modified code from disk makes it loaded
+ load_code(),
+ loaded = code:module_status(?TESTMOD),
+
+ %% removing and recreating a module with same md5
+ remove_code(),
+ removed = code:module_status(?TESTMOD),
+ compile_beam(0),
+ loaded = code:module_status(?TESTMOD),
+
+ case erlang:system_info(hipe_architecture) of
+ undefined ->
+ %% no native support
+ ok;
+ _ ->
+ %% native chunk is ignored if beam code is already loaded
+ load_code(),
+ loaded = code:module_status(?TESTMOD),
+ false = has_native(?TESTMOD),
+ compile_native(0),
+ BeamMD5 = erlang:get_module_info(?TESTMOD, md5),
+ {ok,{?TESTMOD,BeamMD5}} = beam_lib:md5(?TESTMODOBJ), % beam md5 unchanged
+ loaded = code:module_status(?TESTMOD),
+
+ %% native code reported as loaded, though different md5 from beam
+ load_code(),
+ true = has_native(?TESTMOD),
+ NativeMD5 = erlang:get_module_info(?TESTMOD, md5),
+ true = (BeamMD5 =/= NativeMD5),
+ loaded = code:module_status(?TESTMOD),
+
+ %% recompilation ignores timestamps, only md5 matters
+ compile_native(1100), % later timestamp
+ loaded = code:module_status(?TESTMOD),
+
+ %% modifying native module detects different md5
+ make_source_file(<<"2">>),
+ compile_native(0),
+ modified = code:module_status(?TESTMOD),
+
+ %% loading the modified native code from disk makes it loaded
+ load_code(),
+ true = has_native(?TESTMOD),
+ NativeMD5_2 = erlang:get_module_info(?TESTMOD, md5),
+ true = (NativeMD5 =/= NativeMD5_2), % verify native md5 changed
+ {ok,{?TESTMOD,BeamMD5_2}} = beam_lib:md5(?TESTMODOBJ),
+ true = (BeamMD5_2 =/= NativeMD5_2), % verify md5 differs from beam
+ loaded = code:module_status(?TESTMOD),
+
+ %% removing and recreating a native module with same md5
+ remove_code(),
+ removed = code:module_status(?TESTMOD),
+ compile_native(0),
+ loaded = code:module_status(?TESTMOD),
+
+ %% purging/deleting native module
+ code:purge(?TESTMOD),
+ true = code:delete(?TESTMOD),
+ not_loaded = code:module_status(?TESTMOD)
+ end,
+ ok.
+
+compile_beam(Sleep) ->
+ compile(Sleep, []).
+
+compile_native(Sleep) ->
+ compile(Sleep, [native]).
+
+compile(Sleep, Opts) ->
+ timer:sleep(Sleep), % increment compilation timestamp
+ {ok,?TESTMOD} = compile:file(?TESTMODSRC, Opts).
+
+load_code() ->
+ code:purge(?TESTMOD),
+ {module,?TESTMOD} = code:load_file(?TESTMOD).
+
+remove_code() ->
+ ok = file:delete(?TESTMODOBJ).
+
+has_native(Module) ->
+ case erlang:get_module_info(Module, native_addresses) of
+ [] -> false;
+ [_|_] -> true
+ end.
+
+make_source_file(Body) ->
+ ok = file:write_file(?TESTMODSRC, dummy_source(Body)).
+
+dummy_source(Body) ->
+ [<<"-module(" ?TESTMODSTR ").\n"
+ "-export([f/0]).\n"
+ "f() -> ">>, Body, <<".\n">>].
+
+dummy_ast() ->
+ dummy_ast(?TESTMODSTR).
+
+dummy_ast(Mod) when is_atom(Mod) ->
+ dummy_ast(atom_to_list(Mod));
+dummy_ast(ModStr) ->
+ [scan_form("-module(" ++ ModStr ++ ")."),
+ scan_form("-export([f/0])."),
+ scan_form("f() -> ok.")].
+
+scan_form(String) ->
+ {ok,Ts,_} = erl_scan:string(String),
+ {ok,F} = erl_parse:parse_form(Ts),
+ F.
%%-----------------------------------------------------------------
%% error_logger handler.
diff --git a/lib/kernel/test/code_SUITE_data/upgrade_client.erl b/lib/kernel/test/code_SUITE_data/upgrade_client.erl
index bb655e01d3..faa18e1410 100644
--- a/lib/kernel/test/code_SUITE_data/upgrade_client.erl
+++ b/lib/kernel/test/code_SUITE_data/upgrade_client.erl
@@ -9,6 +9,8 @@ run(Dir, Upgradee1, Upgradee2, Other1, Other2) ->
%% Load version 1 of upgradee
code_SUITE:compile_load(upgradee, Dir, 1, Upgradee1),
+ Tracer = start_tracing(),
+
?line 1 = upgradee:exp1(),
?line 1 = upgradee:exp1exp2(),
?line 1 = upgradee:exp1loc2(),
@@ -56,6 +58,15 @@ run(Dir, Upgradee1, Upgradee2, Other1, Other2) ->
?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1),
?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2),
+ Env1 = "Env1",
+ put(loc1_fun, upgradee:get_local_fun(Env1)),
+ ?line {1,Env1} = (get(loc1_fun))(),
+
+ put(exp1exp2_fun, upgradee:get_exp1exp2_fun()),
+ ?line 1 = (get(exp1exp2_fun))(),
+
+ ok = check_tracing(Tracer, 13),
+
%%
%% Load version 1 of other
%%
@@ -78,6 +89,8 @@ run(Dir, Upgradee1, Upgradee2, Other1, Other2) ->
?line {'EXIT',{undef,_}} = proxy_call(P, other, exp2),
?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2),
+ ok = check_tracing(Tracer, 5),
+
%%
%% Load version 2 of upgradee
%%
@@ -130,6 +143,15 @@ run(Dir, Upgradee1, Upgradee2, Other1, Other2) ->
?line {'EXIT',{undef,_}} = proxy_call(P, other, exp2),
?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2),
+ ?line {1,Env1} = (get(loc1_fun))(),
+ Env2 = "Env2",
+ put(loc2_fun, upgradee:get_local_fun(Env2)),
+ ?line {2,Env2} = (get(loc2_fun))(),
+
+ ?line 2 = (get(exp1exp2_fun))(),
+
+ ok = check_tracing(Tracer, 10),
+
%%
%% Load version 2 of other
%%
@@ -182,17 +204,26 @@ run(Dir, Upgradee1, Upgradee2, Other1, Other2) ->
?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1loc2),
?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2),
+ ?line {1,Env1} = (get(loc1_fun))(),
+ ?line {2,Env2} = (get(loc2_fun))(),
+ ?line 2 = (get(exp1exp2_fun))(),
+
+ ok = check_tracing(Tracer, 10),
%%
%% Upgrade proxy to version 2
%%
P ! upgrade_order,
-
%%
- io:format("Delete version 2 of 'upgradee'\n",[]),
+ io:format("Purge version 1 of 'upgradee'\n",[]),
%%
+ put(loc1_fun,undefined),
code:purge(upgradee),
+
+ %%
+ io:format("Delete version 2 of 'upgradee'\n",[]),
+ %%
code:delete(upgradee),
?line {'EXIT',{undef,_}} = (catch upgradee:exp2()),
@@ -239,17 +270,24 @@ run(Dir, Upgradee1, Upgradee2, Other1, Other2) ->
?line {'EXIT',{undef,_}} = proxy_call(P, other, exp1loc2),
?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1loc2),
?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2),
+
+ ?line {'EXIT',{undef,_}} = (catch (get(exp1exp2_fun))()),
+ ok = check_tracing(Tracer, 14),
+
unlink(P),
exit(P, die_please),
io:format("Purge 'upgradee'\n",[]),
+ put(loc2_fun,undefined),
code:purge(upgradee),
io:format("Delete and purge 'other'\n",[]),
code:purge(other),
code:delete(other),
code:purge(other),
+
+ stop_tracing(Tracer),
ok.
proxy_call(Pid, CallType, Func) ->
@@ -257,3 +295,54 @@ proxy_call(Pid, CallType, Func) ->
receive
{Pid, call_result, Func, Ret} -> Ret
end.
+
+
+start_tracing() ->
+ Self = self(),
+ {Tracer,_} = spawn_opt(fun() -> tracer_loop(Self) end, [link,monitor]),
+ ?line 1 = erlang:trace_pattern({error_handler,undefined_function,3},
+ true, [global]),
+ ?line 1 = erlang:trace(Self, true, [call,{tracer,Tracer}]),
+ Tracer.
+
+
+tracer_loop(Receiver) ->
+ receive
+ die_please ->
+ ok;
+ {do_trace_delivered, Tracee} ->
+ _ = erlang:trace_delivered(Tracee),
+ tracer_loop(Receiver);
+
+ Msg ->
+ Receiver ! Msg,
+ tracer_loop(Receiver)
+ end.
+
+check_tracing(Tracer, Expected) ->
+ Tracer ! {do_trace_delivered, self()},
+ case check_tracing_loop(0,[]) of
+ {Expected,_} ->
+ ok;
+ {Got, MsgList} ->
+ io:format("Expected ~p trace msg, got ~p:\n~p\n",
+ [Expected, Got, lists:reverse(MsgList)]),
+ "Trace msg mismatch"
+ end.
+
+check_tracing_loop(N, MsgList) ->
+ Self = self(),
+ receive
+ {trace, _Pid, call, {_M, _F, _Args}} = Msg ->
+ check_tracing_loop(N+1, [Msg | MsgList]);
+ {trace_delivered, Self, _} ->
+ {N, MsgList}
+ end.
+
+
+stop_tracing(Tracer) ->
+ erlang:trace(self(), false, [call]),
+ Tracer ! die_please,
+ receive
+ {'DOWN', _, process, Tracer, _} -> ok
+ end.
diff --git a/lib/kernel/test/code_SUITE_data/upgradee.erl b/lib/kernel/test/code_SUITE_data/upgradee.erl
index 62b1d95e30..8ca660c19c 100644
--- a/lib/kernel/test/code_SUITE_data/upgradee.erl
+++ b/lib/kernel/test/code_SUITE_data/upgradee.erl
@@ -8,6 +8,9 @@
-export([exp1/0]). % only exported in v1
-export([exp1loc2/0]). % exported in v1, local in v2
-export([exp1exp2/0]). % exported in v1 and v2
+-export([get_local_fun/1]).
+-export([get_exp1exp2_fun/0]).
+-export([exp1exp2_fun/0]).
exp1() -> ?VERSION.
loc1() -> ?VERSION.
@@ -20,6 +23,9 @@ loc1() -> ?VERSION.
-export([exp2/0]).
-export([loc1exp2/0]).
-export([exp1exp2/0]).
+-export([get_local_fun/1]).
+-export([get_exp1exp2_fun/0]).
+-export([exp1exp2_fun/0]).
exp2() -> ?VERSION.
loc2() -> ?VERSION.
@@ -31,6 +37,12 @@ exp1loc2() -> ?VERSION.
loc1exp2() -> ?VERSION.
loc1loc2() -> ?VERSION.
+get_local_fun(Env) -> fun() -> {?VERSION,Env} end.
+get_exp1exp2_fun() -> fun ?MODULE:exp1exp2_fun/0.
+
+exp1exp2_fun() ->
+ ?VERSION.
+
dispatch_loop() ->
receive
upgrade_order ->
diff --git a/lib/kernel/test/disk_log_SUITE.erl b/lib/kernel/test/disk_log_SUITE.erl
index f7ad9c0c04..fe2fc778f2 100644
--- a/lib/kernel/test/disk_log_SUITE.erl
+++ b/lib/kernel/test/disk_log_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -421,7 +421,7 @@ halt_ro_alog(Conf) when is_list(Conf) ->
halt_ro_alog_wait_notify(Log, T) ->
Term = term_to_binary(T),
receive
- {disk_log, _, Log,{read_only, Term}} ->
+ {disk_log, _, Log,{read_only, [Term]}} ->
ok;
Other ->
Other
@@ -449,7 +449,7 @@ halt_ro_balog(Conf) when is_list(Conf) ->
halt_ro_balog_wait_notify(Log, T) ->
Term = list_to_binary(T),
receive
- {disk_log, _, Log,{read_only, Term}} ->
+ {disk_log, _, Log,{read_only, [Term]}} ->
ok;
Other ->
Other
@@ -1385,15 +1385,15 @@ blocked_notif(Conf) when is_list(Conf) ->
"The requested operation" ++ _ = format_error(Error1),
ok = disk_log:blog(n, B),
ok = disk_log:alog(n, B),
- rec(1, {disk_log, node(), n, {format_external, term_to_binary(B)}}),
+ rec(1, {disk_log, node(), n, {format_external, [term_to_binary(B)]}}),
ok = disk_log:alog_terms(n, [B,B,B,B]),
rec(1, {disk_log, node(), n, {format_external,
lists:map(fun term_to_binary/1, [B,B,B,B])}}),
ok = disk_log:block(n, false),
ok = disk_log:alog(n, B),
- rec(1, {disk_log, node(), n, {blocked_log, term_to_binary(B)}}),
+ rec(1, {disk_log, node(), n, {blocked_log, [term_to_binary(B)]}}),
ok = disk_log:balog(n, B),
- rec(1, {disk_log, node(), n, {blocked_log, list_to_binary(B)}}),
+ rec(1, {disk_log, node(), n, {blocked_log, [list_to_binary(B)]}}),
ok = disk_log:balog_terms(n, [B,B,B,B]),
disk_log:close(n),
rec(1, {disk_log, node(), n, {blocked_log,
@@ -2493,6 +2493,7 @@ error_repair(Conf) when is_list(Conf) ->
del(File, No),
ok = file:del_dir(Dir),
+ error_logger:add_report_handler(?MODULE, self()),
%% repair a file
P1 = pps(),
{ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap},
@@ -2509,6 +2510,8 @@ error_repair(Conf) when is_list(Conf) ->
ok = disk_log:close(n),
true = (P1 == pps()),
del(File, No),
+ receive {info_msg, _, "disk_log: repairing" ++ _, _} -> ok
+ after 1000 -> ct:fail(failed) end,
%% yet another repair
P2 = pps(),
@@ -2525,6 +2528,8 @@ error_repair(Conf) when is_list(Conf) ->
ok = disk_log:close(n),
true = (P2 == pps()),
del(File, No),
+ receive {info_msg, _, "disk_log: repairing" ++ _, _} -> ok
+ after 1000 -> ct:fail(failed) end,
%% Repair, large term
Big = term_to_binary(lists:duplicate(66000,$a)),
@@ -2540,6 +2545,8 @@ error_repair(Conf) when is_list(Conf) ->
ok = disk_log:close(n),
Got = Big,
del(File, No),
+ receive {info_msg, _, "disk_log: repairing" ++ _, _} -> ok
+ after 1000 -> ct:fail(failed) end,
%% A term a little smaller than a chunk, then big terms.
BigSmall = mk_bytes(1024*64-8-12),
@@ -2560,6 +2567,8 @@ error_repair(Conf) when is_list(Conf) ->
{type, halt}, {format, internal}]),
ok = disk_log:close(n),
file:delete(File),
+ receive {info_msg, _, "disk_log: repairing" ++ _, _} -> ok
+ after 1000 -> ct:fail(failed) end,
%% The header is recovered.
{ok,n} =
@@ -2573,12 +2582,13 @@ error_repair(Conf) when is_list(Conf) ->
crash(File, 30),
{repaired,n,{recovered,3},{badbytes,16}} =
disk_log:open([{name, n}, {file, File}, {type, halt},
- {format, internal},{repair,true},
+ {format, internal},{repair,true}, {quiet, true},
{head_func, {?MODULE, head_fun, [{ok,"head"}]}}]),
["head",'of',terms] = get_all_terms(n),
ok = disk_log:close(n),
-
+ error_logger:delete_report_handler(?MODULE),
file:delete(File),
+ {messages, []} = process_info(self(), messages),
ok.
@@ -4666,7 +4676,7 @@ other_groups(Conf) when is_list(Conf) ->
ok.
--define(MAX, 16384). % MAX in disk_log_1.erl
+-define(MAX, ?MAX_FWRITE_CACHE). % as in disk_log_1.erl
%% Evil cases such as closed file descriptor port.
evil(Conf) when is_list(Conf) ->
Dir = ?privdir(Conf),
@@ -4690,7 +4700,7 @@ evil(Conf) when is_list(Conf) ->
{size,?MAX+50},{format,external}]),
[Fd] = erlang:ports() -- Ports0,
{B,_} = x_mk_bytes(30),
- ok = disk_log:blog(Log, <<0:(?MAX+1)/unit:8>>),
+ ok = disk_log:blog(Log, <<0:(?MAX-1)/unit:8>>),
exit(Fd, kill),
{error, {file_error,_,einval}} = disk_log:blog_terms(Log, [B,B]),
ok= disk_log:close(Log),
@@ -5007,6 +5017,9 @@ init(Tester) ->
handle_event({error_report, _GL, {Pid, crash_report, Report}}, Tester) ->
Tester ! {crash_report, Pid, Report},
{ok, Tester};
+handle_event({info_msg, _GL, {Pid, F,A}}, Tester) ->
+ Tester ! {info_msg, Pid, F, A},
+ {ok, Tester};
handle_event(_Event, State) ->
{ok, State}.
diff --git a/lib/kernel/test/erl_distribution_SUITE.erl b/lib/kernel/test/erl_distribution_SUITE.erl
index eb58e92224..bbfaa9d147 100644
--- a/lib/kernel/test/erl_distribution_SUITE.erl
+++ b/lib/kernel/test/erl_distribution_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,7 +24,10 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
--export([tick/1, tick_change/1, illegal_nodenames/1, hidden_node/1,
+-export([tick/1, tick_change/1,
+ nodenames/1, hostnames/1,
+ illegal_nodenames/1, hidden_node/1,
+ setopts/1,
table_waste/1, net_setuptime/1,
inet_dist_options_options/1,
@@ -42,6 +45,8 @@
-export([get_socket_priorities/0,
tick_cli_test/1, tick_cli_test1/1,
tick_serv_test/2, tick_serv_test1/1,
+ run_remote_test/1,
+ setopts_do/2,
keep_conn/1, time_ping/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -50,7 +55,6 @@
-export([pinger/1]).
-
-define(DUMMY_NODE,dummy@test01).
%%-----------------------------------------------------------------
@@ -65,7 +69,8 @@ suite() ->
{timetrap,{minutes,4}}].
all() ->
- [tick, tick_change, illegal_nodenames, hidden_node,
+ [tick, tick_change, nodenames, hostnames, illegal_nodenames,
+ hidden_node, setopts,
table_waste, net_setuptime, inet_dist_options_options,
{group, monitor_nodes}].
@@ -175,7 +180,105 @@ table_waste(Config) when is_list(Config) ->
stop_node(N),
ok.
+%% Test that starting nodes with different legal name part works, and that illegal
+%% ones are filtered
+nodenames(Config) when is_list(Config) ->
+ legal("a1@b"),
+ legal("a-1@b"),
+ legal("a_1@b"),
+
+ illegal("cdé@a"),
+ illegal("te欢st@a").
+
+%% Test that starting nodes with different legal host part works, and that illegal
+%% ones are filtered
+hostnames(Config) when is_list(Config) ->
+ Host = gethostname(),
+ legal([$a,$@|atom_to_list(Host)]),
+ legal("1@b1"),
+ legal("b@b1-c"),
+ legal("c@b1_c"),
+ legal("d@b1#c"),
+ legal("f@::1"),
+ legal("g@1:bc3:4e3f:f20:0:1"),
+
+ case file:native_name_encoding() of
+ latin1 -> ignore;
+ _ -> legal("e@b1é")
+ end,
+ long_hostnames(net_kernel:longnames()),
+
+ illegal("h@testالع"),
+ illegal("i@языtest"),
+ illegal("j@te欢st").
+
+long_hostnames(true) ->
+ legal("[email protected]"),
+ legal("[email protected]"),
+ legal("[email protected]_c.d"),
+ legal("[email protected]"),
+ legal("[email protected]");
+long_hostnames(false) ->
+ illegal("[email protected]").
+
+legal(Name) ->
+ case test_node(Name) of
+ started ->
+ ok;
+ not_started ->
+ ct:fail("no ~p node started", [Name])
+ end.
+
+illegal(Name) ->
+ case test_node(Name, true) of
+ not_started ->
+ ok;
+ started ->
+ ct:fail("~p node started with illegal name", [Name])
+ end.
+
+test_node(Name) ->
+ test_node(Name, false).
+test_node(Name, Illigal) ->
+ ProgName = atom_to_list(lib:progname()),
+ Command = ProgName ++ " -noinput " ++ long_or_short() ++ Name ++
+ " -eval \"net_adm:ping('" ++ atom_to_list(node()) ++ "')\"" ++
+ case Illigal of
+ true ->
+ " -eval \"timer:sleep(10000),init:stop().\"";
+ false ->
+ ""
+ end,
+ net_kernel:monitor_nodes(true),
+ BinCommand = unicode:characters_to_binary(Command, utf8),
+ Prt = open_port({spawn, BinCommand}, [stream]),
+ Node = list_to_atom(Name),
+ receive
+ {nodeup, Node} ->
+ net_kernel:monitor_nodes(false),
+ slave:stop(Node),
+ started
+ after 5000 ->
+ net_kernel:monitor_nodes(false),
+ not_started
+ end.
+long_or_short() ->
+ case net_kernel:longnames() of
+ true -> " -name ";
+ false -> " -sname "
+ end.
+
+% get the localhost's name, depending on the using name policy
+gethostname() ->
+ Hostname = case net_kernel:longnames() of
+ true->
+ net_adm:localhost();
+ _->
+ {ok, Name}=inet:gethostname(),
+ Name
+ end,
+ list_to_atom(Hostname).
%% Test that pinging an illegal nodename does not kill the node.
illegal_nodenames(Config) when is_list(Config) ->
@@ -226,10 +329,10 @@ time_ping(Node) ->
T0 = erlang:monotonic_time(),
pang = net_adm:ping(Node),
T1 = erlang:monotonic_time(),
- erlang:convert_time_unit(T1 - T0, native, milli_seconds).
+ erlang:convert_time_unit(T1 - T0, native, millisecond).
%% Keep the connection with the client node up.
-%% This is neccessary as the client node runs with much shorter
+%% This is necessary as the client node runs with much shorter
%% tick time !!
keep_conn(Node) ->
sleep(1),
@@ -270,7 +373,7 @@ tick_cli_test1(Node) ->
receive
{whats_the_result, From} ->
Diff = erlang:convert_time_unit(T2-T1, native,
- milli_seconds),
+ millisecond),
case Diff of
T when T > 8000, T < 16000 ->
From ! {tick_test, T};
@@ -282,6 +385,165 @@ tick_cli_test1(Node) ->
end
end.
+setopts(Config) when is_list(Config) ->
+ register(setopts_regname, self()),
+ [N1,N2,N3,N4] = get_nodenames(4, setopts),
+
+ {_N1F,Port1} = start_node_unconnected(N1, ?MODULE, run_remote_test,
+ ["setopts_do", atom_to_list(node()), "1", "ping"]),
+ 0 = wait_for_port_exit(Port1),
+
+ {_N2F,Port2} = start_node_unconnected(N2, ?MODULE, run_remote_test,
+ ["setopts_do", atom_to_list(node()), "2", "ping"]),
+ 0 = wait_for_port_exit(Port2),
+
+ {ok, LSock} = gen_tcp:listen(0, [{packet,2}, {active,false}]),
+ {ok, LTcpPort} = inet:port(LSock),
+
+ {N3F,Port3} = start_node_unconnected(N3, ?MODULE, run_remote_test,
+ ["setopts_do", atom_to_list(node()),
+ "1", integer_to_list(LTcpPort)]),
+ wait_and_connect(LSock, N3F, Port3),
+ 0 = wait_for_port_exit(Port3),
+
+ {N4F,Port4} = start_node_unconnected(N4, ?MODULE, run_remote_test,
+ ["setopts_do", atom_to_list(node()),
+ "2", integer_to_list(LTcpPort)]),
+ wait_and_connect(LSock, N4F, Port4),
+ 0 = wait_for_port_exit(Port4),
+
+ ok.
+
+wait_and_connect(LSock, NodeName, NodePort) ->
+ {ok, Sock} = gen_tcp:accept(LSock),
+ {ok, "Connect please"} = gen_tcp:recv(Sock, 0),
+ flush_from_port(NodePort),
+ pong = net_adm:ping(NodeName),
+ gen_tcp:send(Sock, "Connect done"),
+ gen_tcp:close(Sock).
+
+
+flush_from_port(Port) ->
+ flush_from_port(Port, 10).
+
+flush_from_port(Port, Timeout) ->
+ receive
+ {Port,{data,String}} ->
+ io:format("~p: ~s\n", [Port, String]),
+ flush_from_port(Port, Timeout)
+ after Timeout ->
+ timeout
+ end.
+
+wait_for_port_exit(Port) ->
+ case (receive M -> M end) of
+ {Port,{exit_status,Status}} ->
+ Status;
+ {Port,{data,String}} ->
+ io:format("~p: ~s\n", [Port, String]),
+ wait_for_port_exit(Port)
+ end.
+
+run_remote_test([FuncStr, TestNodeStr | Args]) ->
+ Status = try
+ io:format("Node ~p started~n", [node()]),
+ TestNode = list_to_atom(TestNodeStr),
+ io:format("Node ~p spawning function ~p~n", [node(), FuncStr]),
+ {Pid,Ref} = spawn_monitor(?MODULE, list_to_atom(FuncStr), [TestNode, Args]),
+ io:format("Node ~p waiting for function ~p~n", [node(), FuncStr]),
+ receive
+ {'DOWN', Ref, process, Pid, normal} ->
+ 0;
+ Other ->
+ io:format("Node ~p got unexpected msg: ~p\n",[node(), Other]),
+ 1
+ end
+ catch
+ C:E ->
+ io:format("Node ~p got EXCEPTION ~p:~p\nat ~p\n",
+ [node(), C, E, erlang:get_stacktrace()]),
+ 2
+ end,
+ io:format("Node ~p doing halt(~p).\n",[node(), Status]),
+ erlang:halt(Status).
+
+% Do the actual test on the remote node
+setopts_do(TestNode, [OptNr, ConnectData]) ->
+ [] = nodes(),
+ {Opt, Val} = opt_from_nr(OptNr),
+ ok = net_kernel:setopts(new, [{Opt, Val}]),
+
+ [] = nodes(),
+ {error, noconnection} = net_kernel:getopts(TestNode, [Opt]),
+
+ case ConnectData of
+ "ping" -> % We connect
+ net_adm:ping(TestNode);
+ TcpPort -> % Other connect
+ {ok, Sock} = gen_tcp:connect("localhost", list_to_integer(TcpPort),
+ [{active,false},{packet,2}]),
+ ok = gen_tcp:send(Sock, "Connect please"),
+ {ok, "Connect done"} = gen_tcp:recv(Sock, 0),
+ gen_tcp:close(Sock)
+ end,
+ [TestNode] = nodes(),
+ {ok, [{Opt,Val}]} = net_kernel:getopts(TestNode, [Opt]),
+ {error, noconnection} = net_kernel:getopts('pixie@fairyland', [Opt]),
+
+ NewVal = change_val(Val),
+ ok = net_kernel:setopts(TestNode, [{Opt, NewVal}]),
+ {ok, [{Opt,NewVal}]} = net_kernel:getopts(TestNode, [Opt]),
+
+ ok = net_kernel:setopts(TestNode, [{Opt, Val}]),
+ {ok, [{Opt,Val}]} = net_kernel:getopts(TestNode, [Opt]),
+
+ ok.
+
+opt_from_nr("1") -> {nodelay, true};
+opt_from_nr("2") -> {nodelay, false}.
+
+change_val(true) -> false;
+change_val(false) -> true.
+
+start_node_unconnected(Name, Mod, Func, Args) ->
+ FullName = full_node_name(Name),
+ CmdLine = mk_node_cmdline(Name,Mod,Func,Args),
+ io:format("Starting node ~p: ~s~n", [FullName, CmdLine]),
+ case open_port({spawn, CmdLine}, [exit_status]) of
+ Port when is_port(Port) ->
+ {FullName, Port};
+ Error ->
+ exit({failed_to_start_node, FullName, Error})
+ end.
+
+full_node_name(PreName) ->
+ HostSuffix = lists:dropwhile(fun ($@) -> false; (_) -> true end,
+ atom_to_list(node())),
+ list_to_atom(atom_to_list(PreName) ++ HostSuffix).
+
+mk_node_cmdline(Name,Mod,Func,Args) ->
+ Static = "-noinput",
+ Pa = filename:dirname(code:which(?MODULE)),
+ Prog = case catch init:get_argument(progname) of
+ {ok,[[P]]} -> P;
+ _ -> exit(no_progname_argument_found)
+ end,
+ NameSw = case net_kernel:longnames() of
+ false -> "-sname ";
+ true -> "-name ";
+ _ -> exit(not_distributed_node)
+ end,
+ {ok, Pwd} = file:get_cwd(),
+ NameStr = atom_to_list(Name),
+ Prog ++ " "
+ ++ Static ++ " "
+ ++ NameSw ++ " " ++ NameStr
+ ++ " -pa " ++ Pa
+ ++ " -env ERL_CRASH_DUMP " ++ Pwd ++ "/erl_crash_dump." ++ NameStr
+ ++ " -setcookie " ++ atom_to_list(erlang:get_cookie())
+ ++ " -run " ++ atom_to_list(Mod) ++ " " ++ atom_to_list(Func)
+ ++ " " ++ string:join(Args, " ").
+
%% OTP-4255.
tick_change(Config) when is_list(Config) ->
@@ -896,7 +1158,7 @@ monitor_nodes_otp_6481_test(Config, TestType) when is_list(Config) ->
RemotePid = spawn(Node,
fun () ->
receive after 1500 -> ok end,
- %% infinit loop of msgs
+ %% infinite loop of msgs
%% we want an endless stream of messages and the kill
%% the node mercilessly.
%% We then want to ensure that the nodedown message arrives
diff --git a/lib/kernel/test/erl_distribution_wb_SUITE.erl b/lib/kernel/test/erl_distribution_wb_SUITE.erl
index 6a23ad0d11..03aaee56b7 100644
--- a/lib/kernel/test/erl_distribution_wb_SUITE.erl
+++ b/lib/kernel/test/erl_distribution_wb_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@
%% 1)
%%
-%% Connections are now always set up symetrically with respect to
+%% Connections are now always set up symmetrically with respect to
%% publication. If connecting node doesn't send DFLAG_PUBLISHED
%% the other node wont send DFLAG_PUBLISHED. If the connecting
%% node send DFLAG_PUBLISHED but the other node doesn't send
@@ -56,10 +56,14 @@
-define(DFLAG_HIDDEN_ATOM_CACHE,16#40).
-define(DFLAG_NEW_FUN_TAGS,16#80).
-define(DFLAG_EXTENDED_PIDS_PORTS,16#100).
+-define(DFLAG_UTF8_ATOMS, 16#10000).
%% From R9 and forward extended references is compulsory
%% From R10 and forward extended pids and ports are compulsory
--define(COMPULSORY_DFLAGS, (?DFLAG_EXTENDED_REFERENCES bor ?DFLAG_EXTENDED_PIDS_PORTS)).
+%% From R20 and forward UTF8 atoms are compulsory
+-define(COMPULSORY_DFLAGS, (?DFLAG_EXTENDED_REFERENCES bor
+ ?DFLAG_EXTENDED_PIDS_PORTS bor
+ ?DFLAG_UTF8_ATOMS)).
-define(shutdown(X), exit(X)).
diff --git a/lib/kernel/test/error_logger_SUITE.erl b/lib/kernel/test/error_logger_SUITE.erl
index b6e7551741..2d26a7246c 100644
--- a/lib/kernel/test/error_logger_SUITE.erl
+++ b/lib/kernel/test/error_logger_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
+ off_heap/1,
error_report/1, info_report/1, error/1, info/1,
emulator/1, tty/1, logfile/1, add/1, delete/1]).
@@ -45,7 +46,7 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- [error_report, info_report, error, info, emulator, tty,
+ [off_heap, error_report, info_report, error, info, emulator, tty,
logfile, add, delete].
groups() ->
@@ -66,6 +67,16 @@ end_per_group(_GroupName, Config) ->
%%-----------------------------------------------------------------
+off_heap(_Config) ->
+ %% The error_logger process may receive a huge amount of
+ %% messages. Make sure that they are stored off heap to
+ %% avoid exessive GCs.
+ MQD = message_queue_data,
+ {MQD,off_heap} = process_info(whereis(error_logger), MQD),
+ ok.
+
+%%-----------------------------------------------------------------
+
error_report(Config) when is_list(Config) ->
error_logger:add_report_handler(?MODULE, self()),
Rep1 = [{tag1,"data1"},{tag2,data2},{tag3,3}],
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 5f049c6f99..119e1f24bb 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
%% %CopyrightEnd%
%%
-%% This is a developement feature when developing a new file module,
+%% This is a development feature when developing a new file module,
%% ugly but practical.
-ifndef(FILE_MODULE).
-define(FILE_MODULE, file).
@@ -493,22 +493,13 @@ read_write_file(Config) when is_list(Config) ->
%% Try writing and reading back some term
SomeTerm = {"This term",{will,be},[written,$t,$o],1,file,[]},
- ok = ?FILE_MODULE:write_file(Name,term_to_binary(SomeTerm)),
- {ok,Bin1} = ?FILE_MODULE:read_file(Name),
- SomeTerm = binary_to_term(Bin1),
+ Bin1 = term_to_binary(SomeTerm),
+ ok = do_read_write_file(Name, Bin1),
%% Try a "null" term
NullTerm = [],
- ok = ?FILE_MODULE:write_file(Name,term_to_binary(NullTerm)),
- {ok,Bin2} = ?FILE_MODULE:read_file(Name),
- NullTerm = binary_to_term(Bin2),
-
- %% Try some "complicated" types
- BigNum = 123456789012345678901234567890,
- ComplTerm = {self(),make_ref(),BigNum,3.14159},
- ok = ?FILE_MODULE:write_file(Name,term_to_binary(ComplTerm)),
- {ok,Bin3} = ?FILE_MODULE:read_file(Name),
- ComplTerm = binary_to_term(Bin3),
+ Bin2 = term_to_binary(NullTerm),
+ ok = do_read_write_file(Name, Bin2),
%% Try reading a nonexistent file
Name2 = filename:join(RootDir,
@@ -519,25 +510,42 @@ read_write_file(Config) when is_list(Config) ->
{error, enoent} = ?FILE_MODULE:read_file(''),
%% Try writing to a bad filename
- {error, enoent} =
- ?FILE_MODULE:write_file("",term_to_binary(NullTerm)),
+ {error, enoent} = do_read_write_file("", Bin2),
%% Try writing something else than a binary
- {error, badarg} = ?FILE_MODULE:write_file(Name,{1,2,3}),
- {error, badarg} = ?FILE_MODULE:write_file(Name,self()),
+ {error, badarg} = do_read_write_file(Name, {1,2,3}),
+ {error, badarg} = do_read_write_file(Name, self()),
%% Some non-term binaries
- ok = ?FILE_MODULE:write_file(Name,[]),
- {ok,Bin4} = ?FILE_MODULE:read_file(Name),
- 0 = byte_size(Bin4),
+ ok = do_read_write_file(Name, []),
- ok = ?FILE_MODULE:write_file(Name,[Bin1,[],[[Bin2]]]),
- {ok,Bin5} = ?FILE_MODULE:read_file(Name),
- {Bin1,Bin2} = split_binary(Bin5,byte_size(Bin1)),
+ %% Write some iolists
+ ok = do_read_write_file(Name, [Bin1,[],[[Bin2]]]),
+ ok = do_read_write_file(Name, ["string",<<"binary">>]),
+ ok = do_read_write_file(Name, "pure string"),
[] = flush(),
ok.
+do_read_write_file(Name, Data) ->
+ case ?FILE_MODULE:write_file(Name, Data) of
+ ok ->
+ BinData = iolist_to_binary(Data),
+ {ok,BinData} = ?FILE_MODULE:read_file(Name),
+
+ ok = ?FILE_MODULE:write_file(Name, Data, []),
+ {ok,BinData} = ?FILE_MODULE:read_file(Name),
+
+ ok = ?FILE_MODULE:write_file(Name, Data, [raw]),
+ {ok,BinData} = ?FILE_MODULE:read_file(Name),
+
+ ok;
+ {error,_}=Res ->
+ Res = ?FILE_MODULE:write_file(Name, Data, []),
+ Res = ?FILE_MODULE:write_file(Name, Data, [raw]),
+ Res
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -3730,7 +3738,7 @@ response_analysis(Module, Function, Arguments) ->
{Result, Comment}.
micro_ts() ->
- erlang:monotonic_time(micro_seconds).
+ erlang:monotonic_time(microsecond).
response_stat(init, Ts) ->
{0, 0, Ts, 0, 0};
diff --git a/lib/kernel/test/file_SUITE_data/realmen.html b/lib/kernel/test/file_SUITE_data/realmen.html
index c810a5d088..92e13f23b8 100644
--- a/lib/kernel/test/file_SUITE_data/realmen.html
+++ b/lib/kernel/test/file_SUITE_data/realmen.html
@@ -237,7 +237,7 @@ destroy most of the interesting uses for EQUIVALENCE, and make it
impossible to modify the operating system code with negative
subscripts. Worst of all, bounds checking is inefficient.
-<LI> Source code maintainance systems. A Real Programmer keeps his
+<LI> Source code maintenance systems. A Real Programmer keeps his
code locked up in a card file, because it implies that its owner
cannot leave his important programs unguarded [5].
@@ -396,7 +396,7 @@ double stuff Oreos for special occasions.
<LI> Underneath the Oreos is a flow-charting template, left there by
the previous occupant of the office. (Real Programmers write programs,
-not documentation. Leave that to the maintainence people.)
+not documentation. Leave that to the maintenance people.)
</UL> <P>
diff --git a/lib/kernel/test/file_name_SUITE.erl b/lib/kernel/test/file_name_SUITE.erl
index 10b6b105d0..899102c908 100644
--- a/lib/kernel/test/file_name_SUITE.erl
+++ b/lib/kernel/test/file_name_SUITE.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -383,7 +383,7 @@ check_icky(Mod) ->
ok
end,
- _ = make_icky_dir(Mod, treat_icky(<<"åäö_dir">>)),
+ _ = make_icky_dir(Mod, treat_icky(<<"åäö_dir"/utf8>>)),
if
UniMode and (OS =/= win32) ->
{error,enoent} = Mod:set_cwd("åäö_dir");
diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl
index f836b2aa94..620ab235a0 100644
--- a/lib/kernel/test/gen_sctp_SUITE.erl
+++ b/lib/kernel/test/gen_sctp_SUITE.erl
@@ -117,7 +117,11 @@ xfer_min(Config) when is_list(Config) ->
Stream = 0,
Data = <<"The quick brown fox jumps over a lazy dog 0123456789">>,
Loopback = {127,0,0,1},
+ StatOpts =
+ [recv_avg,recv_cnt,recv_max,recv_oct,
+ send_avg,send_cnt,send_max,send_oct],
{ok,Sb} = gen_sctp:open([{type,seqpacket}]),
+ {ok,SbStat1} = inet:getstat(Sb, StatOpts),
{ok,Pb} = inet:port(Sb),
ok = gen_sctp:listen(Sb, true),
@@ -212,6 +216,8 @@ xfer_min(Config) when is_list(Config) ->
assoc_id=SbAssocId}} =
recv_event(log_ok(gen_sctp:recv(Sb, infinity))),
ok = gen_sctp:close(Sa),
+ {ok,SbStat2} = inet:getstat(Sb, StatOpts),
+ [] = filter_stat_eq(SbStat1, SbStat2),
ok = gen_sctp:close(Sb),
receive
@@ -220,6 +226,18 @@ xfer_min(Config) when is_list(Config) ->
end,
ok.
+filter_stat_eq([], []) ->
+ [];
+filter_stat_eq([{Tag,Val1}=Stat|SbStat1], [{Tag,Val2}|SbStat2]) ->
+ if
+ Val1 == Val2 ->
+ [Stat|filter_stat_eq(SbStat1, SbStat2)];
+ true ->
+ filter_stat_eq(SbStat1, SbStat2)
+ end.
+
+
+
%% Minimal data transfer in active mode.
xfer_active(Config) when is_list(Config) ->
Timeout = 2000,
@@ -383,26 +401,28 @@ def_sndrcvinfo(Config) when is_list(Config) ->
assoc_id=S2AssocId} = S2AssocChange =
log_ok(gen_sctp:connect(S2, Loopback, P1, [])),
?LOGVAR(S2AssocChange),
- case recv_event(log_ok(gen_sctp:recv(S1))) of
- {Loopback,P2,
- #sctp_assoc_change{
- state=comm_up,
- error=0,
- assoc_id=S1AssocId}} ->
- ?LOGVAR(S1AssocId);
- {Loopback,P2,
- #sctp_paddr_change{
- state=addr_confirmed,
- error=0,
- assoc_id=S1AssocId}} ->
- ?LOGVAR(S1AssocId),
+ S1AssocId =
+ case recv_event(log_ok(gen_sctp:recv(S1))) of
{Loopback,P2,
#sctp_assoc_change{
state=comm_up,
error=0,
- assoc_id=S1AssocId}} =
- recv_event(log_ok(gen_sctp:recv(S1)))
- end,
+ assoc_id=AssocId}} ->
+ AssocId;
+ {Loopback,P2,
+ #sctp_paddr_change{
+ state=addr_confirmed,
+ error=0,
+ assoc_id=AssocId}} ->
+ {Loopback,P2,
+ #sctp_assoc_change{
+ state=comm_up,
+ error=0,
+ assoc_id=AssocId}} =
+ recv_event(log_ok(gen_sctp:recv(S1))),
+ AssocId
+ end,
+ ?LOGVAR(S1AssocId),
#sctp_sndrcvinfo{
ppid=17, context=0, timetolive=0} = %, assoc_id=S1AssocId} =
@@ -1055,6 +1075,7 @@ peeloff(Config, SockOpts) when is_list(Config) ->
Addr = {127,0,0,1},
Stream = 0,
Timeout = 333,
+ StartTime = timestamp(),
S1 = socket_open([{ifaddr,Addr}|SockOpts], Timeout),
?LOGVAR(S1),
P1 = socket_call(S1, get_port),
@@ -1077,7 +1098,7 @@ peeloff(Config, SockOpts) when is_list(Config) ->
state=comm_up,
assoc_id=AssocId2}}} -> AssocId2
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
?LOGVAR(S2Ai),
S1Ai =
@@ -1087,7 +1108,7 @@ peeloff(Config, SockOpts) when is_list(Config) ->
state=comm_up,
assoc_id=AssocId1}}} -> AssocId1
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
?LOGVAR(S1Ai),
%%
@@ -1095,13 +1116,13 @@ peeloff(Config, SockOpts) when is_list(Config) ->
receive
{S1,{Addr,P2,S1Ai,Stream,<<"Number one">>}} -> ok
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
socket_call(S2, {send,Socket1,S1Ai,Stream,<<"Number two">>}),
receive
{S2,{Addr,P1,S2Ai,Stream,<<"Number two">>}} -> ok
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
%%
S3 = socket_peeloff(Socket1, S1Ai, SockOpts, Timeout),
@@ -1120,31 +1141,31 @@ peeloff(Config, SockOpts) when is_list(Config) ->
receive
{S2,{Addr,P3,S2Ai,Stream,<<"Number three">>}} -> ok
after Timeout ->
- socket_bailout([S1,S2,S3])
+ socket_bailout([S1,S2,S3], StartTime)
end,
socket_call(S3, {send,Socket2,S2Ai,Stream,<<"Number four">>}),
receive
{S3,{Addr,P2,S3Ai,Stream,<<"Number four">>}} -> ok
after Timeout ->
- socket_bailout([S1,S2,S3])
+ socket_bailout([S1,S2,S3], StartTime)
end,
%%
inet:i(sctp),
- socket_close_verbose(S1),
- socket_close_verbose(S2),
+ socket_close_verbose(S1, StartTime),
+ socket_close_verbose(S2, StartTime),
receive
{S3,{Addr,P2,#sctp_shutdown_event{assoc_id=S3Ai_X}}} ->
match_unless_solaris(S3Ai, S3Ai_X)
after Timeout ->
- socket_bailout([S3])
+ socket_bailout([S3], StartTime)
end,
receive
{S3,{Addr,P2,#sctp_assoc_change{state=shutdown_comp,
assoc_id=S3Ai}}} -> ok
after Timeout ->
- socket_bailout([S3])
+ socket_bailout([S3], StartTime)
end,
- socket_close_verbose(S3),
+ socket_close_verbose(S3, StartTime),
[] = flush(),
ok.
@@ -1156,6 +1177,7 @@ buffers(Config) when is_list(Config) ->
Addr = {127,0,0,1},
Stream = 1,
Timeout = 3333,
+ StartTime = timestamp(),
S1 = socket_open([{ip,Addr}], Timeout),
?LOGVAR(S1),
P1 = socket_call(S1, get_port),
@@ -1174,7 +1196,7 @@ buffers(Config) when is_list(Config) ->
state=comm_up,
assoc_id=AssocId2}}} -> AssocId2
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
S1Ai =
receive
@@ -1183,7 +1205,7 @@ buffers(Config) when is_list(Config) ->
state=comm_up,
assoc_id=AssocId1}}} -> AssocId1
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
%%
socket_call(S1, {setopts,[{recbuf,Limit}]}),
@@ -1197,22 +1219,22 @@ buffers(Config) when is_list(Config) ->
receive
{S1,{Addr,P2,S1Ai,Stream,Data}} -> ok
after Timeout ->
- socket_bailout([S1,S2])
+ socket_bailout([S1,S2], StartTime)
end,
%%
- socket_close_verbose(S1),
+ socket_close_verbose(S1, StartTime),
receive
{S2,{Addr,P1,#sctp_shutdown_event{assoc_id=S2Ai}}} -> ok
after Timeout ->
- socket_bailout([S2])
+ socket_bailout([S2], StartTime)
end,
receive
{S2,{Addr,P1,#sctp_assoc_change{state=shutdown_comp,
assoc_id=S2Ai}}} -> ok
after Timeout ->
- socket_bailout([S2])
+ socket_bailout([S2], StartTime)
end,
- socket_close_verbose(S2),
+ socket_close_verbose(S2, StartTime),
[] = flush(),
ok.
@@ -1521,8 +1543,8 @@ socket_peeloff(Socket, AssocId, SocketOpts, Timeout) ->
end,
s_start(Starter, Timeout).
-socket_close_verbose(S) ->
- History = socket_history(socket_close(S)),
+socket_close_verbose(S, StartTime) ->
+ History = socket_history(socket_close(S), StartTime),
io:format("socket_close ~p:~n ~p.~n", [S,History]),
History.
@@ -1535,19 +1557,19 @@ socket_call(S, Request) ->
%% socket_get(S, Key) ->
%% s_req(S, {get,Key}).
-socket_bailout([S|Ss]) ->
- History = socket_history(socket_close(S)),
+socket_bailout([S|Ss], StartTime) ->
+ History = socket_history(socket_close(S), StartTime),
io:format("bailout ~p:~n ~p.~n", [S,History]),
- socket_bailout(Ss);
-socket_bailout([]) ->
+ socket_bailout(Ss, StartTime);
+socket_bailout([], _) ->
io:format("flush: ~p.~n", [flush()]),
ct:fail(socket_bailout).
-socket_history({State,Flush}) ->
+socket_history({State,Flush}, StartTime) ->
{lists:keysort(
2,
lists:flatten(
- [[{Key,Val} || Val <- Vals]
+ [[{Key,{TS-StartTime,Val}} || {TS,Val} <- Vals]
|| {Key,Vals} <- gb_trees:to_list(State)])),
Flush}.
@@ -1610,14 +1632,12 @@ s_loop(Socket, Timeout, Parent, Handler, State) ->
{Parent,Ref,exit} ->
ok = gen_sctp:close(Socket),
Key = exit,
- Val = {now(),Socket},
- NewState = gb_push(Key, Val, State),
+ NewState = gb_push(Key, Socket, State),
Parent ! {self(),Ref,{NewState,flush()}};
{Parent,Ref,{Msg}} ->
Result = Handler(Msg),
Key = req,
- Val = {now(),{Msg,Result}},
- NewState = gb_push(Key, Val, State),
+ NewState = gb_push(Key, {Msg,Result}, State),
Parent ! {self(),Ref,Result},
s_loop(Socket, Timeout, Parent, Handler, NewState);
%% {Parent,Ref,{get,Key}} ->
@@ -1627,16 +1647,15 @@ s_loop(Socket, Timeout, Parent, Handler, State) ->
{[#sctp_sndrcvinfo{stream=Stream,assoc_id=AssocId}=SRI],Data}}
when not is_tuple(Data) ->
case gb_get({assoc_change,AssocId}, State) of
- [{_,{Addr,Port,
- #sctp_assoc_change{
- state=comm_up,
- inbound_streams=Is}}}|_]
+ [{Addr,Port,
+ #sctp_assoc_change{
+ state=comm_up,
+ inbound_streams=Is}}|_]
when 0 =< Stream, Stream < Is-> ok;
[] -> ok
end,
Key = {msg,AssocId,Stream},
- Val = {now(),{Addr,Port,SRI,Data}},
- NewState = gb_push(Key, Val, State),
+ NewState = gb_push(Key, {Addr,Port,SRI,Data}, State),
Parent ! {self(),{Addr,Port,AssocId,Stream,Data}},
again(Socket),
s_loop(Socket, Timeout, Parent, Handler, NewState);
@@ -1647,13 +1666,12 @@ s_loop(Socket, Timeout, Parent, Handler, State) ->
[] -> ok
end,
Key = {assoc_change,AssocId},
- Val = {now(),{Addr,Port,SAC}},
case {gb_get(Key, State),St} of
{[],_} -> ok;
- {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_],_}
+ {[{Addr,Port,#sctp_assoc_change{state=comm_up}}|_],_}
when St =:= comm_lost; St =:= shutdown_comp -> ok
end,
- NewState = gb_push(Key, Val, State),
+ NewState = gb_push(Key, {Addr,Port,SAC}, State),
Parent ! {self(),{Addr,Port,SAC}},
again(Socket),
s_loop(Socket, Timeout, Parent, Handler, NewState);
@@ -1667,14 +1685,13 @@ 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,Port,#sctp_assoc_change{state=comm_up}}|_],_}
when St =:= addr_available;
St =:= addr_confirmed -> ok;
{[],addr_confirmed} -> ok
end,
Key = {paddr_change,AssocId},
- Val = {now(),{Addr,Port,SPC}},
- NewState = gb_push(Key, Val, State),
+ NewState = gb_push(Key, {Addr,Port,SPC}, State),
again(Socket),
s_loop(Socket, Timeout, Parent, Handler, NewState);
{sctp,Socket,Addr,Port,
@@ -1684,12 +1701,11 @@ s_loop(Socket, Timeout, Parent, Handler, State) ->
[] -> ok
end,
case gb_get({assoc_change,AssocId}, State) of
- [{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_] -> ok;
+ [{Addr,Port,#sctp_assoc_change{state=comm_up}}|_] -> ok;
[] -> ok
end,
Key = {shutdown_event,AssocId},
- Val = {now(),{Addr,Port}},
- NewState = gb_push(Key, Val, State),
+ NewState = gb_push(Key, {Addr,Port}, State),
Parent ! {self(), {Addr,Port,SSE}},
again(Socket),
s_loop(Socket, Timeout, Parent, Handler, NewState);
@@ -1707,11 +1723,12 @@ again(Socket) ->
end.
gb_push(Key, Val, GBT) ->
+ TS = timestamp(),
case gb_trees:lookup(Key, GBT) of
none ->
- gb_trees:insert(Key, [Val], GBT);
+ gb_trees:insert(Key, [{TS,Val}], GBT);
{value,V} ->
- gb_trees:update(Key, [Val|V], GBT)
+ gb_trees:update(Key, [{TS,Val}|V], GBT)
end.
gb_get(Key, GBT) ->
@@ -1719,7 +1736,7 @@ gb_get(Key, GBT) ->
none ->
[];
{value,V} ->
- V
+ [Val || {_TS,Val} <- V]
end.
match_unless_solaris(A, B) ->
@@ -1727,3 +1744,6 @@ match_unless_solaris(A, B) ->
{unix,sunos} -> B;
_ -> A = B
end.
+
+timestamp() ->
+ erlang:monotonic_time().
diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl
index 77ec89b4f4..12d22519ce 100644
--- a/lib/kernel/test/gen_tcp_api_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_api_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -38,7 +38,7 @@
t_local_basic/1, t_local_unbound/1, t_local_fdopen/1,
t_local_fdopen_listen/1, t_local_fdopen_listen_unbound/1,
t_local_fdopen_connect/1, t_local_fdopen_connect_unbound/1,
- t_local_abstract/1]).
+ t_local_abstract/1, t_accept_inet6_tclass/1]).
-export([getsockfd/0,closesockfd/1]).
@@ -50,6 +50,7 @@ all() ->
[{group, t_accept}, {group, t_connect}, {group, t_recv},
t_shutdown_write, t_shutdown_both, t_shutdown_error,
t_shutdown_async, t_fdopen, t_fdconnect, t_implicit_inet6,
+ t_accept_inet6_tclass,
{group, t_local}].
groups() ->
@@ -301,9 +302,9 @@ t_implicit_inet6(Config) when is_list(Config) ->
end.
t_implicit_inet6(Host, Addr) ->
- case gen_tcp:listen(0, [inet6]) of
+ Loopback = {0,0,0,0,0,0,0,1},
+ case gen_tcp:listen(0, [inet6, {ip,Loopback}]) of
{ok,S1} ->
- Loopback = {0,0,0,0,0,0,0,1},
io:format("~s ~p~n", ["::1",Loopback]),
implicit_inet6(S1, Loopback),
ok = gen_tcp:close(S1),
@@ -521,6 +522,24 @@ local_handshake(S, SAddr, C, CAddr) ->
SData = ok(gen_tcp:recv(C, length(SData))),
ok.
+t_accept_inet6_tclass(Config) when is_list(Config) ->
+ TClassOpt = {tclass,8#56 bsl 2}, % Expedited forwarding
+ Loopback = {0,0,0,0,0,0,0,1},
+ case gen_tcp:listen(0, [inet6, {ip, Loopback}, TClassOpt]) of
+ {ok,L} ->
+ LPort = ok(inet:port(L)),
+ Sa = ok(gen_tcp:connect(Loopback, LPort, [])),
+ Sb = ok(gen_tcp:accept(L)),
+ [TClassOpt] = ok(inet:getopts(Sb, [tclass])),
+ ok = gen_tcp:close(Sb),
+ ok = gen_tcp:close(Sa),
+ ok = gen_tcp:close(L),
+ ok;
+ {error,_} ->
+ {skip,"IPv6 TCLASS not supported"}
+ end.
+
+
%%% Utilities
%% Calls M:F/length(A), which should return a timeout error, and complete
diff --git a/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c b/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c
index 2990ddda41..b91dca61d4 100644
--- a/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c
+++ b/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c
@@ -17,7 +17,7 @@
*
* %CopyrightEnd%
*/
-#include "erl_nif.h"
+#include <erl_nif.h>
#include <stdio.h>
#include <string.h>
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index 6b64c83fc2..929f66d400 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -1914,7 +1914,7 @@ so_priority(Config) when is_list(Config) ->
%% Accept test utilities (suites are below)
millis() ->
- erlang:monotonic_time(milli_seconds).
+ erlang:monotonic_time(millisecond).
collect_accepts(0,_) -> [];
collect_accepts(N,Tmo) ->
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index 1029d7ef0a..aa616d43d6 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -717,9 +717,9 @@ implicit_inet6(Config) when is_list(Config) ->
implicit_inet6(Host, Addr) ->
Active = {active,false},
- case gen_udp:open(0, [inet6,Active]) of
+ Loopback = {0,0,0,0,0,0,0,1},
+ case gen_udp:open(0, [inet6,Active,{ip, Loopback}]) of
{ok,S1} ->
- Loopback = {0,0,0,0,0,0,0,1},
io:format("~s ~p~n", ["::1",Loopback]),
implicit_inet6(S1, Active, Loopback),
ok = gen_udp:close(S1),
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index f60c13d2e3..3b502be8b8 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -40,7 +40,8 @@
lookup_bad_search_option/1,
getif/1,
getif_ifr_name_overflow/1,getservbyname_overflow/1, getifaddrs/1,
- parse_strict_address/1, simple_netns/1, simple_netns_open/1]).
+ parse_strict_address/1, simple_netns/1, simple_netns_open/1,
+ simple_bind_to_device/1, simple_bind_to_device_open/1]).
-export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1, parse_address/1,
kill_gethost/0, parallell_gethost/0, test_netns/0]).
@@ -58,7 +59,8 @@ all() ->
gethostnative_debug_level, gethostnative_soft_restart,
lookup_bad_search_option,
getif, getif_ifr_name_overflow, getservbyname_overflow,
- getifaddrs, parse_strict_address, simple_netns, simple_netns_open].
+ getifaddrs, parse_strict_address, simple_netns, simple_netns_open,
+ simple_bind_to_device, simple_bind_to_device_open].
groups() ->
[{parse, [], [parse_hosts, parse_address]}].
@@ -445,91 +447,125 @@ parse_hosts(Config) when is_list(Config) ->
inet_parse:resolv(ResolvErr1).
parse_address(Config) when is_list(Config) ->
- V4Strict =
+ V4Reversable =
[{{0,0,0,0},"0.0.0.0"},
- {{1,2,3,4},"1.2.3.4"},
+ {{1,2,3,4},"1.2.3.4"},
{{253,252,251,250},"253.252.251.250"},
{{1,2,255,254},"1.2.255.254"}],
- V6Strict =
+ V6Reversable =
[{{0,0,0,0,0,0,0,0},"::"},
+ {{0,0,0,0,0,0,0,1},"::1"},
+ {{0,0,0,0,0,0,0,2},"::0.0.0.2"},
{{15,0,0,0,0,0,0,2},"f::2"},
- {{15,16#f11,0,0,0,0,256,2},"f:f11::0100:2"},
- {{0,0,0,0,0,0,0,16#17},"::17"},
- {{16#700,0,0,0,0,0,0,0},"0700::"},
- {{0,0,0,0,0,0,2,1},"::2:1"},
+ {{15,16#f11,0,0,0,0,256,2},"f:f11::100:2"},
+ {{16#700,0,0,0,0,0,0,0},"700::"},
+ {{0,0,0,0,0,0,2,1},"::0.2.0.1"},
{{0,0,0,0,0,3,2,1},"::3:2:1"},
{{0,0,0,0,4,3,2,1},"::4:3:2:1"},
{{0,0,0,5,4,3,2,1},"::5:4:3:2:1"},
{{0,0,6,5,4,3,2,1},"::6:5:4:3:2:1"},
- {{0,7,6,5,4,3,2,1},"::7:6:5:4:3:2:1"},
+ {{0,7,6,5,4,3,2,1},"0:7:6:5:4:3:2:1"},
{{7,0,0,0,0,0,0,0},"7::"},
{{7,6,0,0,0,0,0,0},"7:6::"},
{{7,6,5,0,0,0,0,0},"7:6:5::"},
{{7,6,5,4,0,0,0,0},"7:6:5:4::"},
{{7,6,5,4,3,0,0,0},"7:6:5:4:3::"},
{{7,6,5,4,3,2,0,0},"7:6:5:4:3:2::"},
- {{7,6,5,4,3,2,1,0},"7:6:5:4:3:2:1::"},
+ {{7,6,5,4,3,2,1,0},"7:6:5:4:3:2:1:0"},
+ {{0,0,6,5,4,3,0,0},"::6:5:4:3:0:0"},
+ {{0,0,6,5,4,0,0,0},"0:0:6:5:4::"},
+ {{8,0,0,5,4,0,0,1},"8::5:4:0:0:1"},
+ {{8,0,0,5,0,0,0,1},"8:0:0:5::1"},
+ {{0,7,6,5,4,3,2,0},"0:7:6:5:4:3:2:0"},
+ {{0,0,6,5,4,3,0,0},"::6:5:4:3:0:0"},
+ {{0,0,0,5,4,0,0,0},"::5:4:0:0:0"},
+ {{0,0,0,0,4,0,0,0},"::4:0:0:0"},
+ {{0,0,0,5,0,0,0,0},"0:0:0:5::"},
{{16#c11,16#c22,16#5c33,16#c440,16#55c0,16#c66c,16#77,16#88},
- "c11:0c22:5c33:c440:55c0:c66c:77:0088"},
+ "c11:c22:5c33:c440:55c0:c66c:77:88"},
+ {{0,16#c22,16#5c33,16#c440,16#55c0,16#c66c,16#77,16#88},
+ "0:c22:5c33:c440:55c0:c66c:77:88"},
{{16#c11,0,16#5c33,16#c440,16#55c0,16#c66c,16#77,16#88},
- "c11::5c33:c440:55c0:c66c:77:0088"},
+ "c11:0:5c33:c440:55c0:c66c:77:88"},
{{16#c11,16#c22,0,16#c440,16#55c0,16#c66c,16#77,16#88},
- "c11:0c22::c440:55c0:c66c:77:0088"},
+ "c11:c22:0:c440:55c0:c66c:77:88"},
{{16#c11,16#c22,16#5c33,0,16#55c0,16#c66c,16#77,16#88},
- "c11:0c22:5c33::55c0:c66c:77:0088"},
+ "c11:c22:5c33:0:55c0:c66c:77:88"},
{{16#c11,16#c22,16#5c33,16#c440,0,16#c66c,16#77,16#88},
- "c11:0c22:5c33:c440::c66c:77:0088"},
+ "c11:c22:5c33:c440:0:c66c:77:88"},
{{16#c11,16#c22,16#5c33,16#c440,16#55c0,0,16#77,16#88},
- "c11:0c22:5c33:c440:55c0::77:0088"},
+ "c11:c22:5c33:c440:55c0:0:77:88"},
{{16#c11,16#c22,16#5c33,16#c440,16#55c0,16#c66c,0,16#88},
- "c11:0c22:5c33:c440:55c0:c66c::0088"},
+ "c11:c22:5c33:c440:55c0:c66c:0:88"},
+ {{16#c11,16#c22,16#5c33,16#c440,16#55c0,16#c66c,16#77,0},
+ "c11:c22:5c33:c440:55c0:c66c:77:0"},
+ {{0,0,16#5c33,16#c440,16#55c0,16#c66c,16#77,16#88},
+ "::5c33:c440:55c0:c66c:77:88"},
{{16#c11,0,0,16#c440,16#55c0,16#c66c,16#77,16#88},
- "c11::c440:55c0:c66c:77:0088"},
+ "c11::c440:55c0:c66c:77:88"},
{{16#c11,16#c22,0,0,16#55c0,16#c66c,16#77,16#88},
- "c11:0c22::55c0:c66c:77:0088"},
+ "c11:c22::55c0:c66c:77:88"},
{{16#c11,16#c22,16#5c33,0,0,16#c66c,16#77,16#88},
- "c11:0c22:5c33::c66c:77:0088"},
+ "c11:c22:5c33::c66c:77:88"},
{{16#c11,16#c22,16#5c33,16#c440,0,0,16#77,16#88},
- "c11:0c22:5c33:c440::77:0088"},
+ "c11:c22:5c33:c440::77:88"},
{{16#c11,16#c22,16#5c33,16#c440,16#55c0,0,0,16#88},
- "c11:0c22:5c33:c440:55c0::0088"},
+ "c11:c22:5c33:c440:55c0::88"},
+ {{16#c11,16#c22,16#5c33,16#c440,16#55c0,16#c66c,0,0},
+ "c11:c22:5c33:c440:55c0:c66c::"},
+ {{0,0,0,16#c440,16#55c0,16#c66c,16#77,16#88},
+ "::c440:55c0:c66c:77:88"},
{{16#c11,0,0,0,16#55c0,16#c66c,16#77,16#88},
- "c11::55c0:c66c:77:0088"},
+ "c11::55c0:c66c:77:88"},
{{16#c11,16#c22,0,0,0,16#c66c,16#77,16#88},
- "c11:0c22::c66c:77:0088"},
+ "c11:c22::c66c:77:88"},
{{16#c11,16#c22,16#5c33,0,0,0,16#77,16#88},
- "c11:0c22:5c33::77:0088"},
+ "c11:c22:5c33::77:88"},
{{16#c11,16#c22,16#5c33,16#c440,0,0,0,16#88},
- "c11:0c22:5c33:c440::0088"},
+ "c11:c22:5c33:c440::88"},
+ {{16#c11,16#c22,16#5c33,16#c440,16#55c0,0,0,0},
+ "c11:c22:5c33:c440:55c0::"},
+ {{0,0,0,0,16#55c0,16#c66c,16#77,16#88},
+ "::55c0:c66c:77:88"},
{{16#c11,0,0,0,0,16#c66c,16#77,16#88},
- "c11::c66c:77:0088"},
+ "c11::c66c:77:88"},
{{16#c11,16#c22,0,0,0,0,16#77,16#88},
- "c11:0c22::77:0088"},
+ "c11:c22::77:88"},
{{16#c11,16#c22,16#5c33,0,0,0,0,16#88},
- "c11:0c22:5c33::0088"},
+ "c11:c22:5c33::88"},
+ {{16#c11,16#c22,16#5c33,16#c440,0,0,0,0},
+ "c11:c22:5c33:c440::"},
+ {{0,0,0,0,0,16#c66c,16#77,16#88},
+ "::c66c:77:88"},
{{16#c11,0,0,0,0,0,16#77,16#88},
- "c11::77:0088"},
+ "c11::77:88"},
{{16#c11,16#c22,0,0,0,0,0,16#88},
- "c11:0c22::0088"},
- {{0,0,0,0,0,65535,258,65534},"::FFFF:1.2.255.254"},
+ "c11:c22::88"},
+ {{16#c11,16#c22,16#5c33,0,0,0,0,0},
+ "c11:c22:5c33::"},
+ {{0,0,0,0,0,65535,258,65534},"::ffff:1.2.255.254"},
+ {{16#fe80,12345,0,0,0,0,0,16#12},"fe80::12%012345"},
{{16#ffff,16#ffff,16#ffff,16#ffff,16#ffff,16#ffff,16#ffff,16#ffff},
"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"}
- |[{{D2,0,0,0,0,P,(D1 bsl 8) bor D2,(D3 bsl 8) bor D4},
- erlang:integer_to_list(D2, 16)++"::"++Q++S}
- || {{D1,D2,D3,D4},S} <- V4Strict,
- {P,Q} <- [{0,""},{16#17,"17:"},{16#ff0,"0ff0:"}]]],
+ |[{list_to_tuple(P++[(D1 bsl 8) bor D2,(D3 bsl 8) bor D4]),
+ Q++S}
+ || {{D1,D2,D3,D4},S} <-
+ tl(V4Reversable),
+ {P,Q} <-
+ [{[0,0,0,0,0,16#ffff],"::ffff:"},
+ {[0,0,0,0,0,0],"::"}]]],
V4Sloppy =
[{{10,1,16#98,16#76},"10.0x019876"},
{{8#12,1,8#130,8#321},"012.01.054321"},
- {{255,255,255,255},"255.255.255.0377"},
- {{255,255,255,255},"0Xff.000000000377.0x0000ff.255"},
- {{255,255,255,255},"255.255.65535"},
- {{255,255,255,255},"255.0xFF.0177777"},
- {{255,255,255,255},"255.16777215"},
- {{255,255,255,255},"00377.0XFFFFFF"},
- {{255,255,255,255},"4294967295"},
- {{255,255,255,255},"0xffffffff"},
- {{255,255,255,255},"00000000000037777777777"},
+ {{252,253,254,255},"252.253.254.0377"},
+ {{252,253,254,255},"0Xfc.000000000375.0x0000fe.255"},
+ {{252,253,254,255},"252.253.65279"},
+ {{252,253,254,255},"252.0xFD.0177377"},
+ {{252,253,254,255},"252.16645887"},
+ {{252,253,254,255},"00374.0XFDFEFF"},
+ {{252,253,254,255},"4244504319"},
+ {{252,253,254,255},"0xfcfdfeff"},
+ {{252,253,254,255},"00000000000037477377377"},
{{16#12,16#34,16#56,16#78},"0x12345678"},
{{16#12,16#34,16#56,16#78},"0x12.0x345678"},
{{16#12,16#34,16#56,16#78},"0x12.0X34.0x5678"},
@@ -541,8 +577,14 @@ parse_address(Config) when is_list(Config) ->
{{0,0,0,0},"0.00.0.0"},
{{0,0,0,0},"0.0.000000000000.0"}],
V6Sloppy =
- [{{0,0,0,0,0,65535,(D1 bsl 8) bor D2,(D3 bsl 8) bor D4},S}
- || {{D1,D2,D3,D4},S} <- V4Strict++V4Sloppy],
+ [{{16#a,16#b,16#c,16#0,16#0,16#d,16#e,16#f},"A:B:C::d:e:f"},
+ {{16#fe80,0,0,0,0,0,0,16#12},"fe80::12%XXXXXXX"}]
+ ++
+ [{{P,0,0,0,0,D2,(D1 bsl 8) bor D2,(D3 bsl 8) bor D4},
+ Q++erlang:integer_to_list(D2, 16)++":"++S}
+ || {{D1,D2,D3,D4},S} <- V4Reversable,
+ {P,Q} <-
+ [{16#2001,"2001::"},{16#177,"177::"},{16#ff0,"Ff0::"}]],
V4Err =
["0.256.0.1",
"1.2.3.4.5",
@@ -586,28 +628,36 @@ parse_address(Config) when is_list(Config) ->
"fec0::fFfF:127.0.0.1."],
t_parse_address
(parse_ipv6_address,
- V6Strict++V6Sloppy++V6Err++V4Err),
+ false,
+ V6Reversable++V6Sloppy++V6Err++V4Err),
t_parse_address
(parse_ipv6strict_address,
- V6Strict++V6Err++V4Err++[S || {_,S} <- V6Sloppy]),
+ true,
+ V6Reversable++V6Err++V4Err),
t_parse_address
(parse_ipv4_address,
- V4Strict++V4Sloppy++V4Err++V6Err++[S || {_,S} <- V6Strict]),
+ false,
+ V4Reversable++V4Sloppy++V4Err++V6Err++[S || {_,S} <- V6Reversable]),
t_parse_address
(parse_ipv4strict_address,
- V4Strict++V4Err++V6Err++[S || {_,S} <- V4Sloppy++V6Strict]).
+ true,
+ V4Reversable++V4Err++V6Err++[S || {_,S} <- V4Sloppy++V6Reversable]).
-t_parse_address(Func, []) ->
+t_parse_address(Func, _Reversable, []) ->
io:format("~p done.~n", [Func]),
ok;
-t_parse_address(Func, [{Addr,String}|L]) ->
+t_parse_address(Func, Reversable, [{Addr,String}|L]) ->
io:format("~p = ~p.~n", [Addr,String]),
{ok,Addr} = inet:Func(String),
- t_parse_address(Func, L);
-t_parse_address(Func, [String|L]) ->
+ case Reversable of
+ true ->String = inet:ntoa(Addr);
+ false -> ok
+ end,
+ t_parse_address(Func, Reversable, L);
+t_parse_address(Func, Reversable, [String|L]) ->
io:format("~p.~n", [String]),
{error,einval} = inet:Func(String),
- t_parse_address(Func, L).
+ t_parse_address(Func, Reversable, L).
parse_strict_address(Config) when is_list(Config) ->
{ok, {127,0,0,1}} =
@@ -1247,3 +1297,67 @@ cmd(CmdString) ->
io:put_chars(["# ",CmdString,io_lib:nl()]),
io:put_chars([os:cmd(CmdString++" ; echo ' =>' $?")]),
ok.
+
+-define(CAP_NET_RAW, 13). %% from /usr/include/linux/capability.h
+
+can_bind_to_device({unix, linux}, {Major, _, _})
+ when Major > 2 ->
+ Status = os:cmd("cat /proc/self/status | grep CapEff"),
+ [_, CapEffStr] = string:tokens(Status, [$\n, $\t]),
+ CapEff = list_to_integer(CapEffStr, 16),
+ if CapEff band (1 bsl ?CAP_NET_RAW) =/= 0 ->
+ ok;
+ true ->
+ {skip,"insufficient capabilities, CAP_NET_RAW not granted"}
+ end;
+can_bind_to_device(_OS, _Version) ->
+ {skip,"socket option bind_to_device not supported on this OS or version"}.
+
+simple_bind_to_device(Config) when is_list(Config) ->
+ case can_bind_to_device(os:type(), os:version()) of
+ ok ->
+ {ok,U} = gen_udp:open(0),
+ jog_bind_to_device_opt(U),
+ ok = gen_udp:close(U),
+ %%
+ {ok,L} = gen_tcp:listen(0, []),
+ jog_bind_to_device_opt(L),
+ ok = gen_tcp:close(L),
+ %%
+ case gen_sctp:open() of
+ {ok,S} ->
+ jog_bind_to_device_opt(S),
+ ok = gen_sctp:close(S);
+ {error,eprotonosupport} ->
+ ok
+ end;
+ Other ->
+ Other
+ end.
+
+%% Smoke test bind_to_device support.
+simple_bind_to_device_open(Config) when is_list(Config) ->
+ case can_bind_to_device(os:type(), os:version()) of
+ ok ->
+ {ok,U} = gen_udp:open(0, [binary,{bind_to_device,<<"lo">>},inet]),
+ ok = gen_udp:close(U),
+ {ok,T} = gen_tcp:listen(0, [binary,{bind_to_device,<<"lo">>},inet]),
+ ok = gen_tcp:close(T),
+
+ case gen_sctp:open(0, [binary,{bind_to_device,<<"lo">>},inet]) of
+ {ok,S} ->
+ ok = gen_sctp:close(S);
+ {error,eprotonosupport} ->
+ ok
+ end;
+ Other ->
+ Other
+ end.
+
+jog_bind_to_device_opt(S) ->
+ %% This is just jogging the option mechanics
+ ok = inet:setopts(S, [{bind_to_device,<<>>}]),
+ {ok,[{bind_to_device,<<>>}]} = inet:getopts(S, [bind_to_device]),
+ ok = inet:setopts(S, [{bind_to_device,<<"lo">>}]),
+ {ok,[{bind_to_device,<<"lo">>}]} = inet:getopts(S, [bind_to_device]),
+ ok.
diff --git a/lib/kernel/test/inet_sockopt_SUITE.erl b/lib/kernel/test/inet_sockopt_SUITE.erl
index 322b9f30fe..ada9c2689c 100644
--- a/lib/kernel/test/inet_sockopt_SUITE.erl
+++ b/lib/kernel/test/inet_sockopt_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -620,7 +620,7 @@ ipv6_v6only_close(Module, Socket) ->
%% Test using socket option ipv6_v6only for UDP.
use_ipv6_v6only_udp(Config) when is_list(Config) ->
- case gen_udp:open(0, [inet6,{ipv6_v6only,true}]) of
+ case gen_udp:open(0, [inet6,{ip,{0,0,0,0,0,0,0,1}}, {ipv6_v6only,true}]) of
{ok,S6} ->
case inet:getopts(S6, [ipv6_v6only]) of
{ok,[{ipv6_v6only,true}]} ->
diff --git a/lib/kernel/test/init_SUITE.erl b/lib/kernel/test/init_SUITE.erl
index 1370e23195..2b59eb2bfe 100644
--- a/lib/kernel/test/init_SUITE.erl
+++ b/lib/kernel/test/init_SUITE.erl
@@ -27,7 +27,8 @@
-export([get_arguments/1, get_argument/1, boot_var/1, restart/1,
many_restarts/0, many_restarts/1,
get_plain_arguments/1,
- reboot/1, stop_status/1, stop/1, get_status/1, script_id/1]).
+ reboot/1, stop_status/1, stop/1, get_status/1, script_id/1,
+ find_system_processes/0]).
-export([boot1/1, boot2/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -355,12 +356,16 @@ wait_for(N,Node,EHPid) ->
restart(Config) when is_list(Config) ->
Args = args(),
+ Pa = " -pa " ++ filename:dirname(code:which(?MODULE)),
+
%% Currently test_server:start_node cannot be used. The restarted
%% node immediately halts due to the implementation of
%% test_server:start_node.
- {ok, Node} = loose_node:start(init_test, Args, ?DEFAULT_TIMEOUT_SEC),
+ {ok, Node} = loose_node:start(init_test, Args ++ Pa, ?DEFAULT_TIMEOUT_SEC),
%% Ok, the node is up, now the real test test begins.
erlang:monitor_node(Node, true),
+ SysProcs0 = rpc:call(Node, ?MODULE, find_system_processes, []),
+ [InitPid, PurgerPid, LitCollectorPid, DirtyCodePid] = SysProcs0,
InitPid = rpc:call(Node, erlang, whereis, [init]),
PurgerPid = rpc:call(Node, erlang, whereis, [erts_code_purger]),
Procs = rpc:call(Node, erlang, processes, []),
@@ -375,6 +380,9 @@ restart(Config) when is_list(Config) ->
end,
ok = wait_restart(30, Node),
+ SysProcs1 = rpc:call(Node, ?MODULE, find_system_processes, []),
+ [InitPid1, PurgerPid1, LitCollectorPid1, DirtyCodePid1] = SysProcs1,
+
%% Still the same init process!
InitPid1 = rpc:call(Node, erlang, whereis, [init]),
InitP = pid_to_list(InitPid),
@@ -385,8 +393,24 @@ restart(Config) when is_list(Config) ->
PurgerP = pid_to_list(PurgerPid),
PurgerP = pid_to_list(PurgerPid1),
+ %% and same literal area collector process!
+ case LitCollectorPid of
+ undefined -> undefined = LitCollectorPid1;
+ _ ->
+ LitCollectorP = pid_to_list(LitCollectorPid),
+ LitCollectorP = pid_to_list(LitCollectorPid1)
+ end,
+
+ %% and same dirty process code checker process!
+ case DirtyCodePid of
+ undefined -> undefined = DirtyCodePid1;
+ _ ->
+ DirtyCodeP = pid_to_list(DirtyCodePid),
+ DirtyCodeP = pid_to_list(DirtyCodePid1)
+ end,
+
NewProcs0 = rpc:call(Node, erlang, processes, []),
- NewProcs = NewProcs0 -- [InitPid1, PurgerPid1],
+ NewProcs = NewProcs0 -- SysProcs1,
case check_processes(NewProcs, MaxPid) of
true ->
ok;
@@ -406,6 +430,37 @@ restart(Config) when is_list(Config) ->
loose_node:stop(Node),
ok.
+-record(sys_procs, {init,
+ code_purger,
+ literal_collector,
+ dirty_proc_checker}).
+
+find_system_processes() ->
+ find_system_procs(processes(), #sys_procs{}).
+
+find_system_procs([], SysProcs) ->
+ [SysProcs#sys_procs.init,
+ SysProcs#sys_procs.code_purger,
+ SysProcs#sys_procs.literal_collector,
+ SysProcs#sys_procs.dirty_proc_checker];
+find_system_procs([P|Ps], SysProcs) ->
+ case process_info(P, initial_call) of
+ {initial_call,{otp_ring0,start,2}} ->
+ undefined = SysProcs#sys_procs.init,
+ find_system_procs(Ps, SysProcs#sys_procs{init = P});
+ {initial_call,{erts_code_purger,start,0}} ->
+ undefined = SysProcs#sys_procs.code_purger,
+ find_system_procs(Ps, SysProcs#sys_procs{code_purger = P});
+ {initial_call,{erts_literal_area_collector,start,0}} ->
+ undefined = SysProcs#sys_procs.literal_collector,
+ find_system_procs(Ps, SysProcs#sys_procs{literal_collector = P});
+ {initial_call,{erts_dirty_process_code_checker,start,0}} ->
+ undefined = SysProcs#sys_procs.dirty_proc_checker,
+ find_system_procs(Ps, SysProcs#sys_procs{dirty_proc_checker = P});
+ _ ->
+ find_system_procs(Ps, SysProcs)
+ end.
+
wait_restart(0, _Node) ->
ct:fail(not_restarted);
wait_restart(N, Node) ->
diff --git a/lib/kernel/test/interactive_shell_SUITE.erl b/lib/kernel/test/interactive_shell_SUITE.erl
index fc3706ba1e..298a364a91 100644
--- a/lib/kernel/test/interactive_shell_SUITE.erl
+++ b/lib/kernel/test/interactive_shell_SUITE.erl
@@ -711,7 +711,7 @@ toerl_loop(Port,Acc) ->
end.
millistamp() ->
- erlang:monotonic_time(milli_seconds).
+ erlang:monotonic_time(millisecond).
get_data_within(Port, X, Acc) when X =< 0 ->
?dbg({get_data_within, X, Acc, ?LINE}),
diff --git a/lib/kernel/test/multi_load_SUITE.erl b/lib/kernel/test/multi_load_SUITE.erl
index 369e25ac64..f3258ea520 100644
--- a/lib/kernel/test/multi_load_SUITE.erl
+++ b/lib/kernel/test/multi_load_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -144,14 +144,14 @@ prep_magic([H|T]) ->
prep_magic(Tuple) when is_tuple(Tuple) ->
L = prep_magic(tuple_to_list(Tuple)),
list_to_tuple(L);
-prep_magic(Bin) when is_binary(Bin) ->
- try erlang:has_prepared_code_on_load(Bin) of
+prep_magic(Ref) when is_reference(Ref) ->
+ try erlang:has_prepared_code_on_load(Ref) of
false ->
- %% Create a different kind of magic binary.
+ %% Create a different kind of magic ref.
ets:match_spec_compile([{'_',[true],['$_']}])
catch
_:_ ->
- Bin
+ Ref
end;
prep_magic(Other) ->
Other.
diff --git a/lib/kernel/test/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl
index 2a1e5016ec..53a9e168ef 100644
--- a/lib/kernel/test/os_SUITE.erl
+++ b/lib/kernel/test/os_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,7 +24,8 @@
init_per_testcase/2,end_per_testcase/2]).
-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,
- large_output_command/1, perf_counter_api/1]).
+ large_output_command/1, background_command/0, background_command/1,
+ message_leak/1, close_stdin/0, close_stdin/1, perf_counter_api/1]).
-include_lib("common_test/include/ct.hrl").
@@ -35,7 +36,8 @@ suite() ->
all() ->
[space_in_cwd, quoting, cmd_unicode, space_in_name, bad_command,
find_executable, unix_comment_in_command, deep_list_command,
- large_output_command, perf_counter_api].
+ large_output_command, background_command, message_leak,
+ close_stdin, perf_counter_api].
groups() ->
[].
@@ -52,6 +54,14 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+init_per_testcase(TC, Config)
+ when TC =:= background_command; TC =:= close_stdin ->
+ case os:type() of
+ {win32, _} ->
+ {skip,"Should not work on windows"};
+ _ ->
+ Config
+ end;
init_per_testcase(_TC,Config) ->
Config.
@@ -261,44 +271,86 @@ deep_list_command(Config) when is_list(Config) ->
%% FYI: [$e, $c, "ho"] =:= io_lib:format("ec~s", ["ho"])
ok.
-%% Test to take sure that the correct data is
+%% Test to make sure that the correct data is
%% received when doing large commands.
large_output_command(Config) when is_list(Config) ->
%% Maximum allowed on windows is 8192, so we test well below that
AAA = lists:duplicate(7000, $a),
comp(AAA,os:cmd("echo " ++ AAA)).
+%% Test that it is possible on unix to start a background task using os:cmd.
+background_command() ->
+ [{timetrap, {seconds, 5}}].
+background_command(_Config) ->
+ %% This testcase fails when the os:cmd takes
+ %% longer then the 5 second timeout
+ os:cmd("sleep 10&").
+
+%% Test that message does not leak to the calling process
+message_leak(_Config) ->
+ process_flag(trap_exit, true),
+
+ os:cmd("echo hello"),
+ [] = receive_all(),
+
+ case os:type() of
+ {unix, _} ->
+ os:cmd("for i in $(seq 1 100); do echo hello; done&"),
+ [] = receive_all();
+ _ ->
+ ok % Cannot background on non-unix
+ end,
+
+ process_flag(trap_exit, false).
+
+%% Test that os:cmd closes stdin of the program that is executed
+close_stdin() ->
+ [{timetrap, {seconds, 5}}].
+close_stdin(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ Fds = filename:join(DataDir, "my_fds"),
+
+ "-1" = os:cmd(Fds).
+
+
%% Test that the os:perf_counter api works as expected
perf_counter_api(_Config) ->
true = is_integer(os:perf_counter()),
true = os:perf_counter() > 0,
- T1 = os:perf_counter(),
+ Conv = fun(T1, T2) ->
+ erlang:convert_time_unit(T2 - T1, perf_counter, nanosecond)
+ end,
+
+ do_perf_counter_test([], Conv, 120000000, 80000000),
+ do_perf_counter_test([1000], fun(T1, T2) -> T2 - T1 end, 120, 80).
+
+do_perf_counter_test(CntArgs, Conv, Upper, Lower) ->
+ %% We run the test multiple times to try to get a somewhat
+ %% stable value... what does this test? That the
+ %% calculate_perf_counter_unit in sys_time.c works somewhat ok.
+ do_perf_counter_test(CntArgs, Conv, Upper, Lower, 10).
+
+do_perf_counter_test(CntArgs, _Conv, Upper, Lower, 0) ->
+ ct:fail("perf_counter_test ~p ~p ~p",[CntArgs, Upper, Lower]);
+do_perf_counter_test(CntArgs, Conv, Upper, Lower, Iters) ->
+
+ T1 = apply(os, perf_counter, CntArgs),
timer:sleep(100),
- T2 = os:perf_counter(),
- TsDiff = erlang:convert_time_unit(T2 - T1, perf_counter, nano_seconds),
- ct:pal("T1: ~p~n"
+ T2 = apply(os, perf_counter, CntArgs),
+ TsDiff = Conv(T1, T2),
+ ct:log("T1: ~p~n"
"T2: ~p~n"
"TsDiff: ~p~n",
[T1,T2,TsDiff]),
- %% We allow a 15% diff
- true = TsDiff < 115000000,
- true = TsDiff > 85000000,
-
- T1Ms = os:perf_counter(1000),
- timer:sleep(100),
- T2Ms = os:perf_counter(1000),
- MsDiff = T2Ms - T1Ms,
- ct:pal("T1Ms: ~p~n"
- "T2Ms: ~p~n"
- "MsDiff: ~p~n",
- [T1Ms,T2Ms,MsDiff]),
-
- %% We allow a 15% diff
- true = MsDiff < 115,
- true = MsDiff > 85.
+ if
+ TsDiff < Upper, TsDiff > Lower ->
+ ok;
+ true ->
+ do_perf_counter_test(CntArgs, Conv, Upper, Lower, Iters-1)
+ end.
%% Util functions
diff --git a/lib/kernel/test/os_SUITE_data/Makefile.src b/lib/kernel/test/os_SUITE_data/Makefile.src
index 912d0cbcb1..f83f781411 100644
--- a/lib/kernel/test/os_SUITE_data/Makefile.src
+++ b/lib/kernel/test/os_SUITE_data/Makefile.src
@@ -3,7 +3,7 @@ LD = @LD@
CFLAGS = @CFLAGS@ -I@erl_include@ @DEFS@
CROSSLDFLAGS = @CROSSLDFLAGS@
-PROGS = my_echo@exe@
+PROGS = my_echo@exe@ my_fds@exe@
all: $(PROGS)
@@ -12,3 +12,9 @@ my_echo@exe@: my_echo@obj@
my_echo@obj@: my_echo.c
$(CC) -c -o my_echo@obj@ $(CFLAGS) my_echo.c
+
+my_fds@exe@: my_fds@obj@
+ $(LD) $(CROSSLDFLAGS) -o my_fds my_fds@obj@ @LIBS@
+
+my_fds@obj@: my_fds.c
+ $(CC) -c -o my_fds@obj@ $(CFLAGS) my_fds.c
diff --git a/lib/kernel/test/os_SUITE_data/my_fds.c b/lib/kernel/test/os_SUITE_data/my_fds.c
new file mode 100644
index 0000000000..704a4d1e1d
--- /dev/null
+++ b/lib/kernel/test/os_SUITE_data/my_fds.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int
+main(int argc, char** argv)
+{
+ char buff[1];
+ int res = read(stdin, buff, 1);
+ printf("%d", res);
+}
diff --git a/lib/kernel/test/pdict_SUITE.erl b/lib/kernel/test/pdict_SUITE.erl
index 638d99176e..d105952df9 100644
--- a/lib/kernel/test/pdict_SUITE.erl
+++ b/lib/kernel/test/pdict_SUITE.erl
@@ -32,10 +32,13 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
mixed/1,
+ literals/1,
simple/1, complicated/1, heavy/1, simple_all_keys/1, info/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
-export([other_process/2]).
+-export([put_do/2, get_do/1, erase_do/1]).
+
init_per_testcase(_Case, Config) ->
Config.
@@ -48,6 +51,7 @@ suite() ->
all() ->
[simple, complicated, heavy, simple_all_keys, info,
+ literals,
mixed].
groups() ->
@@ -418,3 +422,59 @@ do_mixed([GoalN | _]=Goals, CurrN, Array0, C, Rand0) ->
Array2 = array:resize(CurrN-1, Array1),
do_mixed(Goals, CurrN-1, Array2, C+1, Rand2)
end.
+
+%% Test hash precalculation of literal keys
+literals(_Config) ->
+ %% Put literal -> get variable
+ put(1742, "1742"),
+ "1742" = ?MODULE:get_do(1742),
+ "1742" = ?MODULE:erase_do(1742),
+
+ put(-1742, "-1742"),
+ "-1742" = ?MODULE:get_do(-1742),
+ "-1742" = ?MODULE:erase_do(-1742),
+
+ put([], "NIL"),
+ "NIL" = ?MODULE:get_do([]),
+ "NIL" = ?MODULE:erase_do([]),
+
+ put(<<"binary">>, "binary"),
+ "binary" = ?MODULE:get_do(<<"binary">>),
+ "binary" = ?MODULE:erase_do(<<"binary">>),
+
+ BigBin = <<"A large binary with a lot of bytes to make it go off heap as shared and reference counted">>,
+ put(BigBin, "bigbin"),
+ "bigbin" = ?MODULE:get_do(BigBin),
+ "bigbin" = ?MODULE:erase_do(BigBin),
+
+ %% Put variable -> get literal
+ ?MODULE:put_do(4217, "4217"),
+ "4217" = get(4217),
+ "4217" = erase(4217),
+
+ ?MODULE:put_do(-4217, "-4217"),
+ "-4217" = get(-4217),
+ "-4217" = erase(-4217),
+
+ ?MODULE:put_do([], "NIL"),
+ "NIL" = get([]),
+ "NIL" = erase([]),
+
+ ?MODULE:put_do(<<"bytes">>, "bytes"),
+ "bytes" = get(<<"bytes">>),
+ "bytes" = erase(<<"bytes">>),
+
+ ?MODULE:put_do(BigBin, "BigBin"),
+ "BigBin" = get(BigBin),
+ "BigBin" = erase(BigBin),
+
+ ok.
+
+put_do(K, V) ->
+ put(K, V).
+
+get_do(K) ->
+ get(K).
+
+erase_do(K) ->
+ erase(K).
diff --git a/lib/kernel/test/pg2_SUITE.erl b/lib/kernel/test/pg2_SUITE.erl
index fdc268cb5a..acecd34ead 100644
--- a/lib/kernel/test/pg2_SUITE.erl
+++ b/lib/kernel/test/pg2_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@
-export([
otp_7277/1, otp_8259/1, otp_8653/1,
- compat/1, basic/1]).
+ basic/1]).
-define(TESTCASE, testcase_name).
-define(testcase, proplists:get_value(?TESTCASE, Config)).
@@ -56,7 +56,7 @@ all() ->
groups() ->
[{tickets, [],
- [otp_7277, otp_8259, otp_8653, compat, basic]}].
+ [otp_7277, otp_8259, otp_8653, basic]}].
init_per_suite(Config) ->
Config.
@@ -218,29 +218,6 @@ loop() ->
exit(normal)
end.
-%% OTP-8259. Check that 'exchange' and 'del_member' work.
-compat(Config) when is_list(Config) ->
- case test_server:is_release_available("r13b") of
- true ->
- Pid = spawn(forever()),
- G = a,
- ok = pg2:create(G),
- ok = pg2:join(G, Pid),
- ok = pg2:join(G, Pid),
- {ok, A} = start_node_rel(r13, r13b, slave),
- pong = net_adm:ping(A),
- wait_for_ready_net(Config),
- {ok, _} = rpc:call(A, pg2, start, []),
- ?UNTIL([Pid,Pid] =:= rpc:call(A, pg2, get_members, [a])),
- true = exit(Pid, kill),
- ?UNTIL([] =:= pg2:get_members(a)),
- ?UNTIL([] =:= rpc:call(A, pg2, get_members, [a])),
- test_server:stop_node(A),
- ok;
- false ->
- {skipped, "No support for old node"}
- end.
-
%% OTP-8259. Some basic tests.
basic(Config) when is_list(Config) ->
_ = [pg2:delete(G) || G <- pg2:which_groups()],
diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl
index 8be94f1e57..2f4330c217 100644
--- a/lib/kernel/test/prim_file_SUITE.erl
+++ b/lib/kernel/test/prim_file_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,8 +19,8 @@
%%
-module(prim_file_SUITE).
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- read_write_file/1]).
+ init_per_group/2,end_per_group/2, init_per_testcase/2, end_per_testcase/2,
+ read_write_file/1, free_memory/0]).
-export([cur_dir_0a/1, cur_dir_0b/1,
cur_dir_1a/1, cur_dir_1b/1,
make_del_dir_a/1, make_del_dir_b/1,
@@ -115,6 +115,18 @@ groups() ->
[make_link_a, make_link_b, read_link_info_for_non_link,
symlinks_a, symlinks_b, list_dir_error]}].
+init_per_testcase(large_write, Config) ->
+ {ok, Started} = application:ensure_all_started(os_mon),
+ [{started, Started}|Config];
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(large_write, Config) ->
+ [application:stop(App) || App <- lists:reverse(proplists:get_value(started, Config))],
+ ok;
+end_per_testcase(_, _Config) ->
+ ok.
+
init_per_group(_GroupName, Config) ->
Config.
@@ -2022,11 +2034,13 @@ run_large_file_test(Config, Run, Name) ->
{{unix,sunos},OsVersion} when OsVersion < {5,5,1} ->
{skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"};
{{unix,_},_} ->
- N = unix_free(proplists:get_value(priv_dir, Config)),
- io:format("Free disk: ~w KByte~n", [N]),
- if N < 5 bsl 20 ->
+ DiscFree = unix_free(proplists:get_value(priv_dir, Config)),
+ MemFree = free_memory(),
+ io:format("Free disk: ~w KByte~n", [DiscFree]),
+ io:format("Free mem: ~w MByte~n", [MemFree]),
+ if DiscFree < 5 bsl 20; MemFree < 5 bsl 10 ->
%% Less than 5 GByte free
- {skip,"Less than 5 GByte free disk"};
+ {skip,"Less than 5 GByte free disk/mem"};
true ->
do_run_large_file_test(Config, Run, Name)
end;
@@ -2079,6 +2093,27 @@ zip_data([], Bs) ->
zip_data(As, []) ->
As.
+%% Stolen from emulator -> alloc_SUITE
+free_memory() ->
+ %% Free memory in MB.
+ try
+ SMD = memsup:get_system_memory_data(),
+ {value, {free_memory, Free}} = lists:keysearch(free_memory, 1, SMD),
+ TotFree = (Free +
+ case lists:keysearch(cached_memory, 1, SMD) of
+ {value, {cached_memory, Cached}} -> Cached;
+ false -> 0
+ end +
+ case lists:keysearch(buffered_memory, 1, SMD) of
+ {value, {buffered_memory, Buffed}} -> Buffed;
+ false -> 0
+ end),
+ TotFree div (1024*1024)
+ catch
+ error : undef ->
+ ct:fail({"os_mon not built"})
+ end.
+
%%%-----------------------------------------------------------------
%%% Utilities
rm_rf(Mod,Dir) ->
diff --git a/lib/kernel/test/rpc_SUITE.erl b/lib/kernel/test/rpc_SUITE.erl
index 1c72ddc87f..a89a7600a2 100644
--- a/lib/kernel/test/rpc_SUITE.erl
+++ b/lib/kernel/test/rpc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,8 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
--export([call/1, block_call/1, multicall/1, multicall_timeout/1,
+-export([off_heap/1,
+ call/1, block_call/1, multicall/1, multicall_timeout/1,
multicall_dies/1, multicall_node_dies/1,
called_dies/1, called_node_dies/1,
called_throws/1, call_benchmark/1, async_call/1]).
@@ -35,7 +36,7 @@ suite() ->
{timetrap,{minutes,2}}].
all() ->
- [call, block_call, multicall, multicall_timeout,
+ [off_heap, call, block_call, multicall, multicall_timeout,
multicall_dies, multicall_node_dies, called_dies,
called_node_dies, called_throws, call_benchmark,
async_call].
@@ -55,6 +56,13 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+off_heap(_Config) ->
+ %% The rex server process may receive a huge amount of
+ %% messages. Make sure that they are stored off heap to
+ %% avoid exessive GCs.
+ MQD = message_queue_data,
+ {MQD,off_heap} = process_info(whereis(rex), MQD),
+ ok.
%% Test different rpc calls.
diff --git a/lib/kernel/test/sendfile_SUITE.erl b/lib/kernel/test/sendfile_SUITE.erl
index 2673c38494..bfa564c32c 100644
--- a/lib/kernel/test/sendfile_SUITE.erl
+++ b/lib/kernel/test/sendfile_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -100,13 +100,13 @@ init_per_testcase(TC,Config) when TC == t_sendfile_recvduring;
%% Check if sendfile is supported on this platform
case catch sendfile_send(Send) of
ok ->
- Config;
+ init_per_testcase(t_sendfile, Config);
Error ->
ct:log("Error: ~p",[Error]),
{skip,"Not supported"}
end;
init_per_testcase(_Tc,Config) ->
- Config.
+ Config ++ [{sendfile_opts,[{use_threads,false}]}].
t_sendfile_small(Config) when is_list(Config) ->
diff --git a/lib/kernel/test/zlib_SUITE.erl b/lib/kernel/test/zlib_SUITE.erl
index f8257bd20c..4b67fce9a8 100644
--- a/lib/kernel/test/zlib_SUITE.erl
+++ b/lib/kernel/test/zlib_SUITE.erl
@@ -83,7 +83,7 @@ groups() ->
[api_open_close, api_deflateInit,
api_deflateSetDictionary, api_deflateReset,
api_deflateParams, api_deflate, api_deflateEnd,
- api_inflateInit, api_inflateSetDictionary,
+ api_inflateInit, api_inflateSetDictionary, api_inflateGetDictionary,
api_inflateSync, api_inflateReset, api_inflate, api_inflateChunk,
api_inflateEnd, api_setBufsz, api_getBufsz, api_crc32,
api_adler32, api_getQSize, api_un_compress, api_un_zip,
@@ -288,6 +288,42 @@ api_inflateSetDictionary(Config) when is_list(Config) ->
?m({'EXIT',{stream_error,_}}, zlib:inflateSetDictionary(Z1,Dict)),
?m(ok, zlib:close(Z1)).
+%% Test inflateGetDictionary.
+api_inflateGetDictionary(Config) when is_list(Config) ->
+ Z1 = zlib:open(),
+ IsOperationSupported =
+ case catch zlib:inflateGetDictionary(Z1) of
+ {'EXIT',{einval,_}} -> true;
+ {'EXIT',{enotsup,_}} -> false
+ end,
+ _ = zlib:close(Z1),
+ api_inflateGetDictionary_if_supported(IsOperationSupported).
+
+api_inflateGetDictionary_if_supported(false) ->
+ {skip, "inflateGetDictionary/1 unsupported in current setup"};
+api_inflateGetDictionary_if_supported(true) ->
+ % Compress payload using custom dictionary
+ Z1 = zlib:open(),
+ ?m(ok, zlib:deflateInit(Z1)),
+ Dict = <<"foobar barfoo foo bar far boo">>,
+ ?m(_, zlib:deflateSetDictionary(Z1, Dict)),
+ Payload = <<"foobarbarbar">>,
+ Compressed = zlib:deflate(Z1, Payload, finish),
+ ?m(ok, zlib:close(Z1)),
+
+ % Decompress and test dictionary extraction
+ Z2 = zlib:open(),
+ ?m(ok, zlib:inflateInit(Z2)),
+ ?m(<<>>, iolist_to_binary(zlib:inflateGetDictionary(Z2))),
+ ?m({'EXIT',{stream_error,_}}, zlib:inflateSetDictionary(Z2, Dict)),
+ ?m({'EXIT',{{need_dictionary,_},_}}, zlib:inflate(Z2, Compressed)),
+ ?m(ok, zlib:inflateSetDictionary(Z2, Dict)),
+ ?m(Dict, iolist_to_binary(zlib:inflateGetDictionary(Z2))),
+ ?m(Payload, iolist_to_binary(zlib:inflate(Z2, Compressed))),
+ ?m(ok, zlib:close(Z2)),
+ ?m(?BARG, zlib:inflateSetDictionary(Z2, Dict)),
+ ok.
+
%% Test inflateSync.
api_inflateSync(Config) when is_list(Config) ->
{skip,"inflateSync/1 sucks"}.