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