1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19
20-module(reltool_server_SUITE).
21
22-compile([export_all, nowarn_export_all]).
23
24-include_lib("reltool/src/reltool.hrl").
25-include("reltool_test_lib.hrl").
26-include_lib("common_test/include/ct.hrl").
27-include_lib("kernel/include/file.hrl").
28
29-define(NODE_NAME, '__RELTOOL__TEMPORARY_TEST__NODE__').
30-define(WORK_DIR, "reltool_work_dir").
31
32%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33%% Initialization functions.
34
35init_per_suite(Config) ->
36    {ok,Cwd} = file:get_cwd(),
37    ?ignore(file:make_dir(?WORK_DIR)),
38    [{cwd,Cwd}|reltool_test_lib:init_per_suite(Config)].
39
40end_per_suite(Config) ->
41    reltool_test_lib:end_per_suite(Config).
42
43init_per_testcase(Func,Config) ->
44    Node = full_node_name(?NODE_NAME),
45    case net_adm:ping(Node) of
46	pong -> stop_node(Node);
47	pang -> ok
48    end,
49    reltool_test_lib:init_per_testcase(Func,Config).
50end_per_testcase(Func,Config) ->
51    ok = file:set_cwd(filename:join(?config(cwd,Config),?WORK_DIR)),
52    {ok,All}  = file:list_dir("."),
53    Files = [F || F <- All, false == lists:prefix("save.",F)],
54    case ?config(tc_status,Config) of
55	ok ->
56	    ok;
57	_Fail ->
58	    SaveDir = "save."++atom_to_list(Func),
59	    ok = file:make_dir(SaveDir),
60	    save_test_result(Files,SaveDir)
61    end,
62    rm_files(Files),
63    ok = file:set_cwd(?config(cwd,Config)),
64    reltool_test_lib:end_per_testcase(Func,Config).
65
66
67save_test_result(Files,DestDir) ->
68    Tar = "copy.tar",
69    ok = erl_tar:create(Tar, Files),
70    ok = erl_tar:extract(Tar, [{cwd,DestDir}]),
71    ok = file:delete(Tar),
72    ok.
73
74rm_files([F | Fs]) ->
75    case file:read_file_info(F) of
76	{ok,#file_info{type=directory}} ->
77	    rm_dir(F);
78	{ok,_Regular} ->
79	    ok = file:delete(F)
80    end,
81    rm_files(Fs);
82rm_files([]) ->
83    ok.
84
85rm_dir(Dir) ->
86    {ok,Files} = file:list_dir(Dir),
87    rm_files([filename:join(Dir, F) || F <- Files]),
88    ok = file:del_dir(Dir).
89
90
91
92
93%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94%% SUITE specification
95
96suite() -> [{ct_hooks,[ts_install_cth]}].
97
98all() ->
99    [start_server,
100     set_config,
101     get_config,
102     create_release,
103     create_release_sort,
104     create_script,
105     create_script_without_dot_erlang,
106     create_script_sort,
107     create_target,
108     create_target_unicode,
109     create_embedded,
110     create_standalone,
111     create_standalone_beam,
112     create_standalone_app,
113     create_standalone_app_clash,
114     create_multiple_standalone,
115     create_old_target,
116     create_slim,
117     eval_target_spec,
118     otp_9135,
119     otp_9229_dupl_mod_exclude_app,
120     otp_9229_dupl_mod_exclude_mod,
121     dupl_mod_in_app_file,
122     include_non_existing_app,
123     exclude_non_existing_app,
124     get_apps,
125     get_mod,
126     get_sys,
127     set_app_and_undo,
128     set_apps_and_undo,
129     set_apps_inlined,
130     set_sys_and_undo,
131     load_config_and_undo,
132     load_config_fail,
133     load_config_escript_path,
134     load_config_same_escript_source,
135     load_config_same_escript_beam,
136     load_config_add_escript,
137     reset_config_and_undo,
138     gen_rel_files,
139     save_config,
140     dependencies,
141     mod_incl_cond_derived,
142     dep_in_app_not_xref,
143     use_selected_vsn,
144     use_selected_vsn_relative_path,
145     non_standard_vsn_id,
146     undefined_regexp,
147     windows_erl_libs].
148
149groups() ->
150    [].
151
152init_per_group(_GroupName, Config) ->
153    Config.
154
155end_per_group(_GroupName, Config) ->
156    Config.
157
158
159%% The test cases
160
161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
162%% A dummy break test case which is NOT in all(), but can be run
163%% directly from the command line with ct_run. It just does a
164%% test_server:break()...
165break(_Config) ->
166    test_server:break(""),
167    ok.
168
169
170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171%% Start a server process and check that it does not crash
172
173start_server(_Config) ->
174    {ok, Pid} = ?msym({ok, _}, reltool:start_server([])),
175    Libs = reltool_test_lib:erl_libs(),
176    StrippedDefault =
177        case Libs of
178            [] -> {sys, []};
179            _  -> {sys, [{lib_dirs, Libs}]}
180        end,
181    ?m({ok, StrippedDefault}, reltool:get_config(Pid)),
182    ?m(ok, reltool:stop(Pid)),
183    ok.
184
185%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
186%% Start a server process and check that it does not crash
187
188set_config(_Config) ->
189    Libs = reltool_test_lib:erl_libs(),
190    Default =
191        {sys,
192         [
193          {mod_cond, all},
194          {incl_cond, derived},
195          {root_dir, code:root_dir()},
196          {lib_dirs, Libs}
197         ]},
198    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Default}])),
199    StrippedDefault =
200        case Libs of
201            [] -> {sys, []};
202            _  -> {sys, [{lib_dirs, Libs}]}
203        end,
204    ?m({ok, StrippedDefault}, reltool:get_config(Pid)),
205
206    ?m(ok, reltool:stop(Pid)),
207    ok.
208
209%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
210%% Check that get_config returns the expected derivates and defaults
211%% as specified
212get_config(_Config) ->
213
214    KVsn = latest(kernel),
215    StdVsn = latest(stdlib),
216    SaslVsn = latest(sasl),
217
218    LibDir = code:lib_dir(),
219    KLibDir = filename:join(LibDir,"kernel-"++KVsn),
220    StdLibDir = filename:join(LibDir,"stdlib-"++StdVsn),
221    SaslLibDir = filename:join(LibDir,"sasl-"++SaslVsn),
222
223    Libs = reltool_test_lib:erl_libs(),
224    LibDirs =
225        case Libs of
226            [] -> [];
227            _ -> [{lib_dirs,Libs}]
228        end,
229
230    Sys = {sys,LibDirs ++
231               [{incl_cond, exclude},
232		{app,kernel,[{incl_cond,include}]},
233		{app,sasl,[{incl_cond,include},{vsn,SaslVsn}]},
234		{app,stdlib,[{incl_cond,include},{lib_dir,StdLibDir}]}]},
235    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
236    ?m({ok, Sys}, reltool:get_config(Pid)),
237    ?m({ok, Sys}, reltool:get_config(Pid,false,false)),
238
239    %% Include derived info
240    case Libs of
241        [] ->
242            ?msym({ok,{sys,[{incl_cond, exclude},
243                            {erts,[]},
244                            {app,kernel,[{incl_cond,include},{mod,_,[]}|_]},
245                            {app,sasl,[{incl_cond,include},{vsn,SaslVsn},
246                                       {mod,_,[]}|_]},
247                            {app,stdlib,[{incl_cond,include},{lib_dir,StdLibDir},
248                                         {mod,_,[]}|_]}]}},
249                  reltool:get_config(Pid,false,true));
250        _ ->
251            ?msym({ok,{sys,[{lib_dirs,Libs},
252                            {incl_cond, exclude},
253                            {erts,[]},
254                            {app,kernel,[{incl_cond,include},{mod,_,[]}|_]},
255                            {app,sasl,[{incl_cond,include},{vsn,SaslVsn},
256                                       {mod,_,[]}|_]},
257                            {app,stdlib,[{incl_cond,include},{lib_dir,StdLibDir},
258                                         {mod,_,[]}|_]}]}},
259                  reltool:get_config(Pid,false,true))
260    end,
261
262    %% Include defaults
263    ?msym({ok,{sys,[{root_dir,_},
264		    {lib_dirs,_},
265		    {mod_cond,all},
266		    {incl_cond,exclude},
267		    {app,kernel,[{incl_cond,include},{vsn,undefined},
268				 {lib_dir,undefined}]},
269		    {app,sasl,[{incl_cond,include},{vsn,SaslVsn},
270			       {lib_dir,undefined}]},
271		    {app,stdlib,[{incl_cond,include},{vsn,undefined},
272				 {lib_dir,StdLibDir}]},
273		    {boot_rel,"start_clean"},
274                    {rel,"no_dot_erlang","1.0",[],[{load_dot_erlang,false}]},
275		    {rel,"start_clean","1.0",[],[{load_dot_erlang,true}]},
276		    {rel,"start_sasl","1.0",[sasl],[{load_dot_erlang,true}]},
277		    {emu_name,"beam"},
278		    {relocatable,true},
279		    {profile,development},
280		    {incl_sys_filters,[".*"]},
281		    {excl_sys_filters,[]},
282		    {incl_app_filters,[".*"]},
283		    {excl_app_filters,[]},
284		    {incl_archive_filters,[".*"]},
285		    {excl_archive_filters,["^include$","^priv$"]},
286		    {archive_opts,[]},
287		    {rel_app_type,permanent},
288		    {app_file,keep},
289		    {debug_info,keep}]}},
290	  reltool:get_config(Pid,true,false)),
291
292    %% Include both defaults and derived info
293    ?msym({ok,{sys,[{root_dir,_},
294		    {lib_dirs,_},
295		    {mod_cond,all},
296		    {incl_cond,exclude},
297		    {erts,[]},
298		    {app,kernel,[{incl_cond,include},{vsn,KVsn},
299				 {lib_dir,KLibDir},{mod,_,[]}|_]},
300		    {app,sasl,[{incl_cond,include},{vsn,SaslVsn},
301				 {lib_dir,SaslLibDir},{mod,_,[]}|_]},
302		    {app,stdlib,[{incl_cond,include},{vsn,StdVsn},
303				 {lib_dir,StdLibDir},{mod,_,[]}|_]},
304		    {boot_rel,"start_clean"},
305                    {rel,"no_dot_erlang","1.0",[],[{load_dot_erlang,false}]},
306		    {rel,"start_clean","1.0",[],[{load_dot_erlang,true}]},
307		    {rel,"start_sasl","1.0",[sasl],[{load_dot_erlang,true}]},
308		    {emu_name,"beam"},
309		    {relocatable,true},
310		    {profile,development},
311		    {incl_sys_filters,[".*"]},
312		    {excl_sys_filters,[]},
313		    {incl_app_filters,[".*"]},
314		    {excl_app_filters,[]},
315		    {incl_archive_filters,[".*"]},
316		    {excl_archive_filters,["^include$","^priv$"]},
317		    {archive_opts,[]},
318		    {rel_app_type,permanent},
319		    {app_file,keep},
320		    {debug_info,keep}]}},
321	  reltool:get_config(Pid,true,true)),
322
323    ?m(ok, reltool:stop(Pid)),
324    ok.
325
326
327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
328%% OTP-9135, test that app_file option can be set to all | keep | strip
329
330otp_9135(_Config) ->
331    Libs = reltool_test_lib:erl_libs(),
332    StrippedDefaultSys =
333        case Libs of
334            [] -> [];
335            _  -> [{lib_dirs, Libs}]
336        end,
337
338    Config1 = {sys,[{app_file, keep}]}, % this is the default
339    {ok, Pid1} = ?msym({ok, _}, reltool:start_server([{config, Config1}])),
340    ?m({ok, {sys,StrippedDefaultSys}}, reltool:get_config(Pid1)),
341    ?m(ok, reltool:stop(Pid1)),
342
343    Config2 = {sys,[{app_file, strip}]},
344    {ok, Pid2} = ?msym({ok, _}, reltool:start_server([{config, Config2}])),
345    ExpectedConfig2 = StrippedDefaultSys++[{app_file,strip}],
346    ?m({ok, {sys,ExpectedConfig2}}, reltool:get_config(Pid2)),
347    ?m(ok, reltool:stop(Pid2)),
348
349    Config3 = {sys,[{app_file, all}]},
350    {ok, Pid3} = ?msym({ok, _}, reltool:start_server([{config, Config3}])),
351    ExpectedConfig3 = StrippedDefaultSys++[{app_file,all}],
352    ?m({ok, {sys,ExpectedConfig3}}, reltool:get_config(Pid3)),
353    ?m(ok, reltool:stop(Pid3)),
354    ok.
355
356%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
357%% Generate releases
358
359create_release(_Config) ->
360    %% Configure the server
361    RelName = "Just testing...",
362    RelVsn = "1.0",
363    Config =
364        {sys,
365         [
366          {lib_dirs, []},
367          {boot_rel, RelName},
368          {rel, RelName, RelVsn, [kernel, stdlib]}
369         ]},
370    %% Generate release
371    ErtsVsn = erlang:system_info(version),
372    Apps = application:loaded_applications(),
373    {value, {_, _, KernelVsn}} = lists:keysearch(kernel, 1, Apps),
374    {value, {_, _, StdlibVsn}} = lists:keysearch(stdlib, 1, Apps),
375    Rel = {release, {RelName, RelVsn},
376           {erts, ErtsVsn},
377           [{kernel, KernelVsn}, {stdlib, StdlibVsn}]},
378    ?m({ok, Rel}, reltool:get_rel([{config, Config}], RelName)),
379    ok.
380
381%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
382%% Generate releases and make sure order of applications specified in
383%% 'rel' parameter is preserved and that included applications are
384%% started before the including application.
385%% Circular dependencies shall also be detected and cause error.
386
387create_release_sort(Config) ->
388    DataDir = ?config(data_dir,Config),
389    %% Configure the server
390    RelName1 = "MnesiaFirst",
391    RelName2 = "SaslFirst",
392    RelName3 = "Include-both",
393    RelName4 = "Include-only-app",
394    RelName5 = "Include-only-rel",
395    RelName6 = "Auto-add-missing-apps",
396    RelName7 = "Circular",
397    RelName8 = "Include-rel-alter-order",
398    RelName9 = "Include-none-overwrite",
399    RelName10= "Uses-order-as-rel",
400    RelName11= "Auto-add-dont-overwrite-load",
401    RelVsn = "1.0",
402    %% Application z (.app file):
403    %%     includes [tools, mnesia]
404    %%     uses [kernel, stdlib, sasl, inets, unknown]
405    %% where unknown is optional dependency
406    Sys =
407        {sys,
408         [
409          {lib_dirs, [filename:join(DataDir,"sort_apps")]},
410          {boot_rel, RelName1},
411          {rel, RelName1, RelVsn, [stdlib, kernel, mnesia, sasl]},
412          {rel, RelName2, RelVsn, [stdlib, kernel, sasl, mnesia]},
413          {rel, RelName3, RelVsn, [stdlib, kernel, {z,[tools]}, tools, mnesia]},
414          {rel, RelName4, RelVsn, [stdlib, kernel, z, mnesia, tools]},
415          {rel, RelName5, RelVsn, [stdlib, kernel, {sasl,[tools]}]},
416          {rel, RelName6, RelVsn, [z]},
417	  {rel, RelName7, RelVsn, [stdlib, kernel, mnesia, y, sasl, x]},
418          {rel, RelName8, RelVsn, [stdlib, kernel, {z,[mnesia,tools]}]},
419          {rel, RelName9, RelVsn, [stdlib, kernel, {z,[]}]},
420          {rel, RelName10, RelVsn, [stdlib, kernel, {z,[]}, inets, sasl]},
421          {rel, RelName11, RelVsn, [stdlib, kernel, z, {inets, load}]},
422	  {incl_cond,exclude},
423	  {mod_cond,app},
424	  {app,kernel,[{incl_cond,include}]},
425	  {app,stdlib,[{incl_cond,include}]},
426	  {app,mnesia,[{incl_cond,include}]},
427	  {app,sasl,[{incl_cond,include}]},
428	  {app,inets,[{incl_cond,include}]},
429	  {app,x,[{incl_cond,include}]},
430	  {app,y,[{incl_cond,include}]},
431	  {app,z,[{incl_cond,include}]},
432	  {app,tools,[{mod_cond,app},{incl_cond,include}]}
433         ]},
434    %% Generate release
435    ?msym({ok, {release, {RelName1, RelVsn},
436		{erts, _},
437		[{kernel, _},
438		 {stdlib, _},
439		 {mnesia, _},
440		 {sasl, _}]}},
441	  reltool:get_rel([{config, Sys}], RelName1)),
442
443    ?msym({ok, {release, {RelName2, RelVsn},
444		{erts, _},
445		[{kernel, _},
446		 {stdlib, _},
447		 {sasl, _},
448		 {mnesia, _}]}},
449	  reltool:get_rel([{config, Sys}], RelName2)),
450
451    ?msym({ok, {release, {RelName3, RelVsn},
452		{erts, _},
453		[{kernel, _},
454		 {stdlib, _},
455		 {sasl, _},
456		 {inets, _},
457		 {tools, _},
458		 {z, _, [tools]},
459		 {mnesia, _}]}},
460	  reltool:get_rel([{config, Sys}], RelName3)),
461
462    ?msym({ok, {release, {RelName4, RelVsn},
463		{erts, _},
464		[{kernel, _},
465		 {stdlib, _},
466		 {sasl, _},
467		 {inets, _},
468		 {mnesia, _},
469		 {tools, _},
470		 {z, _}]}},
471	  reltool:get_rel([{config, Sys}], RelName4)),
472
473    ?m({error,"sasl: These applications are used by release "
474	"Include-only-rel but are missing as included_applications "
475	"in the app file: [tools]"},
476       reltool:get_rel([{config, Sys}], RelName5)),
477
478    ?msym({ok, {release, {RelName6, RelVsn},
479		{erts, _},
480		[{kernel, _},
481		 {stdlib, _},
482		 {sasl, _},
483		 {inets, _},
484		 {tools, _},
485		 {mnesia, _},
486		 {z, _}]}},
487       reltool:get_rel([{config, Sys}], RelName6)),
488
489    ?m({error,"Circular dependencies: [x,y]"},
490       reltool:get_rel([{config, Sys}], RelName7)),
491
492    ?msym({ok, {release, {RelName8, RelVsn},
493		{erts, _},
494		[{kernel, _},
495		 {stdlib, _},
496		 {sasl, _},
497		 {inets, _},
498		 {mnesia, _},
499		 {tools, _},
500		 {z, _, [mnesia,tools]}]}},
501       reltool:get_rel([{config, Sys}], RelName8)),
502
503    ?msym({ok,{release,{RelName9,RelVsn},
504	       {erts,_},
505	       [{kernel,_},
506		{stdlib,_},
507		{sasl, _},
508		{inets, _},
509		{z,_,[]}]}},
510	  reltool:get_rel([{config, Sys}], RelName9)),
511
512    ?msym({ok,{release,{RelName10,RelVsn},
513	       {erts,_},
514	       [{kernel,_},
515		{stdlib,_},
516		{inets, _},
517		{sasl, _},
518		{z,_,[]}]}},
519	  reltool:get_rel([{config, Sys}], RelName10)),
520
521    ?msym({ok,{release,{RelName11,RelVsn},
522	       {erts,_},
523	       [{kernel,_},
524		{stdlib,_},
525		{sasl, _},
526		{inets, _, load},
527		{tools, _},
528		{mnesia, _},
529		{z,_}]}},
530	  reltool:get_rel([{config, Sys}], RelName11)),
531
532    ok.
533
534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
535%% Generate boot scripts
536
537create_script(_Config) ->
538    %% Configure the server
539    RelName = "Just testing",
540    RelVsn = "1.0",
541    Config =
542        {sys,
543         [
544          {lib_dirs, []},
545          {boot_rel, RelName},
546          {rel, RelName, RelVsn, [stdlib, kernel]}
547         ]},
548    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Config}])),
549
550    %% Generate release file
551    ErtsVsn = erlang:system_info(version),
552    Apps = application:loaded_applications(),
553    {value, {_, _, KernelVsn}} = lists:keysearch(kernel, 1, Apps),
554    {value, {_, _, StdlibVsn}} = lists:keysearch(stdlib, 1, Apps),
555    Rel = {release,
556           {RelName, RelVsn},
557           {erts, ErtsVsn},
558           [{kernel, KernelVsn}, {stdlib, StdlibVsn}]},
559    ?m({ok, Rel}, reltool:get_rel(Pid, RelName)),
560    ?m(ok, file:write_file(filename:join([?WORK_DIR, RelName ++ ".rel"]),
561			   io_lib:format("~p.\n", [Rel]))),
562
563    %% Generate script file
564    {ok, Cwd} = file:get_cwd(),
565    ?m(ok, file:set_cwd(?WORK_DIR)),
566    ?m(ok, systools:make_script(RelName, [])),
567    {ok, [OrigScript]} = ?msym({ok, [_]}, file:consult(RelName ++ ".script")),
568    ?m(ok, file:set_cwd(Cwd)),
569    {ok, Script} = ?msym({ok, _}, reltool:get_script(Pid, RelName)),
570    %% OrigScript2 = sort_script(OrigScript),
571    %% Script2 = sort_script(Script),
572    %% ?m(OrigScript2, Script2),
573
574    ?m(equal, diff_script(OrigScript, Script)),
575
576    %% A release defaults to load_dot_erlang == true
577    {script, {RelName, RelVsn}, ScriptInstructions} = Script,
578    ?m(true, lists:member({apply,{c,erlangrc,[]}}, ScriptInstructions)),
579
580    %% Stop server
581    ?m(ok, reltool:stop(Pid)),
582    ok.
583
584create_script_without_dot_erlang(_Config) ->
585    %% Configure the server
586    RelName = "Just testing",
587    RelVsn = "1.0",
588    Config =
589        {sys,
590         [
591          {lib_dirs, []},
592          {boot_rel, RelName},
593          {rel, RelName, RelVsn, [stdlib, kernel], [{load_dot_erlang, false}]}
594         ]},
595    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Config}])),
596
597    %% Confirm that load_dot_erlang == false was used
598    {ok, Script} = ?msym({ok, _}, reltool:get_script(Pid, RelName)),
599    {script, {RelName, RelVsn}, ScriptInstructions} = Script,
600    ?m(false, lists:member({apply,{c,erlangrc,[]}}, ScriptInstructions)),
601
602    %% Stop server
603    ?m(ok, reltool:stop(Pid)),
604    ok.
605
606%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
607%% Test creation of .script with different sorting of applications and
608%% included applications.
609%% Test that result is equal to what systools produces
610create_script_sort(Config) ->
611    DataDir = ?config(data_dir,Config),
612    %% Configure the server
613    RelName1 = "MnesiaFirst",
614    RelName2 = "SaslFirst",
615    RelName3 = "Include-both",
616    RelName4 = "Include-only-app",
617    RelName5 = "Include-only-rel",
618    RelName6 = "Auto-add-missing-apps",
619    RelName7 = "Circular",
620    RelName8 = "Include-rel-alter-order",
621    RelName9 = "Include-none-overwrite",
622    RelName10= "Uses-order-as-rel",
623    RelVsn = "1.0",
624    LibDir = filename:join(DataDir,"sort_apps"),
625    %% Application z (.app file):
626    %%     includes [tools, mnesia]
627    %%     uses [kernel, stdlib, sasl, inets, unknown]
628    %% where unknown is optional dependency
629    Sys =
630        {sys,
631         [
632          {lib_dirs, [LibDir]},
633          {boot_rel, RelName1},
634          {rel, RelName1, RelVsn, [stdlib, kernel, mnesia, sasl]},
635          {rel, RelName2, RelVsn, [stdlib, kernel, sasl, mnesia]},
636          {rel, RelName3, RelVsn, [stdlib, kernel, {z,[tools]}, tools, mnesia]},
637          {rel, RelName4, RelVsn, [stdlib, kernel, z, mnesia, tools]},
638          {rel, RelName5, RelVsn, [stdlib, kernel, {sasl,[tools]}]},
639          {rel, RelName6, RelVsn, [z]},
640	  {rel, RelName7, RelVsn, [stdlib, kernel, mnesia, y, sasl, x]},
641          {rel, RelName8, RelVsn, [stdlib, kernel, {z,[mnesia,tools]}]},
642          {rel, RelName9, RelVsn, [stdlib, kernel, {z,[]}]},
643          {rel, RelName10, RelVsn, [stdlib, kernel, {z,[]}, inets, sasl]},
644	  {incl_cond,exclude},
645	  {mod_cond,app},
646	  {app,kernel,[{incl_cond,include}]},
647	  {app,stdlib,[{incl_cond,include}]},
648	  {app,mnesia,[{incl_cond,include}]},
649	  {app,sasl,[{incl_cond,include}]},
650	  {app,inets,[{incl_cond,include}]},
651	  {app,x,[{incl_cond,include}]},
652	  {app,y,[{incl_cond,include}]},
653	  {app,z,[{incl_cond,include}]},
654	  {app,tools,[{mod_cond,app},{incl_cond,include}]}
655         ]},
656
657    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
658
659    %% Generate release files
660    application:load(sasl),
661    application:load(inets),
662    application:load(mnesia),
663    application:load(tools),
664    {ok,KernelVsn} = application:get_key(kernel,vsn),
665    {ok,StdlibVsn} = application:get_key(stdlib,vsn),
666    {ok,SaslVsn} = application:get_key(sasl,vsn),
667    {ok,InetsVsn} = application:get_key(inets,vsn),
668    {ok,MnesiaVsn} = application:get_key(mnesia,vsn),
669    {ok,ToolsVsn} = application:get_key(tools,vsn),
670    ErtsVsn = erlang:system_info(version),
671
672    Rel1 = {release, {RelName1,RelVsn}, {erts,ErtsVsn},
673	    [{kernel,KernelVsn},
674	     {stdlib,StdlibVsn},
675	     {mnesia,MnesiaVsn},
676	     {sasl,SaslVsn}]},
677    FullName1 = filename:join(?WORK_DIR,RelName1),
678    ?m(ok, file:write_file(FullName1 ++ ".rel", io_lib:format("~p.\n", [Rel1]))),
679    Rel2 = {release, {RelName2,RelVsn}, {erts,ErtsVsn},
680	    [{kernel,KernelVsn},
681	     {stdlib,StdlibVsn},
682	     {sasl,SaslVsn},
683	     {mnesia,MnesiaVsn}]},
684    FullName2 = filename:join(?WORK_DIR,RelName2),
685    ?m(ok, file:write_file(FullName2 ++ ".rel", io_lib:format("~p.\n", [Rel2]))),
686    Rel3 = {release, {RelName3,RelVsn}, {erts,ErtsVsn},
687	     [{kernel,KernelVsn},
688	      {stdlib,StdlibVsn},
689	      {z,"1.0",[tools]},
690	      {tools,ToolsVsn},
691	      {mnesia,MnesiaVsn},
692	      {sasl,SaslVsn},
693	      {inets,InetsVsn}]},
694    FullName3 = filename:join(?WORK_DIR,RelName3),
695    ?m(ok, file:write_file(FullName3 ++ ".rel", io_lib:format("~p.\n", [Rel3]))),
696    Rel4 = {release, {RelName4,RelVsn}, {erts,ErtsVsn},
697	     [{kernel,KernelVsn},
698	      {stdlib,StdlibVsn},
699	      {z,"1.0"},
700	      {mnesia,MnesiaVsn},
701	      {tools,ToolsVsn},
702	      {sasl,SaslVsn},
703	      {inets,InetsVsn}]},
704    FullName4 = filename:join(?WORK_DIR,RelName4),
705    ?m(ok, file:write_file(FullName4 ++ ".rel", io_lib:format("~p.\n", [Rel4]))),
706    Rel5 = {release, {RelName5,RelVsn}, {erts,ErtsVsn},
707	     [{kernel,KernelVsn},
708	      {stdlib,StdlibVsn},
709	      {sasl,SaslVsn,[tools]},
710	      {tools,ToolsVsn}]},
711    FullName5 = filename:join(?WORK_DIR,RelName5),
712    ?m(ok, file:write_file(FullName5 ++ ".rel", io_lib:format("~p.\n", [Rel5]))),
713    Rel6 = {release, {RelName6,RelVsn}, {erts,ErtsVsn},
714	     [{kernel,KernelVsn},
715	      {stdlib,StdlibVsn},
716	      {sasl,SaslVsn},
717	      {inets,InetsVsn},
718	      {tools,ToolsVsn},
719	      {mnesia,MnesiaVsn},
720	      {z,"1.0"}]},
721    FullName6 = filename:join(?WORK_DIR,RelName6),
722    ?m(ok, file:write_file(FullName6 ++ ".rel", io_lib:format("~p.\n", [Rel6]))),
723    Rel7 = {release, {RelName7,RelVsn}, {erts,ErtsVsn},
724	     [{kernel,KernelVsn},
725	      {stdlib,StdlibVsn},
726	      {mnesia,MnesiaVsn},
727	      {y,"1.0"},
728	      {sasl,SaslVsn},
729	      {x,"1.0"}]},
730    FullName7 = filename:join(?WORK_DIR,RelName7),
731    ?m(ok, file:write_file(FullName7 ++ ".rel", io_lib:format("~p.\n", [Rel7]))),
732    Rel8 = {release, {RelName8,RelVsn}, {erts,ErtsVsn},
733	     [{kernel,KernelVsn},
734	      {stdlib,StdlibVsn},
735	      {z,"1.0",[mnesia,tools]},
736	      {sasl,SaslVsn},
737	      {inets,InetsVsn},
738	      {mnesia,MnesiaVsn},
739	      {tools,ToolsVsn}]},
740    FullName8 = filename:join(?WORK_DIR,RelName8),
741    ?m(ok, file:write_file(FullName8 ++ ".rel", io_lib:format("~p.\n", [Rel8]))),
742    Rel9 = {release, {RelName9,RelVsn}, {erts,ErtsVsn},
743	     [{kernel,KernelVsn},
744	      {stdlib,StdlibVsn},
745	      {z,"1.0",[]},
746	      {sasl,SaslVsn},
747	      {inets,InetsVsn}]},
748    FullName9 = filename:join(?WORK_DIR,RelName9),
749    ?m(ok, file:write_file(FullName9 ++ ".rel", io_lib:format("~p.\n", [Rel9]))),
750    Rel10 = {release, {RelName10,RelVsn}, {erts,ErtsVsn},
751	     [{kernel,KernelVsn},
752	      {stdlib,StdlibVsn},
753	      {z,"1.0",[]},
754	      {inets,InetsVsn},
755	      {sasl,SaslVsn}]},
756    FullName10 = filename:join(?WORK_DIR,RelName10),
757    ?m(ok, file:write_file(FullName10 ++ ".rel", io_lib:format("~p.\n", [Rel10]))),
758
759    %% Generate script files with systools and reltool and compare
760    ZPath = filename:join([LibDir,"*",ebin]),
761
762    ?msym({ok,_,_}, systools_make_script(FullName1,ZPath)),
763    {ok, [SystoolsScript1]} = ?msym({ok,[_]}, file:consult(FullName1++".script")),
764    {ok, Script1} = ?msym({ok, _}, reltool:get_script(Pid, RelName1)),
765    ?m(equal, diff_script(SystoolsScript1, Script1)),
766
767    ?msym({ok,_,_}, systools_make_script(FullName2,ZPath)),
768    {ok, [SystoolsScript2]} = ?msym({ok,[_]}, file:consult(FullName2++".script")),
769    {ok, Script2} = ?msym({ok, _}, reltool:get_script(Pid, RelName2)),
770    ?m(equal, diff_script(SystoolsScript2, Script2)),
771
772    ?msym({ok,_,_}, systools_make_script(FullName3,ZPath)),
773    {ok, [SystoolsScript3]} = ?msym({ok,[_]}, file:consult(FullName3++".script")),
774    {ok, Script3} = ?msym({ok, _}, reltool:get_script(Pid, RelName3)),
775    ?m(equal, diff_script(SystoolsScript3, Script3)),
776
777    ?msym({ok,_,_}, systools_make_script(FullName4,ZPath)),
778    {ok, [SystoolsScript4]} = ?msym({ok,[_]}, file:consult(FullName4++".script")),
779    {ok, Script4} = ?msym({ok, _}, reltool:get_script(Pid, RelName4)),
780    ?m(equal, diff_script(SystoolsScript4, Script4)),
781
782    ?msym({error,_,[{error_reading,{sasl,{override_include,_}}}]},
783	  systools_make_script(FullName5,ZPath)),
784    ?m({error,"sasl: These applications are used by release "
785	"Include-only-rel but are missing as included_applications "
786	"in the app file: [tools]"},
787       reltool:get_script(Pid, RelName5)),
788
789    ?msym({ok,_,_}, systools_make_script(FullName6,ZPath)),
790    {ok, [SystoolsScript6]} = ?msym({ok,[_]}, file:consult(FullName6++".script")),
791    {ok, Script6} = ?msym({ok, _}, reltool:get_script(Pid, RelName6)),
792    ?m(equal, diff_script(SystoolsScript6, Script6)),
793
794    ?msym({error,_,{circular_dependencies,_}},
795	  systools_make_script(FullName7,ZPath)),
796    ?m({error,"Circular dependencies: [x,y]"},
797       reltool:get_script(Pid, RelName7)),
798
799    ?msym({ok,_,_}, systools_make_script(FullName8,ZPath)),
800    {ok, [SystoolsScript8]} = ?msym({ok,[_]}, file:consult(FullName8++".script")),
801    {ok, Script8} = ?msym({ok, _}, reltool:get_script(Pid, RelName8)),
802    ?m(equal, diff_script(SystoolsScript8, Script8)),
803
804    ?msym({ok,_,_}, systools_make_script(FullName9,ZPath)),
805    {ok, [SystoolsScript9]} = ?msym({ok,[_]}, file:consult(FullName9++".script")),
806    {ok, Script9} = ?msym({ok, _}, reltool:get_script(Pid, RelName9)),
807    ?m(equal, diff_script(SystoolsScript9, Script9)),
808
809    ?msym({ok,_,_}, systools_make_script(FullName10,ZPath)),
810    {ok, [SystoolsScript10]} = ?msym({ok,[_]}, file:consult(FullName10++".script")),
811    {ok, Script10} = ?msym({ok, _}, reltool:get_script(Pid, RelName10)),
812    ?m(equal, diff_script(SystoolsScript10, Script10)),
813
814    %% Stop server
815    ?m(ok, reltool:stop(Pid)),
816    ok.
817
818
819systools_make_script(Name,Path) ->
820    systools:make_script(Name,[{path,[Path]},{outdir,?WORK_DIR},silent]).
821
822%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
823%% Generate target system
824
825create_target(_Config) ->
826    %% Configure the server
827    RelName1 = "Just testing",
828    RelName2 = "Just testing with SASL",
829    RelVsn = "1.0",
830    Config =
831        {sys,
832         [
833          {root_dir, code:root_dir()},
834          {lib_dirs, []},
835          {boot_rel, RelName2},
836          {rel, RelName1, RelVsn, [stdlib, kernel]},
837          {rel, RelName2, RelVsn, [sasl, stdlib, kernel]},
838          {app, sasl, [{incl_cond, include}]}
839         ]},
840
841    %% Generate target file
842    TargetDir = filename:join([?WORK_DIR, "target_development"]),
843    ?m(ok, reltool_utils:recursive_delete(TargetDir)),
844    ?m(ok, file:make_dir(TargetDir)),
845    ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Config}])]),
846    ok = ?m(ok, reltool:create_target([{config, Config}], TargetDir)),
847
848    Erl = filename:join([TargetDir, "bin", "erl"]),
849    {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
850    ?msym(ok, stop_node(Node)),
851
852    ok.
853
854%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
855%% Generate target system
856
857create_target_unicode(Config) ->
858    DataDir = ?config(data_dir,Config),
859
860    %% If file name translation mode is unicode, then use unicode
861    %% characters release name (which will be used as file name for
862    %% .rel, .script and .boot), and install the release under a path
863    %% which icludes unicode characters.
864    {RelNamePrefix,TargetDirName} =
865	case file:native_name_encoding() of
866	    utf8 ->
867		{"Unicode test αβ","target_unicode_αβ"} ;
868	    latin1 ->
869		{"Unicode test","target_unicode"}
870	end,
871
872    %% Configure the server
873    RelName1 = RelNamePrefix,
874    RelName2 = RelNamePrefix ++ " with SASL",
875    RelVsn = "1.0",
876    Sys =
877        {sys,
878         [
879          {root_dir, code:root_dir()},
880          {lib_dirs, [filename:join(DataDir,"unicode")]},
881	  {app_file, all},
882	  {incl_cond,exclude},
883	  {boot_rel, RelName2},
884          {rel, RelName1, RelVsn, [stdlib, kernel, ua]},
885          {rel, RelName2, RelVsn, [sasl, stdlib, kernel, ua]},
886          {app, kernel, [{incl_cond, include}]},
887          {app, stdlib, [{incl_cond, include}]},
888          {app, sasl, [{incl_cond, include}]},
889          {app, ua, [{incl_cond, include}]}
890         ]},
891
892    %% Generate target file
893    TargetDir = filename:join([?WORK_DIR, TargetDirName]),
894    ?m(ok, reltool_utils:recursive_delete(TargetDir)),
895    ?m(ok, file:make_dir(TargetDir)),
896    ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Sys}])]),
897    ok = ?m(ok, reltool:create_target([{config, Sys}], TargetDir)),
898
899    %% Start a node
900    Erl = filename:join([TargetDir, "bin", "erl"]),
901    {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
902
903
904    %% The ua application has a unicode string as description - check
905    %% that it is translated correctly.
906    wait_for_app(Node,ua,50),
907    Apps = rpc:call(Node,application,which_applications,[]),
908    ?m({ua,"Application for testing unicode in reltool - αβ","1.0"},
909       lists:keyfind(ua,1,Apps)),
910
911    %% Check that the release name is correct (really only
912    %% insteresting if file name translation mode is utf8)
913    [{RelName,_,_,_}] =
914	?msym([{_,_,_,_}],rpc:call(Node,release_handler,which_releases,[])),
915    ?m(true,lists:prefix(RelNamePrefix,RelName)),
916
917    ?msym(ok, stop_node(Node)),
918
919    ok.
920
921%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
922%% Generate embedded target system
923
924create_embedded(_Config) ->
925    %% Configure the server
926    RelName1 = "Just testing",
927    RelName2 = "Just testing with SASL",
928    RelVsn = "1.0",
929    Config =
930        {sys,
931         [
932          {lib_dirs, []},
933          {profile, embedded},
934          {boot_rel, RelName2},
935          {rel, RelName1, RelVsn, [stdlib, kernel]},
936          {rel, RelName2, RelVsn, [sasl, stdlib, kernel]},
937          {app, sasl, [{incl_cond, include}]}
938         ]},
939
940    %% Generate target file
941    TargetDir = filename:join([?WORK_DIR, "target_embedded"]),
942    ?m(ok, reltool_utils:recursive_delete(TargetDir)),
943    ?m(ok, file:make_dir(TargetDir)),
944    ok = ?m(ok, reltool:create_target([{config, Config}], TargetDir)),
945
946    Erl = filename:join([TargetDir, "bin", "erl"]),
947    {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
948    ?msym(ok, stop_node(Node)),
949
950    ok.
951
952%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
953%% Generate standalone system
954
955create_standalone(_Config) ->
956    %% Configure the server
957    ExDir = code:lib_dir(reltool, examples),
958    EscriptName = "display_args",
959    Escript = filename:join([ExDir, EscriptName]),
960    Config =
961        {sys,
962         [
963          {lib_dirs, []},
964          {escript, Escript, [{incl_cond, include}]},
965          {profile, standalone}
966         ]},
967
968    %% Generate target file
969    TargetDir = filename:join([?WORK_DIR, "target_standalone"]),
970    ?m(ok, reltool_utils:recursive_delete(TargetDir)),
971    ?m(ok, file:make_dir(TargetDir)),
972    ok = ?m(ok, reltool:create_target([{config, Config}], TargetDir)),
973
974    %% Start the target system and fetch root dir
975    BinDir = filename:join([TargetDir, "bin"]),
976    Erl = filename:join([BinDir, "erl"]),
977    {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
978    RootDir = ?ignore(rpc:call(Node, code, root_dir, [])),
979    ?msym(ok, stop_node(Node)),
980
981    %% Execute escript
982    Expected =  s2b(["Root dir: ", RootDir, "\n"
983		     "Script args: [\"-arg1\",\"arg2\",\"arg3\"]\n",
984		     "Emuarg: [\"emuvalue\"]\n",
985		     "ExitCode:0"]),
986    io:format("Expected: ~ts\n", [Expected]),
987    ?m(Expected, run(BinDir, EscriptName, "-arg1 arg2 arg3")),
988
989    ok.
990
991%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
992%% Generate standalone system with inlined beam file
993
994create_standalone_beam(Config) ->
995    %% Read beam file
996    DataDir = ?config(data_dir,Config),
997    BeamFile = filename:join([DataDir,escript,"someapp-1.0",ebin,"mymod.beam"]),
998    {ok,BeamBin} = file:read_file(BeamFile),
999
1000    %% Create the escript
1001    EscriptName = "mymod.escript",
1002    Escript = filename:join(?WORK_DIR,EscriptName),
1003    ok = escript:create(Escript,[shebang,{beam,BeamBin}]),
1004    ok = file:change_mode(Escript,8#00744),
1005
1006    %% Configure the server
1007    Sys =
1008        {sys,
1009         [
1010          {lib_dirs, []},
1011          {escript, Escript, [{incl_cond, include}]},
1012          {profile, standalone}
1013         ]},
1014
1015    %% Generate target file
1016    TargetDir = filename:join([?WORK_DIR, "target_standalone_beam"]),
1017    ?m(ok, reltool_utils:recursive_delete(TargetDir)),
1018    ?m(ok, file:make_dir(TargetDir)),
1019    ok = ?m(ok, reltool:create_target([{config, Sys}], TargetDir)),
1020
1021    %% Start the target system and fetch root dir
1022    BinDir = filename:join([TargetDir, "bin"]),
1023    Erl = filename:join([BinDir, "erl"]),
1024    {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
1025    RootDir = ?ignore(rpc:call(Node, code, root_dir, [])),
1026    ?msym(ok, stop_node(Node)),
1027
1028    %% Execute escript
1029    Expected =  s2b(["Module: mymod\n"
1030		     "Root dir: ", RootDir, "\n"
1031		     "Script args: [\"-arg1\",\"arg2\",\"arg3\"]\n",
1032		     "ExitCode:0"]),
1033    io:format("Expected: ~ts\n", [Expected]),
1034    ?m(Expected, run(BinDir, EscriptName, "-arg1 arg2 arg3")),
1035
1036    ok.
1037
1038%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1039%% Generate standalone system with inlined archived application
1040
1041create_standalone_app(Config) ->
1042    %% Create archive
1043    DataDir = ?config(data_dir,Config),
1044    EscriptDir = filename:join(DataDir,escript),
1045    {ok,{_Archive,Bin}} = zip:create("someapp-1.0.ez",["someapp-1.0"],
1046				     [memory,
1047				      {cwd,EscriptDir},
1048				      {compress,all},
1049				      {uncompress,[".beam",".app"]}]),
1050
1051    %% Create the escript
1052    EscriptName = "someapp.escript",
1053    Escript = filename:join(?WORK_DIR,EscriptName),
1054    ok = escript:create(Escript,[shebang,
1055				 {emu_args,"-escript main mymod"},
1056				 {archive,Bin}]),
1057    ok = file:change_mode(Escript,8#00744),
1058
1059    %% Configure the server
1060    Sys =
1061        {sys,
1062         [
1063          {lib_dirs, []},
1064          {escript, Escript, [{incl_cond, include}]},
1065          {profile, standalone}
1066         ]},
1067
1068    %% Generate target file
1069    TargetDir = filename:join([?WORK_DIR, "target_standalone_app"]),
1070    ?m(ok, reltool_utils:recursive_delete(TargetDir)),
1071    ?m(ok, file:make_dir(TargetDir)),
1072    ok = ?m(ok, reltool:create_target([{config, Sys}], TargetDir)),
1073
1074    %% Start the target system and fetch root dir
1075    BinDir = filename:join([TargetDir, "bin"]),
1076    Erl = filename:join([BinDir, "erl"]),
1077    {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
1078    RootDir = ?ignore(rpc:call(Node, code, root_dir, [])),
1079    ?msym(ok, stop_node(Node)),
1080
1081    %% Execute escript
1082    Expected =  s2b(["Module: mymod\n"
1083		     "Root dir: ", RootDir, "\n"
1084		     "Script args: [\"-arg1\",\"arg2\",\"arg3\"]\n",
1085		     "ExitCode:0"]),
1086    io:format("Expected: ~ts\n", [Expected]),
1087    ?m(Expected, run(BinDir, EscriptName, "-arg1 arg2 arg3")),
1088
1089    ok.
1090
1091%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1092%% Generate standalone system with inlined archived application
1093%% Check that the inlined app cannot be explicitly configured
1094
1095create_standalone_app_clash(Config) ->
1096    %% Create archive
1097    DataDir = ?config(data_dir,Config),
1098    EscriptDir = filename:join(DataDir,escript),
1099    {ok,{_Archive,Bin}} = zip:create("someapp-1.0.ez",["someapp-1.0"],
1100				     [memory,
1101				      {cwd,EscriptDir},
1102				      {compress,all},
1103				      {uncompress,[".beam",".app"]}]),
1104
1105    %% Create the escript
1106    EscriptName = "someapp.escript",
1107    Escript = filename:join(?WORK_DIR,EscriptName),
1108    ok = escript:create(Escript,[shebang,
1109				 {emu_args,"-escript main mymod"},
1110				 {archive,Bin}]),
1111    ok = file:change_mode(Escript,8#00744),
1112
1113    %% Configure the server
1114    Sys =
1115        {sys,
1116         [
1117          {lib_dirs, []},
1118          {escript, Escript, [{incl_cond, include}]},
1119          {profile, standalone},
1120	  {app, someapp, [{incl_cond,include}]}
1121         ]},
1122
1123    ?msym({error,"someapp: Application name clash. Escript "++_},
1124	  reltool:start_server([{config,Sys}])),
1125    ok.
1126
1127%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1128%% Generate standalone system with multiple escripts
1129
1130create_multiple_standalone(Config) ->
1131    %% First escript
1132    ExDir = code:lib_dir(reltool, examples),
1133    EscriptName1 = "display_args",
1134    Escript1 = filename:join([ExDir, EscriptName1]),
1135
1136    %% Second escript
1137    DataDir = ?config(data_dir,Config),
1138    BeamFile = filename:join([DataDir,escript,"someapp-1.0",ebin,"mymod.beam"]),
1139    {ok,BeamBin} = file:read_file(BeamFile),
1140    EscriptName2 = "mymod.escript",
1141    Escript2 = filename:join(?WORK_DIR,EscriptName2),
1142    ok = escript:create(Escript2,[shebang,{beam,BeamBin}]),
1143    ok = file:change_mode(Escript2,8#00744),
1144
1145    %% Configure server
1146    Sys =
1147        {sys,
1148         [
1149          {lib_dirs, []},
1150          {escript, Escript1, [{incl_cond, include}]},
1151          {escript, Escript2, [{incl_cond, include}]},
1152          {profile, standalone}
1153         ]},
1154
1155    %% Generate target system
1156    TargetDir = filename:join([?WORK_DIR, "target_multiple_standalone"]),
1157    ?m(ok, reltool_utils:recursive_delete(TargetDir)),
1158    ?m(ok, file:make_dir(TargetDir)),
1159    ok = ?m(ok, reltool:create_target([{config,Sys}], TargetDir)),
1160
1161    %% Start the target system and fetch root dir
1162    BinDir = filename:join([TargetDir, "bin"]),
1163    Erl = filename:join([BinDir, "erl"]),
1164    {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
1165    RootDir = ?ignore(rpc:call(Node, code, root_dir, [])),
1166    ?msym(ok, stop_node(Node)),
1167
1168    %% Execute escript1
1169    Expected1 =  s2b(["Root dir: ", RootDir, "\n"
1170		      "Script args: [\"-arg1\",\"arg2\",\"arg3\"]\n",
1171		      "Emuarg: [\"emuvalue\"]\n",
1172		      "ExitCode:0"]),
1173    io:format("Expected1: ~ts\n", [Expected1]),
1174    ?m(Expected1, run(BinDir, EscriptName1, "-arg1 arg2 arg3")),
1175
1176
1177    %% Execute escript2
1178    Expected2 =  s2b(["Module: mymod\n"
1179		      "Root dir: ", RootDir, "\n"
1180		      "Script args: [\"-arg1\",\"arg2\",\"arg3\"]\n",
1181		      "ExitCode:0"]),
1182    io:format("Expected2: ~ts\n", [Expected2]),
1183    ?m(Expected2, run(BinDir, EscriptName2, "-arg1 arg2 arg3")),
1184
1185    ok.
1186
1187%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1188%% Generate old type of target system
1189create_old_target(_Config) ->
1190
1191    %% Configure the server
1192    RelName1 = "Just testing",
1193    RelName2 = "Just testing with SASL",
1194    RelVsn = "1.0",
1195    Config =
1196        {sys,
1197         [
1198          {lib_dirs, []},
1199          {boot_rel, RelName2},
1200          {rel, RelName1, RelVsn, [stdlib, kernel]},
1201          {rel, RelName2, RelVsn, [sasl, stdlib, kernel]},
1202          {relocatable, false}, % Implies explicit old style installation
1203          {app, sasl, [{incl_cond, include}]}
1204         ]},
1205
1206    %% Generate target file
1207    TargetDir = filename:join([?WORK_DIR, "target_old_style"]),
1208    ?m(ok, reltool_utils:recursive_delete(TargetDir)),
1209    ?m(ok, file:make_dir(TargetDir)),
1210    ok = ?m(ok, reltool:create_target([{config, Config}], TargetDir)),
1211
1212    ok = ?m(ok, reltool:install(RelName2, TargetDir)),
1213
1214    Erl = filename:join([TargetDir, "bin", "erl"]),
1215    {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
1216    ?msym(ok, stop_node(Node)),
1217
1218    ok.
1219
1220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1221%% Generate target system
1222
1223create_slim(Config) ->
1224    %% Configure the server
1225    RelName = "slim",
1226    RelVsn = "1.0",
1227
1228    DataDir =  ?config(data_dir,Config),
1229    LibDir = filename:join(DataDir,"slim"),
1230
1231    Sys =
1232        {sys,
1233         [
1234          {root_dir, code:root_dir()},
1235          {lib_dirs, []},
1236          {boot_rel, RelName},
1237          {rel, RelName, RelVsn, [sasl, stdlib, kernel, a]},
1238          {app, sasl, [{incl_cond, include}]},
1239          {app, a, [{incl_cond, include},
1240		    {lib_dir,filename:join(LibDir,"a-1.0")}]},
1241	  {excl_lib,otp_root}
1242         ]},
1243
1244    %% Generate target file
1245    TargetDir = filename:absname(filename:join([?WORK_DIR, "target_slim"])),
1246    ?m(ok, reltool_utils:recursive_delete(TargetDir)),
1247    ?m(ok, file:make_dir(TargetDir)),
1248    ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Sys}])]),
1249    ok = ?m(ok, reltool:create_target([{config, Sys}], TargetDir)),
1250
1251    TargetLibDir = filename:join(TargetDir,"lib"),
1252    TargetRelDir = filename:join(TargetDir,"releases"),
1253    TargetRelVsnDir = filename:join(TargetRelDir,RelVsn),
1254
1255    {ok,["a-1.0.ez"]} = file:list_dir(TargetLibDir),
1256
1257    RootDir = code:root_dir(),
1258    Erl = filename:join([RootDir, "bin", "erl"]),
1259    Args = ["-boot_var", "RELTOOL_EXT_LIB", TargetLibDir,
1260	    "-boot", filename:join(TargetRelVsnDir,RelName),
1261	    "-sasl", "releases_dir", "\""++TargetRelDir++"\""],
1262    {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl, Args)),
1263    ?msym(RootDir, rpc:call(Node, code, root_dir, [])),
1264    wait_for_app(Node,sasl,50),
1265    ?msym([{RelName,RelVsn,_,permanent}],
1266	  rpc:call(Node,release_handler,which_releases,[])),
1267    ?msym(ok, stop_node(Node)),
1268
1269    ok.
1270
1271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1272%% Generate target system with eval_target_spec/3
1273
1274eval_target_spec(_Config) ->
1275    %% Configure the server
1276    RelName1 = "Just testing",
1277    RelName2 = "Just testing with SASL",
1278    RelVsn = "1.0",
1279    Config =
1280        {sys,
1281         [
1282          {root_dir, code:root_dir()},
1283          {lib_dirs, []},
1284          {boot_rel, RelName2},
1285          {rel, RelName1, RelVsn, [stdlib, kernel]},
1286          {rel, RelName2, RelVsn, [sasl, stdlib, kernel]},
1287          {app, sasl, [{incl_cond, include}]}
1288         ]},
1289
1290    %% Generate target file
1291    TargetDir = filename:join([?WORK_DIR, "eval_target_spec"]),
1292    ?m(ok, reltool_utils:recursive_delete(TargetDir)),
1293    ?m(ok, file:make_dir(TargetDir)),
1294    {ok, Spec} = ?msym({ok,_}, reltool:get_target_spec([{config, Config}])),
1295    ok = ?m(ok, reltool:eval_target_spec(Spec, code:root_dir(), TargetDir)),
1296
1297    Erl = filename:join([TargetDir, "bin", "erl"]),
1298    {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
1299    ?msym(ok, stop_node(Node)),
1300
1301    ok.
1302
1303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1304%% OTP-9229 - handle duplicated module names, i.e. same module name
1305%% exists in two applications.
1306
1307%% Include on app, exclude the other
1308otp_9229_dupl_mod_exclude_app(Config) ->
1309    DataDir =  ?config(data_dir,Config),
1310    LibDir = filename:join(DataDir,"otp_9229"),
1311
1312    %% Configure the server
1313    ExclApp =
1314        {sys,
1315         [
1316          {root_dir, code:root_dir()},
1317          {lib_dirs, [LibDir]},
1318	  {incl_cond,exclude},
1319	  {app,x,[{incl_cond,include}]},
1320	  {app,y,[{incl_cond,exclude}]},
1321	  {app,kernel,[{incl_cond,include}]},
1322	  {app,stdlib,[{incl_cond,include}]},
1323	  {app,sasl,[{incl_cond,include}]}
1324         ]},
1325
1326    %% Generate target file
1327    TargetDir = filename:join([?WORK_DIR, "target_dupl_mod_excl_app"]),
1328    ?m(ok, reltool_utils:recursive_delete(TargetDir)),
1329    ?m(ok, file:make_dir(TargetDir)),
1330    ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, ExclApp}])]),
1331    ?m({ok,["Module mylib exists in applications x and y. Using module from application x."]}, reltool:get_status([{config, ExclApp}])),
1332    ok = ?m(ok, reltool:create_target([{config, ExclApp}], TargetDir)),
1333
1334    Erl = filename:join([TargetDir, "bin", "erl"]),
1335    {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
1336
1337    AbsTargetDir = filename:absname(TargetDir),
1338    XArchive = "x-1.0.ez",
1339    AbsXArchive = filename:join([AbsTargetDir,lib,XArchive]),
1340    XEbin = ["ebin","x-1.0",XArchive],
1341    YArchive = "y-1.0.ez",
1342    AbsYArchive = filename:join([AbsTargetDir,lib,YArchive]),
1343
1344    ?m(true, filelib:is_file(AbsXArchive)),
1345    ?m(XEbin, mod_path(Node,x)),
1346    ?m(XEbin, mod_path(Node,mylib)),
1347    ?m(false, filelib:is_file(AbsYArchive)),
1348    ?m(non_existing, mod_path(Node,y)),
1349
1350    ?msym(ok, stop_node(Node)),
1351
1352    ok.
1353
1354%% Include both apps, but exclude common module from one app
1355otp_9229_dupl_mod_exclude_mod(Config) ->
1356    DataDir =  ?config(data_dir,Config),
1357    LibDir = filename:join(DataDir,"otp_9229"),
1358
1359    %% Configure the server
1360    ExclMod =
1361        {sys,
1362         [
1363          {root_dir, code:root_dir()},
1364          {lib_dirs, [LibDir]},
1365	  {incl_cond,exclude},
1366	  {app,x,[{incl_cond,include}]},
1367	  {app,y,[{incl_cond,include},{mod, mylib,[{incl_cond,exclude}]}]},
1368	  {app,kernel,[{incl_cond,include}]},
1369	  {app,stdlib,[{incl_cond,include}]},
1370	  {app,sasl,[{incl_cond,include}]}
1371         ]},
1372
1373    %% Generate target file
1374    TargetDir = filename:join([?WORK_DIR, "target_dupl_mod_excl_mod"]),
1375    ?m(ok, reltool_utils:recursive_delete(TargetDir)),
1376    ?m(ok, file:make_dir(TargetDir)),
1377    ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, ExclMod}])]),
1378    ?m({ok,["Module mylib exists in applications x and y. Using module from application x."]}, reltool:get_status([{config, ExclMod}])),
1379    ok = ?m(ok, reltool:create_target([{config, ExclMod}], TargetDir)),
1380
1381    Erl = filename:join([TargetDir, "bin", "erl"]),
1382    {ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl)),
1383
1384    AbsTargetDir = filename:absname(TargetDir),
1385    XArchive = "x-1.0.ez",
1386    AbsXArchive = filename:join([AbsTargetDir,lib,XArchive]),
1387    XEbin = ["ebin","x-1.0",XArchive],
1388    YArchive = "y-1.0.ez",
1389    AbsYArchive = filename:join([AbsTargetDir,lib,YArchive]),
1390    YEbin = ["ebin","y-1.0",YArchive],
1391
1392    ?m(true, filelib:is_file(AbsXArchive)),
1393    ?m(XEbin, mod_path(Node,x)),
1394    ?m(XEbin, mod_path(Node,mylib)),
1395    ?m(true, filelib:is_file(AbsYArchive)),
1396    ?m(YEbin, mod_path(Node,y)),
1397
1398    %% Remove path to XEbin and check that mylib is not located in YEbin
1399    Mylib = rpc:call(Node,code,which,[mylib]),
1400    rpc:call(Node,code,del_path,[filename:dirname(Mylib)]),
1401    ?m(non_existing, mod_path(Node,mylib)),
1402
1403    ?msym(ok, stop_node(Node)),
1404
1405    ok.
1406
1407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1408%% Test that if a module is duplicated in a .app file, then a warning
1409%% is produced, but target can still be created.
1410dupl_mod_in_app_file(Config) ->
1411    DataDir =  ?config(data_dir,Config),
1412    LibDir = filename:join(DataDir,"dupl_mod"),
1413
1414    %% Configure the server
1415    Sys =
1416        {sys,
1417         [
1418          {lib_dirs, [LibDir]},
1419	  {incl_cond,exclude},
1420	  {app,a,[{incl_cond,include}]},
1421	  {app,kernel,[{incl_cond,include}]},
1422	  {app,stdlib,[{incl_cond,include}]},
1423	  {app,sasl,[{incl_cond,include}]}
1424         ]},
1425
1426    %% Generate target file
1427    TargetDir = filename:join([?WORK_DIR, "target_dupl_mod_in_app_file"]),
1428    ?m(ok, reltool_utils:recursive_delete(TargetDir)),
1429    ?m(ok, file:make_dir(TargetDir)),
1430    ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Sys}])]),
1431    ?m({ok,["Module a duplicated in app file for application a."]},
1432       reltool:get_status([{config, Sys}])),
1433
1434    %%! test that only one module installed (in spec)
1435
1436    ok.
1437
1438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1439%% Test that a reasonable error message is returned if an application
1440%% is missing
1441include_non_existing_app(_Config) ->
1442    %% Configure the server
1443    Sys =
1444        {sys,
1445         [
1446          {incl_cond,exclude},
1447          {app,foobar,[{incl_cond,include}]},
1448          {app,kernel,[{incl_cond,include}]},
1449          {app,stdlib,[{incl_cond,include}]},
1450          {app,sasl,[{incl_cond,include}]}
1451         ]},
1452
1453    %% Generate target file
1454    TargetDir = filename:join([?WORK_DIR, "target_include_non_existing_app"]),
1455    ?m(ok, reltool_utils:recursive_delete(TargetDir)),
1456    ?m(ok, file:make_dir(TargetDir)),
1457    ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Sys}])]),
1458    ?m({error,"foobar: Missing application directory."},
1459       reltool:get_status([{config, Sys}])),
1460
1461    ok.
1462
1463%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1464%% Test that if a missing application is explicitly excluded a warning
1465%% should be issued.
1466exclude_non_existing_app(_Config) ->
1467    %% Configure the server
1468    Sys =
1469        {sys,
1470         [
1471          {incl_cond,exclude},
1472          {app,foobar,[{incl_cond,exclude}]},
1473          {app,kernel,[{incl_cond,include}]},
1474          {app,stdlib,[{incl_cond,include}]},
1475          {app,sasl,[{incl_cond,include}]}
1476         ]},
1477
1478    %% Generate target file
1479    TargetDir = filename:join([?WORK_DIR, "target_exclude_non_existing_app"]),
1480    ?m(ok, reltool_utils:recursive_delete(TargetDir)),
1481    ?m(ok, file:make_dir(TargetDir)),
1482    ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Sys}])]),
1483    ?m({ok,["foobar: Missing application directory."]},
1484       reltool:get_status([{config, Sys}])),
1485
1486    ok.
1487
1488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1489%% Test the interface used by the GUI:
1490%%  get_app
1491%%  get_apps
1492%%  set_app
1493%%  set_apps
1494%%  load_config
1495%%  reset_config
1496%%
1497%% Also, for each operation which manipulates the config, test
1498%% get_status and undo_config.
1499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1500get_apps(_Config) ->
1501    Sys = {sys,[{app,kernel,[{incl_cond,include}]},
1502		{app,sasl,[{incl_cond,include}]},
1503		{app,stdlib,[{incl_cond,include}]},
1504		{app,tools,[{incl_cond,derived}]},
1505		{app,runtime_tools,[{incl_cond,exclude}]}]},
1506    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
1507
1508    {ok,Sasl} = ?msym({ok,#app{name=sasl}}, reltool_server:get_app(Pid,sasl)),
1509    {ok,[#app{name=kernel},
1510	 #app{name=sasl}=Sasl,
1511	 #app{name=stdlib}] = White} =
1512	?msym({ok,_}, reltool_server:get_apps(Pid,whitelist)),
1513    {ok,[#app{name=runtime_tools}] = Black} =
1514	?msym({ok,_}, reltool_server:get_apps(Pid,blacklist)),
1515
1516    {ok,Derived} = ?msym({ok,_}, reltool_server:get_apps(Pid,derived)),
1517    true = lists:keymember(tools,#app.name,Derived),
1518
1519    {ok,Source} = ?msym({ok,_}, reltool_server:get_apps(Pid,source)),
1520    true = lists:keymember(common_test,#app.name,Source),
1521
1522    %% Check that the four lists are disjoint
1523    Number = length(White) + length(Black) + length(Derived) + length(Source),
1524    WN = lists:usort([N || #app{name=N} <- White]),
1525    BN = lists:usort([N || #app{name=N} <- Black]),
1526    DN = lists:usort([N || #app{name=N} <- Derived]),
1527    SN = lists:usort([N || #app{name=N} <- Source]),
1528    AllN = lists:umerge([WN,BN,DN,SN]),
1529    ?m(Number,length(AllN)),
1530
1531    ?m(ok, reltool:stop(Pid)),
1532    ok.
1533
1534
1535%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1536get_mod(_Config) ->
1537    Sys = {sys,[{app,kernel,[{incl_cond,include}]},
1538		{app,sasl,[{incl_cond,include}]},
1539		{app,stdlib,[{incl_cond,include}]},
1540		{app,tools,[{incl_cond,derived}]},
1541		{app,runtime_tools,[{incl_cond,exclude}]}]},
1542    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
1543
1544    %% Read app and get a module from the #app record
1545    {ok,Tools} = ?msym({ok,#app{name=tools}}, reltool_server:get_app(Pid,tools)),
1546    Cover = lists:keyfind(cover,#mod.name,Tools#app.mods),
1547
1548    %% get_mod - and check that it is equal to the one in #app.mods
1549    ?m({ok,Cover}, reltool_server:get_mod(Pid,cover)),
1550
1551    ?m(ok, reltool:stop(Pid)),
1552    ok.
1553
1554
1555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1556get_sys(_Config) ->
1557    Sys = {sys,[{app,kernel,[{incl_cond,include}]},
1558		{app,sasl,[{incl_cond,include}]},
1559		{app,stdlib,[{incl_cond,include}]},
1560		{app,tools,[{incl_cond,derived}]},
1561		{app,runtime_tools,[{incl_cond,exclude}]}]},
1562    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
1563
1564    RootDir = code:root_dir(),
1565    ?msym({ok,#sys{root_dir=RootDir,apps=undefined}},reltool_server:get_sys(Pid)),
1566
1567    ?m(ok, reltool:stop(Pid)),
1568    ok.
1569
1570%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1571set_app_and_undo(Config) ->
1572    Sys = {sys,[{lib_dirs,[filename:join(datadir(Config),"faulty_app_file")]},
1573		{incl_cond, exclude},
1574		{app,a,[{incl_cond,include}]},
1575		{app,kernel,[{incl_cond,include}]},
1576		{app,sasl,[{incl_cond,include}]},
1577		{app,stdlib,[{incl_cond,include}]},
1578		{app,tools,[{incl_cond,include}]}]},
1579    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
1580    ?m({ok, Sys}, reltool:get_config(Pid)),
1581    ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
1582
1583    %% Get app and mod
1584    {ok,Tools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
1585    {ok,Cover} = ?msym({ok,#mod{name=cover, is_included=true}},
1586		       reltool_server:get_mod(Pid,cover)),
1587
1588    %% Exclude one module with set_app
1589    ExclCover = Cover#mod{incl_cond=exclude},
1590    Mods = Tools#app.mods,
1591    Tools1 = Tools#app{mods = lists:keyreplace(cover,#mod.name,Mods,ExclCover)},
1592    {ok,ToolsNoCover,["a: Cannot parse app file"++_|_]} =
1593	?msym({ok,_,["a: Cannot parse app file"++_|_]},
1594	      reltool_server:set_app(Pid,Tools1)),
1595    ?msym({ok,["a: Cannot parse app file"++_]}, reltool_server:get_status(Pid)),
1596
1597    %% Check that the module is no longer included
1598    ?m({ok,ToolsNoCover}, reltool_server:get_app(Pid,tools)),
1599    {ok,NoIncludeCover} = ?msym({ok,#mod{name=cover, is_included=false}},
1600				reltool_server:get_mod(Pid,cover)),
1601
1602    %% Undo
1603    ?m(ok, reltool_server:undo_config(Pid)),
1604    ?m({ok,Tools}, reltool_server:get_app(Pid,tools)),
1605    ?m({ok,Cover}, reltool_server:get_mod(Pid,cover)),
1606    ?msym({ok,["a: Cannot parse app file"++_]}, reltool_server:get_status(Pid)),
1607
1608    %% Undo again, to check that it toggles
1609    ?msym(ok, reltool_server:undo_config(Pid)),
1610    ?m({ok,ToolsNoCover}, reltool_server:get_app(Pid,tools)),
1611    ?m({ok,NoIncludeCover}, reltool_server:get_mod(Pid,cover)),
1612    ?msym({ok,["a: Cannot parse app file"++_]}, reltool_server:get_status(Pid)),
1613
1614    ?m(ok, reltool:stop(Pid)),
1615    ok.
1616
1617
1618%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1619set_apps_and_undo(Config) ->
1620    Sys = {sys,[{lib_dirs,[filename:join(datadir(Config),"faulty_app_file")]},
1621		{incl_cond, exclude},
1622		{app,kernel,[{incl_cond,include}]},
1623		{app,sasl,[{incl_cond,include}]},
1624		{app,stdlib,[{incl_cond,include}]},
1625		{app,tools,[{incl_cond,include}]}]},
1626    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
1627    ?m({ok, Sys}, reltool:get_config(Pid)),
1628    ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
1629
1630    %% Get app and mod
1631    {ok,Tools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
1632    ?m(true, Tools#app.is_pre_included),
1633    ?m(true, Tools#app.is_included),
1634    {ok,Cover} = ?msym({ok,#mod{name=cover, is_included=true}},
1635		       reltool_server:get_mod(Pid,cover)),
1636
1637    %% Exclude one application with set_apps
1638    ExclTools = Tools#app{incl_cond=exclude},
1639    ?msym({ok,["a: Cannot parse app file"++_]},
1640       reltool_server:set_apps(Pid,[ExclTools])),
1641    ?msym({ok,["a: Cannot parse app file"++_]}, reltool_server:get_status(Pid)),
1642
1643    %% Check that the app and its modules (one of them) are no longer included
1644    {ok,NoTools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
1645    ?m(false, NoTools#app.is_pre_included),
1646    ?m(false, NoTools#app.is_included),
1647    {ok,NoIncludeCover} = ?msym({ok,#mod{name=cover, is_included=false}},
1648				reltool_server:get_mod(Pid,cover)),
1649
1650    %% Undo
1651    ?m(ok, reltool_server:undo_config(Pid)),
1652    ?m({ok,Tools}, reltool_server:get_app(Pid,tools)),
1653    ?m({ok,Cover}, reltool_server:get_mod(Pid,cover)),
1654    ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
1655
1656    %% Undo again, to check that it toggles
1657    ?m(ok, reltool_server:undo_config(Pid)),
1658    ?m({ok,NoTools}, reltool_server:get_app(Pid,tools)),
1659    ?m({ok,NoIncludeCover}, reltool_server:get_mod(Pid,cover)),
1660    ?msym({ok,["a: Cannot parse app file"++_]}, reltool_server:get_status(Pid)),
1661
1662    ?m(ok, reltool:stop(Pid)),
1663    ok.
1664
1665
1666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1667%% Test that escript can be configured, but not its inlined applications
1668set_apps_inlined(Config) ->
1669    %% Create archive
1670    DataDir = ?config(data_dir,Config),
1671    EscriptDir = filename:join(DataDir,escript),
1672    {ok,{_Archive,Bin}} = zip:create("someapp-1.0.ez",["someapp-1.0"],
1673				     [memory,
1674				      {cwd,EscriptDir},
1675				      {compress,all},
1676				      {uncompress,[".beam",".app"]}]),
1677
1678    %% Create the escript
1679    EscriptName = "someapp.escript",
1680    Escript = filename:join(?WORK_DIR,EscriptName),
1681    ok = escript:create(Escript,[shebang,
1682				 {emu_args,"-escript main mymod"},
1683				 {archive,Bin}]),
1684    ok = file:change_mode(Escript,8#00744),
1685
1686    %% Configure the server
1687    Sys = {sys,[{incl_cond, exclude},
1688		{escript,Escript,[]},
1689		{app,kernel,[{incl_cond,include}]},
1690		{app,sasl,[{incl_cond,include}]},
1691		{app,stdlib,[{incl_cond,include}]}]},
1692    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
1693    ?msym({ok,[]},reltool_server:get_status(Pid)),
1694
1695    %% Get app and mod
1696    {ok,EApp} = ?msym({ok,_}, reltool_server:get_app(Pid,'*escript* someapp')),
1697    {ok,Someapp} = ?msym({ok,_}, reltool_server:get_app(Pid,someapp)),
1698    ?m(undefined, EApp#app.incl_cond),
1699    ?m(undefined, Someapp#app.incl_cond),
1700    ?m(false, Someapp#app.is_included),
1701    ?m(false, Someapp#app.is_pre_included),
1702
1703    %% Include escript
1704    EApp1 = EApp#app{incl_cond=include},
1705    ?m({ok,[]}, reltool_server:set_apps(Pid,[EApp1])),
1706    ExpectedEApp = EApp1#app{is_included=true,is_pre_included=true},
1707    ?m({ok,ExpectedEApp}, reltool_server:get_app(Pid,'*escript* someapp')),
1708    {ok,Someapp1} = ?msym({ok,_}, reltool_server:get_app(Pid,someapp)),
1709    ?m(include, Someapp1#app.incl_cond),
1710    ?m(true, Someapp1#app.is_included),
1711    ?m(true, Someapp1#app.is_pre_included),
1712
1713    %% Check that inlined app cannot be configured
1714    Someapp2 = Someapp1#app{incl_cond=exclude},
1715    ?msym({error,
1716	   "Application someapp is inlined in '*escript* someapp'. "
1717	   "Can not change configuration for an inlined application."},
1718	  reltool_server:set_apps(Pid,[Someapp2])),
1719    ?m({ok,Someapp1}, reltool_server:get_app(Pid,someapp)),
1720
1721    %% Exclude escript
1722    {ok,EApp2} = ?msym({ok,_}, reltool_server:get_app(Pid,'*escript* someapp')),
1723    EApp3 = EApp2#app{incl_cond=exclude},
1724    ?m({ok,[]}, reltool_server:set_apps(Pid,[EApp3])),
1725    ExpectedEApp3 = EApp3#app{is_included=false,is_pre_included=false},
1726    ?m({ok,ExpectedEApp3}, reltool_server:get_app(Pid,'*escript* someapp')),
1727    {ok,Someapp3} = ?msym({ok,_}, reltool_server:get_app(Pid,someapp)),
1728    ?m(exclude, Someapp3#app.incl_cond),
1729    ?m(false, Someapp3#app.is_included),
1730    ?m(false, Someapp3#app.is_pre_included),
1731
1732    ?m(ok, reltool:stop(Pid)),
1733    ok.
1734
1735
1736%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1737set_sys_and_undo(Config) ->
1738    Sys1 = {sys,[{incl_cond, exclude},
1739		 {app,kernel,[{incl_cond,include}]},
1740		 {app,sasl,[{incl_cond,include}]},
1741		 {app,stdlib,[{incl_cond,include}]},
1742		 {app,tools,[{incl_cond,include}]}]},
1743    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
1744    ?m({ok,[]}, reltool_server:get_status(Pid)),
1745
1746    %% Read sys record
1747    {ok, SysRec} = reltool_server:get_sys(Pid),
1748
1749    %% Set lib dirs by call to set_sys
1750    NewLib = filename:join(datadir(Config),"faulty_app_file"),
1751    NewLibDirs = [NewLib | SysRec#sys.lib_dirs],
1752    NewSysRec = SysRec#sys{lib_dirs=NewLibDirs},
1753    ?msym({ok,["a: Cannot parse app file"++_]},
1754	  reltool_server:set_sys(Pid, NewSysRec)),
1755    ?m({ok,NewSysRec}, reltool_server:get_sys(Pid)),
1756    ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
1757
1758    %% Undo
1759    ?m(ok, reltool_server:undo_config(Pid)),
1760    ?m({ok,SysRec}, reltool_server:get_sys(Pid)),
1761    ?m({ok,[]}, reltool_server:get_status(Pid)),
1762
1763    %% Undo again, to check that it toggles
1764    ?m(ok,reltool_server:undo_config(Pid)),
1765    ?m({ok,NewSysRec}, reltool_server:get_sys(Pid)),
1766    ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
1767
1768    ?m(ok, reltool:stop(Pid)),
1769    ok.
1770
1771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1772load_config_and_undo(Config) ->
1773    Sys1 = {sys,Cfg1=[{incl_cond, exclude},
1774                      {app,kernel,[{incl_cond,include}]},
1775                      {app,sasl,[{incl_cond,include}]},
1776                      {app,stdlib,[{incl_cond,include}]},
1777                      {app,tools,[{incl_cond,include}]}]},
1778    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
1779    Libs = reltool_test_lib:erl_libs(),
1780    Sys11 =
1781        case Libs of
1782            [] -> Sys1;
1783            _  -> {sys, [{lib_dirs, Libs}|Cfg1]}
1784        end,
1785    ?m({ok, Sys11}, reltool:get_config(Pid)),
1786    ?m({ok,[]}, reltool_server:get_status(Pid)),
1787
1788    %% Get app and mod
1789    {ok,Tools1} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
1790    ?m(true, Tools1#app.is_pre_included),
1791    ?m(true, Tools1#app.is_included),
1792    {ok,Cover1} = ?msym({ok,#mod{name=cover,
1793				 is_included=true,
1794				 is_pre_included=true}},
1795			reltool_server:get_mod(Pid,cover)),
1796
1797    %% Change tools from include to derived by loading new config
1798    Sys2 = {sys,[{lib_dirs,[filename:join(datadir(Config),"faulty_app_file")]},
1799		 {app,a,[{incl_cond,include}]},
1800		 {app,kernel,[{incl_cond,include}]},
1801		 {app,sasl,[{incl_cond,include}]},
1802		 {app,stdlib,[{incl_cond,include}]},
1803		 {app,tools,[{incl_cond,derived}]}]},
1804    ?msym({ok,["a: Cannot parse app file"++_]},
1805	  reltool_server:load_config(Pid,Sys2)),
1806%%% OTP-0702, 15)    ?m({ok, Sys2}, reltool:get_config(Pid)),
1807%%% Note that {incl_cond,exclude} is removed compared to Sys1 -
1808%%% config is merged, not overwritten - is this correct???
1809    ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
1810
1811    %% Check that tools is included (since it is used by sasl) but not
1812    %% pre-included (neither included or excluded => undefined)
1813    {ok,Tools2} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
1814    ?m(undefined, Tools2#app.is_pre_included),
1815    ?m(true, Tools2#app.is_included),
1816    {ok,Cover2} = ?msym({ok,#mod{name=cover,
1817				 is_included=true,
1818				 is_pre_included=undefined}},
1819			reltool_server:get_mod(Pid,cover)),
1820
1821    %% Undo
1822    ?m(ok, reltool_server:undo_config(Pid)),
1823    ?m({ok,Tools1}, reltool_server:get_app(Pid,tools)),
1824    ?m({ok,Cover1}, reltool_server:get_mod(Pid,cover)),
1825    ?m({ok,[]}, reltool_server:get_status(Pid)),
1826
1827    %% Undo again, to check that it toggles
1828    ?m(ok, reltool_server:undo_config(Pid)),
1829    ?m({ok,Tools2}, reltool_server:get_app(Pid,tools)),
1830    ?m({ok,Cover2}, reltool_server:get_mod(Pid,cover)),
1831    ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
1832
1833    ?m(ok, reltool:stop(Pid)),
1834    ok.
1835
1836
1837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1838%% Test that load_config is properly rolled back if it fails
1839load_config_fail(_Config) ->
1840    Sys1 = {sys,Cfg1=[{incl_cond, exclude},
1841                      {app,kernel,[{incl_cond,include}]},
1842                      {app,sasl,[{incl_cond,include}]},
1843                      {app,stdlib,[{incl_cond,include}]},
1844                      {app,tools,[{incl_cond,include}]}]},
1845    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
1846    Libs = reltool_test_lib:erl_libs(),
1847    Sys11 =
1848        case Libs of
1849            [] -> Sys1;
1850            _  -> {sys, [{lib_dirs, Libs}|Cfg1]}
1851        end,
1852    ?m({ok, Sys11}, reltool:get_config(Pid)),
1853    ?m({ok,[]}, reltool_server:get_status(Pid)),
1854
1855    %% Get app and mod
1856    {ok,Tools} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
1857
1858    %% Try to load a config with a faulty rel statement (includes a
1859    %% non-existing application)
1860    Sys2 = {sys,[{incl_cond, exclude},
1861		 {boot_rel, "faulty_rel"},
1862		 {rel, "faulty_rel", "1.0", [kernel, sasl, stdlib, xxx]},
1863		 {app,kernel,[{incl_cond,include}]},
1864		 {app,sasl,[{incl_cond,include}]},
1865		 {app,stdlib,[{incl_cond,include}]}]},
1866    ?msym({error,"Release \"faulty_rel\" uses non existing application xxx"},
1867	  reltool_server:load_config(Pid,Sys2)),
1868
1869    %% Check that a rollback is done to the old configuration
1870    ?m({ok, Sys11}, reltool:get_config(Pid,false,false)),
1871
1872    %% and that tools is not changed (i.e. that the new configuration
1873    %% is not applied)
1874    ?m({ok,Tools}, reltool_server:get_app(Pid,tools)),
1875
1876    ?m(ok, reltool:stop(Pid)),
1877    ok.
1878
1879
1880%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1881%% Load config with escript
1882
1883load_config_escript_path(Config) ->
1884    %% Create escript
1885    DataDir = ?config(data_dir,Config),
1886    BeamFile = filename:join([DataDir,escript,"someapp-1.0",ebin,"mymod.beam"]),
1887    {ok,BeamBin} = file:read_file(BeamFile),
1888    EscriptName = "mymod.escript",
1889    Escript = filename:join(?WORK_DIR,EscriptName),
1890    ok = escript:create(Escript,[shebang,{beam,BeamBin}]),
1891    ok = file:change_mode(Escript,8#00744),
1892
1893    %% Start reltool_server with one escript in configuration
1894    EscriptSys =
1895        {sys,
1896         [
1897          {lib_dirs, []},
1898          {escript, Escript, [{incl_cond, include}]},
1899          {profile, standalone}
1900         ]},
1901
1902    {ok, Pid1} = ?msym({ok, _}, reltool:start_server([{config, EscriptSys}])),
1903    {ok,[#app{name='*escript* mymod'}=A]} =
1904	?msym({ok,[_]}, reltool_server:get_apps(Pid1,whitelist)),
1905    ?m(ok, reltool:stop(Pid1)),
1906
1907
1908    %% Do same again, but now start reltool first with simple config,
1909    %% then add escript by loading new configuration and check that
1910    %% #app is the same
1911    SimpleSys =
1912        {sys,
1913         [
1914          {lib_dirs, []}
1915         ]},
1916
1917    {ok, Pid2} = ?msym({ok, _}, reltool:start_server([{config, SimpleSys}])),
1918    ?m({ok,[]}, reltool_server:get_apps(Pid2,whitelist)),
1919    ?m({ok,[]}, reltool_server:load_config(Pid2,EscriptSys)),
1920    ?m({ok,[A]}, reltool_server:get_apps(Pid2,whitelist)),
1921
1922    ?m(ok, reltool:stop(Pid2)),
1923
1924    ok.
1925
1926%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1927%% Load config with same (source) escript twice and check that the
1928%% application information is not changed.
1929
1930load_config_same_escript_source(_Config) ->
1931    %% Create escript
1932    ExDir = code:lib_dir(reltool, examples),
1933    EscriptName = "display_args",
1934    Escript = filename:join([ExDir, EscriptName]),
1935
1936    %% Start reltool_server with one escript in configuration
1937    Sys =
1938        {sys,
1939         [
1940          {lib_dirs, []},
1941          {escript, Escript, [{incl_cond, include}]},
1942          {profile, standalone}
1943         ]},
1944
1945    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
1946%    {ok,[#app{name='*escript* display_args'}]} =
1947    ?msym({ok,[#app{name='*escript* display_args',mods=[_]}]},
1948	  reltool_server:get_apps(Pid,whitelist)),
1949
1950    %% Load the same config again, then check that app is not changed
1951    ?m({ok,[]}, reltool_server:load_config(Pid,Sys)),
1952    ?msym({ok,[#app{name='*escript* display_args',mods=[_]}]},
1953	  reltool_server:get_apps(Pid,whitelist)),
1954
1955    ?m(ok, reltool:stop(Pid)),
1956
1957    ok.
1958
1959%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1960%% Load config with same (beam) escript twice and check that the
1961%% application information is not changed.
1962
1963load_config_same_escript_beam(Config) ->
1964    %% Create escript
1965    DataDir = ?config(data_dir,Config),
1966    BeamFile = filename:join([DataDir,escript,"someapp-1.0",ebin,"mymod.beam"]),
1967    {ok,BeamBin} = file:read_file(BeamFile),
1968    EscriptName = "mymod.escript",
1969    Escript = filename:join(?WORK_DIR,EscriptName),
1970    ok = escript:create(Escript,[shebang,{beam,BeamBin}]),
1971    ok = file:change_mode(Escript,8#00744),
1972
1973    %% Start reltool_server with one escript in configuration
1974    Sys =
1975        {sys,
1976         [
1977          {lib_dirs, []},
1978          {escript, Escript, [{incl_cond, include}]},
1979          {profile, standalone}
1980         ]},
1981
1982    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
1983    {ok,[#app{name='*escript* mymod'}=A]} =
1984	?msym({ok,[_]}, reltool_server:get_apps(Pid,whitelist)),
1985
1986    %% Load the same config again, then check that app is not changed
1987    ?m({ok,[]}, reltool_server:load_config(Pid,Sys)),
1988    ?m({ok,[A]}, reltool_server:get_apps(Pid,whitelist)),
1989
1990    ?m(ok, reltool:stop(Pid)),
1991
1992    ok.
1993
1994%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1995%% Load config with escript
1996
1997load_config_add_escript(Config) ->
1998    %% First escript
1999    ExDir = code:lib_dir(reltool, examples),
2000    EscriptName1 = "display_args",
2001    Escript1 = filename:join([ExDir, EscriptName1]),
2002
2003    %% Second escript
2004    DataDir = ?config(data_dir,Config),
2005    BeamFile = filename:join([DataDir,escript,"someapp-1.0",ebin,"mymod.beam"]),
2006    {ok,BeamBin} = file:read_file(BeamFile),
2007    EscriptName2 = "mymod.escript",
2008    Escript2 = filename:join(?WORK_DIR,EscriptName2),
2009    ok = escript:create(Escript2,[shebang,{beam,BeamBin}]),
2010    ok = file:change_mode(Escript2,8#00744),
2011
2012    %% Start reltool_server with one escript in configuration
2013    Sys1 =
2014        {sys,
2015         [
2016          {lib_dirs, []},
2017          {escript, Escript2, [{incl_cond, include}]},
2018          {profile, standalone}
2019         ]},
2020
2021    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
2022
2023    %% Add second escript by loading new configuration
2024    Sys2 =
2025        {sys,
2026         [
2027          {lib_dirs, []},
2028          {escript, Escript1, [{incl_cond, include}]},
2029          {escript, Escript2, [{incl_cond, include}]},
2030          {profile, standalone}
2031         ]},
2032
2033    {ok,[]} = ?m({ok,[]}, reltool_server:load_config(Pid,Sys2)),
2034    {ok,[#app{name='*escript* display_args'},
2035	 #app{name='*escript* mymod'}]} =
2036	?msym({ok,[_,_]}, reltool_server:get_apps(Pid,whitelist)),
2037
2038    ?m(ok, reltool:stop(Pid)),
2039
2040    ok.
2041
2042%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2043reset_config_and_undo(Config) ->
2044    Sys1 = {sys,[{lib_dirs,[filename:join(datadir(Config),"faulty_app_file")]},
2045		 {incl_cond, exclude},
2046		 {app,a,[{incl_cond,include}]},
2047		 {app,kernel,[{incl_cond,include}]},
2048		 {app,sasl,[{incl_cond,include}]},
2049		 {app,stdlib,[{incl_cond,include}]},
2050		 {app,tools,[{incl_cond,include}]}]},
2051    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
2052    ?m({ok, Sys1}, reltool:get_config(Pid)),
2053    ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
2054
2055    %% Get app and mod
2056    {ok,Tools1} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
2057    ?m(true, Tools1#app.is_pre_included),
2058    ?m(true, Tools1#app.is_included),
2059    {ok,Cover1} = ?msym({ok,#mod{name=cover,
2060				 is_included=true,
2061				 is_pre_included=true}},
2062			reltool_server:get_mod(Pid,cover)),
2063
2064    %% Exclude tools by loading new config
2065    Sys2 = {sys,[{incl_cond, exclude},
2066		 {app,kernel,[{incl_cond,include}]},
2067		 {app,sasl,[{incl_cond,include}]},
2068		 {app,stdlib,[{incl_cond,include}]},
2069		 {app,tools,[{incl_cond,exclude}]}]},
2070    ?m({ok,[]}, reltool_server:load_config(Pid,Sys2)),
2071    ?m({ok,[]}, reltool_server:get_status(Pid)),
2072
2073    %% Check that tools is excluded
2074    {ok,Tools2} = ?msym({ok,_}, reltool_server:get_app(Pid,tools)),
2075    ?m(false, Tools2#app.is_pre_included),
2076    ?m(false, Tools2#app.is_included),
2077    {ok,Cover2} = ?msym({ok,#mod{name=cover,
2078				 is_included=false,
2079				 is_pre_included=false}},
2080			reltool_server:get_mod(Pid,cover)),
2081
2082    %% Reset
2083    ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:reset_config(Pid)),
2084    ?m({ok,Tools1}, reltool_server:get_app(Pid,tools)),
2085    ?m({ok,Cover1}, reltool_server:get_mod(Pid,cover)),
2086    ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
2087
2088    %% Undo
2089    ?m(ok, reltool_server:undo_config(Pid)),
2090    ?m({ok,Tools2}, reltool_server:get_app(Pid,tools)),
2091    ?m({ok,Cover2}, reltool_server:get_mod(Pid,cover)),
2092    ?m({ok,[]}, reltool_server:get_status(Pid)),
2093
2094    %% Undo again, to check that it toggles
2095    ?m(ok, reltool_server:undo_config(Pid)),
2096    ?m({ok,Tools1}, reltool_server:get_app(Pid,tools)),
2097    ?m({ok,Cover1}, reltool_server:get_mod(Pid,cover)),
2098    ?msym({ok,["a: Cannot parse app file"++_]},reltool_server:get_status(Pid)),
2099
2100    ?m(ok, reltool:stop(Pid)),
2101    ok.
2102
2103%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2104gen_rel_files(_Config) ->
2105    %% Configure the server
2106    RelName = "gen_fel_files_test",
2107    RelVsn = "1.0",
2108    Sys =
2109        {sys,
2110         [
2111          {lib_dirs, []},
2112          {boot_rel, RelName},
2113          {rel, RelName, RelVsn, [kernel, stdlib]}
2114         ]},
2115    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
2116
2117    %% Generate .rel, .script and .boot
2118    Dir = filename:join(?WORK_DIR,"gen_rel_files"),
2119    ok = file:make_dir(Dir),
2120    ?m({ok,[]}, reltool_server:gen_rel_files(Pid,Dir)),
2121
2122    Script = RelName ++ ".script",
2123    Rel = RelName ++ ".rel",
2124    Boot = RelName ++ ".boot",
2125    {ok,Files} = ?msym({ok,_}, file:list_dir(Dir)),
2126    [Boot,Rel,Script] = lists:sort(Files),
2127
2128    %% Check that contents is reasonable
2129    {ok,[S]} = ?msym({ok,[{script,_,_}]},file:consult(filename:join(Dir,Script))),
2130    ?msym({ok,[{release,_,_,_}]}, file:consult(filename:join(Dir,Rel))),
2131    {ok,Bin} = ?msym({ok,_}, file:read_file(filename:join(Dir,Boot))),
2132    ?m(S,binary_to_term(Bin)),
2133
2134    ?m(ok, reltool:stop(Pid)),
2135    ok.
2136
2137%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2138save_config(Config) ->
2139    PrivDir = ?config(priv_dir,Config),
2140    Sys = {sys,Cfg=[{incl_cond, exclude},
2141                    {app,kernel,[{incl_cond,include}]},
2142                    {app,sasl,[{incl_cond,include}]},
2143                    {app,stdlib,[{incl_cond,include}]}]},
2144    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
2145    Libs = reltool_test_lib:erl_libs(),
2146    Sys1 =
2147        case Libs of
2148            [] -> Sys;
2149            _  -> {sys, [{lib_dirs, Libs}|Cfg]}
2150        end,
2151    ?m({ok, Sys1}, reltool:get_config(Pid)),
2152
2153    Simple = filename:join(PrivDir,"save_simple.reltool"),
2154    ?m(ok, reltool_server:save_config(Pid,Simple,false,false)),
2155    ?m({ok,[Sys1]}, file:consult(Simple)),
2156
2157    Derivates = filename:join(PrivDir,"save_derivates.reltool"),
2158    ?m(ok, reltool_server:save_config(Pid,Derivates,false,true)),
2159    case Libs of
2160        [] ->
2161            ?msym({ok,[{sys,[{incl_cond, exclude},
2162                             {erts,[]},
2163                             {app,kernel,[{incl_cond,include},{mod,_,[]}|_]},
2164                             {app,sasl,[{incl_cond,include},{mod,_,[]}|_]},
2165                             {app,stdlib,[{incl_cond,include},{mod,_,[]}|_]}]}]},
2166                  file:consult(Derivates));
2167        _ ->
2168            ?msym({ok,[{sys,[{lib_dirs,Libs},
2169                             {incl_cond, exclude},
2170                             {erts,[]},
2171                             {app,kernel,[{incl_cond,include},{mod,_,[]}|_]},
2172                             {app,sasl,[{incl_cond,include},{mod,_,[]}|_]},
2173                             {app,stdlib,[{incl_cond,include},{mod,_,[]}|_]}]}]},
2174                  file:consult(Derivates))
2175    end,
2176
2177    Defaults = filename:join(PrivDir,"save_defaults.reltool"),
2178    ?m(ok, reltool_server:save_config(Pid,Defaults,true,false)),
2179    ?msym({ok,[{sys,[{root_dir,_},
2180		     {lib_dirs,_},
2181		     {mod_cond,all},
2182		     {incl_cond,exclude},
2183		     {app,kernel,[{incl_cond,include},{vsn,undefined},
2184				  {lib_dir,undefined}]},
2185		     {app,sasl,[{incl_cond,include},{vsn,undefined},
2186				{lib_dir,undefined}]},
2187		     {app,stdlib,[{incl_cond,include},{vsn,undefined},
2188				  {lib_dir,undefined}]},
2189		     {boot_rel,"start_clean"},
2190                     {rel,"no_dot_erlang","1.0",[],[{load_dot_erlang,false}]},
2191		     {rel,"start_clean","1.0",[],[{load_dot_erlang,true}]},
2192		     {rel,"start_sasl","1.0",[sasl],[{load_dot_erlang,true}]},
2193		     {emu_name,"beam"},
2194		     {relocatable,true},
2195		     {profile,development},
2196		     {incl_sys_filters,[".*"]},
2197		     {excl_sys_filters,[]},
2198		     {incl_app_filters,[".*"]},
2199		     {excl_app_filters,[]},
2200		     {incl_archive_filters,[".*"]},
2201		     {excl_archive_filters,["^include$","^priv$"]},
2202		     {archive_opts,[]},
2203		     {rel_app_type,permanent},
2204		     {app_file,keep},
2205		     {debug_info,keep}]}]},
2206	  file:consult(Defaults)),
2207
2208    KVsn = latest(kernel),
2209    StdVsn = latest(stdlib),
2210    SaslVsn = latest(sasl),
2211
2212    LibDir = code:lib_dir(),
2213    KLibDir = filename:join(LibDir,"kernel-"++KVsn),
2214    StdLibDir = filename:join(LibDir,"stdlib-"++StdVsn),
2215    SaslLibDir = filename:join(LibDir,"sasl-"++SaslVsn),
2216
2217    All = filename:join(PrivDir,"save_all.reltool"),
2218    ?m(ok, reltool_server:save_config(Pid,All,true,true)),
2219    ?msym({ok,[{sys,[{root_dir,_},
2220		     {lib_dirs,_},
2221		     {mod_cond,all},
2222		     {incl_cond,exclude},
2223		     {erts,[]},
2224		     {app,kernel,[{incl_cond,include},{vsn,KVsn},
2225				  {lib_dir,KLibDir},{mod,_,[]}|_]},
2226		     {app,sasl,[{incl_cond,include},{vsn,SaslVsn},
2227				{lib_dir,SaslLibDir},{mod,_,[]}|_]},
2228		     {app,stdlib,[{incl_cond,include},{vsn,StdVsn},
2229				  {lib_dir,StdLibDir},{mod,_,[]}|_]},
2230		     {boot_rel,"start_clean"},
2231                     {rel,"no_dot_erlang","1.0",[],[{load_dot_erlang,false}]},
2232		     {rel,"start_clean","1.0",[],[{load_dot_erlang,true}]},
2233		     {rel,"start_sasl","1.0",[sasl],[{load_dot_erlang,true}]},
2234		     {emu_name,"beam"},
2235		     {relocatable,true},
2236		     {profile,development},
2237		     {incl_sys_filters,[".*"]},
2238		     {excl_sys_filters,[]},
2239		     {incl_app_filters,[".*"]},
2240		     {excl_app_filters,[]},
2241		     {incl_archive_filters,[".*"]},
2242		     {excl_archive_filters,["^include$","^priv$"]},
2243		     {archive_opts,[]},
2244		     {rel_app_type,permanent},
2245		     {app_file,keep},
2246		     {debug_info,keep}]}]},
2247	  file:consult(All)),
2248
2249    ?m(ok, reltool:stop(Pid)),
2250    ok.
2251
2252%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2253%% Test calculation of dependencies
2254%% The following test applications are used
2255%%
2256%% x-1.0: x1.erl   x2.erl   x3.erl
2257%%                   \        /         (x2 calls y1, x3 calls y2)
2258%% y-1.0: y0.erl    y1.erl   y2.erl
2259%%                    \                 (y1 calls z1)
2260%% z-1.0            z1.erl
2261%%
2262%% Test includes x and derives y and z.
2263%%
2264dependencies(Config) ->
2265    %% Default: all modules included => y and z are included (derived)
2266    Sys = {sys,[{lib_dirs,[filename:join(datadir(Config),"dependencies")]},
2267		{incl_cond, exclude},
2268		{app,kernel,[{incl_cond,include}]},
2269		{app,sasl,[{incl_cond,include}]},
2270		{app,stdlib,[{incl_cond,include}]},
2271		{app,x,[{incl_cond,include}]},
2272		{app,y,[{incl_cond,derived}]},
2273		{app,z,[{incl_cond,derived}]}]},
2274    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
2275
2276    ?msym({ok,[#app{name=kernel},
2277	       #app{name=sasl},
2278	       #app{name=stdlib},
2279	       #app{name=x,uses_apps=[y]}]},
2280	  reltool_server:get_apps(Pid,whitelist)),
2281    {ok, Der} = ?msym({ok,_},
2282		      reltool_server:get_apps(Pid,derived)),
2283    ?msym([#app{name=y,uses_apps=[z]},
2284	   #app{name=z}],
2285	  rm_missing_app(Der)),
2286    ?msym({ok,[]},
2287	  reltool_server:get_apps(Pid,source)),
2288
2289    %% Excluding x2 => y still included since y2 is used by x3
2290    %%                 z still included since z1 is used by y1
2291    Sys2 = {sys,[{lib_dirs,[filename:join(datadir(Config),"dependencies")]},
2292		 {incl_cond, exclude},
2293		 {app,kernel,[{incl_cond,include}]},
2294		 {app,sasl,[{incl_cond,include}]},
2295		 {app,stdlib,[{incl_cond,include}]},
2296		 {app,x,[{incl_cond,include},{mod,x2,[{incl_cond,exclude}]}]},
2297		 {app,y,[{incl_cond,derived}]},
2298		 {app,z,[{incl_cond,derived}]}]},
2299    ?m({ok,[]}, reltool_server:load_config(Pid,Sys2)),
2300    ?msym({ok,[#app{name=kernel},
2301	       #app{name=sasl},
2302	       #app{name=stdlib},
2303	       #app{name=x,uses_apps=[y]}]},
2304	  reltool_server:get_apps(Pid,whitelist)),
2305    {ok, Der2} = ?msym({ok,_},
2306		       reltool_server:get_apps(Pid,derived)),
2307    ?msym([#app{name=y,uses_apps=[z]},
2308	   #app{name=z}],
2309	  rm_missing_app(Der2)),
2310    ?msym({ok,[]},
2311	  reltool_server:get_apps(Pid,source)),
2312
2313    %% Excluding x3 => y still included since y1 is used by x2
2314    %%                 z still included since z1 is used by y1
2315    Sys3 = {sys,[{lib_dirs,[filename:join(datadir(Config),"dependencies")]},
2316		 {incl_cond, exclude},
2317		 {app,kernel,[{incl_cond,include}]},
2318		 {app,sasl,[{incl_cond,include}]},
2319		 {app,stdlib,[{incl_cond,include}]},
2320		 {app,x,[{incl_cond,include},{mod,x3,[{incl_cond,exclude}]}]},
2321		 {app,y,[{incl_cond,derived}]},
2322		 {app,z,[{incl_cond,derived}]}]},
2323    ?m({ok,[]}, reltool_server:load_config(Pid,Sys3)),
2324    ?msym({ok,[#app{name=kernel},
2325	       #app{name=sasl},
2326	       #app{name=stdlib},
2327	       #app{name=x,uses_apps=[y]}]},
2328	  reltool_server:get_apps(Pid,whitelist)),
2329    {ok, Der3} = ?msym({ok,_},
2330		       reltool_server:get_apps(Pid,derived)),
2331    ?msym([#app{name=y,uses_apps=[z]},
2332	   #app{name=z}],
2333	  rm_missing_app(Der3)),
2334    ?msym({ok,[]},
2335	  reltool_server:get_apps(Pid,source)),
2336
2337    %% Excluding x2 and x3 => y and z excluded
2338    Sys4 = {sys,[{lib_dirs,[filename:join(datadir(Config),"dependencies")]},
2339		 {incl_cond, exclude},
2340		 {app,kernel,[{incl_cond,include}]},
2341		 {app,sasl,[{incl_cond,include}]},
2342		 {app,stdlib,[{incl_cond,include}]},
2343		 {app,x,[{incl_cond,include},
2344			 {mod,x2,[{incl_cond,exclude}]},
2345			 {mod,x3,[{incl_cond,exclude}]}]},
2346		 {app,y,[{incl_cond,derived}]},
2347		 {app,z,[{incl_cond,derived}]}]},
2348    ?m({ok,[]}, reltool_server:load_config(Pid,Sys4)),
2349    ?msym({ok,[#app{name=kernel},
2350	       #app{name=sasl},
2351	       #app{name=stdlib},
2352	       #app{name=x,uses_apps=[]}]},
2353	  reltool_server:get_apps(Pid,whitelist)),
2354    {ok, Der4} = ?msym({ok,_},
2355		       reltool_server:get_apps(Pid,derived)),
2356    ?msym([], rm_missing_app(Der4)),
2357    ?msym({ok,[#app{name=y},
2358	       #app{name=z}]},
2359	  reltool_server:get_apps(Pid,source)),
2360
2361    %% Excluding y1 => y still included since y2 is used by x3
2362    %%                 z excluded since not used by any other than y1
2363    Sys5 = {sys,[{lib_dirs,[filename:join(datadir(Config),"dependencies")]},
2364		 {incl_cond, exclude},
2365		 {app,kernel,[{incl_cond,include}]},
2366		 {app,sasl,[{incl_cond,include}]},
2367		 {app,stdlib,[{incl_cond,include}]},
2368		 {app,x,[{incl_cond,include}]},
2369		 {app,y,[{incl_cond,derived},
2370			 {mod,y1,[{incl_cond,exclude}]}]},
2371		 {app,z,[{incl_cond,derived}]}]},
2372    ?m({ok,[]}, reltool_server:load_config(Pid,Sys5)),
2373    ?msym({ok,[#app{name=kernel},
2374	       #app{name=sasl},
2375	       #app{name=stdlib},
2376	       #app{name=x,uses_apps=[y]}]},
2377	  reltool_server:get_apps(Pid,whitelist)),
2378    {ok, Der5} = ?msym({ok,_},
2379		       reltool_server:get_apps(Pid,derived)),
2380    ?msym([#app{name=y,uses_apps=[]}], rm_missing_app(Der5)),
2381    ?msym({ok,[#app{name=z}]},
2382	  reltool_server:get_apps(Pid,source)),
2383
2384    ?m(ok, reltool:stop(Pid)),
2385    ok.
2386
2387
2388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2389%% Test that incl_cond on mod level overwrites mod_cond on app level
2390%% Uses same test applications as dependencies/1 above
2391mod_incl_cond_derived(Config) ->
2392    %% In app y: mod_cond=none means no module shall be included
2393    %% but mod_cond is overwritten by incl_cond on mod level
2394    Sys = {sys,[{lib_dirs,[filename:join(datadir(Config),"dependencies")]},
2395		{incl_cond, exclude},
2396		{app,kernel,[{incl_cond,include}]},
2397		{app,sasl,[{incl_cond,include}]},
2398		{app,stdlib,[{incl_cond,include}]},
2399		{app,x,[{incl_cond,include}]},
2400		{app,y,[{incl_cond,include},
2401			{mod_cond,none},
2402			{mod,y0,[{incl_cond,derived}]},
2403			{mod,y2,[{incl_cond,derived}]}]}]},
2404    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
2405
2406    ?msym({ok,[#app{name=kernel},
2407	       #app{name=sasl},
2408	       #app{name=stdlib},
2409	       #app{name=x,uses_apps=[y]},
2410	       #app{name=y,uses_apps=[]}]},
2411	  reltool_server:get_apps(Pid,whitelist)),
2412    {ok, Der} = ?msym({ok,_},reltool_server:get_apps(Pid,derived)),
2413    ?msym([], rm_missing_app(Der)),
2414    ?msym({ok,[]}, reltool_server:get_apps(Pid,source)),
2415
2416    %% 1. check that y0 is not included since it has
2417    %% incl_cond=derived, but is not used by any other module.
2418    ?msym({ok,#mod{is_included=undefined}}, reltool_server:get_mod(Pid,y0)),
2419
2420    %% 2. check that y1 is excluded since it has undefined incl_cond
2421    %% on mod level, so mod_cond on app level shall be used.
2422    ?msym({ok,#mod{is_included=false}}, reltool_server:get_mod(Pid,y1)),
2423
2424    %% 3. check that y2 is included since it has incl_cond=derived and
2425    %% is used by x3.
2426    ?msym({ok,#mod{is_included=true}}, reltool_server:get_mod(Pid,y2)),
2427
2428    ok.
2429
2430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2431%% ERL-167, OTP-11993: For applications that are not included in a
2432%% release spec ('rel'), dependencies in the .app files are not
2433%% considered - only those found with xref.
2434dep_in_app_not_xref(Config) ->
2435    RelName = "Just testing...",
2436    RelVsn = "1.0",
2437    Sys =
2438        {sys,
2439         [
2440	  {lib_dirs,[filename:join(datadir(Config),"dep_in_app_not_xref")]},
2441	  {incl_cond,exclude},
2442	  {incl_archive_filters,[]},
2443	  {erts,[{incl_cond,exclude}]},
2444          {boot_rel, RelName},
2445          {rel, RelName, RelVsn, [kernel, stdlib]},
2446	  {app,kernel,[{incl_cond,include}]},
2447	  {app,stdlib,[{incl_cond,include}]},
2448	  {app,x,[{incl_cond,include}]},
2449	  {app,y,[{incl_cond,derived}]},
2450	  {app,z,[{incl_cond,derived}]}
2451         ]},
2452
2453    TargetDir = filename:join([?WORK_DIR, "target_dep_in_app_not_xref"]),
2454    ?m(ok, reltool_utils:recursive_delete(TargetDir)),
2455    ?m(ok, file:make_dir(TargetDir)),
2456    ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Sys}])]),
2457    ok = ?m(ok, reltool:create_target([{config, Sys}], TargetDir)),
2458    ?log("~p~n",[file:list_dir(filename:join([TargetDir,"lib"]))]),
2459
2460    ?m(true, filelib:is_dir(filename:join([TargetDir,"lib","y-1.0"]))),
2461    ?m(true, filelib:is_dir(filename:join([TargetDir,"lib","z-1.0"]))),
2462    ok.
2463
2464%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2465use_selected_vsn(Config) ->
2466    LibDir1 = filename:join(datadir(Config),"use_selected_vsn"),
2467    B1Dir = filename:join(LibDir1,"b-1.0"),
2468    B3Dir = filename:join(LibDir1,"b-3.0"),
2469
2470    LibDir2 = filename:join(LibDir1,"lib2"),
2471    B2Dir = filename:join(LibDir2,"b-2.0"),
2472
2473    %%-----------------------------------------------------------------
2474    %% Pre-selected vsn of app b
2475    Sys1 = {sys,[{lib_dirs,[LibDir1]},
2476		 {incl_cond, exclude},
2477		 {app,kernel,[{incl_cond,include}]},
2478		 {app,sasl,[{incl_cond,include}]},
2479		 {app,stdlib,[{incl_cond,include}]},
2480		 {app,b,[{incl_cond,include},{vsn,"1.0"}]}]},
2481    {ok, Pid1} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
2482    {ok,B11} = ?msym({ok,#app{vsn="1.0",active_dir=B1Dir}},
2483		     reltool_server:get_app(Pid1,b)),
2484
2485    %% Change from a pre-selected vsn to use a specific dir
2486    ?msym({ok, #app{vsn ="3.0", active_dir = B3Dir}, []},
2487	  reltool_server:set_app(Pid1,
2488				 B11#app{active_dir = B3Dir,
2489					 use_selected_vsn = dir,
2490					 label = undefined,
2491					 vsn = undefined,
2492					 info = undefined})),
2493    ?m(ok, reltool:stop(Pid1)),
2494
2495
2496    %%-----------------------------------------------------------------
2497    %% Pre-selected vsn of app b
2498    Sys2 = {sys,[{lib_dirs,[LibDir1]},
2499		 {incl_cond, exclude},
2500		 {app,kernel,[{incl_cond,include}]},
2501		 {app,sasl,[{incl_cond,include}]},
2502		 {app,stdlib,[{incl_cond,include}]},
2503		 {app,b,[{incl_cond,include},{vsn,"1.0"}]}]},
2504    {ok, Pid2} = ?msym({ok, _}, reltool:start_server([{config, Sys2}])),
2505    {ok,B21} = ?msym({ok,#app{vsn="1.0",active_dir=B1Dir}},
2506		     reltool_server:get_app(Pid2,b)),
2507
2508    %% Change from a pre-selected vsn to use latest
2509    ?msym({ok, #app{vsn ="3.0", active_dir = B3Dir}, []},
2510	  reltool_server:set_app(Pid2,
2511				 B21#app{use_selected_vsn=undefined,
2512					 label = undefined,
2513					 vsn = undefined,
2514					 info = undefined})),
2515    ?m(ok, reltool:stop(Pid2)),
2516
2517
2518    %%-----------------------------------------------------------------
2519    %% Pre-selected directory for app b
2520    Sys3 = {sys,[{lib_dirs,[LibDir1]},
2521		 {incl_cond, exclude},
2522		 {app,kernel,[{incl_cond,include}]},
2523		 {app,sasl,[{incl_cond,include}]},
2524		 {app,stdlib,[{incl_cond,include}]},
2525		 {app,b,[{incl_cond,include},{lib_dir,B2Dir}]}]},
2526    {ok, Pid3} = ?msym({ok, _}, reltool:start_server([{config, Sys3}])),
2527%    test_server:break("Pid3 = list_to_pid(\""++pid_to_list(Pid3)++"\")."),
2528    {ok,B31} = ?msym({ok,#app{vsn="2.0",active_dir=B2Dir}},
2529		     reltool_server:get_app(Pid3,b)),
2530    %% Change from a pre-selected dir to use latest
2531    {ok,B32,_} = ?msym({ok, #app{vsn ="3.0", active_dir = B3Dir}, []},
2532		       reltool_server:set_app(Pid3,
2533					      B31#app{use_selected_vsn=undefined,
2534						      label = undefined,
2535						      vsn = undefined,
2536						      info = undefined})),
2537    %% Change back to use selected dir
2538    {ok,B33,_} = ?msym({ok, #app{vsn ="3.0", active_dir = B3Dir}, []},
2539		       reltool_server:set_app(Pid3,
2540					      B32#app{use_selected_vsn = dir})),
2541    %% use dir 1
2542    {ok,B34,_} = ?msym({ok, #app{vsn ="1.0", active_dir = B1Dir}, []},
2543		       reltool_server:set_app(Pid3,
2544					      B33#app{active_dir = B1Dir,
2545						      label = undefined,
2546						      vsn = undefined,
2547						      info = undefined})),
2548    %% use dir 2
2549    {ok,B35,_} = ?msym({ok, #app{vsn ="2.0", active_dir = B2Dir}, []},
2550		       reltool_server:set_app(Pid3,
2551					      B34#app{active_dir = B2Dir,
2552						      label = undefined,
2553						      vsn = undefined,
2554						      info = undefined})),
2555    %% use dir 3
2556    ?msym({ok, #app{vsn ="3.0", active_dir = B3Dir}, []},
2557	  reltool_server:set_app(Pid3,
2558				 B35#app{active_dir = B3Dir,
2559					 label = undefined,
2560					 vsn = undefined,
2561					 info = undefined})),
2562    ?m(ok, reltool:stop(Pid3)),
2563    ok.
2564
2565
2566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2567use_selected_vsn_relative_path(Config) ->
2568    LibDir = filename:join([datadir(Config),"use_selected_vsn","b-1.0"]),
2569    RelDir = filename:join(LibDir,"rel"),
2570
2571    {ok,Cwd} = file:get_cwd(),
2572    ok = file:set_cwd(RelDir),
2573
2574    Sys = {sys,[{incl_cond, exclude},
2575		{app,kernel,[{incl_cond,include}]},
2576		{app,sasl,[{incl_cond,include}]},
2577		{app,stdlib,[{incl_cond,include}]},
2578		{app,b,[{incl_cond,include},{lib_dir,".."}]}]},
2579    {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
2580
2581    ?msym({ok,#app{vsn="1.0",active_dir=LibDir}},reltool_server:get_app(Pid,b)),
2582
2583    ?m(ok, reltool:stop(Pid)),
2584
2585    ok = file:set_cwd(Cwd),
2586    ok.
2587
2588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2589%% Test that reltool recognizes an application with its real name even
2590%% though it uses non standard format for its version number (in the
2591%% directory name)
2592non_standard_vsn_id(Config) ->
2593    LibDir = filename:join(datadir(Config),"non_standard_vsn_id"),
2594    B1Dir = filename:join(LibDir,"b-first"),
2595    B2Dir = filename:join(LibDir,"b-second"),
2596
2597    %%-----------------------------------------------------------------
2598    %% Default vsn of app b
2599    Sys1 = {sys,[{lib_dirs,[LibDir]},
2600		 {incl_cond, exclude},
2601		 {app,kernel,[{incl_cond,include}]},
2602		 {app,sasl,[{incl_cond,include}]},
2603		 {app,stdlib,[{incl_cond,include}]},
2604		 {app,b,[{incl_cond,include}]}]},
2605    {ok, Pid1} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])),
2606    ?msym({ok,#app{vsn="first",active_dir=B1Dir,sorted_dirs=[B1Dir,B2Dir]}},
2607	  reltool_server:get_app(Pid1,b)),
2608
2609    %%-----------------------------------------------------------------
2610    %% Pre-selected vsn of app b
2611    Sys2 = {sys,[{lib_dirs,[LibDir]},
2612		 {incl_cond, exclude},
2613		 {app,kernel,[{incl_cond,include}]},
2614		 {app,sasl,[{incl_cond,include}]},
2615		 {app,stdlib,[{incl_cond,include}]},
2616		 {app,b,[{incl_cond,include},{vsn,"second"}]}]},
2617    {ok, Pid2} = ?msym({ok, _}, reltool:start_server([{config, Sys2}])),
2618    ?msym({ok,#app{vsn="second",active_dir=B2Dir,sorted_dirs=[B1Dir,B2Dir]}},
2619	  reltool_server:get_app(Pid2,b)),
2620   ok.
2621
2622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2623undefined_regexp(_Config) ->
2624    ?msym({ok,_},
2625          reltool:get_config([{sys,[{app,asn1,[{excl_app_filters,
2626                                                {add, ["^priv"]}}]}]}])),
2627    ok.
2628
2629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2630%% Checks that reltool_utils can correctly read Windows ERL_LIBS
2631
2632windows_erl_libs(_Config) ->
2633    WinErlLibs =
2634        "C:\\Program Files\\Erlang Libs;C:\\Program Files\\More Erlang Libs",
2635    Ret = reltool_utils:erl_libs(WinErlLibs, {win32, nt}),
2636    ?m(["C:\\Program Files\\Erlang Libs","C:\\Program Files\\More Erlang Libs"],
2637       Ret),
2638    ok.
2639
2640%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2641%% Library functions
2642
2643datadir(Config) ->
2644    %% Removes the trailing slash...
2645    filename:nativename(?config(data_dir,Config)).
2646
2647latest(App) ->
2648    AppStr = atom_to_list(App),
2649    AppDirs = filelib:wildcard(filename:join(code:lib_dir(),AppStr++"-*")),
2650    [LatestAppDir|_] = lists:reverse(AppDirs),
2651    [_,Vsn] = string:lexemes(filename:basename(LatestAppDir),"-"),
2652    Vsn.
2653
2654rm_missing_app(Apps) ->
2655    lists:keydelete(?MISSING_APP_NAME,#app.name,Apps).
2656
2657%% We will compare the script generated by systools with
2658%% the script generated by Reltool.
2659%%
2660%% The systools script may include additional modules in
2661%% the first primLoad command (as a pure optimization).
2662%% Therefore, we cannot compare the primLoad commands
2663%% directly. Instead we will collect all modules from
2664%% all primLoad commands in each script. The same
2665%% modules must be loaded by both scripts. In addition,
2666%% the error_handler module must be included in the
2667%% first primLoad in each script.
2668
2669diff_script(Script, Script) ->
2670    equal;
2671diff_script({script, Rel, Commands1}, {script, Rel, Commands2}) ->
2672    case diff_cmds(Commands1, Commands2) of
2673	equal ->
2674	    Loaded = diff_get_prim_load(Commands1),
2675	    case diff_get_prim_load(Commands2) of
2676		Loaded ->
2677		    equal;
2678		Other ->
2679		    io:format("Only loaded by systools: ~p",
2680			      [Loaded--Other]),
2681		    io:format("Only loaded by reltool: ~p",
2682			      [Other--Loaded]),
2683		    ct:fail(different_prim_loads)
2684	    end;
2685	Error ->
2686	    Error
2687    end;
2688diff_script({script, Rel1, _}, {script, Rel2, _}) ->
2689    {error, {Rel1, Rel2}}.
2690
2691diff_cmds([{primLoad, Ms1}=Cmd1 | Commands1],
2692	  [{primLoad, Ms2}=Cmd2 | Commands2]) ->
2693    case lists:member(error_handler, Ms1) xor
2694	lists:member(error_handler, Ms2) of
2695	false ->
2696	    %% error_handler either present in both or
2697	    %% absent in both.
2698	    diff_cmds(Commands1, Commands2);
2699	true ->
2700	    %% error_handler only present in one primLoad.
2701	    %% Not OK.
2702	    {diff, missing_error_handler,
2703	     {expected, Cmd1}, {actual, Cmd2}}
2704    end;
2705diff_cmds([Cmd | Commands1], [Cmd | Commands2]) ->
2706    diff_cmds(Commands1, Commands2);
2707diff_cmds([Cmd1 | _Commands1], [Cmd2 | _Commands2]) ->
2708    {diff, {expected, Cmd1}, {actual, Cmd2}};
2709diff_cmds([], []) ->
2710    equal.
2711
2712diff_get_prim_load(Cmds) ->
2713    L = [Ms || {primLoad, Ms} <- Cmds],
2714    lists:sort(lists:flatten(L)).
2715
2716os_cmd(Cmd) when is_list(Cmd) ->
2717    %% Call the plain os:cmd with an echo command appended to print command status
2718    %% io:format("os:cmd(~p).\n", [Cmd]),
2719    case os:cmd(Cmd++";echo \"#$?\"") of
2720        %% There is (as far as I can tell) only one thing that will match this
2721        %% and that is too silly to ever be used, but...
2722        []->
2723            {99, []};
2724        Return->
2725            %% Find the position of the status code wich is last in the string
2726            %% prepended with #
2727            case string:split(Return, "$#", trailing) of
2728                [_] -> %% This happens only if the sh command pipe is somehow interrupted
2729                    {98, Return};
2730                [Result, Status0] ->
2731                    {list_to_integer(string:trim(Status0)), Result}
2732            end
2733    end.
2734
2735%% Returns the location (directory) of the given module. Split,
2736%% reverted and relative to the lib dir.
2737mod_path(Node,Mod) ->
2738    case rpc:call(Node,code,which,[Mod]) of
2739	Path when is_list(Path) ->
2740	    lists:takewhile(
2741	      fun("lib") -> false;
2742		 (_) -> true
2743	      end,
2744	      lists:reverse(filename:split(filename:dirname(Path))));
2745	Other ->
2746	    Other
2747    end.
2748
2749%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2750%% Node handling
2751
2752start_node(Name, ErlPath) ->
2753    start_node(Name, ErlPath, []).
2754start_node(Name, ErlPath, Args0) ->
2755    FullName = full_node_name(Name),
2756    Args = mk_node_args(Name, Args0),
2757    io:format("Starting node ~p: ~ts~n",
2758	      [FullName, lists:flatten([[X," "] || X <- [ErlPath|Args]])]),
2759    %io:format("open_port({spawn_executable, ~p}, [{args,~p}])~n",[ErlPath,Args]),
2760    case open_port({spawn_executable, ErlPath}, [{args,Args}]) of
2761        Port when is_port(Port) ->
2762	    %% no need to close port since node is detached (see
2763	    %% mk_node_args) so port will be closed anyway.
2764            case ping_node(FullName, 50) of
2765                ok -> {ok, FullName};
2766                Other -> exit({failed_to_start_node, FullName, Other})
2767            end;
2768        Error ->
2769            exit({failed_to_start_node, FullName, Error})
2770    end.
2771
2772stop_node(Node) ->
2773    rpc:call(Node,erlang,halt,[]),
2774    wait_for_node_down(Node,50).
2775
2776wait_for_node_down(Node,0) ->
2777    ct:fail({cant_terminate_node,Node});
2778wait_for_node_down(Node,N) ->
2779    case net_adm:ping(Node) of
2780	pong ->
2781	    timer:sleep(1000),
2782	    wait_for_node_down(Node,N-1);
2783	pang ->
2784	    ok
2785    end.
2786
2787mk_node_args(Name, Args) ->
2788    Pa = filename:dirname(code:which(?MODULE)),
2789    NameSw = case net_kernel:longnames() of
2790                 false -> "-sname";
2791                 true -> "-name";
2792                 _ -> exit(not_distributed_node)
2793             end,
2794    {ok, Pwd} = file:get_cwd(),
2795    NameStr = atom_to_list(Name),
2796    ["-detached",
2797     %% Don't want to try to run the debug emulator here
2798     "-emu_type","opt",
2799     NameSw, NameStr,
2800     "-pa", Pa,
2801     "-env", "ERL_CRASH_DUMP", Pwd ++ "/erl_crash_dump." ++ NameStr,
2802     "-setcookie", atom_to_list(erlang:get_cookie())
2803     | Args].
2804
2805full_node_name(PreName) ->
2806    HostSuffix = lists:dropwhile(fun ($@) -> false; (_) -> true end,
2807                                 atom_to_list(node())),
2808    list_to_atom(atom_to_list(PreName) ++ HostSuffix).
2809
2810ping_node(_Node, 0) ->
2811    {error, net_adm};
2812ping_node(Node, N) when is_integer(N), N > 0 ->
2813    case catch net_adm:ping(Node) of
2814        pong ->
2815	    wait_for_process(Node, code_server, 50);
2816        _ ->
2817	    timer:sleep(1000),
2818            ping_node(Node, N-1)
2819    end.
2820
2821wait_for_process(_Node, Name, 0) ->
2822    {error, Name};
2823wait_for_process(Node, Name, N) when is_integer(N), N > 0 ->
2824    case rpc:call(Node, erlang, whereis, [Name]) of
2825	undefined ->
2826	    timer:sleep(1000),
2827	    wait_for_process(Node, Name, N-1);
2828	{badrpc, _} = Reason ->
2829	    erlang:error({Reason, Node});
2830	Pid when is_pid(Pid) ->
2831	    ok
2832    end.
2833
2834wait_for_app(_Node, Name, 0) ->
2835    {error, Name};
2836wait_for_app(Node, Name, N) when is_integer(N), N > 0 ->
2837    case rpc:call(Node,application,which_applications,[]) of
2838	{badrpc,Reason} ->
2839	    ct:fail({failed_to_get_applications,Reason});
2840	Apps ->
2841	    case lists:member(Name,Apps) of
2842		false ->
2843		    timer:sleep(1000),
2844		    wait_for_app(Node, Name, N-1);
2845		true ->
2846		    ok
2847	    end
2848    end.
2849
2850%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2851%% Run escript
2852
2853run(Dir, Script, Args) ->
2854    Cmd0 = filename:rootname(Script) ++ " " ++ Args,
2855    Cmd = case os:type() of
2856              {win32,_} -> filename:nativename(Dir) ++ "\\" ++ Cmd0;
2857              _ -> Cmd0
2858          end,
2859    do_run(Dir, Cmd).
2860
2861run(Dir, Opts, Script, Args) ->
2862    Cmd0 = filename:rootname(Script) ++ " " ++ Args,
2863    Cmd = case os:type() of
2864              {win32,_} -> Opts ++ " " ++ filename:nativename(Dir) ++ "\\" ++ Cmd0;
2865              _ -> Opts ++ " " ++ Dir ++ "/" ++ Cmd0
2866          end,
2867    do_run(Dir, Cmd).
2868
2869do_run(Dir, Cmd) ->
2870    io:format("Run: ~p\n", [Cmd]),
2871    Env = [{"PATH",Dir++":"++os:getenv("PATH")},
2872	   {"ERL_FLAGS",""},   % Make sure no flags are set that can override
2873	   {"ERL_ZFLAGS",""}], % any of the flags set in the escript.
2874    Port = open_port({spawn,Cmd}, [exit_status,eof,in,{env,Env}]),
2875    Res = get_data(Port, []),
2876    receive
2877        {Port,{exit_status,ExitCode}} ->
2878            s2b([Res,"ExitCode:"++integer_to_list(ExitCode)])
2879    end.
2880
2881get_data(Port, SoFar) ->
2882    receive
2883        {Port,{data,Bytes}} ->
2884            get_data(Port, [SoFar|Bytes]);
2885        {Port,eof} ->
2886            erlang:port_close(Port),
2887            SoFar
2888    end.
2889
2890expected_output([data_dir|T], Data) ->
2891    Slash = case os:type() of
2892                {win32,_} -> "\\";
2893                _ -> "/"
2894            end,
2895    [filename:nativename(Data)++Slash|expected_output(T, Data)];
2896expected_output([H|T], Data) ->
2897    [H|expected_output(T, Data)];
2898expected_output([], _) ->
2899    [];
2900expected_output(Bin, _) when is_binary(Bin) ->
2901    Bin.
2902
2903%% Convert the given list to a binary with the same encoding as the
2904%% file name translation mode
2905s2b(List) ->
2906    Enc = file:native_name_encoding(),
2907    unicode:characters_to_binary(List,Enc,Enc).
2908