diff options
author | Björn Gustavsson <[email protected]> | 2016-04-04 13:42:39 +0200 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2016-04-04 13:42:39 +0200 |
commit | 282f18834468ca36e0e56dc12ac637e8ea82e54a (patch) | |
tree | a3fedff82633920a4cb7a9f07edb582e52f2e5cf /lib/kernel | |
parent | d5ee10dd6ad9e7d78fe1e306ad53b78c15f9b7f2 (diff) | |
parent | 17f7dd7a414feb14fa20200299e9115e832ed164 (diff) | |
download | otp-282f18834468ca36e0e56dc12ac637e8ea82e54a.tar.gz otp-282f18834468ca36e0e56dc12ac637e8ea82e54a.tar.bz2 otp-282f18834468ca36e0e56dc12ac637e8ea82e54a.zip |
Merge branch 'bjorn/cuddle-with-tests'
* bjorn/cuddle-with-tests:
inet_SUITE: Handle pointtopoint devices in getifaddrs/1
file_SUITE: Increase timetrap for large_write/1
gen_fsm_SUITE: Make abnormal1/1 stop failing
gen_fsm_SUITE: Use timer:sleep/1 instead of ct:sleep/1
inet_SUITE: Handle {error,enoent} in simple_netns_open
inet_SUITE: Handle missing SCTP support in simple_netns/1
asn1_SUITE: Remove temporary files
file_name_SUITE: Improve handling of missing permission for link creation
file_name_SUITE: Remove useless put/2 to process dictionary
file_name_SUITE: Handle the case that HOMEPATH may not be set
code_SUITE: Skip on_load_embedded/1 if no symlinks
gen_sctp_SUITE: Skip most SCTP test cases on Solaris before 5.12
heart_SUITE: Increase timeout in restart/1
heart_SUITE: Use unique node names
init_SUITE: Quote pathname that may contain a space
gen_tcp_misc_SUITE: Clean up send_timeout{_active}/1
Clean up the determination of the hostname
Diffstat (limited to 'lib/kernel')
-rw-r--r-- | lib/kernel/test/code_SUITE.erl | 3 | ||||
-rw-r--r-- | lib/kernel/test/file_SUITE.erl | 5 | ||||
-rw-r--r-- | lib/kernel/test/file_name_SUITE.erl | 325 | ||||
-rw-r--r-- | lib/kernel/test/gen_sctp_SUITE.erl | 39 | ||||
-rw-r--r-- | lib/kernel/test/gen_tcp_misc_SUITE.erl | 250 | ||||
-rw-r--r-- | lib/kernel/test/heart_SUITE.erl | 31 | ||||
-rw-r--r-- | lib/kernel/test/inet_SUITE.erl | 24 | ||||
-rw-r--r-- | lib/kernel/test/init_SUITE.erl | 3 |
8 files changed, 336 insertions, 344 deletions
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index abea23e854..1b7672d362 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -1221,6 +1221,9 @@ on_load_embedded_1(Config) -> case file:make_symlink(OnLoadApp, LinkName) of {error,enotsup} -> throw({skip,"Support for symlinks required"}); + {error,eperm} -> + %% On Windows, we may not have permissions to create symlinks. + throw({skip,"Support for symlinks required"}); ok -> ok end, diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl index 74db2970af..f0d5b4ac12 100644 --- a/lib/kernel/test/file_SUITE.erl +++ b/lib/kernel/test/file_SUITE.erl @@ -83,7 +83,7 @@ -export([unicode/1]). -export([altname/1]). --export([large_file/0, large_file/1, large_write/1]). +-export([large_file/0, large_file/1, large_write/0, large_write/1]). -export([read_line_1/1, read_line_2/1, read_line_3/1,read_line_4/1]). @@ -3663,6 +3663,9 @@ do_large_file(Name) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +large_write() -> + [{timetrap,{minutes,20}}]. + large_write(Config) when is_list(Config) -> run_large_file_test(Config, fun(Name) -> do_large_write(Name) end, diff --git a/lib/kernel/test/file_name_SUITE.erl b/lib/kernel/test/file_name_SUITE.erl index be4ef9c394..dcd2cb28a6 100644 --- a/lib/kernel/test/file_name_SUITE.erl +++ b/lib/kernel/test/file_name_SUITE.erl @@ -139,7 +139,12 @@ home_dir(Config) when is_list(Config) -> test_server:stop_node(Node), ok after - os:putenv(SaveOldName,SaveOldValue), + case SaveOldValue of + false -> + os:unsetenv(SaveOldName); + _ -> + os:putenv(SaveOldName,SaveOldValue) + end, rm_rf(prim_file,NewHome) end catch @@ -185,9 +190,7 @@ normal(Config) when is_list(Config) -> try Priv = proplists:get_value(priv_dir, Config), file:set_cwd(Priv), - put(file_module,prim_file), ok = check_normal(prim_file), - put(file_module,file), ok = check_normal(file), %% If all is good, delete dir again (avoid hanging dir on windows) rm_rf(file,"normal_dir"), @@ -207,9 +210,7 @@ icky(Config) when is_list(Config) -> try Priv = proplists:get_value(priv_dir, Config), file:set_cwd(Priv), - put(file_module,prim_file), ok = check_icky(prim_file), - put(file_module,file), ok = check_icky(file), %% If all is good, delete dir again (avoid hanging dir on windows) rm_rf(file,"icky_dir"), @@ -228,12 +229,10 @@ very_icky(Config) when is_list(Config) -> try Priv = proplists:get_value(priv_dir, Config), file:set_cwd(Priv), - put(file_module,prim_file), case check_very_icky(prim_file) of need_unicode_mode -> {skipped,"VM needs to be started in Unicode filename mode"}; ok -> - put(file_module,file), ok = check_very_icky(file), %% If all is good, delete dir again %% (avoid hanging dir on windows) @@ -249,10 +248,12 @@ very_icky(Config) when is_list(Config) -> check_normal(Mod) -> {ok,Dir} = Mod:get_cwd(), try - make_normal_dir(Mod), + NormalDir = make_normal_dir(Mod, "normal_dir"), + io:format("Normaldir = ~p\n", [NormalDir]), + L1 = lists:sort(list(NormalDir)), {ok, L0} = Mod:list_dir("."), + io:format("L0 = ~p\n", [L0]), L1 = lists:sort(L0), - L1 = lists:sort(list(normal_dir())), {ok,D2} = Mod:get_cwd(), true = is_list(D2), case Mod:altname("fil1") of @@ -262,45 +263,45 @@ check_normal(Mod) -> ok end, [ true = is_list(El) || El <- L1], - Syms = [ {S,Targ,list_to_binary(get_data(Targ,normal_dir()))} - || {T,S,Targ} <- normal_dir(), T =:= symlink ], + Syms = [ {S,Targ,list_to_binary(get_data(Targ, NormalDir))} + || {T,S,Targ} <- NormalDir, T =:= symlink ], [ {ok, Cont} = Mod:read_file(SymL) || {SymL,_,Cont} <- Syms ], [ {ok, Targ} = fixlink(Mod:read_link(SymL)) || {SymL,Targ,_} <- Syms ], - chk_cre_dir(Mod,[{directory,"temp_dir",normal_dir()}]), + {ok,BeginAt} = Mod:get_cwd(), true = is_list(BeginAt), + TempDir = "temp_dir", + make_normal_dir(Mod, TempDir), {error,enoent} = Mod:set_cwd("tmp_dir"), - ok = Mod:set_cwd("temp_dir"), {ok, NowAt} = Mod:get_cwd(), true = BeginAt =/= NowAt, ok = Mod:set_cwd(".."), {ok,BeginAt} = Mod:get_cwd(), - rm_r(Mod,"temp_dir"), + rm_r(Mod, TempDir), true = is_list(Dir), [ true = is_list(FN) || FN <- L0 ], - case has_links() of - true -> - ok = Mod:make_link("fil1","nisse"), + case Mod:make_link("fil1","nisse") of + ok -> {ok, <<"fil1">>} = Mod:read_file("nisse"), {ok, #file_info{type = regular}} = Mod:read_link_info("nisse"), ok = Mod:delete("nisse"), {ok, <<"fil1">>} = Mod:read_file("fil1"), {error,enoent} = Mod:read_file("nisse"), {error,enoent} = Mod:read_link_info("nisse"); - false -> + {error,enotsup} -> ok end, [ begin {ok, FD} = Mod:open(Name,[read]), {ok, Content} = Mod:read(FD,1024), ok = file:close(FD) - end || {regular,Name,Content} <- normal_dir() ], + end || {regular,Name,Content} <- NormalDir ], [ begin {ok, FD} = Mod:open(Name,[read,binary]), BC = list_to_binary(Content), {ok, BC} = Mod:read(FD,1024), ok = file:close(FD) - end || {regular,Name,Content} <- normal_dir() ], + end || {regular,Name,Content} <- NormalDir ], Mod:rename("fil1","tmp_fil1"), {ok, <<"fil1">>} = Mod:read_file("tmp_fil1"), {error,enoent} = Mod:read_file("fil1"), @@ -333,11 +334,11 @@ check_icky(Mod) -> try true=(length("åäö") =:= 3), UniMode = file:native_name_encoding() =/= latin1, - make_icky_dir(Mod), + IckyDir = make_icky_dir(Mod, "icky_dir"), {ok, L0} = Mod:list_dir_all("."), L1 = lists:sort(L0), - io:format("~p~n~p~n~n",[L1,lists:sort(list(icky_dir()))]), - L1 = lists:sort(convlist(list(icky_dir()))), + io:format("~p~n~p~n~n",[L1,lists:sort(list(IckyDir))]), + L1 = lists:sort(convlist(list(IckyDir))), {ok,D2} = Mod:get_cwd(), true = is_list(D2), %% Altname only on windows, and there are no non native filenames there @@ -348,16 +349,16 @@ check_icky(Mod) -> %% ok %% end, [ true = ((is_list(El) or (UniMode and is_binary(El)))) || El <- L1], - Syms = [ {S,conv(Targ),list_to_binary(get_data(Targ,icky_dir()))} - || {T,S,Targ} <- icky_dir(), T =:= symlink ], + Syms = [ {S,conv(Targ),list_to_binary(get_data(Targ,IckyDir))} + || {T,S,Targ} <- IckyDir, T =:= symlink ], [ {ok, Cont} = Mod:read_file(SymL) || {SymL,_,Cont} <- Syms ], [ {ok, Targ} = fixlink(Mod:read_link_all(SymL)) || {SymL,Targ,_} <- Syms ], - chk_cre_dir(Mod,[{directory,"åäö_dir",icky_dir()}]), + {ok,BeginAt} = Mod:get_cwd(), true = is_list(BeginAt), + _ = make_icky_dir(Mod, "åäö_dir"), {error,enoent} = Mod:set_cwd("åä_dir"), - ok = Mod:set_cwd("åäö_dir"), {ok, NowAt} = Mod:get_cwd(), true = is_list(NowAt), true = BeginAt =/= NowAt, @@ -365,10 +366,11 @@ check_icky(Mod) -> {ok,BeginAt} = Mod:get_cwd(), rm_r2(Mod,"åäö_dir"), {OS,_} = os:type(), + %% Check that treat_icky really converts to the same as the OS case UniMode of true -> - chk_cre_dir(Mod,[{directory,"åäö_dir",[]}]), + ok = Mod:make_dir("åäö_dir"), ok = Mod:set_cwd("åäö_dir"), ok = Mod:write_file(<<"ååå">>,<<"hello">>), Treated = treat_icky(<<"ååå">>), @@ -381,17 +383,17 @@ check_icky(Mod) -> ok end, - chk_cre_dir(Mod,[{directory,treat_icky(<<"åäö_dir">>),icky_dir()}]), + _ = make_icky_dir(Mod, treat_icky(<<"åäö_dir">>)), if UniMode and (OS =/= win32) -> {error,enoent} = Mod:set_cwd("åäö_dir"); true -> ok end, + ok = Mod:set_cwd(".."), {ok,BeginAt} = Mod:get_cwd(), - case has_links() of - true -> - ok = Mod:make_link("fil1","nisseö"), + case Mod:make_link("fil1", "nisseö") of + ok -> {ok, <<"fil1">>} = Mod:read_file("nisseö"), {ok, #file_info{type = regular}} = Mod:read_link_info("nisseö"), ok = Mod:delete("nisseö"), @@ -404,20 +406,20 @@ check_icky(Mod) -> {error,enoent} = Mod:read_link_info("nisseö"), {error,enoent} = Mod:read_file(treat_icky(<<"nisseö">>)), {error,enoent} = Mod:read_link_info(treat_icky(<<"nisseö">>)); - false -> + {error,enotsup} -> ok end, [ begin {ok, FD} = Mod:open(Name,[read]), {ok, Content} = Mod:read(FD,1024), ok = file:close(FD) - end || {regular,Name,Content} <- icky_dir() ], + end || {regular,Name,Content} <- IckyDir ], [ begin {ok, FD} = Mod:open(Name,[read,binary]), BC = list_to_binary([Content]), {ok, BC} = Mod:read(FD,1024), ok = file:close(FD) - end || {regular,Name,Content} <- icky_dir() ], + end || {regular,Name,Content} <- IckyDir ], Mod:rename("åäö2","åäö_fil1"), {ok, <<"åäö2">>} = Mod:read_file("åäö_fil1"), {error,enoent} = Mod:read_file("åäö2"), @@ -471,33 +473,33 @@ check_very_icky(Mod) -> true -> ok end, - make_very_icky_dir(Mod), - {ok, L0} = Mod:list_dir_all("."), - L1 = lists:sort(L0), - L1 = lists:sort(convlist(list(very_icky_dir()))), + VeryIckyDir = make_very_icky_dir(Mod, "very_icky_dir"), + Expected = lists:sort(convlist(list(VeryIckyDir))), + {ok, Actual} = Mod:list_dir_all("."), + Expected = lists:sort(Actual), {ok,D2} = Mod:get_cwd(), true = is_list(D2), - [ true = ((is_list(El) or is_binary(El))) || El <- L1], - Syms = [ {S,conv(Targ),list_to_binary(get_data(Targ,very_icky_dir()))} - || {T,S,Targ} <- very_icky_dir(), T =:= symlink ], + [ true = ((is_list(El) or is_binary(El))) || El <- Expected], + Syms = [{S,conv(Targ),list_to_binary(get_data(Targ, VeryIckyDir))} + || {symlink,S,Targ} <- VeryIckyDir], [ {ok, Cont} = Mod:read_file(SymL) || {SymL,_,Cont} <- Syms ], [ {ok, Targ} = fixlink(Mod:read_link_all(SymL)) || {SymL,Targ,_} <- Syms ], - chk_cre_dir(Mod,[{directory,[1088,1079,1091]++"_dir",very_icky_dir()}]), + {ok,BeginAt} = Mod:get_cwd(), + OtherDir = [1088,1079,1091] ++ "_dir", true = is_list(BeginAt), + make_very_icky_dir(Mod, OtherDir), {error,enoent} = Mod:set_cwd("åä_dir"), - ok = Mod:set_cwd([1088,1079,1091]++"_dir"), {ok, NowAt} = Mod:get_cwd(), true = is_list(NowAt), true = BeginAt =/= NowAt, ok = Mod:set_cwd(".."), {ok,BeginAt} = Mod:get_cwd(), - rm_r2(Mod,[1088,1079,1091]++"_dir"), + rm_r2(Mod, OtherDir), - case has_links() of - true -> - ok = Mod:make_link("fil1","nisse"++[1088,1079,1091]), + case Mod:make_link("fil1","nisse"++[1088,1079,1091]) of + ok -> {ok, <<"fil1">>} = Mod:read_file("nisse"++[1088,1079,1091]), {ok, #file_info{type = regular}} = @@ -513,20 +515,20 @@ check_very_icky(Mod) -> {error,enoent} = Mod:read_link_info("nisse"++[1088,1079,1091]), {error,enoent} = Mod:read_file(<<"nisseö">>), {error,enoent} = Mod:read_link_info(<<"nisseö">>); - false -> + {error,enotsup} -> ok end, [ begin {ok, FD} = Mod:open(Name,[read]), {ok, Content} = Mod:read(FD,1024), ok = file:close(FD) - end || {regular,Name,Content} <- very_icky_dir() ], + end || {regular,Name,Content} <- VeryIckyDir ], [ begin {ok, FD} = Mod:open(Name,[read,binary]), BC = list_to_binary([Content]), {ok, BC} = Mod:read(FD,1024), ok = file:close(FD) - end || {regular,Name,Content} <- very_icky_dir() ], + end || {regular,Name,Content} <- VeryIckyDir ], Mod:rename([956,965,963,954,959,49], [956,965,963,954,959]++"_fil1"), {ok, <<"åäö2">>} = Mod:read_file([956,965,963,954,959]++"_fil1"), @@ -610,90 +612,35 @@ rm_r2(Mod,Dir) -> {ok, #file_info{type = symlink}} -> ok = Mod:delete(Dir) end. -chk_cre_dir(_,[]) -> - ok; -chk_cre_dir(Mod,[{regular,Name,Content}|T]) -> - %% io:format("~p~n",[Name]), - ok = Mod:write_file(Name,Content), - chk_cre_dir(Mod,T); -chk_cre_dir(Mod,[{link,Name,Target}|T]) -> - ok = Mod:make_link(Target,Name), - chk_cre_dir(Mod,T); -chk_cre_dir(Mod,[{symlink,Name,Target}|T]) -> - ok = Mod:make_symlink(Target,Name), - chk_cre_dir(Mod,T); -chk_cre_dir(Mod,[{directory,Name,Content}|T]) -> - ok = Mod:make_dir(Name), - %% io:format("Content = ~p~n",[Content]), - Content2 = [{Ty,filename:join(Name,N),case Ty of link -> filename:join(Name,C); _ -> C end} || {Ty,N,C} <- Content ], - %% io:format("Content2 = ~p~n",[Content2]), - chk_cre_dir(Mod,Content2), - chk_cre_dir(Mod,T). -has_links() -> - case os:type() of - {win32,_} -> - case os:version() of - {N,NN,_} when (N > 5) andalso (NN >= 1) -> - true; - _ -> - false - end; - _ -> - true - end. +make_normal_dir(Mod, DirName) -> + Dir = [{regular,"fil1","fil1"}, + {regular,"fil2","fil2"}, + {hardlink,"fil3","fil2"}, + {symlink,"fil4","fil2"}, + {directory,"subdir", + [{regular,"subfil1","subfil1"}]}], + rm_rf(Mod, DirName), + Mod:make_dir(DirName), + Mod:set_cwd(DirName), + make_dir_contents(Dir, Mod). -make_normal_dir(Mod) -> - rm_rf(Mod,"normal_dir"), - Mod:make_dir("normal_dir"), - Mod:set_cwd("normal_dir"), - Mod:write_file("fil1","fil1"), - Mod:write_file("fil2","fil2"), - case has_links() of - true -> - Mod:make_link("fil2","fil3"), - Mod:make_symlink("fil2","fil4"); - _ -> - ok - end, - Mod:make_dir("subdir"), - Mod:write_file(filename:join("subdir","subfil1"),"subfil1"), - ok. - -normal_dir() -> - [{regular,"fil1","fil1"}, - {regular,"fil2","fil2"}] ++ - case has_links() of - true -> - [{regular,"fil3","fil2"}, - {symlink,"fil4","fil2"}]; - false -> - [] - end ++ - [{directory,"subdir", - [{regular,"subfil1","subfil1"}]}]. - -make_icky_dir(Mod) -> - rm_rf(Mod,"icky_dir"), - Icky=icky_dir(), - chk_cre_dir(Mod,[{directory,"icky_dir",linkify([],Icky)}]), - Mod:set_cwd("icky_dir"), - ok. - -linkify(_Passed,[]) -> - []; -linkify(Passed,[{regular,Name,Content}|T]) -> - Regulars = [ {N,C} || {regular,N,C} <- Passed, N =/= Name ], - case lists:keysearch(Content,2,Regulars) of - {value, {Linkto, Content}} -> - [{link,Name,Linkto} | linkify(Passed,T)]; - _ -> - [{regular,Name,Content} | linkify([{regular,Name,Content}|Passed],T)] - end; -linkify(Passed,[{directory, Name, Content}|T]) -> - [{directory,Name, linkify(Content,Content)}|linkify(Passed,T)]; -linkify(Passed,[H|T]) -> - [H|linkify([H|Passed],T)]. +make_icky_dir(Mod, IckyDirName) -> + Icky = [{regular,"fil1","fil1"}, + {regular,"åäö2","åäö2"}, + {hardlink,"åäö3","åäö2"}, + {symlink,"åäö4","åäö2"}, + {regular,treat_icky(<<"åäö5">>),"åäö5"}, + {symlink,treat_icky(<<"åäö6">>),treat_icky(<<"åäö5">>)}, + {directory,treat_icky(<<"åäösubdir2">>), + [{regular,treat_icky(<<"åäösubfil2">>),"åäösubfil12"}, + {regular,"åäösubfil3","åäösubfil13"}]}, + {directory,"åäösubdir", + [{regular,"åäösubfil1","åäösubfil1"}]}], + rm_rf(Mod, IckyDirName), + ok = Mod:make_dir(IckyDirName), + ok = Mod:set_cwd(IckyDirName), + make_dir_contents(Icky, Mod). hopeless_darwin() -> case {os:type(),os:version()} of @@ -703,58 +650,24 @@ hopeless_darwin() -> false end. -icky_dir() -> - [{regular,"fil1","fil1"}, - {regular,"åäö2","åäö2"}] ++ - case has_links() of - true -> - [{regular,"åäö3","åäö2"}, - {symlink,"åäö4","åäö2"}]; - false -> - [] - end ++ - [{regular,treat_icky(<<"åäö5">>),"åäö5"}] ++ - case has_links() of - true -> - [{symlink,treat_icky(<<"åäö6">>),treat_icky(<<"åäö5">>)}]; - false -> - [] - end ++ - [{directory,treat_icky(<<"åäösubdir2">>), - [{regular,treat_icky(<<"åäösubfil2">>),"åäösubfil12"}, - {regular,"åäösubfil3","åäösubfil13"}]}, - {directory,"åäösubdir", - [{regular,"åäösubfil1","åäösubfil1"}]}]. - -make_very_icky_dir(Mod) -> - rm_rf(Mod,"very_icky_dir"), - Icky=very_icky_dir(), - chk_cre_dir(Mod,[{directory,"very_icky_dir",linkify([],Icky)}]), - Mod:set_cwd("very_icky_dir"), - ok. - -very_icky_dir() -> - [{regular,"fil1","fil1"}, - {regular,[956,965,963,954,959,49],"åäö2"}] ++ - case has_links() of - true -> - [{regular,[956,965,963,954,959,50],"åäö2"}, - {symlink,[956,965,963,954,959,51],[956,965,963,954,959,49]}]; - false -> - [] - end ++ - [{regular,treat_icky(<<"åäö5">>),"åäö5"}] ++ - case has_links() of - true -> - [{symlink,treat_icky(<<"åäö6">>),treat_icky(<<"åäö5">>)}]; - false -> - [] - end ++ - [{directory,treat_icky(<<"åäösubdir2">>), - [{regular,treat_icky(<<"åäösubfil2">>),"åäösubfil12"}, - {regular,"åäösubfil3","åäösubfil13"}]}, - {directory,[956,965,963,954,959]++"subdir1", - [{regular,[956,965,963,954,959]++"subfil1","åäösubfil1"}]}]. +make_very_icky_dir(Mod, DirName) -> + Desc = [{regular,"fil1","fil1"}, + {regular,[956,965,963,954,959,49],"åäö2"}, + {hardlink,[956,965,963,954,959,50], + [956,965,963,954,959,49], + "åäö2"}, + {symlink,[956,965,963,954,959,51],[956,965,963,954,959,49]}, + {regular,treat_icky(<<"åäö5">>),"åäö5"}, + {symlink,treat_icky(<<"åäö6">>),treat_icky(<<"åäö5">>)}, + {directory,treat_icky(<<"åäösubdir2">>), + [{regular,treat_icky(<<"åäösubfil2">>),"åäösubfil12"}, + {regular,"åäösubfil3","åäösubfil13"}]}, + {directory,[956,965,963,954,959]++"subdir1", + [{regular,[956,965,963,954,959]++"subfil1","åäösubfil1"}]}], + rm_rf(Mod, DirName), + ok = Mod:make_dir(DirName), + ok = Mod:set_cwd(DirName), + make_dir_contents(Desc, Mod). %% Some OS'es simply do not allow non UTF8 filenames treat_icky(Bin) -> @@ -827,6 +740,48 @@ conv(L) -> end. +make_dir_contents([{regular,Name,Contents}=H|T], Mod) -> + ok = Mod:write_file(Name, Contents), + [H|make_dir_contents(T, Mod)]; +make_dir_contents([{hardlink,Target,Name}|T], Mod) -> + case Mod:make_link(Name, Target) of + ok -> + [{regular,Target,Name}|make_dir_contents(T, Mod)]; + {error,enotsup} -> + make_dir_contents(T, Mod) + end; +make_dir_contents([{hardlink,Target,Name,Contents}|T], Mod) -> + case Mod:make_link(Name, Target) of + ok -> + [{regular,Target,Contents}|make_dir_contents(T, Mod)]; + {error,enotsup} -> + make_dir_contents(T, Mod) + end; +make_dir_contents([{symlink,Target,Name}=H|T], Mod) -> + case Mod:make_symlink(Name, Target) of + ok -> + [H|make_dir_contents(T, Mod)]; + {error,enotsup} -> + make_dir_contents(T, Mod); + {error,eperm} -> + make_dir_contents(T, Mod) + end; +make_dir_contents([{directory,Dir,C0}|T], Mod) -> + ok = Mod:make_dir(Dir), + C1 = [case Op of + Link when Link =:= hardlink; Link =:= symlink -> + {Op,filename:join(Dir, Name0),filename:join(Dir, Extra)}; + _ -> + {Op,filename:join(Dir, Name0),Extra} + end || {Op,Name0,Extra} <- C0], + C2 = make_dir_contents(C1, Mod), + C = [{Op,filename:basename(Name0),Extra} || + {Op,Name0,Extra} <- C2], + [{directory,Dir,C}|make_dir_contents(T, Mod)]; +make_dir_contents([], _Mod) -> + []. + + rand_comp_decomp(Max) -> N = rand:uniform(Max), L = [ rand_decomp() || _ <- lists:seq(1,N) ], diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index 8e53da210e..48cd245204 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -29,7 +29,8 @@ init_per_group/2,end_per_group/2, init_per_testcase/2, end_per_testcase/2]). -export( - [basic/1, + [skip_old_solaris/1, + basic/1, api_open_close/1,api_listen/1,api_connect_init/1,api_opts/1, xfer_min/1,xfer_active/1,def_sndrcvinfo/1,implicit_inet6/1, open_multihoming_ipv4_socket/1, @@ -46,20 +47,28 @@ suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,1}}]. -all() -> - [basic, api_open_close, api_listen, api_connect_init, - api_opts, xfer_min, xfer_active, def_sndrcvinfo, implicit_inet6, - open_multihoming_ipv4_socket, - open_unihoming_ipv6_socket, - open_multihoming_ipv6_socket, - open_multihoming_ipv4_and_ipv6_socket, active_n, - basic_stream, xfer_stream_min, peeloff_active_once, - peeloff_active_true, peeloff_active_n, buffers, - names_unihoming_ipv4, names_unihoming_ipv6, - names_multihoming_ipv4, names_multihoming_ipv6]. +all() -> + G = case is_old_solaris() of + true -> old_solaris; + false -> extensive + end, + [{group,smoke}, + {group,G}]. groups() -> - []. + [{smoke,[],[basic,basic_stream]}, + {old_solaris,[],[skip_old_solaris]}, + {extensive,[], + [api_open_close, api_listen, api_connect_init, + api_opts, xfer_min, xfer_active, def_sndrcvinfo, implicit_inet6, + open_multihoming_ipv4_socket, + open_unihoming_ipv6_socket, + open_multihoming_ipv6_socket, + open_multihoming_ipv4_and_ipv6_socket, active_n, + xfer_stream_min, peeloff_active_once, + peeloff_active_true, peeloff_active_n, buffers, + names_unihoming_ipv4, names_unihoming_ipv6, + names_multihoming_ipv4, names_multihoming_ipv6]}]. init_per_suite(_Config) -> case gen_sctp:open() of @@ -91,7 +100,11 @@ end_per_testcase(_Func, _Config) -> -define(LOGVAR(Var), begin io:format(??Var" = ~p~n", [Var]) end). +is_old_solaris() -> + os:type() =:= {unix,sunos} andalso os:version() < {5,12,0}. +skip_old_solaris(_Config) -> + {skip,"Unreliable test cases and/or implementation on old Solaris"}. %% Hello world. basic(Config) when is_list(Config) -> diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index 7c3b011eb9..173cf76237 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -2320,70 +2320,82 @@ active_once_closed(Config) when is_list(Config) -> %% Test the send_timeout socket option. send_timeout(Config) when is_list(Config) -> + Dir = filename:dirname(code:which(?MODULE)), + {ok,RNode} = test_server:start_node(?UNIQ_NODE_NAME, slave, + [{args,"-pa " ++ Dir}]), + %% Basic - BasicFun = - fun(AutoClose) -> - {Loop,A,RNode} = setup_timeout_sink(1000, AutoClose), - {error,timeout} = - Loop(fun() -> - Res = gen_tcp:send(A,<<1:10000>>), - %%erlang:display(Res), - Res - end), - %% Check that the socket is not busy/closed... - Error = after_send_timeout(AutoClose), - {error,Error} = gen_tcp:send(A,<<"Hej">>), - test_server:stop_node(RNode) - end, - BasicFun(false), - BasicFun(true), - %% Check timeout length + send_timeout_basic(false, RNode), + send_timeout_basic(true, RNode), + + BinData = <<1:10000>>, + + %% Check timeout length. Self = self(), Pid = spawn(fun() -> - {Loop,A,RNode} = setup_timeout_sink(1000, true), - {error,timeout} = Loop(fun() -> - Res = gen_tcp:send(A,<<1:10000>>), - %%erlang:display(Res), - Self ! Res, - Res - end), - test_server:stop_node(RNode) + A = setup_timeout_sink(RNode, 1000, true), + Send = fun() -> + Res = gen_tcp:send(A, BinData), + Self ! Res, + Res + end, + {error,timeout} = timeout_sink_loop(Send) end), Diff = get_max_diff(), io:format("Max time for send: ~p~n",[Diff]), true = (Diff > 500) and (Diff < 1500), - %% Let test_server slave die... + + %% Wait for the process to die. Mon = erlang:monitor(process, Pid), receive {'DOWN',Mon,process,Pid,_} -> ok end, + %% Check that parallell writers do not hang forever - ParaFun = - fun(AutoClose) -> - {Loop,A,RNode} = setup_timeout_sink(1000, AutoClose), - SenderFun = fun() -> - {error,Error} = - Loop(fun() -> - gen_tcp:send(A, <<1:10000>>) - end), - Self ! {error,Error} - end, - spawn_link(SenderFun), - spawn_link(SenderFun), - receive - {error,timeout} -> ok - after 10000 -> - exit(timeout) - end, - NextErr = after_send_timeout(AutoClose), - receive - {error,NextErr} -> ok - after 10000 -> - exit(timeout) - end, - {error,NextErr} = gen_tcp:send(A,<<"Hej">>), - test_server:stop_node(RNode) - end, - ParaFun(false), - ParaFun(true), + send_timeout_para(false, RNode), + send_timeout_para(true, RNode), + + test_server:stop_node(RNode), + + ok. + +send_timeout_basic(AutoClose, RNode) -> + BinData = <<1:10000>>, + + A = setup_timeout_sink(RNode, 1000, AutoClose), + Send = fun() -> gen_tcp:send(A, BinData) end, + {error,timeout} = timeout_sink_loop(Send), + + %% Check that the socket is not busy/closed... + Error = after_send_timeout(AutoClose), + {error,Error} = gen_tcp:send(A, <<"Hej">>), + ok. + +send_timeout_para(AutoClose, RNode) -> + BinData = <<1:10000>>, + + A = setup_timeout_sink(RNode, 1000, AutoClose), + Self = self(), + SenderFun = fun() -> + Send = fun() -> gen_tcp:send(A, BinData) end, + {error,Error} = timeout_sink_loop(Send), + Self ! {error,Error} + end, + spawn_link(SenderFun), + spawn_link(SenderFun), + + receive + {error,timeout} -> ok + after 10000 -> + exit(timeout) + end, + + NextErr = after_send_timeout(AutoClose), + receive + {error,NextErr} -> ok + after 10000 -> + exit(timeout) + end, + + {error,NextErr} = gen_tcp:send(A, <<"Hej">>), ok. mad_sender(S) -> @@ -2406,31 +2418,33 @@ flush() -> %% Test the send_timeout socket option for active sockets. send_timeout_active(Config) when is_list(Config) -> - %% Basic - BasicFun = - fun(AutoClose) -> - {Loop,A,RNode,C} = setup_active_timeout_sink(1, AutoClose), - inet:setopts(A, [{active, once}]), - Mad = spawn_link(RNode,fun() -> mad_sender(C) end), - {error,timeout} = - Loop(fun() -> - receive - {tcp, _Sock, _Data} -> - inet:setopts(A, [{active, once}]), - Res = gen_tcp:send(A,lists:duplicate(1000, $a)), - Res; - Err -> - io:format("sock closed: ~p~n", [Err]), - Err - end - end), - unlink(Mad), - exit(Mad,kill), - test_server:stop_node(RNode) + Dir = filename:dirname(code:which(?MODULE)), + {ok,RNode} = test_server:start_node(?UNIQ_NODE_NAME, slave, + [{args,"-pa " ++ Dir}]), + do_send_timeout_active(false, RNode), + do_send_timeout_active(true, RNode), + test_server:stop_node(RNode), + ok. + +do_send_timeout_active(AutoClose, RNode) -> + {A,C} = setup_active_timeout_sink(RNode, 1, AutoClose), + inet:setopts(A, [{active, once}]), + Mad = spawn_link(RNode, fun() -> mad_sender(C) end), + ListData = lists:duplicate(1000, $a), + F = fun() -> + receive + {tcp, _Sock, _Data} -> + inet:setopts(A, [{active, once}]), + Res = gen_tcp:send(A, ListData), + Res; + Err -> + io:format("sock closed: ~p~n", [Err]), + Err + end end, - BasicFun(false), - flush(), - BasicFun(true), + {error,timeout} = timeout_sink_loop(F), + unlink(Mad), + exit(Mad, kill), flush(), ok. @@ -2475,7 +2489,7 @@ setup_closed_ao() -> Dir = filename:dirname(code:which(?MODULE)), {ok,R} = test_server:start_node(?UNIQ_NODE_NAME, slave, [{args,"-pa " ++ Dir}]), - Host = list_to_atom(lists:nth(2,string:tokens(atom_to_list(node()),"@"))), + Host = get_hostname(node()), {ok, L} = gen_tcp:listen(0, [{active,false},{packet,2}]), Fun = fun(F) -> receive @@ -2514,11 +2528,8 @@ setup_closed_ao() -> test_server:stop_node(R), {Loop,A}. -setup_timeout_sink(Timeout, AutoClose) -> - Dir = filename:dirname(code:which(?MODULE)), - {ok,R} = test_server:start_node(?UNIQ_NODE_NAME, slave, - [{args,"-pa " ++ Dir}]), - Host = list_to_atom(lists:nth(2,string:tokens(atom_to_list(node()),"@"))), +setup_timeout_sink(RNode, Timeout, AutoClose) -> + Host = get_hostname(node()), {ok, L} = gen_tcp:listen(0, [{active,false},{packet,2}, {send_timeout,Timeout}, {send_timeout_close,AutoClose}]), @@ -2529,7 +2540,7 @@ setup_timeout_sink(Timeout, AutoClose) -> die -> ok end end, - Pid = rpc:call(R,erlang,spawn,[fun() -> Fun(Fun) end]), + Pid = rpc:call(RNode, erlang, spawn, [fun() -> Fun(Fun) end]), {ok, Port} = inet:port(L), Remote = fun(Fu) -> Pid ! {self(), Fu}, @@ -2543,36 +2554,23 @@ setup_timeout_sink(Timeout, AutoClose) -> {ok,A} = gen_tcp:accept(L), gen_tcp:send(A,"Hello"), {ok, "Hello"} = Remote(fun() -> gen_tcp:recv(C,0) end), - Loop2 = fun(_,_,0) -> - {failure, timeout}; - (L2,F2,N) -> - Ret = F2(), - io:format("~p~n",[Ret]), - case Ret of - ok -> receive after 1 -> ok end, - L2(L2,F2,N-1); - Other -> Other - end - end, - Loop = fun(F3) -> Loop2(Loop2,F3,1000) end, - {Loop,A,R}. - -setup_active_timeout_sink(Timeout, AutoClose) -> - Dir = filename:dirname(code:which(?MODULE)), - {ok,R} = test_server:start_node(?UNIQ_NODE_NAME, slave, - [{args,"-pa " ++ Dir}]), - Host = list_to_atom(lists:nth(2,string:tokens(atom_to_list(node()),"@"))), - {ok, L} = gen_tcp:listen(0, [binary,{active,false},{packet,0},{nodelay, true},{keepalive, true}, - {send_timeout,Timeout}, - {send_timeout_close,AutoClose}]), + A. + +setup_active_timeout_sink(RNode, Timeout, AutoClose) -> + Host = get_hostname(node()), + ListenOpts = [binary,{active,false},{packet,0}, + {nodelay,true},{keepalive,true}, + {send_timeout,Timeout},{send_timeout_close,AutoClose}], + {ok, L} = gen_tcp:listen(0, ListenOpts), Fun = fun(F) -> receive {From,X} when is_function(X) -> - From ! {self(),X()}, F(F); + From ! {self(),X()}, + F(F); die -> ok end end, - Pid = rpc:call(R,erlang,spawn,[fun() -> Fun(Fun) end]), + Pid = rpc:call(RNode, erlang, spawn, [fun() -> Fun(Fun) end]), {ok, Port} = inet:port(L), Remote = fun(Fu) -> Pid ! {self(), Fu}, @@ -2580,26 +2578,22 @@ setup_active_timeout_sink(Timeout, AutoClose) -> end end, {ok, C} = Remote(fun() -> - gen_tcp:connect(Host,Port, - [{active,false}]) + gen_tcp:connect(Host, Port, [{active,false}]) end), {ok,A} = gen_tcp:accept(L), - gen_tcp:send(A,"Hello"), - {ok, "H"++_} = Remote(fun() -> gen_tcp:recv(C,0) end), - Loop2 = fun(_,_,0) -> - {failure, timeout}; - (L2,F2,N) -> - Ret = F2(), - io:format("~p~n",[Ret]), - case Ret of - ok -> receive after 1 -> ok end, - L2(L2,F2,N-1); - Other -> Other - end - end, - Loop = fun(F3) -> Loop2(Loop2,F3,1000) end, - {Loop,A,R,C}. + gen_tcp:send(A, "Hello"), + {ok, "H"++_} = Remote(fun() -> gen_tcp:recv(C, 0) end), + {A,C}. +timeout_sink_loop(Action) -> + Ret = Action(), + case Ret of + ok -> + receive after 1 -> ok end, + timeout_sink_loop(Action); + Other -> + Other + end. has_superfluous_schedulers() -> case {erlang:system_info(schedulers), @@ -3016,3 +3010,7 @@ oct_aloop(S,X,Times) -> end. ok({ok,V}) -> V. + +get_hostname(Name) -> + "@"++Host = lists:dropwhile(fun(C) -> C =/= $@ end, atom_to_list(Name)), + Host. diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl index dd6348c610..6ce1ee54e5 100644 --- a/lib/kernel/test/heart_SUITE.erl +++ b/lib/kernel/test/heart_SUITE.erl @@ -37,6 +37,11 @@ -define(DEFAULT_TIMEOUT_SECS, 120). +-define(UNIQ_NODE_NAME, + list_to_atom(?MODULE_STRING ++ "__" ++ + atom_to_list(?FUNCTION_NAME) ++ "_" ++ + integer_to_list(erlang:unique_integer([positive])))). + init_per_testcase(_Func, Config) -> Config. @@ -118,7 +123,7 @@ start_check(Type, Name, Envs) -> {ok, Node}. start(Config) when is_list(Config) -> - {ok, Node} = start_check(slave, heart_test), + {ok, Node} = start_check(slave, ?UNIQ_NODE_NAME), rpc:call(Node, init, reboot, []), receive {nodedown, Node} -> ok @@ -143,12 +148,12 @@ start(Config) when is_list(Config) -> %% Purpose: %% Check that a node is up and running after a init:restart/0 restart(Config) when is_list(Config) -> - {ok, Node} = start_check(loose, heart_test), + {ok, Node} = start_check(loose, ?UNIQ_NODE_NAME), rpc:call(Node, init, restart, []), receive {nodedown, Node} -> ok - after 2000 -> + after 5000 -> ct:fail(node_not_closed) end, timer:sleep(5000), @@ -159,7 +164,7 @@ restart(Config) when is_list(Config) -> %% Purpose: %% Check that a node is up and running after a init:reboot/0 reboot(Config) when is_list(Config) -> - {ok, Node} = start_check(slave, heart_test), + {ok, Node} = start_check(slave, ?UNIQ_NODE_NAME), ok = rpc:call(Node, heart, set_cmd, [atom_to_list(lib:progname()) ++ @@ -193,7 +198,8 @@ node_start_immediately_after_crash(Config) when is_list(Config) -> node_start_immediately_after_crash_test(Config) when is_list(Config) -> - {ok, Node} = start_check(loose, heart_test_imm, [{"ERL_CRASH_DUMP_SECONDS", "0"}]), + {ok, Node} = start_check(loose, ?UNIQ_NODE_NAME, + [{"ERL_CRASH_DUMP_SECONDS", "0"}]), ok = rpc:call(Node, heart, set_cmd, [atom_to_list(lib:progname()) ++ @@ -243,7 +249,8 @@ node_start_soon_after_crash(Config) when is_list(Config) -> end. node_start_soon_after_crash_test(Config) when is_list(Config) -> - {ok, Node} = start_check(loose, heart_test_soon, [{"ERL_CRASH_DUMP_SECONDS", "10"}]), + {ok, Node} = start_check(loose, ?UNIQ_NODE_NAME, + [{"ERL_CRASH_DUMP_SECONDS", "10"}]), ok = rpc:call(Node, heart, set_cmd, [atom_to_list(lib:progname()) ++ @@ -286,7 +293,7 @@ node_check_up_down(Node, Tmo) -> %% Only tests bad command, correct behaviour is tested in reboot/1. set_cmd(Config) when is_list(Config) -> - {ok, Node} = start_check(slave, heart_test), + {ok, Node} = start_check(slave, ?UNIQ_NODE_NAME), Cmd = wrong_atom, {error, {bad_cmd, Cmd}} = rpc:call(Node, heart, set_cmd, [Cmd]), Cmd1 = lists:duplicate(2047, $a), @@ -299,7 +306,7 @@ set_cmd(Config) when is_list(Config) -> ok. clear_cmd(Config) when is_list(Config) -> - {ok, Node} = start_check(slave, heart_test), + {ok, Node} = start_check(slave, ?UNIQ_NODE_NAME), ok = rpc:call(Node, heart, set_cmd, [atom_to_list(lib:progname()) ++ " -noshell -heart " ++ name(Node) ++ "&"]), @@ -337,7 +344,7 @@ clear_cmd(Config) when is_list(Config) -> ok. get_cmd(Config) when is_list(Config) -> - {ok, Node} = start_check(slave, heart_test), + {ok, Node} = start_check(slave, ?UNIQ_NODE_NAME), Cmd = "test", ok = rpc:call(Node, heart, set_cmd, [Cmd]), {ok, Cmd} = rpc:call(Node, heart, get_cmd, []), @@ -345,7 +352,7 @@ get_cmd(Config) when is_list(Config) -> ok. callback_api(Config) when is_list(Config) -> - {ok, Node} = start_check(slave, heart_test), + {ok, Node} = start_check(slave, ?UNIQ_NODE_NAME), none = rpc:call(Node, heart, get_callback, []), M0 = self(), F0 = ok, @@ -379,7 +386,7 @@ callback_api(Config) when is_list(Config) -> ok. options_api(Config) when is_list(Config) -> - {ok, Node} = start_check(slave, heart_test), + {ok, Node} = start_check(slave, ?UNIQ_NODE_NAME), none = rpc:call(Node, heart, get_options, []), M0 = self(), F0 = ok, @@ -474,7 +481,7 @@ kill_pid(Config) when is_list(Config) -> ok = do_kill_pid(Config). do_kill_pid(_Config) -> - Name = heart_test, + Name = ?UNIQ_NODE_NAME, Env = [{"HEART_COMMAND", "nickeNyfikenFarEttJobb"}], {ok,Node} = start_node_run(Name,Env,suicide_by_heart,[]), ok = wait_for_node(Node,15), diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index ee10747b0a..38cb02a6ec 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -1075,6 +1075,10 @@ check_ifopts( #ifopts{addrs=Addrs}=Ifopts) -> check_ifopts(Opts, Ifopts#ifopts{addrs=[{Addr,Netmask,Broadaddr}|Addrs]}); check_ifopts( + [{addr,Addr},{netmask,Netmask},{dstaddr,_}|Opts], + #ifopts{addrs=Addrs}=Ifopts) -> + check_ifopts(Opts, Ifopts#ifopts{addrs=[{Addr,Netmask}|Addrs]}); +check_ifopts( [{addr,Addr},{netmask,Netmask}|Opts], #ifopts{addrs=Addrs}=Ifopts) -> check_ifopts(Opts, Ifopts#ifopts{addrs=[{Addr,Netmask}|Addrs]}); @@ -1118,9 +1122,13 @@ simple_netns(Config) when is_list(Config) -> jog_netns_opt(L), ok = gen_tcp:close(L), %% - {ok,S} = gen_sctp:open(), - jog_netns_opt(S), - ok = gen_sctp:close(S); + case gen_sctp:open() of + {ok,S} -> + jog_netns_opt(S), + ok = gen_sctp:close(S); + {error,eprotonosupport} -> + ok + end; {error,einval} -> {skip,"setns() not supported"} end. @@ -1134,24 +1142,28 @@ jog_netns_opt(S) -> ok. +%% Smoke test netns support. simple_netns_open(Config) when is_list(Config) -> + %% Note: {error,enoent} will be returned if the run-time executable + %% has support for netns, but /proc/self/ns/net is missing. case gen_udp:open(0, [binary,{netns,"/"},inet]) of {ok,U} -> ok = gen_udp:close(U); - {error,E1} when E1 =:= einval; E1 =:= eperm -> + {error,E1} when E1 =:= einval; E1 =:= eperm; E1 =:= enoent -> ok end, case gen_tcp:listen(0, [binary,{netns,"/"},inet]) of {ok,T} -> ok = gen_tcp:close(T); - {error,E2} when E2 =:= einval; E2 =:= eperm -> + {error,E2} when E2 =:= einval; E2 =:= eperm; E2 =:= enoent -> ok end, try gen_sctp:open(0, [binary,{netns,"/"},inet]) of {ok,S} -> ok = gen_sctp:close(S); {error,E3} - when E3 =:= einval; E3 =:= eperm; E3 =:= eprotonosupport -> + when E3 =:= einval; E3 =:= eperm; + E3 =:= enoent; E3 =:= eprotonosupport -> ok catch error:badarg -> diff --git a/lib/kernel/test/init_SUITE.erl b/lib/kernel/test/init_SUITE.erl index 0fa97b585c..e85d50bd0c 100644 --- a/lib/kernel/test/init_SUITE.erl +++ b/lib/kernel/test/init_SUITE.erl @@ -249,7 +249,8 @@ boot_var(Config) when is_list(Config) -> {ok, Node} = start_node(init_test, "-boot " ++ BootScript ++ - " -boot_var TEST_VAR " ++ TEST_VAR), + " -boot_var TEST_VAR \"" ++ + TEST_VAR ++ "\""), stop_node(Node), Res = ok; _ -> |