diff options
Diffstat (limited to 'erts/test/erlexec_SUITE.erl')
-rw-r--r-- | erts/test/erlexec_SUITE.erl | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/erts/test/erlexec_SUITE.erl b/erts/test/erlexec_SUITE.erl new file mode 100644 index 0000000000..fcf1e67e9e --- /dev/null +++ b/erts/test/erlexec_SUITE.erl @@ -0,0 +1,437 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2007-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%%%------------------------------------------------------------------- +%%% File : erlexec_SUITE.erl +%%% Author : Rickard Green <[email protected]> +%%% Description : Test erlexec's command line parsing +%%% +%%% Created : 22 May 2007 by Rickard Green <[email protected]> +%%%------------------------------------------------------------------- +-module(erlexec_SUITE). + + +%-define(line_trace, 1). + +-define(DEFAULT_TIMEOUT, ?t:minutes(1)). + +-export([all/1, init_per_testcase/2, fin_per_testcase/2]). + +-export([args_file/1, evil_args_file/1, env/1, args_file_env/1, otp_7461/1, otp_7461_remote/1, otp_8209/1]). + +-include("test_server.hrl"). + + +init_per_testcase(Case, Config) -> + Dog = ?t:timetrap(?DEFAULT_TIMEOUT), + SavedEnv = save_env(), + [{testcase, Case}, {watchdog, Dog}, {erl_flags_env, SavedEnv} |Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + SavedEnv = ?config(erl_flags_env, Config), + restore_env(SavedEnv), + cleanup_nodes(), + ?t:timetrap_cancel(Dog), + ok. + +all(doc) -> []; +all(suite) -> + [args_file, evil_args_file, env, args_file_env, otp_7461, otp_8209]. + + +otp_8209(doc) -> + ["Test that plain first argument does not " + "destroy -home switch [OTP-8209]"]; +otp_8209(suite) -> + []; +otp_8209(Config) when is_list(Config) -> + ?line {ok,[[PName]]} = init:get_argument(progname), + ?line SNameS = "erlexec_test_01", + ?line SName = list_to_atom(SNameS++"@"++ + hd(tl(string:tokens(atom_to_list(node()),"@")))), + ?line Cmd = PName ++ " dummy_param -sname "++SNameS++" -setcookie "++ + atom_to_list(erlang:get_cookie()), + ?line open_port({spawn,Cmd},[]), + ?line pong = loop_ping(SName,40), + ?line {ok,[[_]]} = rpc:call(SName,init,get_argument,[home]), + ?line ["dummy_param"] = rpc:call(SName,init,get_plain_arguments,[]), + ?line ok = cleanup_nodes(), + ok. + +cleanup_nodes() -> + cleanup_node("erlexec_test_01",20). +cleanup_node(SNameS,0) -> + {error, {would_not_die,list_to_atom(SNameS)}}; +cleanup_node(SNameS,N) -> + SName = list_to_atom(SNameS++"@"++ + hd(tl(string:tokens(atom_to_list(node()),"@")))), + case rpc:call(SName,init,stop,[]) of + {badrpc,_} -> + ok; + ok -> + receive after 500 -> ok end, + cleanup_node(SNameS,N-1) + end. + +loop_ping(_,0) -> + pang; +loop_ping(Node,N) -> + case net_adm:ping(Node) of + pang -> + receive + after 500 -> + ok + end, + loop_ping(Node, N-1); + pong -> + pong + end. + +args_file(doc) -> []; +args_file(suite) -> []; +args_file(Config) when is_list(Config) -> + ?line AFN1 = privfile("1", Config), + ?line AFN2 = privfile("2", Config), + ?line AFN3 = privfile("3", Config), + ?line AFN4 = privfile("4", Config), + ?line AFN5 = privfile("5", Config), + ?line AFN6 = privfile("6", Config), + ?line write_file(AFN1, + "-MiscArg2~n" + "# a comment +\\#1000~n" + "+\\#200 # another comment~n" + "~n" + "# another config file to read~n" + " -args_file ~s#acomment~n" + "~n" + "-MiscArg7~n" + "#~n" + "+\\#700~n" + "-extra +XtraArg6~n", + [AFN2]), + ?line write_file(AFN2, + "-MiscArg3~n" + "+\\#300~n" + "-args_file ~s~n" + "-MiscArg5~n" + "+\\#500#anothercomment -MiscArg10~n" + "-args_file ~s~n" + "-args_file ~s~n" + "-args_file ~s~n" + "-extra +XtraArg5~n", + [AFN3, AFN4, AFN5, AFN6]), + ?line write_file(AFN3, + "# comment again~n" + " -MiscArg4 +\\#400 -extra +XtraArg1"), + ?line write_file(AFN4, + " -MiscArg6 +\\#600 -extra +XtraArg2~n" + "+XtraArg3~n" + "+XtraArg4~n" + "# comment again~n"), + ?line write_file(AFN5, ""), + ?line write_file(AFN6, "-extra # +XtraArg10~n"), + ?line CmdLine = "+#100 -MiscArg1 " + ++ "-args_file " ++ AFN1 + ++ " +#800 -MiscArg8 -extra +XtraArg7 +XtraArg8", + ?line {Emu, Misc, Extra} = emu_args(CmdLine), + ?line verify_args(["-#100", "-#200", "-#300", "-#400", + "-#500", "-#600", "-#700", "-#800"], Emu), + ?line verify_args(["-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4", + "-MiscArg5", "-MiscArg6", "-MiscArg7", "-MiscArg8"], + Misc), + ?line verify_args(["+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", + "+XtraArg5", "+XtraArg6", "+XtraArg7", "+XtraArg8"], + Extra), + ?line verify_not_args(["-MiscArg10", "-#1000", "+XtraArg10", + "-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4", + "-MiscArg5", "-MiscArg6", "-MiscArg7", "-MiscArg8", + "+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", + "+XtraArg5", "+XtraArg6", "+XtraArg7", "+XtraArg8"], + Emu), + ?line verify_not_args(["-MiscArg10", "-#1000", "+XtraArg10", + "-#100", "-#200", "-#300", "-#400", + "-#500", "-#600", "-#700", "-#800", + "+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", + "+XtraArg5", "+XtraArg6", "+XtraArg7", "+XtraArg8"], + Misc), + ?line verify_not_args(["-MiscArg10", "-#1000", "+XtraArg10", + "-#100", "-#200", "-#300", "-#400", + "-#500", "-#600", "-#700", "-#800", + "-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4", + "-MiscArg5", "-MiscArg6", "-MiscArg7", "-MiscArg8"], + Extra), + ?line ok. + +evil_args_file(doc) -> []; +evil_args_file(suite) -> []; +evil_args_file(Config) when is_list(Config) -> + ?line Lim = 300, + ?line FNums = lists:seq(1, Lim), + lists:foreach(fun (End) when End == Lim -> + ?line AFN = privfile(integer_to_list(End), Config), + ?line write_file(AFN, + "-MiscArg~p ", + [End]); + (I) -> + ?line AFNX = privfile(integer_to_list(I), Config), + ?line AFNY = privfile(integer_to_list(I+1), Config), + {Frmt, Args} = + case I rem 2 of + 0 -> + {"-MiscArg~p -args_file ~s -MiscArg~p", + [I, AFNY, I]}; + _ -> + {"-MiscArg~p -args_file ~s", + [I, AFNY]} + end, + ?line write_file(AFNX, Frmt, Args) + end, + FNums), + ?line {_Emu, Misc, _Extra} = emu_args("-args_file " + ++ privfile("1", Config)), + ?line ANums = FNums + ++ lists:reverse(lists:filter(fun (I) when I == Lim -> false; + (I) when I rem 2 == 0 -> true; + (_) -> false + end, FNums)), + ?line verify_args(lists:map(fun (I) -> "-MiscArg"++integer_to_list(I) end, + ANums), + Misc), + ?line ok. + + + +env(doc) -> []; +env(suite) -> []; +env(Config) when is_list(Config) -> + ?line os:putenv("ERL_AFLAGS", "-MiscArg1 +#100 -extra +XtraArg1 +XtraArg2"), + ?line CmdLine = "+#200 -MiscArg2 -extra +XtraArg3 +XtraArg4", + ?line os:putenv("ERL_FLAGS", "-MiscArg3 +#300 -extra +XtraArg5"), + ?line os:putenv("ERL_ZFLAGS", "-MiscArg4 +#400 -extra +XtraArg6"), + ?line {Emu, Misc, Extra} = emu_args(CmdLine), + ?line verify_args(["-#100", "-#200", "-#300", "-#400"], Emu), + ?line verify_args(["-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4"], + Misc), + ?line verify_args(["+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", + "+XtraArg5", "+XtraArg6"], + Extra), + ?line ok. + +args_file_env(doc) -> []; +args_file_env(suite) -> []; +args_file_env(Config) when is_list(Config) -> + ?line AFN1 = privfile("1", Config), + ?line AFN2 = privfile("2", Config), + ?line write_file(AFN1, "-MiscArg2 +\\#200 -extra +XtraArg1"), + ?line write_file(AFN2, "-MiscArg3 +\\#400 -extra +XtraArg3"), + ?line os:putenv("ERL_AFLAGS", + "-MiscArg1 +#100 -args_file "++AFN1++ " -extra +XtraArg2"), + ?line CmdLine = "+#300 -args_file "++AFN2++" -MiscArg4 -extra +XtraArg4", + ?line os:putenv("ERL_FLAGS", "-MiscArg5 +#500 -extra +XtraArg5"), + ?line os:putenv("ERL_ZFLAGS", "-MiscArg6 +#600 -extra +XtraArg6"), + ?line {Emu, Misc, Extra} = emu_args(CmdLine), + ?line verify_args(["-#100", "-#200", "-#300", "-#400", + "-#500", "-#600"], Emu), + ?line verify_args(["-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4", + "-MiscArg5", "-MiscArg6"], + Misc), + ?line verify_args(["+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", + "+XtraArg5", "+XtraArg6"], + Extra), + ?line ok. + +%% Make sure "erl -detached" survives when parent process group gets killed +otp_7461(doc) -> []; +otp_7461(suite) -> []; +otp_7461(Config) when is_list(Config) -> + case os:type() of + {unix,_} -> + {NetStarted, _} = net_kernel:start([test_server, shortnames]), + try + net_kernel:monitor_nodes(true), + register(otp_7461, self()), + + otp_7461_do(Config) + after + catch unregister(otp_7461), + catch net_kernel:monitor_nodes(false), + case NetStarted of + ok -> net_kernel:stop(); + _ -> ok + end + end; + _ -> + {skip,"Only on Unix."} + end. + +otp_7461_do(Config) -> + io:format("alive=~p node=~p\n",[is_alive(), node()]), + TestProg = filename:join([?config(data_dir, Config), "erlexec_tests"]), + {ok, [[ErlProg]]} = init:get_argument(progname), + ?line Cmd = TestProg ++ " " ++ ErlProg ++ + " -detached -sname " ++ get_nodename(otp_7461) ++ + " -setcookie " ++ atom_to_list(erlang:get_cookie()) ++ + " -pa " ++ filename:dirname(code:which(?MODULE)) ++ + " -s erlexec_SUITE otp_7461_remote init " ++ atom_to_list(node()), + + %% otp_7461 --------> erlexec_tests.c --------> cerl -detached + %% open_port fork+exec + + io:format("spawn port prog ~p\n",[Cmd]), + ?line Port = open_port({spawn, Cmd}, [eof]), + + io:format("Wait for node to connect...\n",[]), + ?line {nodeup, Slave} = receive Msg -> Msg + after 20*1000 -> timeout end, + io:format("Node alive: ~p\n", [Slave]), + + ?line pong = net_adm:ping(Slave), + io:format("Ping ok towards ~p\n", [Slave]), + + ?line Port ! { self(), {command, "K"}}, % Kill child process group + ?line {Port, {data, "K"}} = receive Msg2 -> Msg2 end, + ?line port_close(Port), + + %% Now the actual test. Detached node should still be alive. + ?line pong = net_adm:ping(Slave), + io:format("Ping still ok towards ~p\n", [Slave]), + + %% Halt node + ?line rpc:cast(Slave, ?MODULE, otp_7461_remote, [[halt, self()]]), + + ?line {nodedown, Slave} = receive Msg3 -> Msg3 + after 20*1000 -> timeout end, + io:format("Node dead: ~p\n", [Slave]), + ok. + + +%% Executed on slave node +otp_7461_remote([init, Master]) -> + io:format("otp_7461_remote(init,~p) at ~p\n",[Master, node()]), + net_kernel:connect_node(Master); +otp_7461_remote([halt, Pid]) -> + io:format("halt order from ~p to node ~p\n",[Pid,node()]), + halt(). + + + +%% +%% Utils +%% + +save_env() -> + {erl_flags, + os:getenv("ERL_AFLAGS"), + os:getenv("ERL_FLAGS"), + os:getenv("ERL_"++erlang:system_info(otp_release)++"_FLAGS"), + os:getenv("ERL_ZFLAGS")}. + +restore_env(EVar, false) when is_list(EVar) -> + restore_env(EVar, ""); +restore_env(EVar, "") when is_list(EVar) -> + case os:getenv(EVar) of + false -> ok; + "" -> ok; + " " -> ok; + _ -> os:putenv(EVar, " ") + end; +restore_env(EVar, Value) when is_list(EVar), is_list(Value) -> + case os:getenv(EVar) of + Value -> ok; + _ -> os:putenv(EVar, Value) + end. + +restore_env({erl_flags, AFlgs, Flgs, RFlgs, ZFlgs}) -> + restore_env("ERL_AFLAGS", AFlgs), + restore_env("ERL_FLAGS", Flgs), + restore_env("ERL_"++erlang:system_info(otp_release)++"_FLAGS", RFlgs), + restore_env("ERL_ZFLAGS", ZFlgs), + ok. + +privfile(Name, Config) -> + filename:join([?config(priv_dir, Config), + atom_to_list(?config(testcase, Config)) ++ "." ++ Name]). + +write_file(FileName, Frmt) -> + write_file(FileName, Frmt, []). + +write_file(FileName, Frmt, Args) -> + {ok, File} = file:open(FileName, [write]), + io:format(File, Frmt, Args), + ok = file:close(File). + +verify_args([], _Ys) -> + ok; +verify_args(Xs, []) -> + exit({args_not_found_in_order, Xs}); +verify_args([X|Xs], [X|Ys]) -> + verify_args(Xs, Ys); +verify_args(Xs, [_Y|Ys]) -> + verify_args(Xs, Ys). + +verify_not_args(Xs, Ys) -> + lists:foreach(fun (X) -> + case lists:member(X, Ys) of + true -> exit({arg_present, X}); + false -> ok + end + end, + Xs). + +emu_args(CmdLineArgs) -> + io:format("CmdLineArgs = ~s~n", [CmdLineArgs]), + {ok,[[Erl]]} = init:get_argument(progname), + EmuCL = os:cmd(Erl ++ " -emu_args_exit " ++ CmdLineArgs), + io:format("EmuCL = ~s", [EmuCL]), + split_emu_clt(string:tokens(EmuCL, [$ ,$\t,$\n,$\r])). + +split_emu_clt(EmuCLT) -> + split_emu_clt(EmuCLT, [], [], [], emu). + +split_emu_clt([], _Emu, _Misc, _Extra, emu) -> + exit(bad_cmd_line); +split_emu_clt([], Emu, Misc, Extra, _Type) -> + {lists:reverse(Emu), lists:reverse(Misc), lists:reverse(Extra)}; + +split_emu_clt(["--"|As], Emu, Misc, Extra, emu) -> + split_emu_clt(As, Emu, Misc, Extra, misc); +split_emu_clt([A|As], Emu, Misc, Extra, emu = Type) -> + split_emu_clt(As, [A|Emu], Misc, Extra, Type); + +split_emu_clt(["-extra"|As], Emu, Misc, Extra, misc) -> + split_emu_clt(As, Emu, Misc, Extra, extra); +split_emu_clt([A|As], Emu, Misc, Extra, misc = Type) -> + split_emu_clt(As, Emu, [A|Misc], Extra, Type); + +split_emu_clt([A|As], Emu, Misc, Extra, extra = Type) -> + split_emu_clt(As, Emu, Misc, [A|Extra], Type). + + +get_nodename(T) -> + {A, B, C} = now(), + atom_to_list(T) + ++ "-" + ++ atom_to_list(?MODULE) + ++ "-" + ++ integer_to_list(A) + ++ "-" + ++ integer_to_list(B) + ++ "-" + ++ integer_to_list(C). |