1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 1997-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: -module(slave_SUITE). 20: 21: -include_lib("test_server/include/test_server.hrl"). 22: 23: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 24: init_per_group/2,end_per_group/2, t_start/1, t_start_link/1, 25: start_link_nodedown/1, errors/1]). 26: 27: %% Internal exports. 28: -export([fun_init/1, test_errors/1]). 29: -export([timeout_test/1, auth_test/1, rsh_test/1, start_a_slave/3]). 30: 31: suite() -> [{ct_hooks,[ts_install_cth]}]. 32: 33: all() -> 34: [t_start_link, start_link_nodedown, t_start, errors]. 35: 36: groups() -> 37: []. 38: 39: init_per_suite(Config) -> 40: Config. 41: 42: end_per_suite(_Config) -> 43: ok. 44: 45: init_per_group(_GroupName, Config) -> 46: Config. 47: 48: end_per_group(_GroupName, Config) -> 49: Config. 50: 51: 52: t_start_link(suite) -> []; 53: t_start_link(Config) when is_list(Config) -> 54: ?line Dog = test_server:timetrap(test_server:seconds(20)), 55: 56: %% Define useful variables. 57: 58: ?line Host = host(), 59: ?line Slave1 = node_name(Host, slave1), 60: ?line Slave2 = node_name(Host, slave2), 61: 62: %% Test slave:start_link() with one, two, and three arguments. 63: 64: ?line ThisNode = node(), 65: ?line {error, {already_running, ThisNode}} = slave:start_link(Host), 66: ?line {ok, Slave1} = slave:start_link(Host, slave1), 67: ?line {ok, Slave2} = slave:start_link(Host, slave2, "-my_option 42"), 68: ?line {ok, [["42"]]} = rpc:call(Slave2, init, get_argument, [my_option]), 69: 70: %% Kill the two slave nodes and verify that they are dead. 71: 72: ?line rpc:cast(Slave1, erlang, halt, []), 73: ?line rpc:cast(Slave2, erlang, halt, []), 74: ?line is_dead(Slave1), 75: ?line is_dead(Slave2), 76: 77: %% Start two slave nodes from another process and verify that 78: %% the slaves die when that process terminates. 79: 80: Parent = self(), 81: Pid = fun_spawn(fun () -> 82: {ok, Slave1} = slave:start_link(Host, slave1), 83: {ok, Slave2} = slave:start_link(Host, slave2), 84: Parent ! slaves_started, 85: receive never -> ok end 86: end), 87: ?line receive slaves_started -> ok end, 88: ?line process_flag(trap_exit, true), 89: ?line wait_alive(Slave1), 90: ?line wait_alive(Slave2), 91: ?line exit(Pid, kill), 92: ?line receive {'EXIT', Pid, killed} -> ok end, 93: ?line test_server:sleep(250), 94: ?line is_dead(Slave1), 95: ?line is_dead(Slave2), 96: 97: ?line test_server:timetrap_cancel(Dog), 98: ok. 99: 100: %% Test that slave:start_link() works when the master exits. 101: 102: start_link_nodedown(suite) -> []; 103: start_link_nodedown(Config) when is_list(Config) -> 104: ?line Dog = test_server:timetrap(test_server:seconds(20)), 105: 106: %% Define useful variables. 107: 108: ?line Host = host(), 109: ?line Master = node_name(Host, my_master), 110: ?line Slave = node_name(Host, my_slave), 111: 112: ?line Pa = "-pa " ++ filename:dirname(code:which(?MODULE)), 113: ?line {ok, Master} = slave:start_link(Host, my_master, Pa), 114: ?line spawn(Master, ?MODULE, start_a_slave, [self(), Host, my_slave]), 115: ?line {reply, {ok, _Node}} = receive Any -> Any end, 116: 117: ?line rpc:call(Master, erlang, halt, []), 118: ?line receive after 200 -> ok end, 119: ?line pang = net_adm:ping(Slave), 120: 121: ?line test_server:timetrap_cancel(Dog), 122: ok. 123: 124: start_a_slave(ReplyTo, Host, Name) -> 125: ReplyTo ! {reply, slave:start_link(Host, Name)}, 126: receive never -> ok end. 127: 128: %% Test slave:start(). 129: 130: t_start(suite) -> []; 131: t_start(Config) when is_list(Config) -> 132: ?line Dog = test_server:timetrap(test_server:seconds(20)), 133: 134: %% Define useful variables. 135: 136: ?line Host = host(), 137: ?line Slave1 = node_name(Host, slave1), 138: ?line Slave2 = node_name(Host, slave2), 139: 140: %% By running all tests from this master node which is linked 141: %% to this test case, we ensure that all slaves are killed 142: %% if this test case fails. (If they are not, and therefore further 143: %% test cases fail, there is a bug in slave.) 144: 145: ?line {ok, Master} = slave:start_link(Host, master), 146: 147: %% Test slave:start() with one, two, and three arguments. 148: 149: ?line ThisNode = node(), 150: ?line {error, {already_running, ThisNode}} = slave:start(Host), 151: ?line {ok, Slave1} = rpc:call(Master, slave, start, [Host, slave1]), 152: ?line {ok, Slave2} = rpc:call(Master, slave, start, 153: [Host, slave2, "-my_option 42"]), 154: ?line {ok, [["42"]]} = rpc:call(Slave2, init, get_argument, [my_option]), 155: 156: %% Test that a slave terminates when its master node terminates. 157: 158: ?line ok = slave:stop(Slave2), 159: ?line is_dead(Slave2), 160: ?line {ok, Slave2} = rpc:call(Slave1, slave, start, [Host, slave2]), 161: ?line is_alive(Slave2), 162: ?line rpc:call(Slave1, erlang, halt, []), % Kill master. 163: receive after 1000 -> ok end, % Make sure slaves have noticed 164: % their dead master. 165: ?line is_dead(Slave1), 166: ?line is_dead(Slave2), % Slave should be dead, too. 167: 168: %% Kill all slaves and verify that they are dead. 169: 170: ?line ok = slave:stop(Slave1), 171: ?line ok = slave:stop(Slave2), 172: ?line is_dead(Slave1), 173: ?line is_dead(Slave2), 174: 175: ?line test_server:timetrap_cancel(Dog), 176: ok. 177: 178: %% Test the various error conditions in parallell (since the timeout 179: %% in slave is 32 seconds). 180: 181: errors(suite) -> []; 182: errors(Config) when is_list(Config) -> 183: ?line Dog = test_server:timetrap(test_server:seconds(50)), 184: 185: ?line process_flag(trap_exit, true), 186: ?line Pa = filename:dirname(code:which(?MODULE)), 187: ?line {ok, Master} = slave_start_link(host(), master, 188: "-rsh no_rsh_program -pa "++Pa++ 189: " -env ERL_CRASH_DUMP erl_crash_dump.master"), 190: ?line Pids = rpc:call(Master, ?MODULE, test_errors, [self()]), 191: ?line wait_for_result(Pids), 192: 193: ?line test_server:timetrap_cancel(Dog), 194: ok. 195: 196: wait_for_result([]) -> 197: ok; 198: wait_for_result(Pids) -> 199: ?line receive 200: {'EXIT', Pid, normal} -> 201: io:format("Process ~p terminated", [Pid]), 202: wait_for_result(lists:delete(Pid, Pids)); 203: {'EXIT', _, Reason} -> 204: exit(Reason) 205: end. 206: 207: show_process_info(Pid) -> 208: io:format("~p: ~p", [Pid, catch process_info(Pid, initial_call)]). 209: 210: test_errors(ResultTo) -> 211: %% Sigh! We use ordinary spawn instead of fun_spawn/1 to be able 212: %% identify the processes by their initial call. 213: ?line P1 = spawn(?MODULE, timeout_test, [ResultTo]), 214: ?line P2 = spawn(?MODULE, auth_test, [ResultTo]), 215: ?line P3 = spawn(?MODULE, rsh_test, [ResultTo]), 216: Pids =[P1, P2, P3], 217: ?line lists:foreach(fun show_process_info/1, Pids), 218: Pids. 219: 220: timeout_test(ResultTo) -> 221: link(ResultTo), 222: ?line {error, timeout} = slave:start(host(), slave1, "-boot no_boot_script"). 223: 224: auth_test(ResultTo) -> 225: link(ResultTo), 226: ?line {error, timeout} = slave:start(host(), slave2, 227: "-setcookie definitely_not_a_cookie"). 228: 229: rsh_test(ResultTo) -> 230: link(ResultTo), 231: ?line {error, no_rsh} = slave:start(super, slave3). 232: 233: 234: %%% Utilities. 235: 236: 237: wait_alive(Node) -> 238: wait_alive_1(10, Node). 239: 240: wait_alive_1(0, Node) -> 241: ?t:fail({still_not_alive,Node}); 242: wait_alive_1(N, Node) -> 243: case rpc:call(Node, init, get_status, []) of 244: {started,_} -> 245: ok; 246: {starting,_} -> 247: receive after 1 -> ok end, 248: wait_alive_1(N-1, Node) 249: end. 250: 251: is_alive(Node) -> 252: {started, _} = rpc:call(Node, init, get_status, []). 253: 254: is_dead(Node) -> 255: {badrpc, nodedown} = rpc:call(Node, init, get_status, []). 256: 257: node_name(Host, Name) -> 258: list_to_atom(lists:concat([Name, "@", Host])). 259: 260: host() -> 261: from($@, atom_to_list(node())). 262: 263: from(H, [H | T]) -> T; 264: from(H, [_ | T]) -> from(H, T); 265: from(_H, []) -> []. 266: 267: slave_start_link(Host, Name, Args) -> 268: case slave:start_link(Host, Name, Args) of 269: {ok, Node} -> 270: {ok, Node}; 271: Other -> 272: io:format("slave:start_link(~p, ~p, ~p) -> ~p", 273: [Host, Name, Args, Other]) 274: end. 275: 276: fun_spawn(Fun) -> 277: spawn_link(?MODULE, fun_init, [Fun]). 278: 279: fun_init(Fun) -> 280: Fun().