1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 2007-2011. All Rights Reserved. 5: %% 6: %% The contents of this file are subject to the Erlang Public License, 7: %% Version 1.1, (the "License"); you may not use this file except in 8: %% compliance with the License. You should have received a copy of the 9: %% Erlang Public License along with this software. If not, it can be 10: %% retrieved online at http://www.erlang.org/. 11: %% 12: %% Software distributed under the License is distributed on an "AS IS" 13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 14: %% the License for the specific language governing rights and limitations 15: %% under the License. 16: %% 17: %% %CopyrightEnd% 18: %% 19: 20: %%%------------------------------------------------------------------- 21: %%% File : erlexec_SUITE.erl 22: %%% Author : Rickard Green <rickard.s.green@ericsson.com> 23: %%% Description : Test erlexec's command line parsing 24: %%% 25: %%% Created : 22 May 2007 by Rickard Green <rickard.s.green@ericsson.com> 26: %%%------------------------------------------------------------------- 27: -module(erlexec_SUITE). 28: 29: 30: %-define(line_trace, 1). 31: 32: -define(DEFAULT_TIMEOUT, ?t:minutes(1)). 33: 34: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 35: init_per_group/2,end_per_group/2, 36: init_per_testcase/2, end_per_testcase/2]). 37: 38: -export([args_file/1, evil_args_file/1, env/1, args_file_env/1, otp_7461/1, otp_7461_remote/1, otp_8209/1, zdbbl_dist_buf_busy_limit/1]). 39: 40: -include_lib("test_server/include/test_server.hrl"). 41: 42: 43: init_per_testcase(Case, Config) -> 44: Dog = ?t:timetrap(?DEFAULT_TIMEOUT), 45: SavedEnv = save_env(), 46: [{testcase, Case}, {watchdog, Dog}, {erl_flags_env, SavedEnv} |Config]. 47: 48: end_per_testcase(_Case, Config) -> 49: Dog = ?config(watchdog, Config), 50: SavedEnv = ?config(erl_flags_env, Config), 51: restore_env(SavedEnv), 52: cleanup_nodes(), 53: ?t:timetrap_cancel(Dog), 54: ok. 55: 56: suite() -> [{ct_hooks,[ts_install_cth]}]. 57: 58: all() -> 59: [args_file, evil_args_file, env, args_file_env, 60: otp_7461, otp_8209, zdbbl_dist_buf_busy_limit]. 61: 62: groups() -> 63: []. 64: 65: init_per_suite(Config) -> 66: Config. 67: 68: end_per_suite(_Config) -> 69: ok. 70: 71: init_per_group(_GroupName, Config) -> 72: Config. 73: 74: end_per_group(_GroupName, Config) -> 75: Config. 76: 77: otp_8209(doc) -> 78: ["Test that plain first argument does not " 79: "destroy -home switch [OTP-8209]"]; 80: otp_8209(suite) -> 81: []; 82: otp_8209(Config) when is_list(Config) -> 83: ?line {ok,[[PName]]} = init:get_argument(progname), 84: ?line SNameS = "erlexec_test_01", 85: ?line SName = list_to_atom(SNameS++"@"++ 86: hd(tl(string:tokens(atom_to_list(node()),"@")))), 87: ?line Cmd = PName ++ " dummy_param -sname "++SNameS++" -setcookie "++ 88: atom_to_list(erlang:get_cookie()), 89: ?line open_port({spawn,Cmd},[]), 90: ?line pong = loop_ping(SName,40), 91: ?line {ok,[[_]]} = rpc:call(SName,init,get_argument,[home]), 92: ?line ["dummy_param"] = rpc:call(SName,init,get_plain_arguments,[]), 93: ?line ok = cleanup_nodes(), 94: ok. 95: 96: cleanup_nodes() -> 97: cleanup_node("erlexec_test_01",20). 98: cleanup_node(SNameS,0) -> 99: {error, {would_not_die,list_to_atom(SNameS)}}; 100: cleanup_node(SNameS,N) -> 101: SName = list_to_atom(SNameS++"@"++ 102: hd(tl(string:tokens(atom_to_list(node()),"@")))), 103: case rpc:call(SName,init,stop,[]) of 104: {badrpc,_} -> 105: ok; 106: ok -> 107: receive after 500 -> ok end, 108: cleanup_node(SNameS,N-1) 109: end. 110: 111: loop_ping(_,0) -> 112: pang; 113: loop_ping(Node,N) -> 114: case net_adm:ping(Node) of 115: pang -> 116: receive 117: after 500 -> 118: ok 119: end, 120: loop_ping(Node, N-1); 121: pong -> 122: pong 123: end. 124: 125: args_file(doc) -> []; 126: args_file(suite) -> []; 127: args_file(Config) when is_list(Config) -> 128: ?line AFN1 = privfile("1", Config), 129: ?line AFN2 = privfile("2", Config), 130: ?line AFN3 = privfile("3", Config), 131: ?line AFN4 = privfile("4", Config), 132: ?line AFN5 = privfile("5", Config), 133: ?line AFN6 = privfile("6", Config), 134: ?line write_file(AFN1, 135: "-MiscArg2~n" 136: "# a comment +\\#1000~n" 137: "+\\#200 # another comment~n" 138: "~n" 139: "# another config file to read~n" 140: " -args_file ~s#acomment~n" 141: "~n" 142: "-MiscArg7~n" 143: "#~n" 144: "+\\#700~n" 145: "-extra +XtraArg6~n", 146: [AFN2]), 147: ?line write_file(AFN2, 148: "-MiscArg3~n" 149: "+\\#300~n" 150: "-args_file ~s~n" 151: "-MiscArg5~n" 152: "+\\#500#anothercomment -MiscArg10~n" 153: "-args_file ~s~n" 154: "-args_file ~s~n" 155: "-args_file ~s~n" 156: "-extra +XtraArg5~n", 157: [AFN3, AFN4, AFN5, AFN6]), 158: ?line write_file(AFN3, 159: "# comment again~n" 160: " -MiscArg4 +\\#400 -extra +XtraArg1"), 161: ?line write_file(AFN4, 162: " -MiscArg6 +\\#600 -extra +XtraArg2~n" 163: "+XtraArg3~n" 164: "+XtraArg4~n" 165: "# comment again~n"), 166: ?line write_file(AFN5, ""), 167: ?line write_file(AFN6, "-extra # +XtraArg10~n"), 168: ?line CmdLine = "+#100 -MiscArg1 " 169: ++ "-args_file " ++ AFN1 170: ++ " +#800 -MiscArg8 -extra +XtraArg7 +XtraArg8", 171: ?line {Emu, Misc, Extra} = emu_args(CmdLine), 172: ?line verify_args(["-#100", "-#200", "-#300", "-#400", 173: "-#500", "-#600", "-#700", "-#800"], Emu), 174: ?line verify_args(["-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4", 175: "-MiscArg5", "-MiscArg6", "-MiscArg7", "-MiscArg8"], 176: Misc), 177: ?line verify_args(["+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", 178: "+XtraArg5", "+XtraArg6", "+XtraArg7", "+XtraArg8"], 179: Extra), 180: ?line verify_not_args(["-MiscArg10", "-#1000", "+XtraArg10", 181: "-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4", 182: "-MiscArg5", "-MiscArg6", "-MiscArg7", "-MiscArg8", 183: "+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", 184: "+XtraArg5", "+XtraArg6", "+XtraArg7", "+XtraArg8"], 185: Emu), 186: ?line verify_not_args(["-MiscArg10", "-#1000", "+XtraArg10", 187: "-#100", "-#200", "-#300", "-#400", 188: "-#500", "-#600", "-#700", "-#800", 189: "+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", 190: "+XtraArg5", "+XtraArg6", "+XtraArg7", "+XtraArg8"], 191: Misc), 192: ?line verify_not_args(["-MiscArg10", "-#1000", "+XtraArg10", 193: "-#100", "-#200", "-#300", "-#400", 194: "-#500", "-#600", "-#700", "-#800", 195: "-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4", 196: "-MiscArg5", "-MiscArg6", "-MiscArg7", "-MiscArg8"], 197: Extra), 198: ?line ok. 199: 200: evil_args_file(doc) -> []; 201: evil_args_file(suite) -> []; 202: evil_args_file(Config) when is_list(Config) -> 203: ?line Lim = 300, 204: ?line FNums = lists:seq(1, Lim), 205: lists:foreach(fun (End) when End == Lim -> 206: ?line AFN = privfile(integer_to_list(End), Config), 207: ?line write_file(AFN, 208: "-MiscArg~p ", 209: [End]); 210: (I) -> 211: ?line AFNX = privfile(integer_to_list(I), Config), 212: ?line AFNY = privfile(integer_to_list(I+1), Config), 213: {Frmt, Args} = 214: case I rem 2 of 215: 0 -> 216: {"-MiscArg~p -args_file ~s -MiscArg~p", 217: [I, AFNY, I]}; 218: _ -> 219: {"-MiscArg~p -args_file ~s", 220: [I, AFNY]} 221: end, 222: ?line write_file(AFNX, Frmt, Args) 223: end, 224: FNums), 225: ?line {_Emu, Misc, _Extra} = emu_args("-args_file " 226: ++ privfile("1", Config)), 227: ?line ANums = FNums 228: ++ lists:reverse(lists:filter(fun (I) when I == Lim -> false; 229: (I) when I rem 2 == 0 -> true; 230: (_) -> false 231: end, FNums)), 232: ?line verify_args(lists:map(fun (I) -> "-MiscArg"++integer_to_list(I) end, 233: ANums), 234: Misc), 235: ?line ok. 236: 237: 238: 239: env(doc) -> []; 240: env(suite) -> []; 241: env(Config) when is_list(Config) -> 242: ?line os:putenv("ERL_AFLAGS", "-MiscArg1 +#100 -extra +XtraArg1 +XtraArg2"), 243: ?line CmdLine = "+#200 -MiscArg2 -extra +XtraArg3 +XtraArg4", 244: ?line os:putenv("ERL_FLAGS", "-MiscArg3 +#300 -extra +XtraArg5"), 245: ?line os:putenv("ERL_ZFLAGS", "-MiscArg4 +#400 -extra +XtraArg6"), 246: ?line {Emu, Misc, Extra} = emu_args(CmdLine), 247: ?line verify_args(["-#100", "-#200", "-#300", "-#400"], Emu), 248: ?line verify_args(["-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4"], 249: Misc), 250: ?line verify_args(["+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", 251: "+XtraArg5", "+XtraArg6"], 252: Extra), 253: ?line ok. 254: 255: args_file_env(doc) -> []; 256: args_file_env(suite) -> []; 257: args_file_env(Config) when is_list(Config) -> 258: ?line AFN1 = privfile("1", Config), 259: ?line AFN2 = privfile("2", Config), 260: ?line write_file(AFN1, "-MiscArg2 +\\#200 -extra +XtraArg1"), 261: ?line write_file(AFN2, "-MiscArg3 +\\#400 -extra +XtraArg3"), 262: ?line os:putenv("ERL_AFLAGS", 263: "-MiscArg1 +#100 -args_file "++AFN1++ " -extra +XtraArg2"), 264: ?line CmdLine = "+#300 -args_file "++AFN2++" -MiscArg4 -extra +XtraArg4", 265: ?line os:putenv("ERL_FLAGS", "-MiscArg5 +#500 -extra +XtraArg5"), 266: ?line os:putenv("ERL_ZFLAGS", "-MiscArg6 +#600 -extra +XtraArg6"), 267: ?line {Emu, Misc, Extra} = emu_args(CmdLine), 268: ?line verify_args(["-#100", "-#200", "-#300", "-#400", 269: "-#500", "-#600"], Emu), 270: ?line verify_args(["-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4", 271: "-MiscArg5", "-MiscArg6"], 272: Misc), 273: ?line verify_args(["+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", 274: "+XtraArg5", "+XtraArg6"], 275: Extra), 276: ?line ok. 277: 278: %% Make sure "erl -detached" survives when parent process group gets killed 279: otp_7461(doc) -> []; 280: otp_7461(suite) -> []; 281: otp_7461(Config) when is_list(Config) -> 282: case os:type() of 283: {unix,_} -> 284: {NetStarted, _} = net_kernel:start([test_server, shortnames]), 285: try 286: net_kernel:monitor_nodes(true), 287: register(otp_7461, self()), 288: 289: otp_7461_do(Config) 290: after 291: catch unregister(otp_7461), 292: catch net_kernel:monitor_nodes(false), 293: case NetStarted of 294: ok -> net_kernel:stop(); 295: _ -> ok 296: end 297: end; 298: _ -> 299: {skip,"Only on Unix."} 300: end. 301: 302: otp_7461_do(Config) -> 303: io:format("alive=~p node=~p\n",[is_alive(), node()]), 304: TestProg = filename:join([?config(data_dir, Config), "erlexec_tests"]), 305: {ok, [[ErlProg]]} = init:get_argument(progname), 306: ?line Cmd = TestProg ++ " " ++ ErlProg ++ 307: " -detached -sname " ++ get_nodename(otp_7461) ++ 308: " -setcookie " ++ atom_to_list(erlang:get_cookie()) ++ 309: " -pa " ++ filename:dirname(code:which(?MODULE)) ++ 310: " -s erlexec_SUITE otp_7461_remote init " ++ atom_to_list(node()), 311: 312: %% otp_7461 --------> erlexec_tests.c --------> cerl -detached 313: %% open_port fork+exec 314: 315: io:format("spawn port prog ~p\n",[Cmd]), 316: ?line Port = open_port({spawn, Cmd}, [eof]), 317: 318: io:format("Wait for node to connect...\n",[]), 319: ?line {nodeup, Slave} = receive Msg -> Msg 320: after 20*1000 -> timeout end, 321: io:format("Node alive: ~p\n", [Slave]), 322: 323: ?line pong = net_adm:ping(Slave), 324: io:format("Ping ok towards ~p\n", [Slave]), 325: 326: ?line Port ! { self(), {command, "K"}}, % Kill child process group 327: ?line {Port, {data, "K"}} = receive Msg2 -> Msg2 end, 328: ?line port_close(Port), 329: 330: %% Now the actual test. Detached node should still be alive. 331: ?line pong = net_adm:ping(Slave), 332: io:format("Ping still ok towards ~p\n", [Slave]), 333: 334: %% Halt node 335: ?line rpc:cast(Slave, ?MODULE, otp_7461_remote, [[halt, self()]]), 336: 337: ?line {nodedown, Slave} = receive Msg3 -> Msg3 338: after 20*1000 -> timeout end, 339: io:format("Node dead: ~p\n", [Slave]), 340: ok. 341: 342: 343: %% Executed on slave node 344: otp_7461_remote([init, Master]) -> 345: io:format("otp_7461_remote(init,~p) at ~p\n",[Master, node()]), 346: net_kernel:connect_node(Master); 347: otp_7461_remote([halt, Pid]) -> 348: io:format("halt order from ~p to node ~p\n",[Pid,node()]), 349: halt(). 350: 351: zdbbl_dist_buf_busy_limit(doc) -> 352: ["Check +zdbbl flag"]; 353: zdbbl_dist_buf_busy_limit(suite) -> 354: []; 355: zdbbl_dist_buf_busy_limit(Config) when is_list(Config) -> 356: LimKB = 1122233, 357: LimB = LimKB*1024, 358: ?line {ok,[[PName]]} = init:get_argument(progname), 359: ?line SNameS = "erlexec_test_02", 360: ?line SName = list_to_atom(SNameS++"@"++ 361: hd(tl(string:tokens(atom_to_list(node()),"@")))), 362: ?line Cmd = PName ++ " -sname "++SNameS++" -setcookie "++ 363: atom_to_list(erlang:get_cookie()) ++ 364: " +zdbbl " ++ integer_to_list(LimKB), 365: ?line open_port({spawn,Cmd},[]), 366: ?line pong = loop_ping(SName,40), 367: ?line LimB = rpc:call(SName,erlang,system_info,[dist_buf_busy_limit]), 368: ?line ok = cleanup_node(SNameS, 10), 369: ok. 370: 371: 372: %% 373: %% Utils 374: %% 375: 376: save_env() -> 377: {erl_flags, 378: os:getenv("ERL_AFLAGS"), 379: os:getenv("ERL_FLAGS"), 380: os:getenv("ERL_"++erlang:system_info(otp_release)++"_FLAGS"), 381: os:getenv("ERL_ZFLAGS")}. 382: 383: restore_env(EVar, false) when is_list(EVar) -> 384: restore_env(EVar, ""); 385: restore_env(EVar, "") when is_list(EVar) -> 386: case os:getenv(EVar) of 387: false -> ok; 388: "" -> ok; 389: " " -> ok; 390: _ -> os:putenv(EVar, " ") 391: end; 392: restore_env(EVar, Value) when is_list(EVar), is_list(Value) -> 393: case os:getenv(EVar) of 394: Value -> ok; 395: _ -> os:putenv(EVar, Value) 396: end. 397: 398: restore_env({erl_flags, AFlgs, Flgs, RFlgs, ZFlgs}) -> 399: restore_env("ERL_AFLAGS", AFlgs), 400: restore_env("ERL_FLAGS", Flgs), 401: restore_env("ERL_"++erlang:system_info(otp_release)++"_FLAGS", RFlgs), 402: restore_env("ERL_ZFLAGS", ZFlgs), 403: ok. 404: 405: privfile(Name, Config) -> 406: filename:join([?config(priv_dir, Config), 407: atom_to_list(?config(testcase, Config)) ++ "." ++ Name]). 408: 409: write_file(FileName, Frmt) -> 410: write_file(FileName, Frmt, []). 411: 412: write_file(FileName, Frmt, Args) -> 413: {ok, File} = file:open(FileName, [write]), 414: io:format(File, Frmt, Args), 415: ok = file:close(File). 416: 417: verify_args([], _Ys) -> 418: ok; 419: verify_args(Xs, []) -> 420: exit({args_not_found_in_order, Xs}); 421: verify_args([X|Xs], [X|Ys]) -> 422: verify_args(Xs, Ys); 423: verify_args(Xs, [_Y|Ys]) -> 424: verify_args(Xs, Ys). 425: 426: verify_not_args(Xs, Ys) -> 427: lists:foreach(fun (X) -> 428: case lists:member(X, Ys) of 429: true -> exit({arg_present, X}); 430: false -> ok 431: end 432: end, 433: Xs). 434: 435: emu_args(CmdLineArgs) -> 436: io:format("CmdLineArgs = ~s~n", [CmdLineArgs]), 437: {ok,[[Erl]]} = init:get_argument(progname), 438: EmuCL = os:cmd(Erl ++ " -emu_args_exit " ++ CmdLineArgs), 439: io:format("EmuCL = ~s", [EmuCL]), 440: split_emu_clt(string:tokens(EmuCL, [$ ,$\t,$\n,$\r])). 441: 442: split_emu_clt(EmuCLT) -> 443: split_emu_clt(EmuCLT, [], [], [], emu). 444: 445: split_emu_clt([], _Emu, _Misc, _Extra, emu) -> 446: exit(bad_cmd_line); 447: split_emu_clt([], Emu, Misc, Extra, _Type) -> 448: {lists:reverse(Emu), lists:reverse(Misc), lists:reverse(Extra)}; 449: 450: split_emu_clt(["--"|As], Emu, Misc, Extra, emu) -> 451: split_emu_clt(As, Emu, Misc, Extra, misc); 452: split_emu_clt([A|As], Emu, Misc, Extra, emu = Type) -> 453: split_emu_clt(As, [A|Emu], Misc, Extra, Type); 454: 455: split_emu_clt(["-extra"|As], Emu, Misc, Extra, misc) -> 456: split_emu_clt(As, Emu, Misc, Extra, extra); 457: split_emu_clt([A|As], Emu, Misc, Extra, misc = Type) -> 458: split_emu_clt(As, Emu, [A|Misc], Extra, Type); 459: 460: split_emu_clt([A|As], Emu, Misc, Extra, extra = Type) -> 461: split_emu_clt(As, Emu, Misc, [A|Extra], Type). 462: 463: 464: get_nodename(T) -> 465: {A, B, C} = now(), 466: atom_to_list(T) 467: ++ "-" 468: ++ atom_to_list(?MODULE) 469: ++ "-" 470: ++ integer_to_list(A) 471: ++ "-" 472: ++ integer_to_list(B) 473: ++ "-" 474: ++ integer_to_list(C).