diff options
Diffstat (limited to 'lib/kernel/test/erl_boot_server_SUITE.erl')
-rw-r--r-- | lib/kernel/test/erl_boot_server_SUITE.erl | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/lib/kernel/test/erl_boot_server_SUITE.erl b/lib/kernel/test/erl_boot_server_SUITE.erl new file mode 100644 index 0000000000..241d68fef4 --- /dev/null +++ b/lib/kernel/test/erl_boot_server_SUITE.erl @@ -0,0 +1,338 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-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% +%% +-module(erl_boot_server_SUITE). + +-include("test_server.hrl"). + +-export([all/1]). + +-export([start/1, start_link/1, stop/1, add/1, delete/1, responses/1]). + +%%----------------------------------------------------------------- +%% Test suite for erl_boot_server. +%% +%% This module is mainly tested in the erl_prim_loader_SUITE, +%% but the interface functions are tested here. +%% +%% Changed for the new erl_boot_server for R3A by Bjorn Gustavsson. +%%----------------------------------------------------------------- + +all(suite) -> + [start, start_link, stop, add, delete, responses]. + +-define(all_ones, {255, 255, 255, 255}). + +start(doc) -> "Tests the erl_boot_server:start/1 function."; +start(Config) when is_list(Config) -> + ?line Dog = test_server:timetrap(test_server:seconds(50)), + ?line [Host1, Host2|_] = good_hosts(Config), + + %% Bad arguments. + BadHost = "bad__host", + ?line {error, {badarg, {}}} = erl_boot_server:start({}), + ?line {error, {badarg, atom}} = erl_boot_server:start(atom), + ?line {error, {badarg, [atom, BadHost]}} = + erl_boot_server:start([atom, BadHost]), + ?line {error, {badarg, [Host1, BadHost]}} = + erl_boot_server:start([Host1, BadHost]), + + %% Test once. + ?line {ok, Pid1} = erl_boot_server:start([Host1]), + ?line {error, {already_started, Pid1}} = + erl_boot_server:start([Host1]), + ?line exit(Pid1, kill), + + %% Test again. + test_server:sleep(1), + ?line {ok, Pid2} = erl_boot_server:start([Host1, Host2]), + ?line {error, {already_started, Pid2}} = + erl_boot_server:start([Host1, Host2]), + ?line exit(Pid2, kill), + test_server:sleep(1), + + ?line test_server:timetrap_cancel(Dog), + ok. + +start_link(doc) -> "Tests the erl_boot_server:start_link/1 function."; +start_link(Config) when is_list(Config) -> + ?line Dog = test_server:timetrap(test_server:seconds(5)), + ?line [Host1, Host2|_] = good_hosts(Config), + + OldFlag = process_flag(trap_exit, true), + ?line {error, {badarg, {}}} = erl_boot_server:start_link({}), + ?line {error, {badarg, atom}} = erl_boot_server:start_link(atom), + ?line BadHost = "bad__host", + ?line {error, {badarg, [atom, BadHost]}} = + erl_boot_server:start_link([atom, BadHost]), + + ?line {ok, Pid1} = erl_boot_server:start_link([Host1]), + ?line {error, {already_started, Pid1}} = + erl_boot_server:start_link([Host1]), + ?line shutdown(Pid1), + + ?line {ok, Pid2} = erl_boot_server:start_link([Host1, Host2]), + ?line {error, {already_started, Pid2}} = + erl_boot_server:start_link([Host1, Host2]), + ?line shutdown(Pid2), + process_flag(trap_exit, OldFlag), + + ?line test_server:timetrap_cancel(Dog), + ok. + +stop(doc) -> "Tests that no processes are left if a boot server is killed."; +stop(Config) when is_list(Config) -> + ?line Dog = test_server:timetrap(test_server:seconds(50)), + ?line [Host1|_] = good_hosts(Config), + + %% Start a boot server and kill it. Make sure that any helper processes + %% dies. + % Make sure the inet_gethost_native server is already started, + % otherwise it will make this test fail: + ?line inet:getaddr(localhost, inet), + ?line Before = processes(), + ?line {ok, Pid} = erl_boot_server:start([Host1]), + ?line New = processes() -- [Pid|Before], + ?line exit(Pid, kill), + ?line receive after 100 -> ok end, + ?line case [P || P <- New, is_process_alive(P)] of + [] -> + ok; + NotKilled -> + test_server:fail({not_killed, NotKilled}) + end, + ?line test_server:timetrap_cancel(Dog), + ok. + +add(doc) -> "Tests the erl_boot_server:add/1 function."; +add(Config) when is_list(Config) -> + ?line Dog = test_server:timetrap(test_server:seconds(5)), + ?line OldFlag = process_flag(trap_exit, true), + ?line {ok, Pid1} = erl_boot_server:start_link([]), + ?line [] = erl_boot_server:which_slaves(), + ?line [Host1, Host2, Host3|_] = good_hosts(Config), + + %% Try bad values. + ?line {error, {badarg, {}}} = erl_boot_server:add_slave({}), + ?line {error, {badarg, [atom]}} = erl_boot_server:add_slave([atom]), + ?line BadHost = "bad__host", + ?line {error, {badarg, BadHost}} = erl_boot_server:add_slave(BadHost), + ?line [] = erl_boot_server:which_slaves(), + + %% Add good host names. + ?line {ok, Ip1} = inet:getaddr(Host1, inet), + ?line {ok, Ip2} = inet:getaddr(Host2, inet), + ?line {ok, Ip3} = inet:getaddr(Host3, inet), + ?line MIp1 = {?all_ones, Ip1}, + ?line MIp2 = {?all_ones, Ip2}, + ?line MIp3 = {?all_ones, Ip3}, + ?line ok = erl_boot_server:add_slave(Host1), + ?line [MIp1] = erl_boot_server:which_slaves(), + ?line ok = erl_boot_server:add_slave(Host2), + ?line M_Ip1_Ip2 = lists:sort([MIp1, MIp2]), + ?line M_Ip1_Ip2 = lists:sort(erl_boot_server:which_slaves()), + ?line ok = erl_boot_server:add_slave(Host3), + ?line M_Ip1_Ip2_Ip3 = lists:sort([MIp3|M_Ip1_Ip2]), + ?line M_Ip1_Ip2_Ip3 = erl_boot_server:which_slaves(), + + %% Add duplicate names. + ?line ok = erl_boot_server:add_slave(Host3), + ?line M_Ip1_Ip2_Ip3 = erl_boot_server:which_slaves(), + + %% More bad names. + ?line {error, {badarg, BadHost}} = erl_boot_server:add_slave(BadHost), + ?line M_Ip1_Ip2_Ip3 = erl_boot_server:which_slaves(), + + %% Cleanup. + ?line shutdown(Pid1), + ?line process_flag(trap_exit, OldFlag), + ?line test_server:timetrap_cancel(Dog), + ok. + +delete(doc) -> "Tests the erl_boot_server:delete/1 function."; +delete(Config) when is_list(Config) -> + ?line Dog = test_server:timetrap(test_server:seconds(5)), + ?line OldFlag = process_flag(trap_exit, true), + + ?line [Host1, Host2, Host3|_] = good_hosts(Config), + ?line {ok, Ip1} = inet:getaddr(Host1, inet), + ?line {ok, Ip2} = inet:getaddr(Host2, inet), + ?line {ok, Ip3} = inet:getaddr(Host3, inet), + ?line MIp1 = {?all_ones, Ip1}, + ?line MIp2 = {?all_ones, Ip2}, + ?line MIp3 = {?all_ones, Ip3}, + + ?line {ok, Pid1} = erl_boot_server:start_link([Host1, Host2, Host3]), + ?line M_Ip123 = lists:sort([MIp1, MIp2, MIp3]), + ?line M_Ip123 = erl_boot_server:which_slaves(), + + %% Do some bad attempts and check that the list of slaves is intact. + ?line {error, {badarg, {}}} = erl_boot_server:delete_slave({}), + ?line {error, {badarg, [atom]}} = erl_boot_server:delete_slave([atom]), + ?line BadHost = "bad__host", + ?line {error, {badarg, BadHost}} = erl_boot_server:delete_slave(BadHost), + ?line M_Ip123 = erl_boot_server:which_slaves(), + + %% Delete Host2 and make sure it's gone. + ?line ok = erl_boot_server:delete_slave(Host2), + ?line M_Ip13 = lists:sort([MIp1, MIp3]), + ?line M_Ip13 = erl_boot_server:which_slaves(), + + ?line ok = erl_boot_server:delete_slave(Host1), + ?line [MIp3] = erl_boot_server:which_slaves(), + ?line ok = erl_boot_server:delete_slave(Host1), + ?line [MIp3] = erl_boot_server:which_slaves(), + + ?line {error, {badarg, BadHost}} = erl_boot_server:delete_slave(BadHost), + ?line [MIp3] = erl_boot_server:which_slaves(), + + ?line ok = erl_boot_server:delete_slave(Ip3), + ?line [] = erl_boot_server:which_slaves(), + ?line ok = erl_boot_server:delete_slave(Ip3), + ?line [] = erl_boot_server:which_slaves(), + + ?line shutdown(Pid1), + ?line process_flag(trap_exit, OldFlag), + ?line test_server:timetrap_cancel(Dog), + ok. + +responses(doc) -> "Tests erl_boot_server responses to slave requests."; +responses(Config) when is_list(Config) -> + ?line Dog = test_server:timetrap(test_server:seconds(30)), + ?line process_flag(trap_exit, true), + %% Copy from inet_boot.hrl + EBOOT_PORT = 4368, + EBOOT_REQUEST = "EBOOTQ", + EBOOT_REPLY = "EBOOTR", + + ?line {ok,Host} = inet:gethostname(), + ?line {ok,Ip} = inet:getaddr(Host, inet), + + ThisVer = erlang:system_info(version), + + ?line {ok,BootPid} = erl_boot_server:start_link([Host]), + + %% Send junk + ?line S1 = open_udp(), + ?line prim_inet:sendto(S1, Ip, EBOOT_PORT, ["0"]), + receive + What -> + ?line close_udp(S1), + ?line ?t:fail({"got unexpected response",What}) + after 100 -> + ok + end, + + %% Req from a slave with same erlang vsn. + ?line S2 = open_udp(), + ?line prim_inet:sendto(S2, Ip, EBOOT_PORT, [EBOOT_REQUEST,ThisVer]), + receive + {udp,S2,Ip,_Port1,Resp1} -> + ?line close_udp(S2), + ?line EBOOT_REPLY = string:substr(Resp1, 1, length(EBOOT_REPLY)), + ?line Rest1 = string:substr(Resp1, length(EBOOT_REPLY)+1, length(Resp1)), + ?line [_,_,_ | ThisVer] = Rest1 + after 2000 -> + ?line close_udp(S2), + ?line ?t:fail("no boot server response; same vsn") + end, + + %% Req from a slave with other erlang vsn. + ?line S3 = open_udp(), + ?line prim_inet:sendto(S3, Ip, EBOOT_PORT, [EBOOT_REQUEST,"1.0"]), + receive + Anything -> + ?line close_udp(S3), + ?line ?t:fail({"got unexpected response",Anything}) + after 100 -> + ok + end, + + %% Kill the boot server and wait for it to disappear. + ?line unlink(BootPid), + ?line BootPidMref = erlang:monitor(process, BootPid), + ?line exit(BootPid, kill), + receive + {'DOWN',BootPidMref,_,_,_} -> ok + end, + + ?line {ok,BootPid2} = erl_boot_server:start_link(["127.0.0.1"]), + + %% Req from slave with invalid ip address. + ?line S4 = open_udp(), + Ret = + case Ip of + {127,0,0,1} -> + {comment,"IP address for this host is 127.0.0.1"}; + _ -> + ?line prim_inet:sendto(S4, Ip, EBOOT_PORT, + [EBOOT_REQUEST,ThisVer]), + receive + Huh -> + ?line close_udp(S4), + ?line ?t:fail({"got unexpected response",Huh}) + after 100 -> + ok + end + end, + + ?line unlink(BootPid2), + ?line exit(BootPid2, kill), + + %% Now wait for any late unexpected messages. + receive + Whatever -> + ?line ?t:fail({unexpected_message,Whatever}) + after 4000 -> + ?line close_udp(S1), + ?line close_udp(S3), + ?line close_udp(S4), + ok + end, + + ?line test_server:timetrap_cancel(Dog), + Ret. + +shutdown(Pid) -> + exit(Pid, shutdown), + receive + {'EXIT', Pid, shutdown} -> + ok + after 1000 -> + %% The timeout used to be 1 ms, which could be too short time for the + %% SMP emulator on a slow computer with one CPU. + test_server:fail(shutdown) + end. + +good_hosts(_Config) -> + %% XXX The hostnames should not be hard-coded like this. Really! + + {ok, GoodHost1} = inet:gethostname(), + GoodHost2 = "gandalf", + GoodHost3 = "sauron", + [GoodHost1, GoodHost2, GoodHost3]. + +open_udp() -> + ?line {ok, S} = prim_inet:open(udp, inet), + ?line ok = prim_inet:setopts(S, [{mode,list},{active,true}, + {deliver,term},{broadcast,true}]), + ?line {ok,_} = prim_inet:bind(S, {0,0,0,0}, 0), + S. + +close_udp(S) -> + prim_inet:close(S). |