4
%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
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/.
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
19
-module(reltool_server_SUITE).
21
-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
22
init_per_suite/1, end_per_suite/1,
23
init_per_testcase/2, end_per_testcase/2]).
27
-include("reltool_test_lib.hrl").
29
-define(NODE_NAME, '__RELTOOL__TEMPORARY_TEST__NODE__').
30
-define(WORK_DIR, "reltool_work_dir").
32
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33
%% Initialization functions.
35
init_per_suite(Config) ->
36
?ignore(file:make_dir(?WORK_DIR)),
37
reltool_test_lib:init_per_suite(Config).
39
end_per_suite(Config) ->
40
reltool_test_lib:end_per_suite(Config).
42
init_per_testcase(Func,Config) ->
43
reltool_test_lib:init_per_testcase(Func,Config).
44
end_per_testcase(Func,Config) ->
45
reltool_test_lib:end_per_testcase(Func,Config).
47
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
48
%% SUITE specification
50
suite() -> [{ct_hooks,[ts_install_cth]}].
53
[start_server, set_config, create_release,
54
create_script, create_target, create_embedded,
55
create_standalone, create_old_target].
60
init_per_group(_GroupName, Config) ->
63
end_per_group(_GroupName, Config) ->
69
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
70
%% Start a server process and check that it does not crash
72
start_server(TestInfo) when is_atom(TestInfo) ->
73
reltool_test_lib:tc_info(TestInfo);
74
start_server(_Config) ->
75
{ok, Pid} = ?msym({ok, _}, reltool:start_server([])),
76
Libs = lists:sort(erl_libs()),
80
_ -> {sys, [{lib_dirs, Libs}]}
82
?m({ok, StrippedDefault}, reltool:get_config(Pid)),
83
?m(ok, reltool:stop(Pid)),
86
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
87
%% Start a server process and check that it does not crash
89
set_config(TestInfo) when is_atom(TestInfo) ->
90
reltool_test_lib:tc_info(TestInfo);
91
set_config(_Config) ->
92
Libs = lists:sort(erl_libs()),
98
{root_dir, code:root_dir()},
101
{ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Default}])),
105
_ -> {sys, [{lib_dirs, Libs}]}
107
?m({ok, StrippedDefault}, reltool:get_config(Pid)),
109
?m(ok, reltool:stop(Pid)),
112
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
115
create_release(TestInfo) when is_atom(TestInfo) ->
116
reltool_test_lib:tc_info(TestInfo);
117
create_release(_Config) ->
118
%% Configure the server
119
RelName = "Just testing...",
126
{rel, RelName, RelVsn, [kernel, stdlib]}
129
ErtsVsn = erlang:system_info(version),
130
Apps = application:loaded_applications(),
131
{value, {_, _, KernelVsn}} = lists:keysearch(kernel, 1, Apps),
132
{value, {_, _, StdlibVsn}} = lists:keysearch(stdlib, 1, Apps),
133
Rel = {release, {RelName, RelVsn},
135
[{kernel, KernelVsn}, {stdlib, StdlibVsn}]},
136
?m({ok, Rel}, reltool:get_rel([{config, Config}], RelName)),
139
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140
%% Generate boot scripts
142
create_script(TestInfo) when is_atom(TestInfo) ->
143
reltool_test_lib:tc_info(TestInfo);
144
create_script(_Config) ->
145
%% Configure the server
146
RelName = "Just testing",
153
{rel, RelName, RelVsn, [stdlib, kernel]}
155
{ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Config}])),
157
%% Generate release file
158
ErtsVsn = erlang:system_info(version),
159
Apps = application:loaded_applications(),
160
{value, {_, _, KernelVsn}} = lists:keysearch(kernel, 1, Apps),
161
{value, {_, _, StdlibVsn}} = lists:keysearch(stdlib, 1, Apps),
165
[{kernel, KernelVsn}, {stdlib, StdlibVsn}]},
166
?m({ok, Rel}, reltool:get_rel(Pid, RelName)),
167
?m(ok, file:write_file(filename:join([?WORK_DIR, RelName ++ ".rel"]),
168
io_lib:format("~p.\n", [Rel]))),
170
%% Generate script file
171
{ok, Cwd} = file:get_cwd(),
172
?m(ok, file:set_cwd(?WORK_DIR)),
173
?m(ok, systools:make_script(RelName, [])),
174
{ok, [OrigScript]} = ?msym({ok, [_]}, file:consult(RelName ++ ".script")),
175
?m(ok, file:set_cwd(Cwd)),
176
{ok, Script} = ?msym({ok, _}, reltool:get_script(Pid, RelName)),
177
%% OrigScript2 = sort_script(OrigScript),
178
%% Script2 = sort_script(Script),
179
%% ?m(OrigScript2, Script2),
181
?m(equal, diff_script(OrigScript, Script)),
184
?m(ok, reltool:stop(Pid)),
187
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
188
%% Generate target system
190
create_target(TestInfo) when is_atom(TestInfo) ->
191
reltool_test_lib:tc_info(TestInfo);
192
create_target(_Config) ->
193
%% Configure the server
194
RelName1 = "Just testing",
195
RelName2 = "Just testing with SASL",
200
{root_dir, code:root_dir()},
202
{boot_rel, RelName2},
203
{rel, RelName1, RelVsn, [stdlib, kernel]},
204
{rel, RelName2, RelVsn, [sasl, stdlib, kernel]},
205
{app, sasl, [{incl_cond, include}]}
208
%% Generate target file
209
TargetDir = filename:join([?WORK_DIR, "target_development"]),
210
?m(ok, reltool_utils:recursive_delete(TargetDir)),
211
?m(ok, file:make_dir(TargetDir)),
212
?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Config}])]),
213
?m(ok, reltool:create_target([{config, Config}], TargetDir)),
215
Erl = filename:join([TargetDir, "bin", "erl"]),
216
{ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
217
?msym(ok, stop_node(Node)),
221
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222
%% Generate embedded target system
224
create_embedded(TestInfo) when is_atom(TestInfo) ->
225
reltool_test_lib:tc_info(TestInfo);
226
create_embedded(_Config) ->
227
%% Configure the server
228
RelName1 = "Just testing",
229
RelName2 = "Just testing with SASL",
236
{boot_rel, RelName2},
237
{rel, RelName1, RelVsn, [stdlib, kernel]},
238
{rel, RelName2, RelVsn, [sasl, stdlib, kernel]},
239
{app, sasl, [{incl_cond, include}]}
242
%% Generate target file
243
TargetDir = filename:join([?WORK_DIR, "target_embedded"]),
244
?m(ok, reltool_utils:recursive_delete(TargetDir)),
245
?m(ok, file:make_dir(TargetDir)),
246
?m(ok, reltool:create_target([{config, Config}], TargetDir)),
248
Erl = filename:join([TargetDir, "bin", "erl"]),
249
{ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
250
?msym(ok, stop_node(Node)),
254
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
255
%% Generate standalone system
257
create_standalone(TestInfo) when is_atom(TestInfo) ->
258
reltool_test_lib:tc_info(TestInfo);
259
create_standalone(_Config) ->
260
%% Configure the server
261
ExDir = code:lib_dir(reltool, examples),
262
EscriptName = "display_args",
263
Escript = filename:join([ExDir, EscriptName]),
268
{escript, Escript, [{incl_cond, include}]},
269
{profile, standalone}
272
%% Generate target file
273
TargetDir = filename:join([?WORK_DIR, "target_standalone"]),
274
?m(ok, reltool_utils:recursive_delete(TargetDir)),
275
?m(ok, file:make_dir(TargetDir)),
276
?m(ok, reltool:create_target([{config, Config}], TargetDir)),
278
BinDir = filename:join([TargetDir, "bin"]),
279
Erl = filename:join([BinDir, "erl"]),
280
{ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
281
RootDir = ?ignore(rpc:call(Node, code, root_dir, [])),
282
?msym(ok, stop_node(Node)),
284
Expected = iolist_to_binary(["Root dir: ", RootDir, "\n"
285
"Script args: [\"-arg1\",\"arg2\",\"arg3\"]\n",
288
io:format("Expected: ~s\n", [Expected]),
289
?m(Expected, run(BinDir, EscriptName ++ " -arg1 arg2 arg3")),
293
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
294
%% Generate old type of target system
296
create_old_target(TestInfo) when is_atom(TestInfo) ->
297
reltool_test_lib:tc_info(TestInfo);
298
create_old_target(_Config) ->
299
?skip("Old style of target", []),
301
%% Configure the server
302
RelName1 = "Just testing",
303
RelName2 = "Just testing with SASL",
309
{boot_rel, RelName2},
310
{rel, RelName1, RelVsn, [stdlib, kernel]},
311
{rel, RelName2, RelVsn, [sasl, stdlib, kernel]},
312
{relocatable, false}, % Implies explicit old style installation
313
{app, sasl, [{incl_cond, include}]}
316
%% Generate target file
317
TargetDir = filename:join([?WORK_DIR, "target_old_style"]),
318
?m(ok, reltool_utils:recursive_delete(TargetDir)),
319
?m(ok, file:make_dir(TargetDir)),
320
?m(ok, reltool:create_target([{config, Config}], TargetDir)),
322
%% io:format("Will fail on Windows (should patch erl.ini)\n", []),
323
?m(ok, reltool:install(RelName2, TargetDir)),
325
Erl = filename:join([TargetDir, "bin", "erl"]),
326
{ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
327
?msym(ok, stop_node(Node)),
331
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
335
case os:getenv("ERL_LIBS") of
337
LibStr -> string:tokens(LibStr, ":;")
340
diff_script(Script, Script) ->
342
diff_script({script, Rel, Commands1}, {script, Rel, Commands2}) ->
343
diff_cmds(Commands1, Commands2);
344
diff_script({script, Rel1, _}, {script, Rel2, _}) ->
345
{error, {Rel1, Rel2}}.
347
diff_cmds([Cmd | Commands1], [Cmd | Commands2]) ->
348
diff_cmds(Commands1, Commands2);
349
diff_cmds([Cmd1 | _Commands1], [Cmd2 | _Commands2]) ->
350
{diff, {expected, Cmd1}, {actual, Cmd2}};
354
os_cmd(Cmd) when is_list(Cmd) ->
355
%% Call the plain os:cmd with an echo command appended to print command status
356
%% io:format("os:cmd(~p).\n", [Cmd]),
357
case os:cmd(Cmd++";echo \"#$?\"") of
358
%% There is (as far as I can tell) only one thing that will match this
359
%% and that is too silly to ever be used, but...
363
%% Find the position of the status code wich is last in the string
365
case string:rchr(Return, $#) of
367
%% This happens only if the sh command pipe is somehow interrupted
372
Result = string:left(Return,Position - 1),
373
Status = string:substr(Return,Position + 1, length(Return) - Position - 1),
374
{list_to_integer(Status), Result}
378
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
381
start_node(Name, ErlPath) ->
382
FullName = full_node_name(Name),
383
CmdLine = mk_node_cmdline(Name, ErlPath),
384
io:format("Starting node ~p: ~s~n", [FullName, CmdLine]),
385
case open_port({spawn, CmdLine}, []) of
386
Port when is_port(Port) ->
388
erlang:port_close(Port),
389
case ping_node(FullName, 50) of
390
ok -> {ok, FullName};
391
Other -> exit({failed_to_start_node, FullName, Other})
394
exit({failed_to_start_node, FullName, Error})
398
monitor_node(Node, true),
399
spawn(Node, fun () -> halt() end),
400
receive {nodedown, Node} -> ok end.
402
mk_node_cmdline(Name) ->
403
Prog = case catch init:get_argument(progname) of
405
_ -> exit(no_progname_argument_found)
407
mk_node_cmdline(Name, Prog).
409
mk_node_cmdline(Name, Prog) ->
410
Static = "-detached -noinput",
411
Pa = filename:dirname(code:which(?MODULE)),
412
NameSw = case net_kernel:longnames() of
415
_ -> exit(not_distributed_node)
417
{ok, Pwd} = file:get_cwd(),
418
NameStr = atom_to_list(Name),
421
++ NameSw ++ " " ++ NameStr ++ " "
422
++ "-pa " ++ Pa ++ " "
423
++ "-env ERL_CRASH_DUMP " ++ Pwd ++ "/erl_crash_dump." ++ NameStr ++ " "
424
++ "-setcookie " ++ atom_to_list(erlang:get_cookie()).
426
full_node_name(PreName) ->
427
HostSuffix = lists:dropwhile(fun ($@) -> false; (_) -> true end,
428
atom_to_list(node())),
429
list_to_atom(atom_to_list(PreName) ++ HostSuffix).
431
ping_node(_Node, 0) ->
433
ping_node(Node, N) when is_integer(N), N > 0 ->
434
case catch net_adm:ping(Node) of
436
wait_for_process(Node, code_server, 50);
442
wait_for_process(_Node, Name, 0) ->
444
wait_for_process(Node, Name, N) when is_integer(N), N > 0 ->
445
case rpc:call(Node, erlang, whereis, [Name]) of
448
wait_for_process(Node, Name, N-1);
449
{badrpc, _} = Reason ->
450
erlang:error({Reason, Node});
451
Pid when is_pid(Pid) ->
455
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
459
Cmd = case os:type() of
460
{win32,_} -> filename:nativename(Dir) ++ "\\" ++ Cmd0;
465
run(Dir, Opts, Cmd0) ->
466
Cmd = case os:type() of
467
{win32,_} -> Opts ++ " " ++ filename:nativename(Dir) ++ "\\" ++ Cmd0;
468
_ -> Opts ++ " " ++ Dir ++ "/" ++ Cmd0
473
io:format("Run: ~p\n", [Cmd]),
474
Env = [{"PATH",Dir++":"++os:getenv("PATH")}],
475
Port = open_port({spawn,Cmd}, [exit_status,eof,in,{env,Env}]),
476
Res = get_data(Port, []),
478
{Port,{exit_status,ExitCode}} ->
479
iolist_to_binary([Res,"ExitCode:"++integer_to_list(ExitCode)])
482
get_data(Port, SoFar) ->
484
{Port,{data,Bytes}} ->
485
get_data(Port, [SoFar|Bytes]);
487
erlang:port_close(Port),
491
expected_output([data_dir|T], Data) ->
492
Slash = case os:type() of
496
[filename:nativename(Data)++Slash|expected_output(T, Data)];
497
expected_output([H|T], Data) ->
498
[H|expected_output(T, Data)];
499
expected_output([], _) ->
501
expected_output(Bin, _) when is_binary(Bin) ->