aboutsummaryrefslogtreecommitdiffstats
path: root/lib/reltool/test/reltool_server_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/reltool/test/reltool_server_SUITE.erl')
-rw-r--r--lib/reltool/test/reltool_server_SUITE.erl494
1 files changed, 494 insertions, 0 deletions
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
new file mode 100644
index 0000000000..cf951191a0
--- /dev/null
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -0,0 +1,494 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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(reltool_server_SUITE).
+
+-export([all/0, init_per_suite/1, end_per_suite/1,
+ init_per_testcase/2, fin_per_testcase/2, end_per_testcase/2]).
+
+-compile(export_all).
+
+-include("reltool_test_lib.hrl").
+
+-define(NODE_NAME, '__RELTOOL__TEMPORARY_TEST__NODE__').
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Initialization functions.
+
+init_per_suite(Config) ->
+ reltool_test_lib:init_per_suite(Config).
+
+end_per_suite(Config) ->
+ reltool_test_lib:end_per_suite(Config).
+
+init_per_testcase(Func,Config) ->
+ reltool_test_lib:init_per_testcase(Func,Config).
+end_per_testcase(Func,Config) ->
+ reltool_test_lib:end_per_testcase(Func,Config).
+fin_per_testcase(Func,Config) -> %% For test_server
+ reltool_test_lib:end_per_testcase(Func,Config).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SUITE specification
+
+all() ->
+ all(suite).
+all(suite) ->
+ [
+ start_server,
+ set_config,
+ create_release,
+ create_script,
+ create_target,
+ create_embedded,
+ create_standalone,
+ create_old_target
+ ].
+
+%% The test cases
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Start a server process and check that it does not crash
+
+start_server(TestInfo) when is_atom(TestInfo) ->
+ reltool_test_lib:tc_info(TestInfo);
+start_server(_Config) ->
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([])),
+ Libs = lists:sort(erl_libs()),
+ StrippedDefault =
+ case Libs of
+ [] -> {sys, []};
+ _ -> {sys, [{lib_dirs, Libs}]}
+ end,
+ ?m({ok, StrippedDefault}, reltool:get_config(Pid)),
+ ?m(ok, reltool:stop(Pid)),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Start a server process and check that it does not crash
+
+set_config(TestInfo) when is_atom(TestInfo) ->
+ reltool_test_lib:tc_info(TestInfo);
+set_config(_Config) ->
+ Libs = lists:sort(erl_libs()),
+ Default =
+ {sys,
+ [
+ {mod_cond, all},
+ {incl_cond, derived},
+ {root_dir, code:root_dir()},
+ {lib_dirs, Libs}
+ ]},
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Default}])),
+ StrippedDefault =
+ case Libs of
+ [] -> {sys, []};
+ _ -> {sys, [{lib_dirs, Libs}]}
+ end,
+ ?m({ok, StrippedDefault}, reltool:get_config(Pid)),
+
+ ?m(ok, reltool:stop(Pid)),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate releases
+
+create_release(TestInfo) when is_atom(TestInfo) ->
+ reltool_test_lib:tc_info(TestInfo);
+create_release(_Config) ->
+ %% Configure the server
+ RelName = "Just testing...",
+ RelVsn = "1.0",
+ Config =
+ {sys,
+ [
+ {lib_dirs, []},
+ {boot_rel, RelName},
+ {rel, RelName, RelVsn, [kernel, stdlib]}
+ ]},
+ %% Generate release
+ ErtsVsn = erlang:system_info(version),
+ Apps = application:loaded_applications(),
+ {value, {_, _, KernelVsn}} = lists:keysearch(kernel, 1, Apps),
+ {value, {_, _, StdlibVsn}} = lists:keysearch(stdlib, 1, Apps),
+ Rel = {release, {RelName, RelVsn},
+ {erts, ErtsVsn},
+ [{kernel, KernelVsn},
+ {stdlib, StdlibVsn}]},
+ ?m({ok, Rel}, reltool:get_rel([{config, Config}], RelName)),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate boot scripts
+
+create_script(TestInfo) when is_atom(TestInfo) ->
+ reltool_test_lib:tc_info(TestInfo);
+create_script(_Config) ->
+ %% Configure the server
+ RelName = "Just testing",
+ RelVsn = "1.0",
+ Config =
+ {sys,
+ [
+ {lib_dirs, []},
+ {boot_rel, RelName},
+ {rel, RelName, RelVsn, [stdlib, kernel]}
+ ]},
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Config}])),
+
+ %% Generate release file
+ ErtsVsn = erlang:system_info(version),
+ Apps = application:loaded_applications(),
+ {value, {_, _, KernelVsn}} = lists:keysearch(kernel, 1, Apps),
+ {value, {_, _, StdlibVsn}} = lists:keysearch(stdlib, 1, Apps),
+ Rel = {release,
+ {RelName, RelVsn},
+ {erts, ErtsVsn},
+ [{stdlib, StdlibVsn}, {kernel, KernelVsn}]},
+ ?m({ok, Rel}, reltool:get_rel(Pid, RelName)),
+ RelFile = RelName ++ ".rel",
+ ?m(ok, file:write_file(RelFile, io_lib:format("~p.\n", [Rel]))),
+
+ %% Generate script file
+ ?m(ok, systools:make_script(RelName, [])),
+ ScriptFile = RelName ++ ".script",
+ {ok, [OrigScript]} = ?msym({ok, [_]}, file:consult(ScriptFile)),
+ {ok, Script} = ?msym({ok, _}, reltool:get_script(Pid, RelName)),
+ %% OrigScript2 = sort_script(OrigScript),
+ %% Script2 = sort_script(Script),
+ %% ?m(OrigScript2, Script2),
+
+ ?m(equal, diff_script(OrigScript, Script)),
+
+ %% Stop server
+ ?m(ok, reltool:stop(Pid)),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate target system
+
+create_target(TestInfo) when is_atom(TestInfo) ->
+ reltool_test_lib:tc_info(TestInfo);
+create_target(_Config) ->
+ %% Configure the server
+ RelName1 = "Just testing",
+ RelName2 = "Just testing with SASL",
+ RelVsn = "1.0",
+ Config =
+ {sys,
+ [
+ {root_dir, code:root_dir()},
+ {lib_dirs, []},
+ {boot_rel, RelName2},
+ {rel, RelName1, RelVsn, [stdlib, kernel]},
+ {rel, RelName2, RelVsn, [sasl, stdlib, kernel]},
+ {app, sasl, [{incl_cond, include}]}
+ ]},
+
+ %% Generate target file
+ TargetDir = "reltool_target_dir_development",
+ ?m(ok, reltool_utils:recursive_delete(TargetDir)),
+ ?m(ok, file:make_dir(TargetDir)),
+ ?m(ok, reltool:create_target([{config, Config}], TargetDir)),
+
+ Erl = filename:join([TargetDir, "bin", "erl"]),
+ {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
+ ?msym(ok, stop_node(Node)),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate embedded target system
+
+create_embedded(TestInfo) when is_atom(TestInfo) ->
+ reltool_test_lib:tc_info(TestInfo);
+create_embedded(_Config) ->
+ %% Configure the server
+ RelName1 = "Just testing",
+ RelName2 = "Just testing with SASL",
+ RelVsn = "1.0",
+ Config =
+ {sys,
+ [
+ {lib_dirs, []},
+ {profile, embedded},
+ {boot_rel, RelName2},
+ {rel, RelName1, RelVsn, [stdlib, kernel]},
+ {rel, RelName2, RelVsn, [sasl, stdlib, kernel]},
+ {app, sasl, [{incl_cond, include}]}
+ ]},
+
+ %% Generate target file
+ TargetDir = "reltool_target_dir_embedded",
+ ?m(ok, reltool_utils:recursive_delete(TargetDir)),
+ ?m(ok, file:make_dir(TargetDir)),
+ ?m(ok, reltool:create_target([{config, Config}], TargetDir)),
+
+ Erl = filename:join([TargetDir, "bin", "erl"]),
+ {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
+ ?msym(ok, stop_node(Node)),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate standalone system
+
+create_standalone(TestInfo) when is_atom(TestInfo) ->
+ reltool_test_lib:tc_info(TestInfo);
+create_standalone(_Config) ->
+ %% Configure the server
+ ExDir = code:lib_dir(reltool, examples),
+ EscriptName = "display_args",
+ Escript = filename:join([ExDir, EscriptName]),
+ Config =
+ {sys,
+ [
+ {lib_dirs, []},
+ {escript, Escript, [{incl_cond, include}]},
+ {profile, standalone}
+ ]},
+
+ %% Generate target file
+ TargetDir = "reltool_target_dir_standalone",
+ ?m(ok, reltool_utils:recursive_delete(TargetDir)),
+ ?m(ok, file:make_dir(TargetDir)),
+ ?m(ok, reltool:create_target([{config, Config}], TargetDir)),
+
+ BinDir = filename:join([TargetDir, "bin"]),
+ Erl = filename:join([BinDir, "erl"]),
+ {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
+ RootDir = ?ignore(rpc:call(Node, code, root_dir, [])),
+ ?msym(ok, stop_node(Node)),
+
+ Expected = iolist_to_binary(["Root dir: ", RootDir, "\n"
+ "Script args: [\"-arg1\",\"arg2\",\"arg3\"]\n",
+ "Smp: false\n",
+ "ExitCode:0"]),
+ io:format("Expected: ~s\n", [Expected]),
+ ?m(Expected, run(BinDir, EscriptName ++ " -arg1 arg2 arg3")),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate old type of target system
+
+create_old_target(TestInfo) when is_atom(TestInfo) ->
+ reltool_test_lib:tc_info(TestInfo);
+create_old_target(_Config) ->
+ %% Configure the server
+ RelName1 = "Just testing",
+ RelName2 = "Just testing with SASL",
+ RelVsn = "1.0",
+ Config =
+ {sys,
+ [
+ {lib_dirs, []},
+ {boot_rel, RelName2},
+ {rel, RelName1, RelVsn, [stdlib, kernel]},
+ {rel, RelName2, RelVsn, [sasl, stdlib, kernel]},
+ {relocatable, false}, % Implies explicit old style installation
+ {app, sasl, [{incl_cond, include}]}
+ ]},
+
+ %% Generate target file
+ TargetDir = "reltool_target_dir_old",
+ ?m(ok, reltool_utils:recursive_delete(TargetDir)),
+ ?m(ok, file:make_dir(TargetDir)),
+ ?m(ok, reltool:create_target([{config, Config}], TargetDir)),
+
+ %% io:format("Will fail on Windows (should patch erl.ini)\n", []),
+ ?m(ok, reltool:install(RelName2, TargetDir)),
+
+ Erl = filename:join([TargetDir, "bin", "erl"]),
+ {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
+ ?msym(ok, stop_node(Node)),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Library functions
+
+erl_libs() ->
+ case os:getenv("ERL_LIBS") of
+ false -> [];
+ LibStr -> string:tokens(LibStr, ":;")
+ end.
+
+diff_script(Script, Script) ->
+ equal;
+diff_script({script, Rel, Commands1}, {script, Rel, Commands2}) ->
+ diff_cmds(Commands1, Commands2);
+diff_script({script, Rel1, _}, {script, Rel2, _}) ->
+ {error, {Rel1, Rel2}}.
+
+diff_cmds([Cmd | Commands1], [Cmd | Commands2]) ->
+ diff_cmds(Commands1, Commands2);
+diff_cmds([Cmd1 | _Commands1], [Cmd2 | _Commands2]) ->
+ {diff, {expected, Cmd1}, {actual, Cmd2}};
+diff_cmds([], []) ->
+ equal.
+
+os_cmd(Cmd) when is_list(Cmd) ->
+ %% Call the plain os:cmd with an echo command appended to print command status
+ %% io:format("os:cmd(~p).\n", [Cmd]),
+ case os:cmd(Cmd++";echo \"#$?\"") of
+ %% There is (as far as I can tell) only one thing that will match this
+ %% and that is too silly to ever be used, but...
+ []->
+ {99, []};
+ Return->
+ %% Find the position of the status code wich is last in the string
+ %% prepended with #
+ case string:rchr(Return, $#) of
+
+ %% This happens only if the sh command pipe is somehow interrupted
+ 0->
+ {98, Return};
+
+ Position->
+ Result = string:left(Return,Position - 1),
+ Status = string:substr(Return,Position + 1, length(Return) - Position - 1),
+ {list_to_integer(Status), Result}
+ end
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Node handling
+
+start_node(Name, ErlPath) ->
+ FullName = full_node_name(Name),
+ CmdLine = mk_node_cmdline(Name, ErlPath),
+ io:format("Starting node ~p: ~s~n", [FullName, CmdLine]),
+ case open_port({spawn, CmdLine}, []) of
+ Port when is_port(Port) ->
+ unlink(Port),
+ erlang:port_close(Port),
+ case ping_node(FullName, 50) of
+ ok -> {ok, FullName};
+ Other -> exit({failed_to_start_node, FullName, Other})
+ end;
+ Error ->
+ exit({failed_to_start_node, FullName, Error})
+ end.
+
+stop_node(Node) ->
+ monitor_node(Node, true),
+ spawn(Node, fun () -> halt() end),
+ receive {nodedown, Node} -> ok end.
+
+mk_node_cmdline(Name) ->
+ Prog = case catch init:get_argument(progname) of
+ {ok,[[P]]} -> P;
+ _ -> exit(no_progname_argument_found)
+ end,
+ mk_node_cmdline(Name, Prog).
+
+mk_node_cmdline(Name, Prog) ->
+ Static = "-detached -noinput",
+ Pa = filename:dirname(code:which(?MODULE)),
+ NameSw = case net_kernel:longnames() of
+ false -> "-sname ";
+ true -> "-name ";
+ _ -> exit(not_distributed_node)
+ end,
+ {ok, Pwd} = file:get_cwd(),
+ NameStr = atom_to_list(Name),
+ Prog ++ " "
+ ++ Static ++ " "
+ ++ NameSw ++ " " ++ NameStr ++ " "
+ ++ "-pa " ++ Pa ++ " "
+ ++ "-env ERL_CRASH_DUMP " ++ Pwd ++ "/erl_crash_dump." ++ NameStr ++ " "
+ ++ "-setcookie " ++ atom_to_list(erlang:get_cookie()).
+
+full_node_name(PreName) ->
+ HostSuffix = lists:dropwhile(fun ($@) -> false; (_) -> true end,
+ atom_to_list(node())),
+ list_to_atom(atom_to_list(PreName) ++ HostSuffix).
+
+ping_node(_Node, 0) ->
+ {error, net_adm};
+ping_node(Node, N) when is_integer(N), N > 0 ->
+ case catch net_adm:ping(Node) of
+ pong ->
+ wait_for_process(Node, code_server, 50);
+ _ ->
+ timer:sleep(1000),
+ ping_node(Node, N-1)
+ end.
+
+wait_for_process(_Node, Name, 0) ->
+ {error, Name};
+wait_for_process(Node, Name, N) when is_integer(N), N > 0 ->
+ case rpc:call(Node, erlang, whereis, [Name]) of
+ undefined ->
+ timer:sleep(1000),
+ wait_for_process(Node, Name, N-1);
+ {badrpc, _} = Reason ->
+ erlang:error({Reason, Node});
+ Pid when is_pid(Pid) ->
+ ok
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Run escript
+
+run(Dir, Cmd0) ->
+ Cmd = case os:type() of
+ {win32,_} -> filename:nativename(Dir) ++ "\\" ++ Cmd0;
+ _ -> Cmd0
+ end,
+ do_run(Dir, Cmd).
+
+run(Dir, Opts, Cmd0) ->
+ Cmd = case os:type() of
+ {win32,_} -> Opts ++ " " ++ filename:nativename(Dir) ++ "\\" ++ Cmd0;
+ _ -> Opts ++ " " ++ Dir ++ "/" ++ Cmd0
+ end,
+ do_run(Dir, Cmd).
+
+do_run(Dir, Cmd) ->
+ io:format("Run: ~p\n", [Cmd]),
+ Env = [{"PATH",Dir++":"++os:getenv("PATH")}],
+ Port = open_port({spawn,Cmd}, [exit_status,eof,in,{env,Env}]),
+ Res = get_data(Port, []),
+ receive
+ {Port,{exit_status,ExitCode}} ->
+ iolist_to_binary([Res,"ExitCode:"++integer_to_list(ExitCode)])
+ end.
+
+get_data(Port, SoFar) ->
+ receive
+ {Port,{data,Bytes}} ->
+ get_data(Port, [SoFar|Bytes]);
+ {Port,eof} ->
+ erlang:port_close(Port),
+ SoFar
+ end.
+
+expected_output([data_dir|T], Data) ->
+ Slash = case os:type() of
+ {win32,_} -> "\\";
+ _ -> "/"
+ end,
+ [filename:nativename(Data)++Slash|expected_output(T, Data)];
+expected_output([H|T], Data) ->
+ [H|expected_output(T, Data)];
+expected_output([], _) ->
+ [];
+expected_output(Bin, _) when is_binary(Bin) ->
+ Bin.