diff options
Diffstat (limited to 'lib/sasl')
62 files changed, 5134 insertions, 2436 deletions
diff --git a/lib/sasl/doc/src/Makefile b/lib/sasl/doc/src/Makefile index eb880ccb78..b0ec671adc 100644 --- a/lib/sasl/doc/src/Makefile +++ b/lib/sasl/doc/src/Makefile @@ -116,18 +116,18 @@ clean clean_docs: include $(ERL_TOP)/make/otp_release_targets.mk release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf - $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf" + $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf" + $(INSTALL_DIR) "$(RELSYSDIR)/doc/html" $(INSTALL_DATA) $(HTMLDIR)/* \ - $(RELSYSDIR)/doc/html - $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) - $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 - $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 - $(INSTALL_DIR) $(RELEASE_PATH)/man/man4 - $(INSTALL_DATA) $(MAN4_FILES) $(RELEASE_PATH)/man/man4 - $(INSTALL_DIR) $(RELEASE_PATH)/man/man6 - $(INSTALL_DATA) $(MAN6_FILES) $(RELEASE_PATH)/man/man6 + "$(RELSYSDIR)/doc/html" + $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)" + $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3" + $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3" + $(INSTALL_DIR) "$(RELEASE_PATH)/man/man4" + $(INSTALL_DATA) $(MAN4_FILES) "$(RELEASE_PATH)/man/man4" + $(INSTALL_DIR) "$(RELEASE_PATH)/man/man6" + $(INSTALL_DATA) $(MAN6_FILES) "$(RELEASE_PATH)/man/man6" release_spec: diff --git a/lib/sasl/doc/src/appup.xml b/lib/sasl/doc/src/appup.xml index 89bcf23b5e..bacfaa76ef 100644 --- a/lib/sasl/doc/src/appup.xml +++ b/lib/sasl/doc/src/appup.xml @@ -4,7 +4,7 @@ <fileref> <header> <copyright> - <year>1997</year><year>2011</year> + <year>1997</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -56,12 +56,20 @@ the application.</p> </item> <item> - <p><c>UpFromVsn = string()</c> is an earlier version of - the application to upgrade from.</p> + <p><c>UpFromVsn = string() | binary()</c> is an earlier + version of the application to upgrade from. If it is a + string, it will be interpreted as a specific version + number. If it is a binary, it will be interpreted as a + regular expression which can match multiple version + numbers.</p> </item> <item> - <p><c>DownToVsn = string()</c> is an earlier version of - the application to downgrade to.</p> + <p><c>DownToVsn = string() | binary()</c> is an earlier + version of the application to downgrade to. If it is a + string, it will be interpreted as a specific version + number. If it is a binary, it will be interpreted as a + regular expression which can match multiple version + numbers.</p> </item> <item> <p><c>Instructions</c> is a list of <em>release upgrade instructions</em>, see below. It is recommended to use @@ -70,6 +78,12 @@ creating the <c>relup</c> file.</p> </item> </list> + <p>In order to avoid duplication of upgrade instructions it is + allowed to use regular expressions to specify the <c>UpFromVsn</c> + and <c>DownToVsn</c>. To be considered a regular expression, the + version identifier must be specified as a binary, e.g.</p> + <code type="none"><<"2\\.1\\.[0-9]+">></code> + <p>will match all versions <c>2.1.x</c>, where x is any number.</p> </section> <section> @@ -319,12 +333,37 @@ point_of_no_return <pre> restart_new_emulator </pre> - <p>Shuts down the current emulator and starts a ne one. All - processes are terminated gracefully. The new release must still - be made permanent when the new emulator is up and running. - Otherwise, the old emulator is started in case of a emulator - restart. This instruction should be used when a new emulator is - introduced, or if a complete reboot of the system should be done.</p> + <p>This instruction is used when erts, kernel, stdlib or sasl is + upgraded. It shuts down the current emulator and starts a new + one. All processes are terminated gracefully, and the new + version of erts, kernel, stdlib and sasl are used when the + emulator restarts. Only one <c>restart_new_emulator</c> + instruction is allowed in the relup, and it shall be placed + first. <seealso marker="systools#make_relup/3">systools:make_relup3,4</seealso> + will ensure this when the relup is generated. The rest of the + relup script is executed after the restart as a part of the boot + script.</p> + <p>An info report will be written when the upgrade is + completed. To programatically find out if the upgrade is + complete, + call <seealso marker="release_handler#which_releases/0"> + release_handler:which_releases</seealso> and check if the + expected release has status <c>current</c>.</p> + <p>The new release must still be made permanent after the upgrade + is completed. Otherwise, the old emulator is started in case of + an emulator restart.</p> + <pre> +restart_emulator + </pre> + <p>This instruction is similar to <c>restart_new_emulator</c>, + except it shall be placed at the end of the relup script. It is + not related to an upgrade of the emulator or the core + applications, but can be used by any application when a complete + reboot of the system is reqiured. When generating the + relup, <seealso marker="systools#make_relup/3">systools:make_relup/3,4</seealso> + ensures that there is only one <c>restart_emulator</c> + instruction and that it is the last instruction of the + relup.</p> </section> <section> diff --git a/lib/sasl/doc/src/make.dep b/lib/sasl/doc/src/make.dep deleted file mode 100644 index 4843b7934a..0000000000 --- a/lib/sasl/doc/src/make.dep +++ /dev/null @@ -1,22 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: alarm_handler.tex appup.tex book.tex error_logging.tex \ - overload.tex part.tex rb.tex ref_man.tex rel.tex \ - release_handler.tex relup.tex sasl_app.tex \ - sasl_intro.tex script.tex systools.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/sasl/doc/src/notes.xml b/lib/sasl/doc/src/notes.xml index 01cdc4b29e..1333e375b1 100644 --- a/lib/sasl/doc/src/notes.xml +++ b/lib/sasl/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2004</year><year>2011</year> + <year>2004</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -30,6 +30,167 @@ </header> <p>This document describes the changes made to the SASL application.</p> +<section><title>SASL 2.2.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + If sys.config existed, but was not readable or parseable, + this would not be detected until after the upgrade and at + the next node restart. The possibility for this to happen + is now reduced by adding a check to systools:make_tar + which fails the creation of the tar file if sys.config or + relup does not have reasonable contents. Note that there + are no detailed checks, only parsing and erlang term + format check.</p> + <p> + Own Id: OTP-9539</p> + </item> + <item> + <p> + systools:make_script would allow {kernel,Vsn,load} in the + .rel file, causing a .boot file which only loaded kernel + and did not start it. This has been corrected. Only start + type 'permanent', which is the default, is now allowed + for kernel and stdlib.</p> + <p> + Own Id: OTP-9652</p> + </item> + <item> + <p> + release_handler:remove_release/1 now handles symlinked + files properly</p> + <p> + Own Id: OTP-9864</p> + </item> + <item> + <p> + If stdlib was stated with a start type different from + <c>permanent</c> in a .rel file, systools would + incorrectly say that sasl had faulty start type. This has + been corrected.</p> + <p> + Own Id: OTP-9888</p> + </item> + <item> + <p> + Sasl documentation earlier said that the InclApps + parameters in a .rel file defaults to the empty list. + This is not correct. It defaults to the same value as + specified in the .app file. This has been corrected.</p> + <p> + Own Id: OTP-9980</p> + </item> + <item> + <p> + Applications that are listed in + <c>{applications,Apps}</c> in the .app file were not + sorted correctly by <c>systools:make_script/1,2</c>. They + got the reverse order of how they were listed in the .app + file. This is corrected so they are now sorted + (internally between each other) in the same order as they + are listed in the .rel file (i.e. the order they are + listed in the .app file does no longer matter).</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9984</p> + </item> + <item> + <p> + Documentation of .appup files now also states that + <c>UpFromVsn</c> and <c>DownToVsn</c> can be specified as + regular expressions in order to avoid duplicated upgrade + instructions.</p> + <p> + Own Id: OTP-10001</p> + </item> + <item> + <p> + Reltool would sometimes generate a .app file containing + <c>{start_phases,undefined}</c>, which would cause an + exception in systools at parse time. This has been + corrected so reltool now omits the <c>start_phases</c> + entry if the value is <c>undefined</c>. (Thanks to Juan + Jose Comellas)</p> + <p> + In order to align with reltool, sasl will also omit + <c>start_phases</c> entries with value <c>undefined</c> + in .script files.</p> + <p> + Own Id: OTP-10003</p> + </item> + </list> + </section> + +</section> + +<section><title>SASL 2.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix the mechanism for upgrading emulator.</p> + <p> + The appup files for kernel, stdlib and sasl do now + recognize two major releases back and include a + 'restart_new_emulator' instruction. </p> + <p> + Appup files can include regular expressions for matching + earlier releases.</p> + <p> + The mechanism for upgrading the emulator is changed so + 'restart_new_emulator' will be the first instruction + executed. The rest of the upgrade instruction will be + executed after the emulator restart.</p> + <p> + A new upgrade instruction 'restart_emulator' is added for + the case where the emulator shall be restarted after all + other upgrade instructions.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9438</p> + </item> + <item> + <p> + Add release_handler:which_releases/1</p> + <p> + This is an extension to which_releases that allows a user + to specify the status of the releases they wish to be + returned. For instance it allows for quickly determining + which release is 'permanent' without the need of parsing + the entire release list. (Thanks to Joe Williams)</p> + <p> + Own Id: OTP-9717</p> + </item> + <item> + <p> + Add copy of rel file in releases/Vsn in release tar file</p> + <p> + systool:make_tar stores the rel file in the releases + directory. When unpacking with + release_handler:unpack_release, the file is automatically + moved to releases/Vsn/. If, however, the tar file is + unpacked manually, the rel file might not be moved, and + the next release unpacked might overwrite the rel file. + To overcome this, systools:make_tar now stores a copy of + the rel file in releases/Vsn/ directly and it is not + longer necessary to move the file after unpacking.</p> + <p> + The reason for keeping the file in the releases directory + also is that is needs to be extracted separately before + the release version (Vsn) is known.</p> + <p> + Own Id: OTP-9746</p> + </item> + </list> + </section> + +</section> + <section><title>SASL 2.1.10</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/sasl/doc/src/rb.xml b/lib/sasl/doc/src/rb.xml index f35ceb5777..3da825878e 100644 --- a/lib/sasl/doc/src/rb.xml +++ b/lib/sasl/doc/src/rb.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2010</year> + <year>1996</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -123,7 +123,9 @@ <fsummary>List all reports</fsummary> <type> <v>Type = type()</v> - <v>type() = crash_report | supervisor_report | error | progress</v> + <v>type() = error | error_report | info_msg | info_report | + warning_msg | warning_report | crash_report | + supervisor_report | progress</v> </type> <desc> <p>This function lists all reports loaded in the diff --git a/lib/sasl/doc/src/rel.xml b/lib/sasl/doc/src/rel.xml index 470adf3c03..68ef90330f 100644 --- a/lib/sasl/doc/src/rel.xml +++ b/lib/sasl/doc/src/rel.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>1997</year> - <year>2011</year> + <year>2012</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -88,7 +88,7 @@ <p>The list must be a subset of the included applications specified in the application resource file (<c>Application.app</c>) and overrides this value. Defaults - to the empty list.</p> + to the same value as in the application resource file.</p> </item> </list> <note> diff --git a/lib/sasl/doc/src/release_handler.xml b/lib/sasl/doc/src/release_handler.xml index 5ac0dc1acc..e3438ede41 100644 --- a/lib/sasl/doc/src/release_handler.xml +++ b/lib/sasl/doc/src/release_handler.xml @@ -64,10 +64,10 @@ downgraded to the specified version by evaluating the instructions in <c>relup</c>. An installed release can be made <em>permanent</em>. There can only be one permanent release in - the system, and this is the release that is used if the system is - restarted. An installed release, except the permanent one, can be - <em>removed</em>. When a release is removed, all files that - belong to that release only are deleted.</p> + the system, and this is the release that is used if the system + is restarted. An installed release, except the permanent one, + can be <em>removed</em>. When a release is removed, all files + that belong to that release only are deleted.</p> <p>Each version of the release has a status. The status can be <c>unpacked</c>, <c>current</c>, <c>permanent</c>, or <c>old</c>. There is always one latest release which either has status @@ -107,16 +107,17 @@ old reboot_old permanent restarted. This is taken care of automatically if Erlang is started as an embedded system. Read about this in <em>Embedded System</em>. In this case, the system configuration file <c>sys.config</c> is mandatory.</p> - <p>A new release may restart the system. Which program to use is - specified by the SASL configuration parameter <c>start_prg</c> - which defaults to <c>$ROOT/bin/start</c>.</p> + <p>The installation of a new release may restart the system. Which + program to use is specified by the SASL configuration + parameter <c>start_prg</c> which defaults + to <c>$ROOT/bin/start</c>.</p> <p>The emulator restart on Windows NT expects that the system is started using the <c>erlsrv</c> program (as a service). Furthermore the release handler expects that the service is named <em>NodeName</em>_<em>Release</em>, where <em>NodeName</em> is the first part of the Erlang nodename (up to, but not including - the "@") and <em>Release</em> is the current release of - the application. The release handler furthermore expects that a + the "@") and <em>Release</em> is the current version of + the release. The release handler furthermore expects that a program like <c>start_erl.exe</c> is specified as "machine" to <c>erlsrv</c>. During upgrading with restart, a new service will be registered and started. The new service will be set to @@ -238,7 +239,7 @@ old reboot_old permanent </func> <func> <name>install_release(Vsn) -> {ok, OtherVsn, Descr} | {error, Reason}</name> - <name>install_release(Vsn, [Opt]) -> {ok, OtherVsn, Descr} | {error, Reason}</name> + <name>install_release(Vsn, [Opt]) -> {ok, OtherVsn, Descr} | {continue_after_restart, OtherVsn, Descr} | {error, Reason}</name> <fsummary>Install a release in the system.</fsummary> <type> <v>Vsn = OtherVsn = string()</v> @@ -248,7 +249,8 @@ old reboot_old permanent <v> Timeout = default | infinity | int()>0</v> <v> Bool = boolean()</v> <v>Descr = term()</v> - <v>Reason = {illegal_option, Opt} | {already_installed, Vsn} | {change_appl_data, term()} | term()</v> + <v>Reason = {illegal_option, Opt} | {already_installed, Vsn} | {change_appl_data, term()} | {missing_base_app, OtherVsn, App} | {could_not_create_hybrid_boot, term()} | term()</v> + <v>App = atom()</v> </type> <desc> <p>Installs the specified version <c>Vsn</c> of the release. @@ -268,6 +270,15 @@ old reboot_old permanent <c>OtherVsn</c> and <c>Descr</c> are the version (<c>UpFromVsn</c> or <c>Vsn</c>) and description (<c>Descr1</c> or <c>Descr2</c>) as specified in the script.</p> + <p>If <c>{continue_after_restart,OtherVsn,Descr}</c> is + returned, it means that the emulator will be restarted + before the upgrade instructions are executed. This will + happen if the emulator or any of the applications kernel, + stdlib or sasl are updated. The new version of the emulator + and these core applications will execute after the restart, + but for all other applications the old versions will be + started and the upgrade will be performed as normal by + executing the upgrade instructions.</p> <p>If a recoverable error occurs, the function returns <c>{error,Reason}</c> and the original application specifications are restored. If a non-recoverable error @@ -325,6 +336,18 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). upgrade, but it will allow checks and purge to be executed in the background before the real upgrade is started.</p> </note> + <note> + <p>When upgrading the emulator from a version older than OTP + R15, there will be an attempt to load new application beam + code into the old emulator. In some cases, the new beam + format can not be read by the old emulator, and so the code + loading will fail and terminate the complete upgrade. To + overcome this problem, the new application code should be + compiled with the old emulator. See <seealso + marker="doc/design_principles:appup_cookbook">Design + Principles</seealso> for more information about emulator + upgrade from pre OTP R15 versions.</p> + </note> </desc> </func> <func> @@ -431,6 +454,18 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). <p>Returns all releases known to the release handler.</p> </desc> </func> + <func> + <name>which_releases(Status) -> [{Name, Vsn, Apps, Status}]</name> + <fsummary>Return all known releases of a specific status</fsummary> + <type> + <v>Name = Vsn = string()</v> + <v>Apps = ["App-Vsn"]</v> + <v>Status = unpacked | current | permanent | old</v> + </type> + <desc> + <p>Returns all releases known to the release handler of a specific status.</p> + </desc> + </func> </funcs> <section> @@ -442,7 +477,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). and evaluated exactly in the same way as <c>release_handler</c> does.</p> <warning> - <p>These function is primarily intended for simplified testing of + <p>These functions are primarily intended for simplified testing of <c>.appup</c> files. They are not run within the context of the <c>release_handler</c> process. They must therefore <em>not</em> be used together with calls to @@ -450,7 +485,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). <c>release_handler</c> to end up in an inconsistent state.</p> <p>No persistent information is updated, why these functions can be used on any Erlang node, embedded or not. Also, using these - functions does not effect which code will be loaded in case of + functions does not affect which code will be loaded in case of a reboot.</p> <p>If the upgrade or downgrade fails, the application may end up in an inconsistent state.</p> @@ -458,7 +493,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). </section> <funcs> <func> - <name>upgrade_app(App, Dir) -> {ok, Unpurged} | restart_new_emulator | {error, Reason}</name> + <name>upgrade_app(App, Dir) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name> <fsummary>Upgrade to a new application version</fsummary> <type> <v>App = atom()</v> @@ -487,14 +522,21 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). does.</p> <p>Returns <c>{ok, Unpurged}</c> if evaluating the script is successful, where <c>Unpurged</c> is a list of unpurged - modules, or <c>restart_new_emulator</c> if this instruction is + modules, or <c>restart_emulator</c> if this instruction is encountered in the script, or <c>{error, Reason}</c> if an error occurred when finding or evaluating the script.</p> + <p>If the <c>restart_new_emulator</c> instruction is found in + the script, <c>upgrade_app/2</c> will return + <c>{error,restart_new_emulator}</c>. The reason for this is + that this instruction requires that a new version of the + emulator is started before the rest of the upgrade + instructions can be executed, and this can only be done by + <c>install_release/1,2</c>.</p> </desc> </func> <func> <name>downgrade_app(App, Dir) -></name> - <name>downgrade_app(App, OldVsn, Dir) -> {ok, Unpurged} | restart_new_emulator | {error, Reason}</name> + <name>downgrade_app(App, OldVsn, Dir) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name> <fsummary>Downgrade to a previous application version</fsummary> <type> <v>App = atom()</v> @@ -528,7 +570,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). does.</p> <p>Returns <c>{ok, Unpurged}</c> if evaluating the script is successful, where <c>Unpurged</c> is a list of unpurged - modules, or <c>restart_new_emulator</c> if this instruction is + modules, or <c>restart_emulator</c> if this instruction is encountered in the script, or <c>{error, Reason}</c> if an error occurred when finding or evaluating the script.</p> </desc> @@ -604,7 +646,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). </desc> </func> <func> - <name>eval_appup_script(App, ToVsn, ToDir, Script) -> {ok, Unpurged} | restart_new_emulator | {error, Reason}</name> + <name>eval_appup_script(App, ToVsn, ToDir, Script) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name> <fsummary>Evaluate an application upgrade or downgrade script</fsummary> <type> <v>App = atom()</v> @@ -617,8 +659,8 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). <desc> <p>Evaluates an application upgrade or downgrade script <c>Script</c>, the result from calling - <seealso marker="#upgrade_app/2">upgrade_app/2</seealso> or - <seealso marker="#downgrade_app/3">downgrade_app/2,3</seealso>, + <seealso marker="#upgrade_app/2">upgrade_script/2</seealso> or + <seealso marker="#downgrade_app/3">downgrade_script/3</seealso>, exactly in the same way as <seealso marker="#install_release/1">install_release/1,2</seealso> does.</p> @@ -629,9 +671,16 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). <c>.appup</c> files should be located under <c>Dir/ebin</c>.</p> <p>Returns <c>{ok, Unpurged}</c> if evaluating the script is successful, where <c>Unpurged</c> is a list of unpurged - modules, or <c>restart_new_emulator</c> if this instruction is + modules, or <c>restart_emulator</c> if this instruction is encountered in the script, or <c>{error, Reason}</c> if an error occurred when evaluating the script.</p> + <p>If the <c>restart_new_emulator</c> instruction is found in + the script, <c>eval_appup_script/4</c> will return + <c>{error,restart_new_emulator}</c>. The reason for this is + that this instruction requires that a new version of the + emulator is started before the rest of the upgrade + instructions can be executed, and this can only be done by + <c>install_release/1,2</c>.</p> </desc> </func> </funcs> diff --git a/lib/sasl/doc/src/systools.xml b/lib/sasl/doc/src/systools.xml index 8c1c327d74..84fed0a25f 100644 --- a/lib/sasl/doc/src/systools.xml +++ b/lib/sasl/doc/src/systools.xml @@ -111,6 +111,11 @@ low-level instruction to restart the emulator is appended to the relup scripts. This ensures that a complete reboot of the system is done when the system is upgraded or downgraded.</p> + <p>If an upgrade includes a change from an emulator earlier + than OTP R15 to OTP R15 or later, the warning + <c>pre_R15_emulator_upgrade</c> is issued. See <seealso + marker="doc/design_principles:appup_cookbook">Design + Principles</seealso> for more information about this.</p> <p>By default, errors and warnings are printed to tty and the function returns <c>ok</c> or <c>error</c>. If the option <c>silent</c> is provided, the function instead returns @@ -133,8 +138,9 @@ <fsummary>Generate a boot script <c>.script/.boot</c>.</fsummary> <type> <v>Name = string()</v> - <v>Opt = src_tests | {path,[Dir]} | local | {variables,[Var]} | exref | {exref,[App]}] - | silent | {outdir,Dir} | warnings_as_errors</v> + <v>Opt = src_tests | {path,[Dir]} | local | {variables,[Var]} | exref | + {exref,[App]}] | silent | {outdir,Dir} | no_warn_sasl | + warnings_as_errors</v> <v> Dir = string()</v> <v> Var = {VarName,Prefix}</v> <v> VarName = Prefix = string()</v> @@ -190,6 +196,14 @@ <p>The applications are sorted according to the dependencies between the applications. Where there are no dependencies, the order in the <c>.rel</c> file is kept.</p> + <p>The function will fail if the mandatory + applications <c>kernel</c> and <c>stdlib</c> are not + included in the <c>.rel</c> file and have start + type <c>permanent</c> (default).</p> + <p>If <c>sasl</c> is not included as an application in + the <c>.rel</c> file, a warning is emitted because such a + release can not be used in an upgrade. To turn off this + warning, add the option <c>no_warn_sasl</c>.</p> <p>All files are searched for in the current path. It is assumed that the <c>.app</c> and <c>.beam</c> files for an application is located in the same directory. The <c>.erl</c> @@ -220,7 +234,7 @@ <p>Example: If the option <c>{variables,[{"TEST","lib"}]}</c> is supplied, and <c>myapp.app</c> is found in <c>lib/myapp/ebin</c>, then the path to this application in - the boot script will be <c>$TEST/myapp-1/ebin"</c>. If + the boot script will be <c>"$TEST/myapp-1/ebin"</c>. If <c>myapp.app</c> is found in <c>lib/test</c>, then the path will be <c>$TEST/test/myapp-1/ebin</c>.</p> <p>The checks performed before the boot script is generated can diff --git a/lib/sasl/examples/src/Makefile b/lib/sasl/examples/src/Makefile index 9cf0d4c25d..c0d73aab1d 100644 --- a/lib/sasl/examples/src/Makefile +++ b/lib/sasl/examples/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# Copyright Ericsson AB 2010-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -63,10 +63,10 @@ docs: include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/examples/src - $(INSTALL_DIR) $(RELSYSDIR)/examples/ebin - (cd ..; tar cf - src ebin | (cd $(RELSYSDIR)/examples; tar xf -)) - chmod -R ug+w $(RELSYSDIR)/examples + $(INSTALL_DIR) "$(RELSYSDIR)/examples/src" + $(INSTALL_DIR) "$(RELSYSDIR)/examples/ebin" + (cd ..; tar cf - src ebin | (cd "$(RELSYSDIR)/examples"; tar xf -)) + chmod -R ug+w "$(RELSYSDIR)/examples" release_docs_spec: diff --git a/lib/sasl/examples/src/target_system.erl b/lib/sasl/examples/src/target_system.erl index 0e1e0b2324..ffc0fcf443 100644 --- a/lib/sasl/examples/src/target_system.erl +++ b/lib/sasl/examples/src/target_system.erl @@ -16,6 +16,7 @@ %% %% %CopyrightEnd% %% +%module -module(target_system). -export([create/1, create/2, install/2]). @@ -130,14 +131,14 @@ install(RelFileName, RootDir) -> [ErlVsn, _RelVsn| _] = string:tokens(StartErlData, " \n"), ErtsBinDir = filename:join([RootDir, "erts-" ++ ErlVsn, "bin"]), BinDir = filename:join([RootDir, "bin"]), - io:fwrite("Substituting in erl.src, start.src and start_erl.src to\n" + io:fwrite("Substituting in erl.src, start.src and start_erl.src to " "form erl, start and start_erl ...\n"), subst_src_scripts(["erl", "start", "start_erl"], ErtsBinDir, BinDir, [{"FINAL_ROOTDIR", RootDir}, {"EMU", "beam"}], [preserve]), io:fwrite("Creating the RELEASES file ...\n"), - create_RELEASES(RootDir, - filename:join([RootDir, "releases", RelFileName])). + create_RELEASES(RootDir, filename:join([RootDir, "releases", + filename:basename(RelFileName)])). %% LOCALS @@ -257,3 +258,4 @@ remove_all_files(Dir, Files) -> file:delete(FilePath) end end, Files). +%module diff --git a/lib/sasl/src/Makefile b/lib/sasl/src/Makefile index 9a5d1e42d9..de0c45e6ae 100644 --- a/lib/sasl/src/Makefile +++ b/lib/sasl/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2009. All Rights Reserved. +# Copyright Ericsson AB 1996-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -91,10 +91,10 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/src - $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src - $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src - $(INSTALL_DIR) $(RELSYSDIR)/ebin - $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin + $(INSTALL_DIR) "$(RELSYSDIR)/src" + $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src" + $(INSTALL_DATA) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src" + $(INSTALL_DIR) "$(RELSYSDIR)/ebin" + $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin" release_docs_spec: diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl index bc08f94dff..5efd932c92 100644 --- a/lib/sasl/src/release_handler.erl +++ b/lib/sasl/src/release_handler.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -26,8 +26,9 @@ create_RELEASES/1, create_RELEASES/2, create_RELEASES/4, unpack_release/1, check_install_release/1, check_install_release/2, - install_release/1, install_release/2, remove_release/1, - which_releases/0, make_permanent/1, reboot_old_release/1, + install_release/1, install_release/2, new_emulator_upgrade/2, + remove_release/1, which_releases/0, which_releases/1, + make_permanent/1, reboot_old_release/1, set_unpacked/2, set_removed/1, install_file/2]). -export([upgrade_app/2, downgrade_app/2, downgrade_app/3, upgrade_script/2, downgrade_script/3, @@ -40,7 +41,7 @@ %% Internal exports, a client release_handler may call this functions. -export([do_write_release/3, do_copy_file/2, do_copy_files/2, do_copy_files/1, do_rename_files/1, do_remove_files/1, - do_write_file/2, do_ensure_RELEASES/1]). + remove_file/1, do_write_file/2, do_ensure_RELEASES/1]). -record(state, {unpurged = [], root, @@ -61,10 +62,11 @@ %% remove - %% current make_permanent permanent %% install other old +%% restart node unpacked %% remove - %% permanent make other permanent old %% install permanent -%% old reboot permanen +%% old reboot_old permanent %% install current %% remove - %%----------------------------------------------------------------- @@ -74,6 +76,14 @@ -define(timeout, 10000). %%----------------------------------------------------------------- +%% The version set on the temporary release that will be used when the +%% emulator is upgraded. +-define(tmp_vsn(__BaseVsn__), "__new_emulator__"++__BaseVsn__). + + + + +%%----------------------------------------------------------------- %% Assumes the following file structure: %% root --- lib --- Appl-Vsn1 --- <src> %% | | |- ebin @@ -183,11 +193,15 @@ check_check_install_options([],Purge) -> %%----------------------------------------------------------------- %% Purpose: Executes the relup script for the specified version. %% The release must be unpacked. -%% Returns: {ok, FromVsn, Descr} | {error, Reason} +%% Returns: {ok, FromVsn, Descr} | +%% {continue_after_restart, FromVsn, Descr} | +%% {error, Reason} %% Reason = {already_installed, Vsn} | %% {bad_relup_file, RelFile} | %% {no_such_release, Vsn} | %% {no_such_from_vsn, Vsn} | +%% {could_not_create_hybrid_boot,Why} | +%% {missing_base_app,Vsn,App} | %% {illegal_option, Opt}} | %% exit_reason() %%----------------------------------------------------------------- @@ -230,6 +244,21 @@ check_timeout(Int) when is_integer(Int), Int > 0 -> true; check_timeout(_Else) -> false. %%----------------------------------------------------------------- +%% Purpose: Called by boot script after emulator is restarted due to +%% new erts version. +%% Returns: Same as install_release/2 +%% If this crashes, the emulator restart will fail +%% (since the function is called from the boot script) +%% and there will be a rollback. +%%----------------------------------------------------------------- +new_emulator_upgrade(Vsn, Opts) -> + Result = call({install_release, Vsn, reboot, Opts}), + error_logger:info_msg( + "~p:install_release(~p,~p) completed after node restart " + "with new emulator version~nResult: ~p~n",[?MODULE,Vsn,Opts,Result]), + Result. + +%%----------------------------------------------------------------- %% Purpose: Makes the specified release version be the one that is %% used when the system starts (or restarts). %% The release must be installed (not unpacked). @@ -305,6 +334,14 @@ which_releases() -> call(which_releases). %%----------------------------------------------------------------- +%% Returns: [{Name, Vsn, [LibName], Status}] +%% Status = unpacked | current | permanent | old +%%----------------------------------------------------------------- +which_releases(Status) -> + Releases = which_releases(), + get_releases_with_status(Releases, Status, []). + +%%----------------------------------------------------------------- %% check_script(Script, LibDirs) -> ok | {error, Reason} %%----------------------------------------------------------------- check_script(Script, LibDirs) -> @@ -313,7 +350,7 @@ check_script(Script, LibDirs) -> %%----------------------------------------------------------------- %% eval_script(Script, Apps, LibDirs, NewLibs, Opts) -> %% {ok, UnPurged} | -%% restart_new_emulator | +%% restart_emulator | %% {error, Error} %% {'EXIT', Reason} %% If sync_nodes is present, the calling process must have called @@ -350,7 +387,7 @@ create_RELEASES(Root, RelDir, RelFile, LibDirs) -> %%----------------------------------------------------------------- %% Func: upgrade_app(App, Dir) -> {ok, Unpurged} -%% | restart_new_emulator +%% | restart_emulator %% | {error, Error} %% Types: %% App = atom() @@ -370,7 +407,7 @@ upgrade_app(App, NewDir) -> %%----------------------------------------------------------------- %% Func: downgrade_app(App, Dir) %% downgrade_app(App, Vsn, Dir) -> {ok, Unpurged} -%% | restart_new_emulator +%% | restart_emulator %% | {error, Error} %% Types: %% App = atom() @@ -578,7 +615,7 @@ handle_call({check_install_release, Vsn, Purge}, _From, S) -> handle_call({install_release, Vsn, ErrorAction, Opts}, From, S) -> NS = resend_sync_nodes(S), case catch do_install_release(S, Vsn, Opts) of - {ok, NewReleases, CurrentVsn, Descr} -> + {ok, NewReleases, [], CurrentVsn, Descr} -> {reply, {ok, CurrentVsn, Descr}, NS#state{releases=NewReleases}}; {ok, NewReleases, Unpurged, CurrentVsn, Descr} -> Timer = @@ -593,10 +630,14 @@ handle_call({install_release, Vsn, ErrorAction, Opts}, From, S) -> {reply, {ok, CurrentVsn, Descr}, NewS}; {error, Reason} -> {reply, {error, Reason}, NS}; - {restart_new_emulator, CurrentVsn, Descr} -> + {restart_emulator, CurrentVsn, Descr} -> gen_server:reply(From, {ok, CurrentVsn, Descr}), init:reboot(), {noreply, NS}; + {restart_new_emulator, CurrentVsn, Descr} -> + gen_server:reply(From, {continue_after_restart, CurrentVsn, Descr}), + init:reboot(), + {noreply, NS}; {'EXIT', Reason} -> io:format("release_handler:" "install_release(Vsn=~p Opts=~p) failed, " @@ -801,8 +842,13 @@ do_unpack_release(Root, RelDir, ReleaseName, Releases) -> extract_tar(Root, Tar), NewReleases = [Release#release{status = unpacked} | Releases], write_releases(RelDir, NewReleases, false), + + %% Keeping this for backwards compatibility reasons with older + %% systools:make_tar, where there is no copy of the .rel file in + %% the releases/<vsn> dir. See OTP-9746. Dir = filename:join([RelDir, Vsn]), copy_file(RelFile, Dir, false), + {ok, NewReleases, Vsn}. %% Note that this function is not executed by a client @@ -941,7 +987,38 @@ do_install_release(#state{start_prg = StartPrg, {value, Release} -> LatestRelease = get_latest_release(Releases), case get_rh_script(LatestRelease, Release, RelDir, Masters) of + {ok, {_CurrentVsn, _Descr, [restart_new_emulator|_Script]}} + when Static == true -> + throw(static_emulator); + {ok, {CurrentVsn, Descr, [restart_new_emulator|_Script]}} -> + %% This will only happen if the upgrade includes + %% an emulator upgrade (and it is not a downgrade) + %% - then the new emulator must be started before + %% new code can be loaded. + %% Create a temporary release which includes new + %% emulator, kernel, stdlib and sasl - and old + %% versions of other applications. + {TmpVsn,TmpRelease} = + new_emulator_make_tmp_release(LatestRelease,Release, + RelDir,Opts,Masters), + NReleases = [TmpRelease|Releases], + + %% Then uppgrade to the temporary release. + %% The rest of the upgrade will continue after the restart + prepare_restart_new_emulator(StartPrg, RootDir, + RelDir, TmpVsn, TmpRelease, + NReleases, Masters), + {restart_new_emulator, CurrentVsn, Descr}; {ok, {CurrentVsn, Descr, Script}} -> + %% In case there has been an emulator upgrade, + %% remove the temporary release + NReleases = + new_emulator_rm_tmp_release( + LatestRelease#release.vsn, + LatestRelease#release.erts_vsn, + Vsn,RelDir,Releases,Masters), + + %% Then execute the relup script mon_nodes(true), EnvBefore = application_controller:prep_config_change(), Apps = change_appl_data(RelDir, Release, Masters), @@ -949,31 +1026,19 @@ do_install_release(#state{start_prg = StartPrg, NewLibs = get_new_libs(LatestRelease#release.libs, Release#release.libs), case eval_script(Script, Apps, LibDirs, NewLibs, Opts) of - {ok, []} -> - application_controller:config_change(EnvBefore), - mon_nodes(false), - NewReleases = set_status(Vsn, current, Releases), - {ok, NewReleases, CurrentVsn, Descr}; {ok, Unpurged} -> application_controller:config_change(EnvBefore), mon_nodes(false), - NewReleases = set_status(Vsn, current, Releases), - {ok, NewReleases, Unpurged, CurrentVsn, Descr}; - restart_new_emulator when Static == true -> + NReleases1 = set_status(Vsn, current, NReleases), + {ok, NReleases1, Unpurged, CurrentVsn, Descr}; + restart_emulator when Static == true -> throw(static_emulator); - restart_new_emulator -> + restart_emulator -> mon_nodes(false), - {value, PermanentRelease} = - lists:keysearch(permanent, #release.status, - Releases), - NReleases = set_status(Vsn, current, Releases), - NReleases2 = set_status(Vsn,tmp_current,NReleases), - write_releases(RelDir, NReleases2, Masters), prepare_restart_new_emulator(StartPrg, RootDir, - RelDir, Release, - PermanentRelease, - Masters), - {restart_new_emulator, CurrentVsn, Descr}; + RelDir, Vsn, Release, + NReleases, Masters), + {restart_emulator, CurrentVsn, Descr}; Else -> application_controller:config_change(EnvBefore), mon_nodes(false), @@ -986,6 +1051,158 @@ do_install_release(#state{start_prg = StartPrg, {error, {no_such_release, Vsn}} end. +new_emulator_make_tmp_release(CurrentRelease,ToRelease,RelDir,Opts,Masters) -> + CurrentVsn = CurrentRelease#release.vsn, + ToVsn = ToRelease#release.vsn, + TmpVsn = ?tmp_vsn(CurrentVsn), + case get_base_libs(ToRelease#release.libs) of + {ok,{Kernel,Stdlib,Sasl}=BaseLibs,_} -> + case get_base_libs(ToRelease#release.libs) of + {ok,_,RestLibs} -> + TmpErtsVsn = ToRelease#release.erts_vsn, + TmpLibs = [Kernel,Stdlib,Sasl|RestLibs], + TmpRelease = CurrentRelease#release{vsn=TmpVsn, + erts_vsn=TmpErtsVsn, + libs = TmpLibs, + status = unpacked}, + new_emulator_make_hybrid_boot(CurrentVsn,ToVsn,TmpVsn, + BaseLibs,RelDir,Opts,Masters), + new_emulator_make_hybrid_config(CurrentVsn,ToVsn,TmpVsn, + RelDir,Masters), + {TmpVsn,TmpRelease}; + {error,{missing,Missing}} -> + throw({error,{missing_base_app,CurrentVsn,Missing}}) + end; + {error,{missing,Missing}} -> + throw({error,{missing_base_app,ToVsn,Missing}}) + end. + +%% Get kernel, stdlib and sasl libs, +%% and also return the rest of the libs as a list. +%% Return error if any of kernel, stdlib or sasl does not exist. +get_base_libs(Libs) -> + get_base_libs(Libs,undefined,undefined,undefined,[]). +get_base_libs([{kernel,_,_}=Kernel|Libs],undefined,Stdlib,Sasl,Rest) -> + get_base_libs(Libs,Kernel,Stdlib,Sasl,Rest); +get_base_libs([{stdlib,_,_}=Stdlib|Libs],Kernel,undefined,Sasl,Rest) -> + get_base_libs(Libs,Kernel,Stdlib,Sasl,Rest); +get_base_libs([{sasl,_,_}=Sasl|Libs],Kernel,Stdlib,undefined,Rest) -> + get_base_libs(Libs,Kernel,Stdlib,Sasl,Rest); +get_base_libs([Lib|Libs],Kernel,Stdlib,Sasl,Rest) -> + get_base_libs(Libs,Kernel,Stdlib,Sasl,[Lib|Rest]); +get_base_libs([],undefined,_Stdlib,_Sasl,_Rest) -> + {error,{missing,kernel}}; +get_base_libs([],_Kernel,undefined,_Sasl,_Rest) -> + {error,{missing,stdlib}}; +get_base_libs([],_Kernel,_Stdlib,undefined,_Rest) -> + {error,{missing,sasl}}; +get_base_libs([],Kernel,Stdlib,Sasl,Rest) -> + {ok,{Kernel,Stdlib,Sasl},lists:reverse(Rest)}. + +new_emulator_make_hybrid_boot(CurrentVsn,ToVsn,TmpVsn,BaseLibs,RelDir,Opts,Masters) -> + FromBootFile = filename:join([RelDir,CurrentVsn,"start.boot"]), + ToBootFile = filename:join([RelDir,ToVsn,"start.boot"]), + TmpBootFile = filename:join([RelDir,TmpVsn,"start.boot"]), + ensure_dir(TmpBootFile,Masters), + Args = [ToVsn,Opts], + {ok,FromBoot} = read_file(FromBootFile,Masters), + {ok,ToBoot} = read_file(ToBootFile,Masters), + {{_,_,KernelPath},{_,_,SaslPath},{_,_,StdlibPath}} = BaseLibs, + Paths = {filename:join(KernelPath,"ebin"), + filename:join(StdlibPath,"ebin"), + filename:join(SaslPath,"ebin")}, + case systools_make:make_hybrid_boot(TmpVsn,FromBoot,ToBoot,Paths,Args) of + {ok,TmpBoot} -> + write_file(TmpBootFile,TmpBoot,Masters); + {error,Reason} -> + throw({error,{could_not_create_hybrid_boot,Reason}}) + end. + +new_emulator_make_hybrid_config(CurrentVsn,ToVsn,TmpVsn,RelDir,Masters) -> + FromFile = filename:join([RelDir,CurrentVsn,"sys.config"]), + ToFile = filename:join([RelDir,ToVsn,"sys.config"]), + TmpFile = filename:join([RelDir,TmpVsn,"sys.config"]), + + FromConfig = + case consult(FromFile,Masters) of + {ok,[FC]} -> + FC; + {error,Error1} -> + io:format("Warning: ~p can not read ~p: ~p~n", + [?MODULE,FromFile,Error1]), + [] + end, + + [Kernel,Stdlib,Sasl] = + case consult(ToFile,Masters) of + {ok,[ToConfig]} -> + [lists:keyfind(App,1,ToConfig) || App <- [kernel,stdlib,sasl]]; + {error,Error2} -> + io:format("Warning: ~p can not read ~p: ~p~n", + [?MODULE,ToFile,Error2]), + [false,false,false] + end, + + Config1 = replace_config(kernel,FromConfig,Kernel), + Config2 = replace_config(stdlib,Config1,Stdlib), + Config3 = replace_config(sasl,Config2,Sasl), + + ConfigStr = io_lib:format("~p.~n",[Config3]), + write_file(TmpFile,ConfigStr,Masters). + +%% Take the configuration for application App from the new config and +%% insert in the old config. +%% If no entry exists in the new config, then delete the entry (if it exists) +%% from the old config. +%% If entry exists in the new config, but not in the old config, then +%% add the entry. +replace_config(App,Config,false) -> + lists:keydelete(App,1,Config); +replace_config(App,Config,AppConfig) -> + lists:keystore(App,1,Config,AppConfig). + +%% Remove all files related to the temporary release +new_emulator_rm_tmp_release(?tmp_vsn(_)=TmpVsn,EVsn,NewVsn, + RelDir,Releases,Masters) -> + case os:type() of + {win32, nt} -> + rename_tmp_service(EVsn,TmpVsn,NewVsn); + _ -> + ok + end, + remove_dir(filename:join(RelDir,TmpVsn),Masters), + lists:keydelete(TmpVsn,#release.vsn,Releases); +new_emulator_rm_tmp_release(_,_,_,_,Releases,_) -> + Releases. + +%% Rename the tempoarary service (for erts ugprade) to the real ToVsn +rename_tmp_service(EVsn,TmpVsn,NewVsn) -> + FromName = hd(string:tokens(atom_to_list(node()),"@")) ++ "_" ++ TmpVsn, + ToName = hd(string:tokens(atom_to_list(node()),"@")) ++ "_" ++ NewVsn, + case erlsrv:get_service(EVsn,ToName) of + {error, _Error} -> + ok; + _Data -> + erlsrv:remove_service(ToName) + end, + rename_service(EVsn,FromName,ToName). + + +%% Rename a service and check that it succeeded +rename_service(EVsn,FromName,ToName) -> + case erlsrv:rename_service(EVsn,FromName,ToName) of + {ok,_} -> + case erlsrv:get_service(EVsn,ToName) of + {error,Error1} -> + throw({error,Error1}); + _Data2 -> + ok + end; + Error2 -> + throw({error,{service_rename_failed, Error2}}) + end. + + %%% This code chunk updates the services in one of two ways, %%% Either the emulator is restarted, in which case the old service %%% is to be removed and the new enabled, or the emulator is NOT restarted @@ -1002,26 +1219,16 @@ do_make_services_permanent(PermanentVsn,Vsn, PermanentEVsn, EVsn) -> %% rename. case os:getenv("ERLSRV_SERVICE_NAME") == PermName of true -> - case erlsrv:rename_service(EVsn,PermName,Name) of - {ok,_} -> - case erlsrv:get_service(EVsn,Name) of - {error,Error2} -> - throw({error,Error2}); - _Data2 -> - %% The interfaces for doing this are - %% NOT published and may be subject to - %% change. Do NOT do this anywhere else! - - os:putenv("ERLSRV_SERVICE_NAME", Name), - - %% Restart heart port program, this - %% function is only to be used here. - heart:cycle(), - ok - end; - Error3 -> - throw({error,{service_rename_failed, Error3}}) - end; + rename_service(EVsn,PermName,Name), + %% The interfaces for doing this are + %% NOT published and may be subject to + %% change. Do NOT do this anywhere else! + + os:putenv("ERLSRV_SERVICE_NAME", Name), + + %% Restart heart port program, this + %% function is only to be used here. + heart:cycle(); false -> throw({error,service_name_missmatch}) end; @@ -1260,21 +1467,31 @@ do_set_removed(RelDir, Vsn, Releases, Masters) -> %% corresponding relup instructions, we check if it's possible to %% downgrade from CurrentVsn to ToVsn. %%----------------------------------------------------------------- +get_rh_script(#release{vsn = ?tmp_vsn(CurrentVsn)}, + #release{vsn = ToVsn}, + RelDir, + Masters) -> + {ok,{Vsn,Descr,[restart_new_emulator|Script]}} = + do_get_rh_script(CurrentVsn,ToVsn,RelDir,Masters), + {ok,{Vsn,Descr,Script}}; get_rh_script(#release{vsn = CurrentVsn}, - #release{vsn = Vsn}, + #release{vsn = ToVsn}, RelDir, Masters) -> - Relup = filename:join([RelDir, Vsn, "relup"]), - case try_upgrade(Vsn, CurrentVsn, Relup, Masters) of + do_get_rh_script(CurrentVsn,ToVsn,RelDir,Masters). + +do_get_rh_script(CurrentVsn, ToVsn, RelDir, Masters) -> + Relup = filename:join([RelDir, ToVsn, "relup"]), + case try_upgrade(ToVsn, CurrentVsn, Relup, Masters) of {ok, RhScript} -> {ok, RhScript}; _ -> Relup2 = filename:join([RelDir, CurrentVsn,"relup"]), - case try_downgrade(Vsn, CurrentVsn, Relup2, Masters) of + case try_downgrade(ToVsn, CurrentVsn, Relup2, Masters) of {ok, RhScript} -> {ok, RhScript}; _ -> - throw({error, {no_matching_relup, Vsn, CurrentVsn}}) + throw({error, {no_matching_relup, ToVsn, CurrentVsn}}) end end. @@ -1355,7 +1572,7 @@ memlib(_Lib, []) -> false. %% recursively remove file or directory remove_file(File) -> - case file:read_file_info(File) of + case file:read_link_info(File) of {ok, Info} when Info#file_info.type==directory -> case file:list_dir(File) of {ok, Files} -> @@ -1487,6 +1704,15 @@ prepare_restart_nt(#release{erts_vsn = EVsn, vsn = Vsn}, %% restart is performed by calling init:reboot() higher up. %%----------------------------------------------------------------- prepare_restart_new_emulator(StartPrg, RootDir, RelDir, + Vsn, Release, Releases, Masters) -> + {value, PRelease} = lists:keysearch(permanent, #release.status,Releases), + NReleases1 = set_status(Vsn, current, Releases), + NReleases2 = set_status(Vsn,tmp_current,NReleases1), + write_releases(RelDir, NReleases2, Masters), + prepare_restart_new_emulator(StartPrg, RootDir, RelDir, + Release, PRelease, Masters). + +prepare_restart_new_emulator(StartPrg, RootDir, RelDir, Release, PRelease, Masters) -> #release{erts_vsn = EVsn, vsn = Vsn} = Release, Data = EVsn ++ " " ++ Vsn, @@ -1512,19 +1738,10 @@ check_start_prg({do_check, StartPrg}, Masters) -> check_start_prg({_, StartPrg}, _) -> StartPrg. -write_new_start_erl(Data, RelDir, false) -> - DataFile = filename:join([RelDir, "new_start_erl.data"]), - case do_write_file(DataFile, Data) of - ok -> DataFile; - Error -> throw(Error) - end; write_new_start_erl(Data, RelDir, Masters) -> DataFile = filename:join([RelDir, "new_start_erl.data"]), - case at_all_masters(Masters, ?MODULE, do_write_file, - [DataFile, Data]) of - ok -> DataFile; - Error -> throw(Error) - end. + write_file(DataFile, Data, Masters), + DataFile. %%----------------------------------------------------------------- %% When a new emulator shall be restarted, the current release @@ -1538,27 +1755,41 @@ write_new_start_erl(Data, RelDir, Masters) -> %% If the release is made permanent, this is written to disk. %%----------------------------------------------------------------- transform_release(ReleaseDir, Releases, Masters) -> - F = fun(Release) when Release#release.status == tmp_current -> - Release#release{status = unpacked}; - (Release) -> Release - end, - case lists:map(F, Releases) of - Releases -> - Releases; - DReleases -> + case init:script_id() of + {Name, ?tmp_vsn(_)=TmpVsn} -> + %% This is was a reboot due to a new emulator version. The + %% current release is a temporary internal release, which + %% must be removed. It is the "real new release" that is + %% set to unpacked on disk and current in memory. + DReleases = lists:keydelete(TmpVsn,#release.vsn,Releases), write_releases(ReleaseDir, DReleases, Masters), - F1 = fun(Release) when Release#release.status == tmp_current -> - case init:script_id() of - {_Name, Vsn} when Release#release.vsn == Vsn -> - Release#release{status = current}; - _ -> - Release#release{status = unpacked} - end; - (Release) -> Release - end, - lists:map(F1, Releases) + set_current({Name,TmpVsn},Releases); + ScriptId -> + F = fun(Release) when Release#release.status == tmp_current -> + Release#release{status = unpacked}; + (Release) -> Release + end, + case lists:map(F, Releases) of + Releases -> + Releases; + DReleases -> + write_releases(ReleaseDir, DReleases, Masters), + set_current(ScriptId, Releases) + end end. +set_current(ScriptId, Releases) -> + F1 = fun(Release) when Release#release.status == tmp_current -> + case ScriptId of + {_Name,Vsn} when Release#release.vsn == Vsn -> + Release#release{status = current}; + _ -> + Release#release{status = unpacked} + end; + (Release) -> Release + end, + lists:map(F1, Releases). + %%----------------------------------------------------------------- %% Functions handling files, RELEASES, start_erl.data etc. %% This functions consider if the release_handler is a client and @@ -1617,12 +1848,25 @@ extract_tar(Root, Tar) -> throw({error, {cannot_extract_file, Name, Reason}}) end. -write_releases(Dir, NewReleases, false) -> +write_releases(Dir, Releases, Masters) -> + %% We must never write 'current' to disk, since this will confuse + %% us after a node restart - since we would then have a permanent + %% release running, but state set to current for a non-running + %% release. + NewReleases = lists:zf(fun(Release) when Release#release.status == current -> + {true, Release#release{status = unpacked}}; + (_) -> + true + end, Releases), + write_releases_1(Dir, NewReleases, Masters). + + +write_releases_1(Dir, NewReleases, false) -> case do_write_release(Dir, "RELEASES", NewReleases) of ok -> ok; Error -> throw(Error) end; -write_releases(Dir, NewReleases, Masters) -> +write_releases_1(Dir, NewReleases, Masters) -> all_masters(Masters), write_releases_m(Dir, NewReleases, Masters). @@ -1844,6 +2088,37 @@ read_file(File, false) -> read_file(File, Masters) -> read_master(Masters, File). +write_file(File, Data, false) -> + case file:write_file(File, Data) of + ok -> ok; + Error -> throw(Error) + end; +write_file(File, Data, Masters) -> + case at_all_masters(Masters, file, write_file, [File, Data]) of + ok -> ok; + Error -> throw(Error) + end. + +ensure_dir(File, false) -> + case filelib:ensure_dir(File) of + ok -> ok; + Error -> throw(Error) + end; +ensure_dir(File, Masters) -> + case at_all_masters(Masters,filelib,ensure_dir,[File]) of + ok -> ok; + Error -> throw(Error) + end. + +remove_dir(Dir, false) -> + remove_file(Dir); +remove_dir(Dir, Masters) -> + case at_all_masters(Masters,?MODULE,remove_file,[Dir]) of + ok -> ok; + Error -> throw(Error) + end. + + %% Ignore status of each delete ! remove_files(Master, Files, Masters) -> takewhile(Master, Masters, ?MODULE, do_remove_files, [Files]). @@ -2010,3 +2285,14 @@ get_new_libs([{App,Vsn,_LibDir}|CurrentLibs], NewLibs) -> end; get_new_libs([],_) -> []. + +%%----------------------------------------------------------------- +%% Return a list of releases witch a specific status +%%----------------------------------------------------------------- +get_releases_with_status([], _, Acc) -> + Acc; +get_releases_with_status([ {_, _, _, ReleaseStatus } = Head | Tail], + Status, Acc) when ReleaseStatus == Status -> + get_releases_with_status(Tail, Status, [Head | Acc]); +get_releases_with_status([_ | Tail], Status, Acc) -> + get_releases_with_status(Tail, Status, Acc). diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl index 8d0baf3ab1..93d12cf609 100644 --- a/lib/sasl/src/release_handler_1.erl +++ b/lib/sasl/src/release_handler_1.erl @@ -47,26 +47,38 @@ %%%----------------------------------------------------------------- %%% This is a low-level release handler. %%%----------------------------------------------------------------- +check_script([restart_new_emulator|Script], LibDirs) -> + %% There is no need to check for old processes, since the node + %% will be restarted before anything else happens. + do_check_script(Script, LibDirs, []); check_script(Script, LibDirs) -> case catch check_old_processes(Script,soft_purge) of {ok, PurgeMods} -> - {Before, _After} = split_instructions(Script), - case catch lists:foldl(fun(Instruction, EvalState1) -> - eval(Instruction, EvalState1) - end, - #eval_state{libdirs = LibDirs}, - Before) of - EvalState2 when is_record(EvalState2, eval_state) -> - {ok,PurgeMods}; - {error, Error} -> - {error, Error}; - Other -> - {error, Other} - end; + do_check_script(Script, LibDirs, PurgeMods); {error, Mod} -> {error, {old_processes, Mod}} end. +do_check_script(Script, LibDirs, PurgeMods) -> + {Before, After} = split_instructions(Script), + case catch lists:foldl(fun(Instruction, EvalState1) -> + eval(Instruction, EvalState1) + end, + #eval_state{libdirs = LibDirs}, + Before) of + EvalState2 when is_record(EvalState2, eval_state) -> + case catch syntax_check_script(After) of + ok -> + {ok,PurgeMods}; + Other -> + {error,Other} + end; + {error, Error} -> + {error, Error}; + Other -> + {error, Other} + end. + %% eval_script/1 - For testing only - no apps added, just testing instructions eval_script(Script) -> eval_script(Script, [], [], [], []). @@ -83,22 +95,30 @@ eval_script(Script, Apps, LibDirs, NewLibs, Opts) -> newlibs = NewLibs, opts = Opts}, Before) of - EvalState2 when is_record(EvalState2, eval_state) -> - case catch lists:foldl(fun(Instruction, EvalState3) -> - eval(Instruction, EvalState3) - end, - EvalState2, - After) of - EvalState4 when is_record(EvalState4, eval_state) -> - {ok, EvalState4#eval_state.unpurged}; - restart_new_emulator -> - restart_new_emulator; - Error -> - {'EXIT', Error} - end; - {error, Error} -> {error, Error}; - Other -> {error, Other} - end; + EvalState2 when is_record(EvalState2, eval_state) -> + case catch syntax_check_script(After) of + ok -> + case catch lists:foldl( + fun(Instruction, EvalState3) -> + eval(Instruction, + EvalState3) + end, + EvalState2, + After) of + EvalState4 + when is_record(EvalState4, eval_state) -> + {ok, EvalState4#eval_state.unpurged}; + restart_emulator -> + restart_emulator; + Error -> + {'EXIT', Error} + end; + Other -> + {error,Other} + end; + {error, Error} -> {error, Error}; + Other -> {error, Other} + end; {error, Mod} -> {error, {old_processes, Mod}} end. @@ -174,6 +194,42 @@ do_check_old_code(Mod,Procs) -> [Mod]. +%% Check the last part of the script, i.e. the part after point_of_no_return. +%% More or less a syntax check in case the script was handwritten. +syntax_check_script([point_of_no_return | Script]) -> + syntax_check_script(Script); +syntax_check_script([{load, {_,_,_}} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{remove, {_,_,_}} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{purge, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{suspend, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{resume, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{code_change, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{code_change, _, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{stop, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{start, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{sync_nodes, _, {_,_,_}} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{sync_nodes, _, _} | Script]) -> + syntax_check_script(Script); +syntax_check_script([{apply, {_,_,_}} | Script]) -> + syntax_check_script(Script); +syntax_check_script([restart_emulator | Script]) -> + syntax_check_script(Script); +syntax_check_script([Illegal | _Script]) -> + throw({illegal_instruction_after_point_of_no_return,Illegal}); +syntax_check_script([]) -> + ok. + + %%----------------------------------------------------------------- %% An unpurged module is a module for which there exist an old %% version of the code. This should only be the case if there are @@ -243,7 +299,7 @@ do_check_old_code(Mod,Procs) -> %% must also exectue the same line. Waits for all these nodes to get %% to this line. %% point_of_no_return -%% restart_new_emulator +%% restart_emulator %% {stop_application, Appl} - Impl with apply %% {unload_application, Appl} - Impl with {remove..} %% {load_application, Appl} - Impl with {load..} @@ -402,6 +458,8 @@ eval({sync_nodes, Id, Nodes}, EvalState) -> eval({apply, {M, F, A}}, EvalState) -> apply(M, F, A), EvalState; +eval(restart_emulator, _EvalState) -> + throw(restart_emulator); eval(restart_new_emulator, _EvalState) -> throw(restart_new_emulator). @@ -447,15 +505,20 @@ resume(Pids) -> change_code(Pids, Mod, Vsn, Extra, Timeout) -> Fun = fun(Pid) -> - case Timeout of - default -> - ok = sys:change_code(Pid, Mod, Vsn, Extra); - _Else -> - ok = sys:change_code(Pid, Mod, Vsn, Extra, Timeout) + case sys_change_code(Pid, Mod, Vsn, Extra, Timeout) of + ok -> + ok; + {error,Reason} -> + throw({code_change_failed,Pid,Mod,Vsn,Reason}) end end, lists:foreach(Fun, Pids). +sys_change_code(Pid, Mod, Vsn, Extra, default) -> + sys:change_code(Pid, Mod, Vsn, Extra); +sys_change_code(Pid, Mod, Vsn, Extra, Timeout) -> + sys:change_code(Pid, Mod, Vsn, Extra, Timeout). + stop(Mod, Procs) -> lists:zf(fun({undefined, _Name, _Pid, _Mods}) -> false; diff --git a/lib/sasl/src/sasl.appup.src b/lib/sasl/src/sasl.appup.src index 64c653a4e5..ce4aa1f8f8 100644 --- a/lib/sasl/src/sasl.appup.src +++ b/lib/sasl/src/sasl.appup.src @@ -1,25 +1,27 @@ -%% +%% -*- erlang -*- %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% -%% %CopyrightEnd% %% - +%% %CopyrightEnd% {"%VSN%", - [{"2.1.4", [{load_module, release_handler}, - {load_module, systools_relup}]}], - [{"2.1.4", [{load_module, release_handler}, - {load_module, systools_relup}]}] + %% Up from - max two major revisions back + [{<<"2\\.2(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.1\\.10(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14B04 (and later?) + {<<"2\\.1\\.[6-9](\\.[0-9]+)*">>,[restart_new_emulator]}],%% R13B-R14B03 + %% Down to - max two major revisions back + [{<<"2\\.2(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.1\\.10(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14B04 (and later?) + {<<"2\\.1\\.[6-9](\\.[0-9]+)*">>,[restart_new_emulator]}] %% R13B-R14B03 }. diff --git a/lib/sasl/src/systools.hrl b/lib/sasl/src/systools.hrl index 9a3e98221c..da531dbee5 100644 --- a/lib/sasl/src/systools.hrl +++ b/lib/sasl/src/systools.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -60,7 +60,8 @@ %% integer() | infinity. mod = [], %% [] | {Mod, StartArgs}, Mod= atom(), %% StartArgs = list(). - start_phases = [], %% [] | {Phase, PhaseArgs}, Phase = atom(), + start_phases, %% [{Phase, PhaseArgs}] | undefined, + %% Phase = atom(), %% PhaseArgs = list(). dir = "" %% The directory where the .app file was %% found (internal use). diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl index 7f400f5cce..61e660e918 100644 --- a/lib/sasl/src/systools_make.erl +++ b/lib/sasl/src/systools_make.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -31,6 +31,8 @@ -export([read_application/4]). +-export([make_hybrid_boot/5]). + -import(lists, [filter/2, keysort/2, keysearch/3, map/2, reverse/1, append/1, foldl/3, member/2, foreach/2]). @@ -56,6 +58,7 @@ %% {variables,[{Name,AbsString}]} %% {machine, jam | beam | vee} %% exref | {exref, [AppName]} +%% no_warn_sasl %%----------------------------------------------------------------- make_script(RelName) when is_list(RelName) -> @@ -86,7 +89,8 @@ make_script(RelName, Output, Flags) when is_list(RelName), Path = make_set(Path1 ++ code:get_path()), ModTestP = {member(src_tests, Flags),xref_p(Flags)}, case get_release(RelName, Path, ModTestP, machine(Flags)) of - {ok, Release, Appls, Warnings} -> + {ok, Release, Appls, Warnings0} -> + Warnings = wsasl(Flags, Warnings0), case systools_lib:werror(Flags, Warnings) of true -> return(ok,Warnings,Flags); @@ -110,7 +114,13 @@ make_script(RelName, _Output, Flags) when is_list(Flags) -> make_script(RelName, _Output, Flags) -> badarg(Flags,[RelName, Flags]). -%% Inlined. + +wsasl(Options, Warnings) -> + case lists:member(no_warn_sasl,Options) of + true -> lists:delete({warning,missing_sasl},Warnings); + false -> Warnings + end. + badarg(BadArg, Args) -> erlang:error({badarg,BadArg}, Args). @@ -162,6 +172,118 @@ return({error,Mod,Error},_,Flags) -> error end. + +%%----------------------------------------------------------------- +%% Make hybrid boot file for upgrading emulator. The resulting boot +%% file is a combination of the two input files, where kernel, stdlib +%% and sasl versions are taken from the second file (the boot file of +%% the new release), and all other application versions from the first +%% file (the boot file of the old release). +%% +%% The most important thing that can fail here is that the input boot +%% files do not contain all three base applications - kernel, stdlib +%% and sasl. +%% +%% TmpVsn = string(), +%% Paths = {KernelPath,StdlibPath,SaslPath} +%% Returns {ok,Boot} | {error,Reason} +%% Boot1 = Boot2 = Boot = binary() +%% Reason = {app_not_found,App} | {app_not_replaced,App} +%% App = kernel | stdlib | sasl +make_hybrid_boot(TmpVsn, Boot1, Boot2, Paths, Args) -> + catch do_make_hybrid_boot(TmpVsn, Boot1, Boot2, Paths, Args). +do_make_hybrid_boot(TmpVsn, Boot1, Boot2, Paths, Args) -> + {script,{_RelName1,_RelVsn1},Script1} = binary_to_term(Boot1), + {script,{RelName2,_RelVsn2},Script2} = binary_to_term(Boot2), + MatchPaths = get_regexp_path(Paths), + NewScript1 = replace_paths(Script1,MatchPaths), + {Kernel,Stdlib,Sasl} = get_apps(Script2,undefined,undefined,undefined), + NewScript2 = replace_apps(NewScript1,Kernel,Stdlib,Sasl), + NewScript3 = add_apply_upgrade(NewScript2,Args), + Boot = term_to_binary({script,{RelName2,TmpVsn},NewScript3}), + {ok,Boot}. + +%% For each app, compile a regexp that can be used for finding its path +get_regexp_path({KernelPath,StdlibPath,SaslPath}) -> + {ok,KernelMP} = re:compile("kernel-[0-9\.]+",[unicode]), + {ok,StdlibMP} = re:compile("stdlib-[0-9\.]+",[unicode]), + {ok,SaslMP} = re:compile("sasl-[0-9\.]+",[unicode]), + [{KernelMP,KernelPath},{StdlibMP,StdlibPath},{SaslMP,SaslPath}]. + +%% For each path in the script, check if it matches any of the MPs +%% found above, and if so replace it with the correct new path. +replace_paths([{path,Path}|Script],MatchPaths) -> + [{path,replace_path(Path,MatchPaths)}|replace_paths(Script,MatchPaths)]; +replace_paths([Stuff|Script],MatchPaths) -> + [Stuff|replace_paths(Script,MatchPaths)]; +replace_paths([],_) -> + []. + +replace_path([Path|Paths],MatchPaths) -> + [do_replace_path(Path,MatchPaths)|replace_path(Paths,MatchPaths)]; +replace_path([],_) -> + []. + +do_replace_path(Path,[{MP,ReplacePath}|MatchPaths]) -> + case re:run(Path,MP,[{capture,none}]) of + nomatch -> do_replace_path(Path,MatchPaths); + match -> ReplacePath + end; +do_replace_path(Path,[]) -> + Path. + +%% Return the entries for loading the three base applications +get_apps([{kernelProcess,application_controller, + {application_controller,start,[{application,kernel,_}]}}=Kernel| + Script],_,Stdlib,Sasl) -> + get_apps(Script,Kernel,Stdlib,Sasl); +get_apps([{apply,{application,load,[{application,stdlib,_}]}}=Stdlib|Script], + Kernel,_,Sasl) -> + get_apps(Script,Kernel,Stdlib,Sasl); +get_apps([{apply,{application,load,[{application,sasl,_}]}}=Sasl|_Script], + Kernel,Stdlib,_) -> + {Kernel,Stdlib,Sasl}; +get_apps([_|Script],Kernel,Stdlib,Sasl) -> + get_apps(Script,Kernel,Stdlib,Sasl); +get_apps([],undefined,_,_) -> + throw({error,{app_not_found,kernel}}); +get_apps([],_,undefined,_) -> + throw({error,{app_not_found,stdlib}}); +get_apps([],_,_,undefined) -> + throw({error,{app_not_found,sasl}}). + + +%% Replace the entries for loading the base applications +replace_apps([{kernelProcess,application_controller, + {application_controller,start,[{application,kernel,_}]}}| + Script],Kernel,Stdlib,Sasl) -> + [Kernel|replace_apps(Script,undefined,Stdlib,Sasl)]; +replace_apps([{apply,{application,load,[{application,stdlib,_}]}}|Script], + Kernel,Stdlib,Sasl) -> + [Stdlib|replace_apps(Script,Kernel,undefined,Sasl)]; +replace_apps([{apply,{application,load,[{application,sasl,_}]}}|Script], + _Kernel,_Stdlib,Sasl) -> + [Sasl|Script]; +replace_apps([Stuff|Script],Kernel,Stdlib,Sasl) -> + [Stuff|replace_apps(Script,Kernel,Stdlib,Sasl)]; +replace_apps([],undefined,undefined,_) -> + throw({error,{app_not_replaced,sasl}}); +replace_apps([],undefined,_,_) -> + throw({error,{app_not_replaced,stdlib}}); +replace_apps([],_,_,_) -> + throw({error,{app_not_replaced,kernel}}). + + +%% Finally add an apply of release_handler:new_emulator_upgrade - which will +%% complete the execution of the upgrade script (relup). +add_apply_upgrade(Script,Args) -> + [{progress, started} | RevScript] = lists:reverse(Script), + lists:reverse([{progress,started}, + {apply,{release_handler,new_emulator_upgrade,Args}} | + RevScript]). + + + %%----------------------------------------------------------------- %% Create a release package from a release file. %% Options is a list of {path, Path} | silent | @@ -250,13 +372,13 @@ get_release(File, Path, ModTestP, Machine) -> end. get_release1(File, Path, ModTestP, Machine) -> - {ok, Release} = read_release(File, Path), + {ok, Release, Warnings1} = read_release(File, Path), {ok, Appls0} = collect_applications(Release, Path), {ok, Appls1} = check_applications(Appls0), - {ok, Appls2} = sort_included_applications(Appls1, Release), % OTP-4121 - {ok, Warnings} = check_modules(Appls2, Path, ModTestP, Machine), + {ok, Appls2} = sort_used_and_incl_appls(Appls1, Release), % OTP-4121, OTP-9984 + {ok, Warnings2} = check_modules(Appls2, Path, ModTestP, Machine), {ok, Appls} = sort_appls(Appls2), - {ok, Release, Appls, Warnings}. + {ok, Release, Appls, Warnings1 ++ Warnings2}. %%______________________________________________________________________ %% read_release(File, Path) -> {ok, #release} | throw({error, What}) @@ -271,11 +393,12 @@ read_release(File, Path) -> check_rel(Release) -> case catch check_rel1(Release) of - {ok, {Name,Vsn,Evsn,Appl,Incl}} -> + {ok, {Name,Vsn,Evsn,Appl,Incl}, Ws} -> {ok, #release{name=Name, vsn=Vsn, erts_vsn=Evsn, applications=Appl, - incl_apps=Incl}}; + incl_apps=Incl}, + Ws}; {error, Error} -> throw({error,?MODULE,Error}); Error -> @@ -286,8 +409,8 @@ check_rel1({release,{Name,Vsn},{erts,EVsn},Appl}) when is_list(Appl) -> check_name(Name), check_vsn(Vsn), check_evsn(EVsn), - {Appls,Incls} = check_appl(Appl), - {ok, {Name,Vsn,EVsn,Appls,Incls}}; + {{Appls,Incls},Ws} = check_appl(Appl), + {ok, {Name,Vsn,EVsn,Appls,Incls},Ws}; check_rel1(_) -> {error, badly_formatted_release}. @@ -340,25 +463,35 @@ check_appl(Appl) -> end, Appl) of [] -> - mandatory_applications(Appl), - split_app_incl(Appl); + {ApplsNoIncls,Incls} = split_app_incl(Appl), + {ok,Ws} = mandatory_applications(ApplsNoIncls,undefined, + undefined,undefined), + {{ApplsNoIncls,Incls},Ws}; Illegal -> throw({error, {illegal_applications,Illegal}}) end. -mandatory_applications(Appl) -> - AppNames = map(fun(AppT) -> element(1, AppT) end, - Appl), - Mand = mandatory_applications(), - case filter(fun(X) -> member(X, AppNames) end, Mand) of - Mand -> - ok; - _ -> - throw({error, {missing_mandatory_app, Mand}}) - end. - -mandatory_applications() -> - [kernel, stdlib]. +mandatory_applications([{kernel,_,Type}|Apps],undefined,Stdlib,Sasl) -> + mandatory_applications(Apps,Type,Stdlib,Sasl); +mandatory_applications([{stdlib,_,Type}|Apps],Kernel,undefined,Sasl) -> + mandatory_applications(Apps,Kernel,Type,Sasl); +mandatory_applications([{sasl,_,Type}|Apps],Kernel,Stdlib,undefined) -> + mandatory_applications(Apps,Kernel,Stdlib,Type); +mandatory_applications([_|Apps],Kernel,Stdlib,Sasl) -> + mandatory_applications(Apps,Kernel,Stdlib,Sasl); +mandatory_applications([],Type,_,_) when Type=/=permanent -> + error_mandatory_application(kernel,Type); +mandatory_applications([],_,Type,_) when Type=/=permanent -> + error_mandatory_application(stdlib,Type); +mandatory_applications([],_,_,undefined) -> + {ok, [{warning,missing_sasl}]}; +mandatory_applications([],_,_,_) -> + {ok,[]}. + +error_mandatory_application(App,undefined) -> + throw({error, {missing_mandatory_app, App}}); +error_mandatory_application(App,Type) -> + throw({error, {mandatory_app, App, Type}}). split_app_incl(Appl) -> split_app_incl(Appl, [], []). @@ -709,34 +842,45 @@ undefined_applications(Appls) -> filter(fun(X) -> not member(X, Defined) end, Uses). %%______________________________________________________________________ -%% sort_included_applications(Applications, Release) -> Applications +%% sort_used_and_incl_appls(Applications, Release) -> Applications %% Applications = [{{Name,Vsn},#application}] %% Release = #release{} %% -%% Check that included applications are given in the same order as in -%% the release resource file (.rel). Otherwise load instructions in -%% the boot script, and consequently release upgrade instructions in -%% relup, may end up in the wrong order. +%% OTP-4121, OTP-9984 +%% Check that used and included applications are given in the same +%% order as in the release resource file (.rel). Otherwise load and +%% start instructions in the boot script, and consequently release +%% upgrade instructions in relup, may end up in the wrong order. -sort_included_applications(Applications, Release) when is_tuple(Release) -> +sort_used_and_incl_appls(Applications, Release) when is_tuple(Release) -> {ok, - sort_included_applications(Applications, Release#release.applications)}; - -sort_included_applications([{Tuple,Appl}|Appls], OrderedAppls) -> - case Appl#application.includes of - Incls when length(Incls)>1 -> - IndexedIncls = find_pos(Incls, OrderedAppls), - SortedIndexedIncls = lists:keysort(1, IndexedIncls), - Incls2 = lists:map(fun({_Index,Name}) -> Name end, - SortedIndexedIncls), - Appl2 = Appl#application{includes=Incls2}, - [{Tuple,Appl2}|sort_included_applications(Appls, OrderedAppls)]; - _Incls -> - [{Tuple,Appl}|sort_included_applications(Appls, OrderedAppls)] - end; -sort_included_applications([], _OrderedAppls) -> + sort_used_and_incl_appls(Applications, Release#release.applications)}; + +sort_used_and_incl_appls([{Tuple,Appl}|Appls], OrderedAppls) -> + Incls2 = + case Appl#application.includes of + Incls when length(Incls)>1 -> + sort_appl_list(Incls, OrderedAppls); + Incls -> + Incls + end, + Uses2 = + case Appl#application.uses of + Uses when length(Uses)>1 -> + sort_appl_list(Uses, OrderedAppls); + Uses -> + Uses + end, + Appl2 = Appl#application{includes=Incls2, uses=Uses2}, + [{Tuple,Appl2}|sort_used_and_incl_appls(Appls, OrderedAppls)]; +sort_used_and_incl_appls([], _OrderedAppls) -> []. +sort_appl_list(List, Order) -> + IndexedList = find_pos(List, Order), + SortedIndexedList = lists:keysort(1, IndexedList), + lists:map(fun({_Index,Name}) -> Name end, SortedIndexedList). + find_pos([Name|Incs], OrderedAppls) -> [find_pos(1, Name, OrderedAppls)|find_pos(Incs, OrderedAppls)]; find_pos([], _OrderedAppls) -> @@ -1120,7 +1264,8 @@ sort_appls(Appls) -> {ok, sort_appls(Appls, [], [], [])}. sort_appls([{N, A}|T], Missing, Circular, Visited) -> {Name,_Vsn} = N, - {Uses, T1, NotFnd1} = find_all(Name, A#application.uses, T, Visited, [], []), + {Uses, T1, NotFnd1} = find_all(Name, lists:reverse(A#application.uses), + T, Visited, [], []), {Incs, T2, NotFnd2} = find_all(Name, lists:reverse(A#application.includes), T1, Visited, [], []), Missing1 = NotFnd1 ++ NotFnd2 ++ Missing, @@ -1323,15 +1468,18 @@ pack_app(#application{name=Name,vsn=V,id=Id,description=D,modules=M, {applications, App}, {included_applications, Incs}, {env, Env}, - {start_phases, SF}, {maxT, MaxT}, {maxP, MaxP} | - behave(Mod)]}. - + behave([{start_phases,SF},{mod,Mod}])]}. + +behave([{mod,[]}|T]) -> + behave(T); +behave([{start_phases,undefined}|T]) -> + behave(T); +behave([H|T]) -> + [H|behave(T)]; behave([]) -> - []; -behave(Mod) -> - [{mod, Mod}]. + []. %%______________________________________________________________________ %% mandatory modules; this modules must be loaded before processes @@ -1510,8 +1658,19 @@ add_system_files(Tar, RelName, Release, Path1) -> SVsn = Release#release.vsn, RelName0 = filename:basename(RelName), + RelVsnDir = filename:join("releases", SVsn), + + %% OTP-9746: store rel file in releases/<vsn> + %% Adding rel file to + %% 1) releases directory - so it can be easily extracted + %% separately (see release_handler:unpack_release) + %% 2) releases/<vsn> - so the file must not be explicitly moved + %% after unpack. add_to_tar(Tar, RelName ++ ".rel", filename:join("releases", RelName0 ++ ".rel")), + add_to_tar(Tar, RelName ++ ".rel", + filename:join(RelVsnDir, RelName0 ++ ".rel")), + %% OTP-6226 Look for the system files not only in cwd %% -- @@ -1527,26 +1686,27 @@ add_system_files(Tar, RelName, Release, Path1) -> [RelDir, "."|Path1] end, - ToDir = filename:join("releases", SVsn), case lookup_file(RelName0 ++ ".boot", Path) of false -> throw({error, {tar_error,{add, RelName0++".boot",enoent}}}); Boot -> - add_to_tar(Tar, Boot, filename:join(ToDir, "start.boot")) + add_to_tar(Tar, Boot, filename:join(RelVsnDir, "start.boot")) end, case lookup_file("relup", Path) of false -> ignore; Relup -> - add_to_tar(Tar, Relup, filename:join(ToDir, "relup")) + check_relup(Relup), + add_to_tar(Tar, Relup, filename:join(RelVsnDir, "relup")) end, case lookup_file("sys.config", Path) of false -> ignore; Sys -> - add_to_tar(Tar, Sys, filename:join(ToDir, "sys.config")) + check_sys_config(Sys), + add_to_tar(Tar, Sys, filename:join(RelVsnDir, "sys.config")) end, ok. @@ -1562,6 +1722,44 @@ lookup_file(Name, [Dir|Path]) -> lookup_file(_Name, []) -> false. +%% Check that relup can be parsed and has expected format +check_relup(File) -> + case file:consult(File) of + {ok,[{Vsn,UpFrom,DownTo}]} when is_list(Vsn), is_integer(hd(Vsn)), + is_list(UpFrom), is_list(DownTo) -> + ok; + {ok,_} -> + throw({error,{tar_error,{add,"relup",[invalid_format]}}}); + Other -> + throw({error,{tar_error,{add,"relup",[Other]}}}) + end. + +%% Check that sys.config can be parsed and has expected format +check_sys_config(File) -> + case file:consult(File) of + {ok,[SysConfig]} -> + case lists:all(fun({App,KeyVals}) when is_atom(App), + is_list(KeyVals)-> + true; + (OtherConfig) when is_list(OtherConfig), + is_integer(hd(OtherConfig)) -> + true; + (_) -> + false + end, + SysConfig) of + true -> + ok; + false -> + throw({error,{tar_error, + {add,"sys.config",[invalid_format]}}}) + end; + {ok,_} -> + throw({error,{tar_error,{add,"sys.config",[invalid_format]}}}); + Other -> + throw({error,{tar_error,{add,"sys.config",[Other]}}}) + end. + %%______________________________________________________________________ %% Add either a application located under a variable dir or all other %% applications to a tar file. @@ -1850,90 +2048,67 @@ get_flag(_,_) -> false. %% Check Options for make_script check_args_script(Args) -> - cas(Args, - {undef, undef, undef, undef, undef, undef, undef, undef, - undef, []}). + cas(Args, []). -cas([], {_Path,_Sil,_Loc,_Test,_Var,_Mach,_Xref,_XrefApps,_Werror, X}) -> +cas([], X) -> X; %%% path --------------------------------------------------------------- -cas([{path, P} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, - XrefApps, Werror, X}) when is_list(P) -> +cas([{path, P} | Args], X) when is_list(P) -> case check_path(P) of ok -> - cas(Args, {P, Sil, Loc, Test, Var, Mach, Xref, XrefApps, - Werror, X}); + cas(Args, X); error -> - cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, - Werror, X++[{path,P}]}) + cas(Args, X++[{path,P}]) end; %%% silent ------------------------------------------------------------- -cas([silent | Args], {Path, _Sil, Loc, Test, Var, Mach, Xref, - XrefApps, Werror, X}) -> - cas(Args, {Path, silent, Loc, Test, Var, Mach, Xref, XrefApps, - Werror, X}); +cas([silent | Args], X) -> + cas(Args, X); %%% local -------------------------------------------------------------- -cas([local | Args], {Path, Sil, _Loc, Test, Var, Mach, Xref, - XrefApps, Werror, X}) -> - cas(Args, {Path, Sil, local, Test, Var, Mach, Xref, XrefApps, - Werror, X}); +cas([local | Args], X) -> + cas(Args, X); %%% src_tests ------------------------------------------------------- -cas([src_tests | Args], {Path, Sil, Loc, _Test, Var, Mach, Xref, - XrefApps, Werror, X}) -> - cas(Args, - {Path, Sil, Loc, src_tests, Var, Mach, Xref, Werror, XrefApps,X}); +cas([src_tests | Args], X) -> + cas(Args, X); %%% variables ---------------------------------------------------------- -cas([{variables, V} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, - XrefApps, Werror, X}) when is_list(V) -> +cas([{variables, V} | Args], X) when is_list(V) -> case check_vars(V) of ok -> - cas(Args, - {Path, Sil, Loc, Test, V, Mach, Xref, XrefApps, Werror, X}); + cas(Args, X); error -> - cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, - Werror, X++[{variables, V}]}) + cas(Args, X++[{variables, V}]) end; %%% machine ------------------------------------------------------------ -cas([{machine, M} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, - XrefApps, Werror, X}) when is_atom(M) -> - cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X}); +cas([{machine, M} | Args], X) when is_atom(M) -> + cas(Args, X); %%% exref -------------------------------------------------------------- -cas([exref | Args], {Path, Sil, Loc, Test, Var, Mach, _Xref, - XrefApps, Werror, X}) -> - cas(Args, {Path, Sil, Loc, Test, Var, Mach, exref, XrefApps, Werror, X}); +cas([exref | Args], X) -> + cas(Args, X); %%% exref Apps --------------------------------------------------------- -cas([{exref, Apps} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, - XrefApps, Werror, X}) when is_list(Apps) -> +cas([{exref, Apps} | Args], X) when is_list(Apps) -> case check_apps(Apps) of ok -> - cas(Args, {Path, Sil, Loc, Test, Var, Mach, - Xref, Apps, Werror, X}); + cas(Args, X); error -> - cas(Args, {Path, Sil, Loc, Test, Var, Mach, - Xref, XrefApps, Werror, X++[{exref, Apps}]}) + cas(Args, X++[{exref, Apps}]) end; %%% outdir Dir --------------------------------------------------------- -cas([{outdir, Dir} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, - XrefApps, Werror, X}) when is_list(Dir) -> - cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X}); +cas([{outdir, Dir} | Args], X) when is_list(Dir) -> + cas(Args, X); %%% otp_build (secret, not documented) --------------------------------- -cas([otp_build | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, - XrefApps, Werror, X}) -> - cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X}); +cas([otp_build | Args], X) -> + cas(Args, X); +%%% warnings_as_errors ------------------------------------------------- +cas([warnings_as_errors | Args], X) -> + cas(Args, X); +%%% no_warn_sasl ------------------------------------------------------- +cas([no_warn_sasl | Args], X) -> + cas(Args, X); %%% no_module_tests (kept for backwards compatibility, but ignored) ---- -cas([no_module_tests | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, - XrefApps, Werror, X}) -> - cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X}); -%%% warnings_as_errors (kept for backwards compatibility, but ignored) ---- -cas([warnings_as_errors | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, - XrefApps, _Werror, X}) -> - cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, - warnings_as_errors, X}); +cas([no_module_tests | Args], X) -> + cas(Args, X); %%% ERROR -------------------------------------------------------------- -cas([Y | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, - Werror, X}) -> - cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, - X++[Y]}). +cas([Y | Args], X) -> + cas(Args, X++[Y]). @@ -2072,9 +2247,12 @@ format_error({missing_parameter,Par}) -> format_error({illegal_applications,Names}) -> io_lib:format("Illegal applications in the release file: ~p~n", [Names]); -format_error({missing_mandatory_app,Names}) -> - io_lib:format("Mandatory applications (~p) must be specified in the release file~n", - [Names]); +format_error({missing_mandatory_app,Name}) -> + io_lib:format("Mandatory application ~p must be specified in the release file~n", + [Name]); +format_error({mandatory_app,Name,Type}) -> + io_lib:format("Mandatory application ~p must be of type 'permanent' in the release file. Is '~p'.~n", + [Name,Type]); format_error({duplicate_register,Dups}) -> io_lib:format("Duplicated register names: ~n~s", [map(fun({{Reg,App1,_,_},{Reg,App2,_,_}}) -> @@ -2198,5 +2376,9 @@ form_warn(Prefix, {exref_undef, Undef}) -> [Prefix,M,F,A]) end, map(F, Undef); +form_warn(Prefix, missing_sasl) -> + io_lib:format("~s: Missing application sasl. " + "Can not upgrade with this release~n", + [Prefix]); form_warn(Prefix, What) -> io_lib:format("~s ~p~n", [Prefix,What]). diff --git a/lib/sasl/src/systools_rc.erl b/lib/sasl/src/systools_rc.erl index daadb79967..c16f6aa845 100644 --- a/lib/sasl/src/systools_rc.erl +++ b/lib/sasl/src/systools_rc.erl @@ -54,6 +54,7 @@ %% {sync_nodes, Id, Nodes} %% {apply, {M, F, A}} %% restart_new_emulator +%% restart_emulator %%----------------------------------------------------------------- %% High-level instructions that contain dependencies @@ -144,7 +145,10 @@ translate_merged_script(Mode, Script, Appls, PreAppls) -> {Before2, After2} = translate_dependent_instrs(Mode, Before1, After1, Appls), Before3 = merge_load_object_code(Before2), - NewScript = Before3 ++ [point_of_no_return | After2], + + {Before4,After4} = sort_emulator_restart(Mode,Before3,After2), + NewScript = Before4 ++ [point_of_no_return | After4], + check_syntax(NewScript), {ok, NewScript}. @@ -699,6 +703,39 @@ mlo([{load_object_code, {Lib, LibVsn, Mods}} | T]) -> mlo([]) -> []. %%----------------------------------------------------------------- +%% RESTART EMULATOR +%% ----------------------------------------------------------------- +%% ----------------------------------------------------------------- +%% Check if there are any 'restart_new_emulator' instructions (i.e. if +%% the emulator or core application version is changed). If so, this +%% must be done first for upgrade and last for downgrade. +%% Check if there are any 'restart_emulator' instructions, if so +%% remove all and place one the end. +%% ----------------------------------------------------------------- +sort_emulator_restart(Mode,Before,After) -> + {Before1,After1} = + case filter_out(restart_new_emulator, After) of + After -> + {Before,After}; + A1 when Mode==up -> + {[restart_new_emulator|Before],A1}; + A1 when Mode==dn -> + {Before,A1++[restart_emulator]} + end, + After2 = + case filter_out(restart_emulator, After1) of + After1 -> + After1; + A2 -> + A2++[restart_emulator] + end, + {Before1,After2}. + + +filter_out(What,List) -> + lists:filter(fun(X) when X=:=What -> false; (_) -> true end, List). + +%%----------------------------------------------------------------- %% SYNTAX CHECK %%----------------------------------------------------------------- %%----------------------------------------------------------------- @@ -817,6 +854,7 @@ check_op({apply, {M, F, A}}) -> check_func(F), check_args(A); check_op(restart_new_emulator) -> ok; +check_op(restart_emulator) -> ok; check_op(X) -> throw({error, {bad_instruction, X}}). check_mod(Mod) when is_atom(Mod) -> ok; diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl index 6d9e922900..7fb623bb85 100644 --- a/lib/sasl/src/systools_relup.erl +++ b/lib/sasl/src/systools_relup.erl @@ -112,6 +112,11 @@ -export([mk_relup/3, mk_relup/4, format_error/1, format_warning/1]). -include("systools.hrl"). +-define(R15_SASL_VSN,"2.2"). + +%% For test purposes only - used by kernel, stdlib and sasl tests +-export([appup_search_for_version/2]). + %%----------------------------------------------------------------- %% mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs) %% mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, Opts) -> Ret @@ -200,7 +205,13 @@ do_mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, Path, Opts) -> %% TopRel = #release %% NameVsnApps = [{{Name, Vsn}, #application}] {ok, TopRel, NameVsnApps, Ws0} -> - %% + case lists:member({warning,missing_sasl},Ws0) of + true -> + throw({error,?MODULE,{missing_sasl,TopRel}}); + false -> + ok + end, + %% TopApps = [#application] TopApps = lists:map(fun({_, App}) -> App end, NameVsnApps), @@ -247,7 +258,21 @@ foreach_baserel_up(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts, Ws, Acc) -> BaseRelFile = extract_filename(BaseRelDc), - {ok, BaseRel} = systools_make:read_release(BaseRelFile, Path), + {BaseRel, {BaseNameVsns, BaseApps}, Ws0} = + case systools_make:get_release(BaseRelFile, Path) of + {ok, BR, NameVsnApps, Warns} -> + case lists:member({warning,missing_sasl},Warns) of + true -> + throw({error,?MODULE,{missing_sasl,BR}}); + false -> + %% NameVsnApps = [{{Name,Vsn},#application}] + %% Gives two lists - [{Name,Vsn}] and [#application] + {BR,lists:unzip(NameVsnApps),Warns} + end; + Other1 -> + throw(Other1) + end, + %% %% BaseRel = #release @@ -257,29 +282,23 @@ foreach_baserel_up(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts, %% application, one for each added applications, and one for %% each removed applications. %% - {RUs1, Ws1} = collect_appup_scripts(up, TopApps, BaseRel, Ws, []), + {RUs1, Ws1} = collect_appup_scripts(up, TopApps, BaseRel, Ws0++Ws, []), {RUs2, Ws2} = create_add_app_scripts(BaseRel, TopRel, RUs1, Ws1), {RUs3, Ws3} = create_remove_app_scripts(BaseRel, TopRel, RUs2, Ws2), - {RUs4, Ws4} = - check_for_emulator_restart(TopRel, BaseRel, RUs3, Ws3, Opts), - - BaseApps = - case systools_make:get_release(BaseRelFile, Path) of - {ok, _, NameVsnApps, _Warns} -> - lists:map(fun({_,App}) -> App end, NameVsnApps); - Other1 -> - throw(Other1) - end, + {RUs4, Ws4} = check_for_emulator_restart(TopRel, BaseRel, RUs3, Ws3, Opts), case systools_rc:translate_scripts(up, RUs4, TopApps, BaseApps) of - {ok, RUs} -> + {ok, RUs5} -> + + {RUs, Ws5} = fix_r15_sasl_upgrade(RUs5,Ws4,BaseNameVsns), + VDR = {BaseRel#release.vsn, extract_description(BaseRelDc), RUs}, foreach_baserel_up(TopRel, TopApps, BaseRelDcs, Path, - Opts, Ws4, [VDR| Acc]); + Opts, Ws5, [VDR| Acc]); XXX -> throw(XXX) end; @@ -294,42 +313,41 @@ foreach_baserel_dn(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts, Ws, Acc) -> BaseRelFile = extract_filename(BaseRelDc), - {ok, BaseRel} = systools_make:read_release(BaseRelFile, Path), - - %% BaseRel = #release - - %% RUs = (release upgrade scripts) - %% - {RUs1, Ws1} = collect_appup_scripts(dn, TopApps, BaseRel, Ws, []), - - {BaseApps, Ws2} = + {BaseRel, BaseApps, Ws0} = case systools_make:get_release(BaseRelFile, Path) of %% %% NameVsnApps = [{{Name, Vsn}, #application}] - {ok, _, NameVsnApps, Warns} -> - %% - %% NApps = [#application] - NApps = lists:map(fun({_,App}) -> App end, NameVsnApps), - {NApps, Warns ++ Ws1}; + {ok, BR, NameVsnApps, Warns} -> + case lists:member({warning,missing_sasl},Warns) of + true -> + throw({error,?MODULE,{missing_sasl,BR}}); + false -> + %% NApps = [#application] + NApps = lists:map(fun({_,App}) -> App end, NameVsnApps), + {BR, NApps, Warns} + end; Other -> throw(Other) end, - RUs2 = RUs1, + %% BaseRel = #release + + %% RUs = (release upgrade scripts) + %% + {RUs1, Ws1} = collect_appup_scripts(dn, TopApps, BaseRel, Ws0++Ws, []), - {RUs3, Ws3} = create_add_app_scripts(TopRel, BaseRel, RUs2, Ws2), + {RUs2, Ws2} = create_add_app_scripts(TopRel, BaseRel, RUs1, Ws1), - {RUs4, Ws4} = create_remove_app_scripts(TopRel, BaseRel, RUs3, Ws3), + {RUs3, Ws3} = create_remove_app_scripts(TopRel, BaseRel, RUs2, Ws2), - {RUs5, Ws5} = check_for_emulator_restart(TopRel, BaseRel, - RUs4, Ws4, Opts), + {RUs4, Ws4} = check_for_emulator_restart(TopRel, BaseRel, RUs3, Ws3, Opts), - case systools_rc:translate_scripts(dn, RUs5, BaseApps, TopApps) of + case systools_rc:translate_scripts(dn, RUs4, BaseApps, TopApps) of {ok, RUs} -> VDR = {BaseRel#release.vsn, extract_description(BaseRelDc), RUs}, foreach_baserel_dn(TopRel, TopApps, BaseRelDcs, Path, - Opts, Ws5, [VDR| Acc]); + Opts, Ws4, [VDR| Acc]); XXX -> throw(XXX) end; @@ -343,14 +361,42 @@ foreach_baserel_dn( _, _, [], _, _, Ws, Acc) -> %% check_for_emulator_restart(#release{erts_vsn = Vsn1, name = N1}, #release{erts_vsn = Vsn2, name = N2}, RUs, Ws, - _Opts) when Vsn1 /= Vsn2 -> - {RUs++[[restart_new_emulator]], [{erts_vsn_changed, {N1, N2}} | Ws]}; + Opts) when Vsn1 /= Vsn2 -> + %% Automatically insert a restart_new_emulator instruction when + %% erts version is changed. Also allow extra restart at the end of + %% the upgrade if restart_emulator option is given. + NewRUs = [[restart_new_emulator]|RUs], + NewWs = [{erts_vsn_changed, {{N1,Vsn1}, {N2,Vsn2}}} | Ws], + check_for_restart_emulator_opt(NewRUs, NewWs, Opts); check_for_emulator_restart(_, _, RUs, Ws, Opts) -> + check_for_restart_emulator_opt(RUs, Ws, Opts). + +check_for_restart_emulator_opt(RUs, Ws, Opts) -> case get_opt(restart_emulator, Opts) of - true -> {RUs++[[restart_new_emulator]], Ws}; + true -> {RUs++[[restart_emulator]], Ws}; _ -> {RUs, Ws} end. + +%% Special handling of the upgrade from pre R15 to post R15. In R15, +%% upgrade of the emulator was improved by moving the restart of the +%% emulator before the rest of the upgrade instructions. However, it +%% can only work if the release_handler is already upgraded to a post +%% R15 version. If not, the upgrade instructions must be backwards +%% compatible - i.e. restart_new_emulator will be the last +%% instruction, executed after all code loading, code_change etc. +fix_r15_sasl_upgrade([restart_new_emulator | RestRUs]=RUs, Ws, BaseApps) -> + case lists:keyfind(sasl,1,BaseApps) of + {sasl,Vsn} when Vsn < ?R15_SASL_VSN -> + {lists:delete(restart_emulator,RestRUs) ++ [restart_new_emulator], + [pre_R15_emulator_upgrade|Ws]}; + _ -> + {RUs,Ws} + end; +fix_r15_sasl_upgrade(RUs, Ws, _BaseApps) -> + {RUs,Ws}. + + %% collect_appup_scripts(Mode, TopApps, BaseRel, Ws, RUs) -> {NRUs, NWs} %% Mode = up | dn %% TopApps = [#application] @@ -440,13 +486,32 @@ get_script_from_appup(Mode, TopApp, BaseVsn, Ws, RUs) -> %% XXX Why is this a warning only? [{bad_vsn, {TopVsn, TopApp#application.vsn}}| Ws] end, - case lists:keysearch(BaseVsn, 1, VsnRUs) of - {value, {_, RU}} -> + case appup_search_for_version(BaseVsn, VsnRUs) of + {ok, RU} -> {RUs ++ [RU], Ws1}; - _ -> + error -> throw({error, ?MODULE, {no_relup, FName, TopApp, BaseVsn}}) end. +appup_search_for_version(BaseVsn, VsnRUs) -> + appup_search_for_version(BaseVsn, length(BaseVsn), VsnRUs). + +appup_search_for_version(BaseVsn,_,[{BaseVsn,RU}|_]) -> + {ok,RU}; +appup_search_for_version(BaseVsn,Size,[{Vsn,RU}|VsnRUs]) when is_binary(Vsn) -> + case re:run(BaseVsn,Vsn,[unicode,{capture,first,index}]) of + {match,[{0,Size}]} -> + {ok, RU}; + _ -> + appup_search_for_version(BaseVsn,Size,VsnRUs) + end; +appup_search_for_version(BaseVsn,Size,[_|VsnRUs]) -> + appup_search_for_version(BaseVsn,Size,VsnRUs); +appup_search_for_version(_,_,[]) -> + error. + + + %% Primitives for the "lists of release names" that we upgrade from %% and to. @@ -543,7 +608,9 @@ format_error({no_relup, File, App, Vsn}) -> "in file ~p~n", [App#application.name, App#application.vsn, App#application.name, Vsn, File]); - +format_error({missing_sasl,Release}) -> + io_lib:format("No sasl application in release ~p, ~p. Can not be upgraded.", + [Release#release.name, Release#release.vsn]); format_error(Error) -> io:format("~p~n", [Error]). diff --git a/lib/sasl/test/Makefile b/lib/sasl/test/Makefile index 65be134462..837abf74d4 100644 --- a/lib/sasl/test/Makefile +++ b/lib/sasl/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2011. All Rights Reserved. +# Copyright Ericsson AB 2011-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -36,6 +36,8 @@ MODULES= \ ERL_FILES= $(MODULES:%=%.erl) +HRL_FILES= test_lib.hrl + TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) INSTALL_PROGS= $(TARGET_FILES) @@ -83,10 +85,10 @@ include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt release_tests_spec: make_emakefile - $(INSTALL_DIR) $(RELSYSDIR) - $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR) - $(INSTALL_DATA) sasl.spec sasl.cover $(EMAKEFILE) $(RELSYSDIR) - chmod -R u+w $(RELSYSDIR) - @tar cfh - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) + $(INSTALL_DIR) "$(RELSYSDIR)" + $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)" + $(INSTALL_DATA) sasl.spec sasl.cover $(EMAKEFILE) "$(RELSYSDIR)" + chmod -R u+w "$(RELSYSDIR)" + @tar cfh - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -) release_docs_spec: diff --git a/lib/sasl/test/alarm_handler_SUITE.erl b/lib/sasl/test/alarm_handler_SUITE.erl index a98e8c9c67..a4064ef27a 100644 --- a/lib/sasl/test/alarm_handler_SUITE.erl +++ b/lib/sasl/test/alarm_handler_SUITE.erl @@ -18,7 +18,7 @@ %% -module(alarm_handler_SUITE). --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). %%----------------------------------------------------------------- %% We will add an own alarm handler in order to verify that the @@ -56,34 +56,32 @@ end_per_group(_GroupName, Config) -> %%----------------------------------------------------------------- -set_alarm(suite) -> []; set_alarm(Config) when is_list(Config) -> - ?line gen_event:add_handler(alarm_handler, ?MODULE, self()), + gen_event:add_handler(alarm_handler, ?MODULE, self()), Alarm1 = {alarm1, "this is the alarm"}, Alarm2 = {"alarm2", this_is_the_alarm}, Alarm3 = {{alarm3}, {this_is,"the_alarm"}}, - ?line ok = alarm_handler:set_alarm(Alarm1), + ok = alarm_handler:set_alarm(Alarm1), reported(set_alarm, Alarm1), - ?line ok = alarm_handler:set_alarm(Alarm2), + ok = alarm_handler:set_alarm(Alarm2), reported(set_alarm, Alarm2), - ?line ok = alarm_handler:set_alarm(Alarm3), + ok = alarm_handler:set_alarm(Alarm3), reported(set_alarm, Alarm3), - ?line [Alarm3,Alarm2,Alarm1] = alarm_handler:get_alarms(), + [Alarm3,Alarm2,Alarm1] = alarm_handler:get_alarms(), alarm_handler:clear_alarm(alarm1), alarm_handler:clear_alarm("alarm2"), alarm_handler:clear_alarm({alarm3}), - ?line [] = alarm_handler:get_alarms(), + [] = alarm_handler:get_alarms(), test_server:messages_get(), - ?line my_yes = gen_event:delete_handler(alarm_handler, ?MODULE, []), + my_yes = gen_event:delete_handler(alarm_handler, ?MODULE, []), ok. %%----------------------------------------------------------------- -clear_alarm(suite) -> []; clear_alarm(Config) when is_list(Config) -> - ?line gen_event:add_handler(alarm_handler, ?MODULE, self()), + gen_event:add_handler(alarm_handler, ?MODULE, self()), Alarm1 = {alarm1, "this is the alarm"}, Alarm2 = {"alarm2", this_is_the_alarm}, Alarm3 = {{alarm3}, {this_is,"the_alarm"}}, @@ -92,44 +90,42 @@ clear_alarm(Config) when is_list(Config) -> alarm_handler:set_alarm(Alarm3), test_server:messages_get(), - ?line ok = alarm_handler:clear_alarm(alarm1), + ok = alarm_handler:clear_alarm(alarm1), reported(clear_alarm, alarm1), - ?line ok = alarm_handler:clear_alarm("alarm2"), + ok = alarm_handler:clear_alarm("alarm2"), reported(clear_alarm, "alarm2"), - ?line ok = alarm_handler:clear_alarm({alarm3}), + ok = alarm_handler:clear_alarm({alarm3}), reported(clear_alarm, {alarm3}), - ?line [] = alarm_handler:get_alarms(), + [] = alarm_handler:get_alarms(), - ?line my_yes = gen_event:delete_handler(alarm_handler, ?MODULE, []), + my_yes = gen_event:delete_handler(alarm_handler, ?MODULE, []), ok. %%----------------------------------------------------------------- -swap(suite) -> []; swap(Config) when is_list(Config) -> - ?line Alarm1 = {alarm1, "this is the alarm"}, - ?line Alarm2 = {"alarm2", this_is_the_alarm}, - ?line Alarm3 = {{alarm3}, {this_is,"the_alarm"}}, - ?line alarm_handler:set_alarm(Alarm1), - ?line alarm_handler:set_alarm(Alarm2), - ?line alarm_handler:set_alarm(Alarm3), - - ?line foo, + Alarm1 = {alarm1, "this is the alarm"}, + Alarm2 = {"alarm2", this_is_the_alarm}, + Alarm3 = {{alarm3}, {this_is,"the_alarm"}}, + alarm_handler:set_alarm(Alarm1), + alarm_handler:set_alarm(Alarm2), + alarm_handler:set_alarm(Alarm3), + case gen_event:which_handlers(alarm_handler) of [alarm_handler] -> - ?line ok = gen_event:swap_handler(alarm_handler, - {alarm_handler, swap}, - {?MODULE, self()}), - ?line [?MODULE] = gen_event:which_handlers(alarm_handler), + ok = gen_event:swap_handler(alarm_handler, + {alarm_handler, swap}, + {?MODULE, self()}), + [?MODULE] = gen_event:which_handlers(alarm_handler), Alarms = [Alarm3, Alarm2, Alarm1], reported(swap_alarms, Alarms), %% get_alarms is only valid with the default handler installed. - ?line {error, _} = alarm_handler:get_alarms(), + {error, _} = alarm_handler:get_alarms(), - ?line my_yes = gen_event:delete_handler(alarm_handler, - ?MODULE, []), - ?line gen_event:add_handler(alarm_handler, alarm_handler, []), + my_yes = gen_event:delete_handler(alarm_handler, + ?MODULE, []), + gen_event:add_handler(alarm_handler, alarm_handler, []), ok; _ -> alarm_handler:clear_alarm(alarm1), diff --git a/lib/sasl/test/installer.erl b/lib/sasl/test/installer.erl index f5ceab0dc4..709269a73c 100644 --- a/lib/sasl/test/installer.erl +++ b/lib/sasl/test/installer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011. All Rights Reserved. +%% Copyright Ericsson AB 2011-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -19,20 +19,33 @@ -module(installer). +-include("test_lib.hrl"). + %%-compile(export_all). -export([install_1/2]). -export([install_2/1]). -export([install_3/2]). --export([install_3a/1]). +-export([install_6a/1]). -export([install_4/1]). -export([install_5/1]). -export([install_5a/1]). -export([install_6/1]). -export([install_7/1]). +-export([install_7a/1]). -export([install_8/1]). +-export([install_8a/1]). -export([install_9/1]). -export([install_10/1]). -export([install_11/1]). +-export([install_12/1]). +-export([install_13/1]). +-export([install_14/1]). +-export([upgrade_restart_1/2]). +-export([upgrade_restart_1a/1]). +-export([upgrade_restart_2/1]). +-export([upgrade_restart_2a/1]). +-export([upgrade_restart_2b/1]). +-export([upgrade_restart_3/1]). -export([client1_1/4]). -export([client2/3]). -export([stop/1]). @@ -46,28 +59,35 @@ -define(fail(Term), exit({?MODULE, ?LINE, Term})). -define(fail_line(Line,Term), exit({?MODULE, Line, Term})). --define(check_release(Vsn,Status,Apps), - check_release(TestNode,node(),Vsn,Status,Apps,?LINE)). --define(check_release_client(Node,Vsn,Status,Apps), - check_release(TestNode,Node,Vsn,Status,Apps,?LINE)). +-define(check_release_states(States), + check_release_states(TestNode,node(),States,?LINE)). +-define(check_release_states_client(Node,States), + check_release_states(TestNode,Node,States,?LINE)). + +-define(check_release_lib(Vsn,Apps), + check_release_lib(TestNode,node(),Vsn,Apps,?LINE)). +-define(check_release_lib_client(Node,Vsn,Apps), + check_release_lib(TestNode,Node,Vsn,Apps,?LINE)). -define(check_running_app(App,Vsn), check_running_app(TestNode,node(),App,Vsn,?LINE)). -define(check_running_app_client(Node,App,Vsn), check_running_app(TestNode,Node,App,Vsn,?LINE)). +-define(check_disallowed_calls,check_disallowed_calls(TestNode,?LINE)). + install_1(TestNode,PrivDir) -> ?print([TestNode]), ?print(["install_1 start"]), + ?check_release_states([permanent]), % Unpack and install P1H {ok, "P1H"} = unpack_release(PrivDir,"rel1"), - ?print(["unpack_release P1H ok"]), - ?check_release("P1H",unpacked,["a-1.0"]), + ?check_release_states([permanent,unpacked]), + ?check_release_lib("P1H",["a-1.0"]), {ok,"P1G",[new_appl]} = release_handler:install_release("P1H"), - ?print(["install_release P1H ok"]), - ?check_release("P1H",current,["a-1.0"]), + ?check_release_states([permanent,current]), ?check_running_app(a,"1.0"), X = a:a(), ?print(["X", X]), @@ -81,173 +101,351 @@ install_2(TestNode) -> ?print(["install_2 start"]), % Check that P1H is still unpacked, install it and make_permanent - ?check_release("P1H",unpacked,["a-1.0"]), - ?print(["install_2 P1H unpacked"]), + ?check_release_states([permanent,unpacked]), {ok,"P1G",[new_appl]} = release_handler:install_release("P1H"), ?print(["install_2 install_release ok"]), - ?check_release("P1H",current,["a-1.0"]), + ?check_release_states([permanent,current]), + ?check_running_app(a,"1.0"), + ok = release_handler:make_permanent("P1H"), + ?print(["install_2 make permanent P1H ok"]), + ?check_release_states([old,permanent]), ?check_running_app(a,"1.0"), - ok = release_handler:make_permanent("P1H"). + ok. % release_handler_SUITE will reboot this node now! install_3(TestNode,PrivDir) -> ?print(["install_3 start"]), % Check that P1H is permanent - ?check_release("P1H",permanent,["a-1.0"]), + ?check_release_states([old,permanent]), + ?check_running_app(a,"1.0"), X = a:a(), {key2, val2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), % Unpack and install P1I {ok, "P1I"} = unpack_release(PrivDir,"rel2"), - ?print(["install_3 unpack_release P1I ok"]), - ?check_release("P1I",unpacked,["a-1.1"]), + ?check_release_states([old,permanent,unpacked]), + ?check_release_lib("P1I",["a-1.1"]), {ok,"P1H",[{extra, gott}]} = release_handler:check_install_release("P1I"), + ?print(["install_3 check_install_release P1I ok"]), {error,_} = release_handler:check_install_release("P1J"), + ?print(["install_3 check_install_release P1J fails - ok"]), {ok,"P1H",[{extra, gott}]} = release_handler:install_release("P1I"), - ?print(["install_3 install_release P1I ok"]), - ?check_release("P1I",current,["a-1.1"]), + ?check_release_states([old,permanent,current]), ?check_running_app(a,"1.1"), X2 = a:a(), {key2, newval2} = lists:keyfind(key2, 1, X2), {key1, val1} = lists:keyfind(key1, 1, X2), {ok, bval} = a:b(), + ?print(["install_3 env ok"]), - % Unpack and install P2A + % Unpack P2A {ok, "P2A"} = unpack_release(PrivDir,"rel3"), - ?print(["install_3 unpack_release P2A ok"]), - ?check_release("P2A",unpacked,["a-1.1"]), + ?check_release_states([old,permanent,current,unpacked]), + ?check_release_lib("P2A",["a-1.1"]), {ok, "P1I", [new_emu]} = release_handler:check_install_release("P2A"), ?print(["install_3 check_install_release P2A ok"]), - ok = release_handler:make_permanent("P1I"), - ?print(["install_3 make_permanent P1I ok"]), - ?check_release("P1I",permanent,["a-1.1"]), ok. + % release_handler_SUITE will reboot this node now! + +install_4(TestNode) -> + ?print(["install_4 start"]), -install_3a(TestNode) -> - {ok, "P1I", [new_emu]} = release_handler:install_release("P2A"), + %% Check that P1H is the one that is used + ?check_release_states([old,permanent,unpacked,unpacked]), + ?check_running_app(a,"1.0"), + + %% Install P2A + {continue_after_restart, "P1H", [new_emu,new_appl]} = + release_handler:install_release("P2A"), %% Node is rebooted by the release_handler:install_release %% (init:reboot) because P2A includes a new erts vsn and the relup %% file contains a 'restart_new_emulator' instruction. - ?print(["install_3 P2A installed"]), + ?print(["install_4 P2A installed"]), ok. +install_5(TestNode) -> + ?print(["install_5 start"]), -install_4(TestNode) -> - ?print(["install_4 start"]), + %% Check that the upgrade was done via a temporary release due to + %% new emulator version. + {"SASL-test","__new_emulator__P1H"} = init:script_id(), + + %% Check that P2A is in use. + ?check_release_states([old,permanent,unpacked,current]), + ?check_running_app(a,"1.1"), + X = a:a(), + {key2, newval2} = lists:keyfind(key2, 1, X), + {key1, val1} = lists:keyfind(key1, 1, X), + {ok, bval} = a:b(), + ?print(["install_5 check env ok"]), + ok. + +install_5a(TestNode) -> + ?print(["install_5a start"]), + + %% Install P1I (this will be a downgrade) + {ok, "P1I", [old_emu]} = release_handler:install_release("P1I"), + %% Node is rebooted by the release_handler:install_release + %% (init:reboot) because P2A includes a new erts vsn and the relup + %% file contains a 'restart_new_emulator' instruction. + ?print(["install_5a P1I installed"]), + ok. + +install_6(TestNode) -> + ?print(["install_6 start"]), + + %% Check that P1I is used + ?check_release_states([old,permanent,current,old]), + ?check_running_app(a,"1.1"), + + %% Make P1I permanent + ok = release_handler:make_permanent("P1I"), + ?check_release_states([old,old,permanent,old]), + ?check_running_app(a,"1.1"), + ok. + +install_6a(TestNode) -> + %% Install P2A + {continue_after_restart, "P1I", [new_emu]} = + release_handler:install_release("P2A"), + %% Node is rebooted by the release_handler:install_release + %% (init:reboot) because P2A includes a new erts vsn and the relup + %% file contains a 'restart_new_emulator' instruction. + ?print(["install_6a P2A installed"]), + ok. + +install_7(TestNode) -> + ?print(["install_7 start"]), + + %% Check that the upgrade was done via a temporary release due to + %% new emulator version. + {"SASL-test","__new_emulator__P1I"} = init:script_id(), % Check that P2A is in use. - ?check_release("P2A",current,["a-1.1"]), + ?check_release_states([old,old,permanent,current]), ?check_running_app(a,"1.1"), X = a:a(), {key2, newval2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), {ok, bval} = a:b(), + ?print(["install_7 check env ok"]), ok. - % release_handler_SUITE will reboot this node now! -install_5(TestNode) -> - ?print(["install_5 start"]), +install_7a(TestNode) -> + %% Install P1H (this will be a downgrade) + {ok, "P1H", [old_emu,old_appl]} = release_handler:install_release("P1H"), + %% Node is rebooted by the release_handler:install_release + %% (init:reboot) because P2A includes a new erts vsn and the relup + %% file contains a 'restart_new_emulator' instruction. + ?print(["install_7a P1H installed"]), + ok. - % Check that P1I is used - {ok, "P1I", [new_emu]} = release_handler:check_install_release("P2A"), +install_8(TestNode) -> + ?print(["install_8 start"]), + + %% Check that P1H is used + ?check_release_states([old,current,permanent,old]), + ?check_running_app(a,"1.0"), + {ok,"P1H",[new_emu,new_appl]} = release_handler:check_install_release("P2A"), + ?print(["install_8 check_install_release P2A ok"]), + + %% Install P1I and check that it is permanent + {ok,"P1H",[{extra, gott}]} = release_handler:install_release("P1I"), + ?check_release_states([old,old,permanent,old]), + ?check_running_app(a,"1.1"), ok. -install_5a(TestNode) -> +install_8a(TestNode) -> % Install P2A again - {ok, "P1I", [new_emu]} = release_handler:install_release("P2A"), + {continue_after_restart, "P1I", [new_emu]} = + release_handler:install_release("P2A"), %% Node is rebooted by the release_handler:install_release %% (init:reboot) because P2A includes a new erts vsn and the relup %% file contains a 'restart_new_emulator' instruction. - ?print(["install_5 P2A installed"]), + ?print(["install_8a P2A installed"]), ok. -install_6(TestNode) -> - ?print(["install_6 start"]), +install_9(TestNode) -> + ?print(["install_9 start"]), + + %% Check that the upgrade was done via a temporary release due to + %% new emulator version. + {"SASL-test","__new_emulator__P1I"} = init:script_id(), % Check that P2A is used - ?check_release("P2A",current,["a-1.1"]), + ?check_release_states([old,old,permanent,current]), ?check_running_app(a,"1.1"), X = a:a(), {key2, newval2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), {ok, bval} = a:b(), - ok = release_handler:make_permanent("P2A"). + ?print(["install_9 check env ok"]), + ok = release_handler:make_permanent("P2A"), + ?check_release_states([old,old,old,permanent]), + ?check_running_app(a,"1.1"), + ok. % release_handler_SUITE will reboot this node now! -install_7(TestNode) -> - ?print(["install_7 start"]), +install_10(TestNode) -> + ?print(["install_10 start"]), % Check that P2A is used - ?check_release("P2A",permanent,["a-1.1"]), + ?check_release_states([old,old,old,permanent]), + ?check_running_app(a,"1.1"), % Install old P1H ok = release_handler:reboot_old_release("P1H"), + ?print(["install_10 reboot_old ok"]), ok. -install_8(TestNode) -> - ?print(["install_8 start"]), + +install_11(TestNode) -> + ?print(["install_11 start"]), % Check that P1H is permanent - ?check_release("P1H",permanent,["a-1.0"]), + ?check_release_states([old,permanent,old,old]), + ?check_running_app(a,"1.0"), X = a:a(), {key2, val2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), + ?print(["install_11 check env ok"]), %% Remove P1I and P2A and check that a-1.1 and erts-<latest> are removed ok = release_handler:remove_release("P2A"), + ?check_release_states([old,permanent,old]), ok = release_handler:remove_release("P1I"), + ?check_release_states([old,permanent]), {ok, Libs} = file:list_dir(code:lib_dir()), {_,_,StdlibVsn} = lists:keyfind(stdlib,1,application:which_applications()), true = lists:member("stdlib-"++StdlibVsn, Libs), true = lists:member("a-1.0", Libs), false = lists:member("a-1.1", Libs), {ok, Dirs} = file:list_dir(code:root_dir()), - ["erts-4.4"] = lists:filter(fun(Dir) -> lists:prefix("erts-",Dir) end, Dirs), + ErtsDir = "erts-"++?ertsvsn, + [ErtsDir] = lists:filter(fun(Dir) -> lists:prefix("erts-",Dir) end, Dirs), + ?print(["install_11 file checks ok"]), ok. % release_handler_SUITE will reboot this node now! -install_9(TestNode) -> - ?print(["install_9 start"]), +install_12(TestNode) -> + ?print(["install_12 start"]), % Check that P1H is permanent - ?check_release("P1H",permanent,["a-1.0"]), + ?check_release_states([old,permanent]), + ?check_running_app(a,"1.0"), X = a:a(), {key2, val2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), + ?print(["install_12 check env ok"]), % Install old P1G ok = release_handler:reboot_old_release("P1G"), + ?print(["install_12 reboot_old ok"]), ok. -install_10(TestNode) -> - ?print(["install_10 start"]), +install_13(TestNode) -> + ?print(["install_13 start"]), % Check that P1G is permanent - ?check_release("P1G",permanent,[]), - ?check_release("P1H",old,["a-1.0"]), + ?check_release_states([permanent,old]), + false = lists:keysearch(a,1,application:loaded_applications()), + ?print(["install_13 no a application found - ok"]), %% Remove P1H and check that both versions of application a is removed ok = release_handler:remove_release("P1H"), + ?check_release_states([permanent]), {ok, Libs} = file:list_dir(code:lib_dir()), {_,_,StdlibVsn} = lists:keyfind(stdlib,1,application:which_applications()), true = lists:member("stdlib-"++StdlibVsn, Libs), false = lists:member("a-1.0", Libs), false = lists:member("a-1.1", Libs), + ?print(["install_13 file checks ok"]), ok. % release_handler_SUITE will reboot this node now! -install_11(TestNode) -> - ?print(["install_11 start"]), +install_14(TestNode) -> + ?print(["install_14 start"]), % Check that P1G is permanent - ?check_release("P1G",permanent,[]), + ?check_release_states([permanent]), + false = lists:keysearch(a,1,application:loaded_applications()), + ?print(["install_13 no a application found - ok"]), ok. +%%%----------------------------------------------------------------- +%%% Ths test checks that an upgrade which both upgrades to a new +%%% emulator version, and had a restart_emulator option to +%%% systools:make_relup will be restarted twice on upgrade. +%%% (On downgrade it will happen only once.) +upgrade_restart_1(TestNode,PrivDir) -> + ?print([TestNode]), + ?print(["upgrade_restart_1 start"]), + ?check_release_states([permanent]), + + {ok, "P2B"} = unpack_release(PrivDir,"rel4"), + ?check_release_states([permanent,unpacked]), + ?check_release_lib("P2B",["a-1.1"]), + ok. + +upgrade_restart_1a(TestNode) -> + ?print(["upgrade_restart_1a start"]), + + {continue_after_restart,"P1G",[new_emu,add_appl]} = + release_handler:install_release("P2B"), + ?print(["upgrade_restart_1a P2B installed"]), + ok. + +upgrade_restart_2(TestNode) -> + ?print(["upgrade_restart_2 start"]), + + %% Check that the node has been restarted once more after the tmp release + case init:script_id() of + {"SASL-test","P2B"} -> + upgrade_restart_2a(TestNode); + {"SASL-test","__new_emulator__P1G"} -> + %% catched the node too early - give it another try + {wait,whereis(init)} + end. + +upgrade_restart_2a(TestNode) -> + ?print(["upgrade_restart_2a start"]), + + %% This time we must be there, else something is definitely wrong + {"SASL-test","P2B"} = init:script_id(), + + ?check_release_states([permanent,current]), + ?check_running_app(a,"1.1"), + + ok = release_handler:make_permanent("P2B"), + ?check_release_states([old,permanent]), + + ok. + +upgrade_restart_2b(TestNode) -> + ?print(["upgrade_restart_2b start"]), + + {ok,"P1G",[old_emu,rm_appl]} = release_handler:install_release("P1G"), + ?print(["upgrade_restart_2b P1G installed"]), + ok. + +upgrade_restart_3(TestNode) -> + ?print(["upgrade_restart_3 start"]), + + %% Ideally we should test that the node has only been restarted + %% once... but that's not so easy. Let's just check that P1G is running. + ?check_release_states([current,permanent]), + false = lists:keysearch(a,1,application:loaded_applications()), + ?print(["upgrade_restart_3 no a application found - ok"]), + + ok. + + + %%----------------------------------------------------------------- %% This test starts a client node which uses this node as master @@ -272,6 +470,8 @@ client1_1(TestNode,PrivDir,MasterDir,ClientSname) -> Node = start_client(TestNode,client1,ClientSname), trace_disallowed_calls(Node), + ?check_release_states_client(Node,[permanent]), + %% Check env var for SASL on client node SaslEnv = rpc:call(Node, application, get_all_env, [sasl]), ?print([{client1_1,sasl_env},SaslEnv]), @@ -300,13 +500,14 @@ client1_1(TestNode,PrivDir,MasterDir,ClientSname) -> %% as default. But it is given here in order to force hitting the %% release_handler:check_path function so it can be checked that %% it does not use file:read_file_info on the client node, see - %% trace_disallowed_calls/1 and check_disallowed_calls/0 below. + %% trace_disallowed_calls/1 and check_disallowed_calls/2 below. %% (OTP-9142) {ok, "P1H"} = rpc:call(Node, release_handler, set_unpacked, [filename:join(P1HDir, "rel1.rel"), [{a,"1.0",filename:join(MasterDir,lib)}]]), - ?check_release_client(Node,"P1H",unpacked,["a-1.0"]), + ?check_release_states_client(Node,[permanent,unpacked]), + ?check_release_lib_client(Node,"P1H",["a-1.0"]), ok = rpc:call(Node, release_handler, install_file, ["P1H", filename:join(P1HDir, "start.boot")]), @@ -323,13 +524,16 @@ client1_1(TestNode,PrivDir,MasterDir,ClientSname) -> {ok,"P1G",[new_appl]} = rpc:call(Node, release_handler, install_release, ["P1H"]), + ?check_release_states_client(Node,[permanent,current]), + ?check_running_app_client(Node,a,"1.0"), + Apps = rpc:call(Node, application, which_applications, []), {a,"A CXC 138 11","1.0"} = lists:keyfind(a, 1, Apps), X = rpc:call(Node, a, a, []), {key2, val2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), - check_disallowed_calls(), + ?check_disallowed_calls, reboot(TestNode,Node), trace_disallowed_calls(Node), @@ -339,17 +543,17 @@ client1_2(TestNode,PrivDir,Node) -> ?print(["client1_2 start"]), %% Check that P1H is still unpacked, install it and make_permanent - ?check_release_client(Node,"P1H",unpacked,["a-1.0"]), + ?check_release_states_client(Node,[permanent,unpacked]), {ok,"P1G",[new_appl]} = rpc:call(Node, release_handler, install_release, ["P1H"]), - ?check_release_client(Node,"P1H",current,["a-1.0"]), + ?check_release_states_client(Node,[permanent,current]), ?check_running_app_client(Node,a,"1.0"), ok = rpc:call(Node, release_handler, make_permanent, ["P1H"]), - ?check_release_client(Node,"P1H",permanent,["a-1.0"]), + ?check_release_states_client(Node,[old,permanent]), - check_disallowed_calls(), + ?check_disallowed_calls, reboot(TestNode,Node), trace_disallowed_calls(Node), @@ -359,10 +563,8 @@ client1_3(TestNode,PrivDir,Node) -> ?print(["client1_3 start"]), %% Check that P1H is permanent - ?check_release_client(Node,"P1H",permanent,["a-1.0"]), - X = rpc:call(Node, a, a, []), - {key2, val2} = lists:keyfind(key2, 1, X), - {key1, val1} = lists:keyfind(key1, 1, X), + ?check_release_states_client(Node,[old,permanent]), + ?check_running_app_client(Node,a,"1.0"), %% Unpack P1I on master {ok, "P1I"} = unpack_release(PrivDir,"rel2"), @@ -374,7 +576,8 @@ client1_3(TestNode,PrivDir,Node) -> {ok, "P1I"} = rpc:call(Node, release_handler, set_unpacked, [filename:join(P1IDir, "rel2.rel"),[]]), - ?check_release_client(Node,"P1I",unpacked,["a-1.1"]), + ?check_release_states_client(Node,[old,permanent,unpacked]), + ?check_release_lib_client(Node,"P1I",["a-1.1"]), ok = rpc:call(Node, release_handler, install_file, ["P1I", filename:join(P1IDir, "start.boot")]), @@ -389,6 +592,7 @@ client1_3(TestNode,PrivDir,Node) -> {ok,"P1H",[{extra, gott}]} = rpc:call(Node, release_handler, install_release, ["P1I"]), + ?check_release_states_client(Node,[old,permanent,current]), ?check_running_app_client(Node,a,"1.1"), X2 = rpc:call(Node, a, a, []), {key2, newval2} = lists:keyfind(key2, 1, X2), @@ -404,6 +608,9 @@ client1_3(TestNode,PrivDir,Node) -> rpc:call(Node, release_handler, set_unpacked, [filename:join(P2ADir, "rel3.rel"),[]]), + ?check_release_states_client(Node,[old,permanent,current,unpacked]), + ?check_release_lib_client(Node,"P2A",["a-1.1"]), + ok = rpc:call(Node, release_handler, install_file, ["P2A", filename:join(P2ADir, "start.boot")]), ok = rpc:call(Node, release_handler, install_file, @@ -413,66 +620,136 @@ client1_3(TestNode,PrivDir,Node) -> {ok, "P1I", [new_emu]} = rpc:call(Node, release_handler, check_install_release, ["P2A"]), + + %% Reboot from P1H + ?check_disallowed_calls, + reboot(TestNode,Node), + trace_disallowed_calls(Node), + + client1_4(TestNode,Node). + +client1_4(TestNode,Node) -> + ?print(["client1_4 start"]), + + %% check that P1H is used + ?check_release_states_client(Node,[old,permanent,unpacked,unpacked]), + + %% since the install_release below reboot the node... + ?check_disallowed_calls, + cover_client(TestNode,Node,stop_cover), + + {continue_after_restart, "P1H", [new_emu,new_appl]} = + rpc:call(Node, release_handler, install_release, ["P2A"]), + %% Reboots the client ! + + check_reboot(TestNode,Node), + trace_disallowed_calls(Node), + + client1_5(TestNode,Node). + +client1_5(TestNode,Node) -> + ?print(["client1_5 start"]), + + %% Check that P2A is in use. + ?check_release_states_client(Node,[old,permanent,unpacked,current]), + ?check_running_app_client(Node,a,"1.1"), + X = rpc:call(Node, a, a, []), + {key2, newval2} = lists:keyfind(key2, 1, X), + {key1, val1} = lists:keyfind(key1, 1, X), + {ok, bval} = rpc:call(Node, a, b, []), + + %% since the install_release below reboot the node... + ?check_disallowed_calls, + cover_client(TestNode,Node,stop_cover), + + {ok,"P1I",[old_emu]} = + rpc:call(Node, release_handler, install_release, ["P1I"]), + + check_reboot(TestNode,Node), + trace_disallowed_calls(Node), + + client1_6(TestNode,Node). + +client1_6(TestNode,Node) -> + ?print(["client1_6 start"]), + + ?check_release_states_client(Node,[old,permanent,current,old]), + ?check_running_app_client(Node,a,"1.1"), + ok = rpc:call(Node, release_handler, make_permanent, ["P1I"]), - ?check_release_client(Node,"P1I",permanent,["a-1.1"]), + ?check_release_states_client(Node,[old,old,permanent,old]), %% since the install_release below reboot the node... - check_disallowed_calls(), + ?check_disallowed_calls, cover_client(TestNode,Node,stop_cover), - {ok, "P1I", [new_emu]} = + {continue_after_restart, "P1I", [new_emu]} = rpc:call(Node, release_handler, install_release, ["P2A"]), %% Reboots the client ! check_reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_4(TestNode,Node). + client1_7(TestNode,Node). -client1_4(TestNode,Node) -> - ?print(["client1_4 start"]), +client1_7(TestNode,Node) -> + ?print(["client1_7 start"]), %% Check that P2A is in use. - ?check_release_client(Node,"P2A",current,["a-1.1"]), + ?check_release_states_client(Node,[old,old,permanent,current]), ?check_running_app_client(Node,a,"1.1"), X = rpc:call(Node, a, a, []), {key2, newval2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), {ok, bval} = rpc:call(Node, a, b, []), - %% Reboot from P1I - check_disallowed_calls(), - reboot(TestNode,Node), + %% since the install_release below reboot the node... + ?check_disallowed_calls, + cover_client(TestNode,Node,stop_cover), + + {ok,"P1H",[old_emu,old_appl]} = + rpc:call(Node, release_handler, install_release, ["P1H"]), + + check_reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_5(TestNode,Node). + client1_8(TestNode,Node). -client1_5(TestNode,Node) -> - ?print(["client1_5 start"]), +client1_8(TestNode,Node) -> + ?print(["client1_8 start"]), - %% Check that P1I is used - {ok, "P1I", [new_emu]} = + %% Check that P1H is used + ?check_release_states_client(Node,[old,current,permanent,old]), + ?check_running_app_client(Node,a,"1.0"), + {ok, "P1H", [new_emu,new_appl]} = rpc:call(Node, release_handler, check_install_release, ["P2A"]), + + {ok,"P1H",[{extra, gott}]} = + rpc:call(Node, release_handler, install_release, ["P1I"]), + ?check_release_states_client(Node,[old,old,permanent,old]), + ?check_running_app_client(Node,a,"1.1"), + + %% since the install_release below will reboot the node... - check_disallowed_calls(), + ?check_disallowed_calls, cover_client(TestNode,Node,stop_cover), %% Install P2A again - {ok, "P1I", [new_emu]} = + {continue_after_restart, "P1I", [new_emu]} = rpc:call(Node, release_handler, install_release, ["P2A"]), %% We are rebooted again. check_reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_6(TestNode,Node). + client1_9(TestNode,Node). -client1_6(TestNode,Node) -> - ?print(["client1_6 start"]), +client1_9(TestNode,Node) -> + ?print(["client1_9 start"]), %% Check that P2A is used - ?check_release_client(Node,"P2A",current,["a-1.1"]), + ?check_release_states_client(Node,[old,old,permanent,current]), ?check_running_app_client(Node,a,"1.1"), X = rpc:call(Node, a, a, []), {key2, newval2} = lists:keyfind(key2, 1, X), @@ -481,22 +758,23 @@ client1_6(TestNode,Node) -> %% Make P2A permanent ok = rpc:call(Node, release_handler, make_permanent, ["P2A"]), + ?check_release_states_client(Node,[old,old,old,permanent]), %% Reboot from P2A - check_disallowed_calls(), + ?check_disallowed_calls, reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_7(TestNode,Node). + client1_10(TestNode,Node). -client1_7(TestNode,Node) -> - ?print(["client1_7 start"]), +client1_10(TestNode,Node) -> + ?print(["client1_10 start"]), %% Check that P2A is used - ?check_release_client(Node,"P2A",permanent,["a-1.1"]), + ?check_release_states_client(Node,[old,old,old,permanent]), %% since the reboot_old_release below will reboot the node - check_disallowed_calls(), + ?check_disallowed_calls, cover_client(TestNode,Node,stop_cover), %% Install old P1H @@ -505,41 +783,45 @@ client1_7(TestNode,Node) -> check_reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_8(TestNode,Node). + client1_11(TestNode,Node). -client1_8(TestNode,Node) -> - ?print(["client1_8 start"]), +client1_11(TestNode,Node) -> + ?print(["client1_11 start"]), %% Check that P1H is permanent - ?check_release_client(Node,"P1H",permanent,["a-1.0"]), + ?check_release_states_client(Node,[old,permanent,old,old]), + ?check_running_app_client(Node,a,"1.0"), X = rpc:call(Node, a, a, []), {key2, val2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), - %% Remove P1I and P2I from client + %% Remove P1I and P2A from client ok = rpc:call(Node, release_handler, set_removed, ["P2A"]), + ?check_release_states_client(Node,[old,permanent,old]), ok = rpc:call(Node, release_handler, set_removed, ["P1I"]), + ?check_release_states_client(Node,[old,permanent]), - check_disallowed_calls(), - reboot(TestNode,Node), - trace_disallowed_calls(Node), - - client1_9(TestNode,Node). - -client1_9(TestNode,Node) -> - ?print(["client1_9 start"]), - - %% Check that P2A and P1I does not exists and that PiH is permanent. + %% Check that P2A and P1I does not exists Rels = rpc:call(Node, release_handler, which_releases, []), false = lists:keysearch("P2A", 2, Rels), false = lists:keysearch("P1I", 2, Rels), - ?check_release_client(Node,"P1H",permanent,["a-1.0"]), X = rpc:call(Node, a, a, []), {key2, val2} = lists:keyfind(key2, 1, X), {key1, val1} = lists:keyfind(key1, 1, X), + ?check_disallowed_calls, + reboot(TestNode,Node), + trace_disallowed_calls(Node), + + client1_12(TestNode,Node). + +client1_12(TestNode,Node) -> + ?print(["client1_12 start"]), + + ?check_release_states_client(Node,[old,permanent]), + %% since the reboot_old_release below will reboot the node - check_disallowed_calls(), + ?check_disallowed_calls, cover_client(TestNode,Node,stop_cover), %% Install old P1G @@ -548,33 +830,34 @@ client1_9(TestNode,Node) -> check_reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_10(TestNode,Node). + client1_13(TestNode,Node). -client1_10(TestNode,Node) -> - ?print(["client1_10 start"]), +client1_13(TestNode,Node) -> + ?print(["client1_13 start"]), %% Check that P1G is permanent - ?check_release_client(Node,"P1G",permanent,[]), - ?check_release_client(Node,"P1H",old,["a-1.0"]), + ?check_release_states_client(Node,[permanent,old]), {error,client_node} = rpc:call(Node,release_handler,remove_release,["P1H"]), ok = rpc:call(Node, release_handler, set_removed, ["P1H"]), + ?check_release_states_client(Node,[permanent]), - check_disallowed_calls(), + ?check_disallowed_calls, reboot(TestNode,Node), trace_disallowed_calls(Node), - client1_11(TestNode,Node). + client1_14(TestNode,Node). -client1_11(TestNode,Node) -> - ?print(["client1_11 start"]), +client1_14(TestNode,Node) -> + ?print(["client1_14 start"]), %% Check that P1G is permanent - ?check_release_client(Node,"P1G",permanent,[]), + ?check_release_states_client(Node,[permanent]), - check_disallowed_calls(), + ?check_disallowed_calls, stop_client(TestNode,Node), %% TEST IS OK !! net_kernel:monitor_nodes(false), + %% Remove releases from master ok = release_handler:remove_release("P2A"), ok = release_handler:remove_release("P1I"), ok = release_handler:remove_release("P1H"), @@ -593,11 +876,14 @@ trace_disallowed_calls(Node) -> MasterProc = self(), rpc:call(Node,dbg,tracer,[process,{fun(T,_) -> MasterProc ! T end,[]}]), rpc:call(Node,dbg,p,[all,call]), - rpc:call(Node,dbg,tp,[file,[{'_',[],[{message,{caller}}]}]]). + rpc:call(Node,dbg,tp,[file,[{'_',[],[{message,{caller}}]}]]), + %% File:native_name_encoding/0 is a BIF and OK to use + rpc:call(Node,dbg,ctp,[file,native_name_encoding,0]). -check_disallowed_calls() -> +check_disallowed_calls(TestNode,Line) -> receive Trace when element(1,Trace)==trace -> + ?print_line(Line,["Disallowed function called",Trace]), exit({disallowed_function_call,Trace}) after 0 -> ok @@ -628,7 +914,7 @@ start_client_unix(TestNode,Sname,Node) -> start_client_win32(TestNode,Client,ClientSname) -> Name = atom_to_list(ClientSname) ++ "_P1G", RootDir = code:root_dir(), - ErtsBinDir = filename:join(RootDir,"erts-4.4/bin"), + ErtsBinDir = filename:join([RootDir,"erts-"++?ertsvsn,"bin"]), {ClientArgs,RelClientDir} = rh_test_lib:get_client_args(Client,ClientSname, RootDir), @@ -729,8 +1015,10 @@ client2(TestNode,PrivDir,ClientSname) -> ok end, + %% Unpack P1H on master {ok, "P1H"} = unpack_release(PrivDir,"rel1"), + %% Try to set P1H unpacked on client Root = code:root_dir(), {error,{bad_masters,[Master2]}} = rpc:call(Node, release_handler, set_unpacked, @@ -755,15 +1043,17 @@ stop(Now) -> unpack_p1h(TestNode,PrivDir) -> {ok, "P1H"} = unpack_release(PrivDir,"rel1"), - ?check_release("P1H",unpacked,["a-1.0"]), + ?check_release_states([permanent,unpacked]), + ?check_release_lib("P1H",["a-1.0"]), ok. permanent_p1h(TestNode) -> - ?check_release("P1H",unpacked,["a-1.0"]), + ?check_release_states([permanent,unpacked]), + ?check_release_lib("P1H",["a-1.0"]), {ok,"P1G",[new_appl]} = release_handler:install_release("P1H"), - ?check_release("P1H",current,["a-1.0"]), + ?check_release_states([permanent,current]), ok = release_handler:make_permanent("P1H"), - ?check_release("P1H",permanent,["a-1.0"]), + ?check_release_states([old,permanent]), ok. @@ -779,24 +1069,38 @@ registered_loop(_Name) -> exit(killed) end. -check_release(TestNode,Node,Vsn,Status,Apps,Line) -> +%% Checks that the list of states for all releases (sorted on vsn) +%% equals the input States +check_release_states(TestNode,Node,States,Line) -> + case rpc:call(Node,release_handler,which_releases,[]) of + {badrpc,_}=Error -> + ?fail_line(Line,{check_release_states,Node,States,Error}); + Rels -> + ?print_line(Line,["check_release_states:", Rels]), + States = [Status || {_,_,_,Status} <- lists:keysort(2,Rels)], + ok + end. + +%% Check that the given release (Vsn) sees the correct vsn of App. +check_release_lib(TestNode,Node,Vsn,Apps,Line) -> case rpc:call(Node,release_handler,which_releases,[]) of {badrpc,_}=Error -> - ?fail_line(Line,{check_release,Node,Vsn,Status,Error}); + ?fail_line(Line,{check_release_lib,Node,Vsn,Apps,Error}); Rels -> - ?print_line(Line,["check_release:", Rels]), - {"SASL-test", Vsn, Libs, Status} = lists:keyfind(Vsn, 2, Rels), + ?print_line(Line,["check_release_lib:", Rels]), + {"SASL-test", Vsn, Libs, _Status} = lists:keyfind(Vsn, 2, Rels), true = lists:all(fun(App) -> lists:member(App,Libs) end,Apps), ok end. +%% Check that the given Vsn of App is executed check_running_app(TestNode,Node,App,Vsn,Line) -> case rpc:call(Node,application,which_applications,[]) of {badrpc,_}=Error -> ?fail_line(Line,{check_running_app,Node,App,Vsn,Error}); Apps -> ?print_line(Line,["check_running_app:", Apps]), - {App, _, Vsn} = lists:keyfind(a, 1, Apps), + {App, _, Vsn} = lists:keyfind(App, 1, Apps), ok end. diff --git a/lib/sasl/test/overload_SUITE.erl b/lib/sasl/test/overload_SUITE.erl index 92b1aaed6e..e7f180b2ea 100644 --- a/lib/sasl/test/overload_SUITE.erl +++ b/lib/sasl/test/overload_SUITE.erl @@ -18,14 +18,13 @@ %% -module(overload_SUITE). --include("test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). -compile(export_all). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% all() -> [info, set_config_data, set_env_vars, request, timeout]. -all(suite) -> all(). init_per_testcase(_Case,Config) -> restart_sasl(), @@ -38,37 +37,34 @@ end_per_testcase(Case,Config) -> ok. %%%----------------------------------------------------------------- -info(suite) -> []; info(_Config) -> - ?line Info = overload:get_overload_info(), - ?line [{total_intensity,0.0}, - {accept_intensity,0.0}, - {max_intensity,0.8}, - {weight,0.1}, - {total_requests,0}, - {accepted_requests,0}] = Info. + Info = overload:get_overload_info(), + [{total_intensity,0.0}, + {accept_intensity,0.0}, + {max_intensity,0.8}, + {weight,0.1}, + {total_requests,0}, + {accepted_requests,0}] = Info. %%%----------------------------------------------------------------- -set_config_data(suite) -> []; set_config_data(_Config) -> - ?line InfoDefault = overload:get_overload_info(), - ?line ok = check_info(0.8,0.1,InfoDefault), - ?line ok = overload:set_config_data(0.5,0.4), - ?line Info1 = overload:get_overload_info(), - ?line ok = check_info(0.5,0.4,Info1), + InfoDefault = overload:get_overload_info(), + ok = check_info(0.8,0.1,InfoDefault), + ok = overload:set_config_data(0.5,0.4), + Info1 = overload:get_overload_info(), + ok = check_info(0.5,0.4,Info1), ok. %%%----------------------------------------------------------------- -set_env_vars(suite) -> []; set_env_vars(_Config) -> - ?line InfoDefault = overload:get_overload_info(), - ?line ok = check_info(0.8,0.1,InfoDefault), - ?line ok = application:set_env(sasl,overload_max_intensity,0.5), - ?line ok = application:set_env(sasl,overload_weight,0.4), - ?line ok = application:stop(sasl), - ?line ok = application:start(sasl), - ?line Info1 = overload:get_overload_info(), - ?line ok = check_info(0.5,0.4,Info1), + InfoDefault = overload:get_overload_info(), + ok = check_info(0.8,0.1,InfoDefault), + ok = application:set_env(sasl,overload_max_intensity,0.5), + ok = application:set_env(sasl,overload_weight,0.4), + ok = application:stop(sasl), + ok = application:start(sasl), + Info1 = overload:get_overload_info(), + ok = check_info(0.5,0.4,Info1), ok. set_env_vars(cleanup,_Config) -> application:unset_env(sasl,overload_max_intensity), @@ -76,63 +72,61 @@ set_env_vars(cleanup,_Config) -> ok. %%%----------------------------------------------------------------- -request(suite) -> []; request(_Config) -> %% Find number of request that can be done with default settings %% and no delay - ?line overload:set_config_data(0.8, 0.1), - ?line NDefault = do_many_requests(0), - ?line restart_sasl(), - ?line ?t:format("NDefault: ~p",[NDefault]), - + overload:set_config_data(0.8, 0.1), + NDefault = do_many_requests(0), + restart_sasl(), + ?t:format("NDefault: ~p",[NDefault]), + %% Check that the number of requests increases when max_intensity %% increases - ?line overload:set_config_data(2, 0.1), - ?line NLargeMI = do_many_requests(0), - ?line restart_sasl(), - ?line ?t:format("NLargeMI: ~p",[NLargeMI]), - ?line true = NLargeMI > NDefault, + overload:set_config_data(2, 0.1), + NLargeMI = do_many_requests(0), + restart_sasl(), + ?t:format("NLargeMI: ~p",[NLargeMI]), + true = NLargeMI > NDefault, %% Check that the number of requests decreases when weight %% increases - ?line overload:set_config_data(0.8, 1), - ?line NLargeWeight = do_many_requests(0), - ?line restart_sasl(), - ?line ?t:format("NLargeWeight: ~p",[NLargeWeight]), - ?line true = NLargeWeight < NDefault, + overload:set_config_data(0.8, 1), + NLargeWeight = do_many_requests(0), + restart_sasl(), + ?t:format("NLargeWeight: ~p",[NLargeWeight]), + true = NLargeWeight < NDefault, %% Check that number of requests increases when delay between %% requests increases. %% (Keeping same config and comparing to large weight in order to %% minimize the time needed for this case.) - ?line overload:set_config_data(0.8, 1), - ?line NLargeTime = do_many_requests(500), - ?line restart_sasl(), - ?line ?t:format("NLargeTime: ~p",[NLargeTime]), - ?line true = NLargeTime > NLargeWeight, + overload:set_config_data(0.8, 1), + NLargeTime = do_many_requests(500), + restart_sasl(), + ?t:format("NLargeTime: ~p",[NLargeTime]), + true = NLargeTime > NLargeWeight, ok. %%%----------------------------------------------------------------- -timeout(suite) -> []; timeout(_Config) -> - ?line overload:set_config_data(0.8, 1), - ?line _N = do_many_requests(0), - + overload:set_config_data(0.8, 1), + _N = do_many_requests(0), + %% Check that the overload alarm is raised - ?line [{overload,_}] = alarm_handler:get_alarms(), + [{overload,_}] = alarm_handler:get_alarms(), %% Fake a clear timeout in overload.erl and check that, since it %% came very soon after the overload situation, the alarm is not %% cleared - ?line overload ! timeout, - ?line timer:sleep(1000), - ?line [{overload,_}] = alarm_handler:get_alarms(), + overload ! timeout, + timer:sleep(1000), + [{overload,_}] = alarm_handler:get_alarms(), %% A bit later, try again and check that this time the alarm is %% cleared - ?line overload ! timeout, - ?line timer:sleep(1000), - ?line [] = alarm_handler:get_alarms(), + overload ! timeout, + timer:sleep(1000), + [] = alarm_handler:get_alarms(), ok. @@ -171,5 +165,3 @@ check_info(MI,W,Info) -> {{_,MI},{_,W}} -> ok; _ -> ?t:fail({unexpected_info,MI,W,Info}) end. - - diff --git a/lib/sasl/test/rb_SUITE.erl b/lib/sasl/test/rb_SUITE.erl index b53c382609..35a4eb7e7b 100644 --- a/lib/sasl/test/rb_SUITE.erl +++ b/lib/sasl/test/rb_SUITE.erl @@ -18,7 +18,8 @@ %% -module(rb_SUITE). --include("test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). + -compile(export_all). @@ -45,19 +46,10 @@ groups() -> ]}]. -all(suite) -> - no_group_cases() ++ - [{conf, - install_mf_h, - element(3,lists:keyfind(running_error_logger,1,groups())), - remove_mf_h} - ]. - - init_per_suite(Config) -> - ?line PrivDir = ?config(priv_dir,Config), - ?line RbDir = filename:join(PrivDir,rb), - ?line ok = file:make_dir(RbDir), + PrivDir = ?config(priv_dir,Config), + RbDir = filename:join(PrivDir,rb), + ok = file:make_dir(RbDir), NewConfig = [{rb_dir,RbDir}|Config], reset_sasl(NewConfig), NewConfig. @@ -66,10 +58,18 @@ end_per_suite(_Config) -> ok. init_per_group(running_error_logger,Config) -> - install_mf_h(Config). + %% Install log_mf_h + RbDir = ?config(rb_dir,Config), + ok = application:set_env(sasl,error_logger_mf_dir,RbDir), + ok = application:set_env(sasl,error_logger_mf_maxbytes,5000), + ok = application:set_env(sasl,error_logger_mf_maxfiles,2), + restart_sasl(), + Config. end_per_group(running_error_logger,Config) -> - remove_mf_h(Config). + %% Remove log_mf_h??? + ok. + init_per_testcase(_Case,Config) -> case whereis(?SUP) of @@ -92,187 +92,152 @@ end_per_testcase(Case,Config) -> %%%----------------------------------------------------------------- +%%% Test cases -help() -> help(suite). -help(suite) -> []; help(_Config) -> - ?line Help = capture(fun() -> rb:h() end), - ?line "Report Browser Tool - usage" = hd(Help), - ?line "rb:stop - stop the rb_server" = lists:last(Help), + Help = capture(fun() -> rb:h() end), + "Report Browser Tool - usage" = hd(Help), + "rb:stop - stop the rb_server" = lists:last(Help), ok. - -start_error_stop() -> start_error_stop(suite). -start_error_stop(suite) -> []; +%% Test that all three sasl env vars must be set for a successful start of rb +%% Then stop rb. start_error_stop(Config) -> - ?line RbDir = ?config(rb_dir,Config), - - ?line {error,{"cannot locate report directory",_}} = rb:start(), - - - ?line ok = application:set_env(sasl,error_logger_mf_dir,"invaliddir"), - ?line ok = application:set_env(sasl,error_logger_mf_maxbytes,1000), - ?line ok = application:set_env(sasl,error_logger_mf_maxfiles,2), - ?line restart_sasl(), - ?line {error,{"cannot read the index file",_}} = rb:start(), - ?line ok = application:set_env(sasl,error_logger_mf_dir,RbDir), - ?line restart_sasl(), - ?line {ok,_} = rb:start(), - - ?line ok = rb:stop(), - ok. + RbDir = ?config(rb_dir,Config), + {error,{"cannot locate report directory",_}} = rb:start(), -%% start_opts(suite) -> []; -%% start_opts(Config) -> -%% PrivDir = ?config(priv_dir,Config), -%% RbDir = filename:join(PrivDir,rb_opts), -%% ok = file:make_dir(RbDir), - -install_mf_h(Config) -> - ?line RbDir = ?config(rb_dir,Config), - ?line ok = application:set_env(sasl,error_logger_mf_dir,RbDir), - ?line ok = application:set_env(sasl,error_logger_mf_maxbytes,5000), - ?line ok = application:set_env(sasl,error_logger_mf_maxfiles,2), - ?line restart_sasl(), - Config. + ok = application:set_env(sasl,error_logger_mf_dir,"invaliddir"), + ok = application:set_env(sasl,error_logger_mf_maxbytes,1000), + ok = application:set_env(sasl,error_logger_mf_maxfiles,2), + restart_sasl(), + {error,{"cannot read the index file",_}} = rb:start(), + ok = application:set_env(sasl,error_logger_mf_dir,RbDir), + restart_sasl(), + {ok,_} = rb:start(), -remove_mf_h(_Config) -> + ok = rb:stop(), ok. - - -show() -> show(suite). -show(suite) -> []; show(Config) -> - ?line PrivDir = ?config(priv_dir,Config), - ?line OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), - + PrivDir = ?config(priv_dir,Config), + OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), + %% Insert some reports in the error log and start rb init_error_logs(), - ?line ok = start_rb(OutFile), + ok = start_rb(OutFile), %% Show all reports - ?line All = check_report(fun() -> rb:show() end,OutFile), + All = check_report(fun() -> rb:show() end,OutFile), %% Show by number - ?line [{_,First}] = check_report(fun() -> rb:show(1) end,OutFile), - ?line {1,First} = lists:keyfind(1,1,All), + [{_,First}] = check_report(fun() -> rb:show(1) end,OutFile), + {1,First} = lists:keyfind(1,1,All), %% Show by type - ?line [{_,CR}] = check_report(fun() -> rb:show(crash_report) end,OutFile), - ?line true = contains(CR,"rb_test_crash"), - ?line [{_,EC},{_,EM}] = check_report(fun() -> rb:show(error) end,OutFile), - ?line true = contains(EC,"rb_test_crash"), - ?line true = contains(EM,"rb_test_error_msg"), - ?line [{_,ER}] = check_report(fun() -> rb:show(error_report) end,OutFile), - ?line true = contains(ER,"rb_test_error"), - ?line [{_,IR}] = check_report(fun() -> rb:show(info_report) end,OutFile), - ?line true = contains(IR,"rb_test_info"), - ?line [{_,IM}] = check_report(fun() -> rb:show(info_msg) end,OutFile), - ?line true = contains(IM,"rb_test_info_msg"), - ?line [_|_] = check_report(fun() -> rb:show(progress) end,OutFile), - ?line [{_,SR}] = check_report(fun() -> rb:show(supervisor_report) end, - OutFile), - ?line true = contains(SR,"child_terminated"), - ?line true = contains(SR,"{rb_SUITE,rb_test_crash}"), + [{_,CR}] = check_report(fun() -> rb:show(crash_report) end,OutFile), + true = contains(CR,"rb_test_crash"), + [{_,EC},{_,EM}] = check_report(fun() -> rb:show(error) end,OutFile), + true = contains(EC,"rb_test_crash"), + true = contains(EM,"rb_test_error_msg"), + [{_,ER}] = check_report(fun() -> rb:show(error_report) end,OutFile), + true = contains(ER,"rb_test_error"), + [{_,IR}] = check_report(fun() -> rb:show(info_report) end,OutFile), + true = contains(IR,"rb_test_info"), + [{_,IM}] = check_report(fun() -> rb:show(info_msg) end,OutFile), + true = contains(IM,"rb_test_info_msg"), + [_|_] = check_report(fun() -> rb:show(progress) end,OutFile), + [{_,SR}] = check_report(fun() -> rb:show(supervisor_report) end, + OutFile), + true = contains(SR,"child_terminated"), + true = contains(SR,"{rb_SUITE,rb_test_crash}"), ok. -list() -> list(suite). -list(suite) -> []; list(Config) -> - ?line PrivDir = ?config(priv_dir,Config), - ?line OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), + PrivDir = ?config(priv_dir,Config), + OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), %% Insert some reports in the error log and start rb init_error_logs(), - ?line ok = start_rb(OutFile), - - ?line All = capture(fun() -> rb:list() end), - ?line [{crash_report,[_]=CR}, - {error,[_,_]=EM}, - {error_report,[_]=ER}, - {info_msg,[_]=IM}, - {info_report,[_]=IR}, - {progress,[_|_]=P}, - {supervisor_report,[_]=SR}] = sort_list(All), - - ?line [{crash_report,CR}] = + ok = start_rb(OutFile), + + All = capture(fun() -> rb:list() end), + [{crash_report,[_]=CR}, + {error,[_,_]=EM}, + {error_report,[_]=ER}, + {info_msg,[_]=IM}, + {info_report,[_]=IR}, + {progress,[_|_]=P}, + {supervisor_report,[_]=SR}] = sort_list(All), + + [{crash_report,CR}] = sort_list(capture(fun() -> rb:list(crash_report) end)), - ?line [{error,EM}] = + [{error,EM}] = sort_list(capture(fun() -> rb:list(error) end)), - ?line [{error_report,ER}] = + [{error_report,ER}] = sort_list(capture(fun() -> rb:list(error_report) end)), - ?line [{info_msg,IM}] = + [{info_msg,IM}] = sort_list(capture(fun() -> rb:list(info_msg) end)), - ?line [{info_report,IR}] = + [{info_report,IR}] = sort_list(capture(fun() -> rb:list(info_report) end)), - ?line [{progress,P}] = + [{progress,P}] = sort_list(capture(fun() -> rb:list(progress) end)), - ?line [{supervisor_report,SR}] = + [{supervisor_report,SR}] = sort_list(capture(fun() -> rb:list(supervisor_report) end)), - - ok. + ok. -grep() -> grep(suite). -grep(suite) -> []; grep(Config) -> - ?line PrivDir = ?config(priv_dir,Config), - ?line OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), + PrivDir = ?config(priv_dir,Config), + OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), %% Insert some reports in the error log and start rb init_error_logs(), - ?line ok = start_rb(OutFile), - - ?line [{_,S}, - {_,CR}, - {_,EC}, - {_,IM}, - {_,IR}, - {_,EM}, - {_,ER}]= check_report(fun() -> rb:grep("rb_test_") end,OutFile), - ?line true = contains(S, "rb_test_crash"), - ?line true = contains(CR, "rb_test_crash"), - ?line true = contains(EC, "rb_test_crash"), - ?line true = contains(IM, "rb_test_info_msg"), - ?line true = contains(IR, "rb_test_info"), - ?line true = contains(EM, "rb_test_error_msg"), - ?line true = contains(ER, "rb_test_error"), + ok = start_rb(OutFile), + + [{_,S}, + {_,CR}, + {_,EC}, + {_,IM}, + {_,IR}, + {_,EM}, + {_,ER}]= check_report(fun() -> rb:grep("rb_test_") end,OutFile), + true = contains(S, "rb_test_crash"), + true = contains(CR, "rb_test_crash"), + true = contains(EC, "rb_test_crash"), + true = contains(IM, "rb_test_info_msg"), + true = contains(IR, "rb_test_info"), + true = contains(EM, "rb_test_error_msg"), + true = contains(ER, "rb_test_error"), ok. - -filter_filter() -> filter_filter(suite). -filter_filter(suite) -> []; filter_filter(Config) -> - ?line PrivDir = ?config(priv_dir,Config), - ?line OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), + PrivDir = ?config(priv_dir,Config), + OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), %% Insert some reports in the error log and start rb init_error_logs(), - ?line ok = start_rb(OutFile), + ok = start_rb(OutFile), - ?line All = check_report(fun() -> rb:show() end,OutFile), + All = check_report(fun() -> rb:show() end,OutFile), - ?line ER = [_] = rb_filter([{rb_SUITE,rb_test_error}],OutFile), - ?line [] = rb_filter([{rb_SUITE,rb_test}],OutFile), - ?line _E = [_,_] = rb_filter([{rb_SUITE,"rb_test",re}],OutFile), - ?line AllButER = rb_filter([{rb_SUITE,rb_test_error,no}],OutFile), + ER = [_] = rb_filter([{rb_SUITE,rb_test_error}],OutFile), + [] = rb_filter([{rb_SUITE,rb_test}],OutFile), + _E = [_,_] = rb_filter([{rb_SUITE,"rb_test",re}],OutFile), + AllButER = rb_filter([{rb_SUITE,rb_test_error,no}],OutFile), {_,AllRep} = lists:unzip(All), {_,ERRep} = lists:unzip(ER), {_,AllButERRep} = lists:unzip(AllButER), - ?line AllButERRep = AllRep -- ERRep, + AllButERRep = AllRep -- ERRep, ok. -filter_date() -> filter_date(suite). -filter_date(suite) -> []; filter_date(Config) -> - ?line PrivDir = ?config(priv_dir,Config), - ?line OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), + PrivDir = ?config(priv_dir,Config), + OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), %% Insert some reports in the error log and start rb @@ -280,35 +245,33 @@ filter_date(Config) -> Between1 = calendar:local_time(), timer:sleep(1000), Between2 = calendar:local_time(), - ?line ok = start_rb(OutFile), + ok = start_rb(OutFile), - ?line All = check_report(fun() -> rb:show() end,OutFile), + All = check_report(fun() -> rb:show() end,OutFile), Before = calendar:gregorian_seconds_to_datetime( - calendar:datetime_to_gregorian_seconds(calendar:local_time()) - 10), + calendar:datetime_to_gregorian_seconds(calendar:local_time()) - 10), After = calendar:gregorian_seconds_to_datetime( calendar:datetime_to_gregorian_seconds(calendar:local_time()) + 1), - ?line All = rb_filter([],{Before,from},OutFile), - ?line All = rb_filter([],{After,to},OutFile), - ?line [] = rb_filter([],{Before,to},OutFile), - ?line [] = rb_filter([],{After,from},OutFile), - ?line All = rb_filter([],{Before,After},OutFile), + All = rb_filter([],{Before,from},OutFile), + All = rb_filter([],{After,to},OutFile), + [] = rb_filter([],{Before,to},OutFile), + [] = rb_filter([],{After,from},OutFile), + All = rb_filter([],{Before,After},OutFile), %%?t:format("~p~n",[All]), - ?line AllButLast = [{N-1,R} || {N,R} <- tl(All)], - ?line AllButLast = rb_filter([],{Before,Between1},OutFile), + AllButLast = [{N-1,R} || {N,R} <- tl(All)], + AllButLast = rb_filter([],{Before,Between1},OutFile), - ?line Last = hd(All), - ?line [Last] = rb_filter([],{Between2,After},OutFile), + Last = hd(All), + [Last] = rb_filter([],{Between2,After},OutFile), ok. -filter_filter_and_date() -> filter_filter_and_date(suite). -filter_filter_and_date(suite) -> []; filter_filter_and_date(Config) -> - ?line PrivDir = ?config(priv_dir,Config), - ?line OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), + PrivDir = ?config(priv_dir,Config), + OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), %% Insert some reports in the error log and start rb @@ -316,102 +279,96 @@ filter_filter_and_date(Config) -> Between1 = calendar:local_time(), timer:sleep(1000), Between2 = calendar:local_time(), - ?line error_logger:error_report([{rb_SUITE,rb_test_filter}]), - ?line ok = start_rb(OutFile), + error_logger:error_report([{rb_SUITE,rb_test_filter}]), + ok = start_rb(OutFile), Before = calendar:gregorian_seconds_to_datetime( - calendar:datetime_to_gregorian_seconds(calendar:local_time()) - 10), + calendar:datetime_to_gregorian_seconds(calendar:local_time()) - 10), After = calendar:gregorian_seconds_to_datetime( calendar:datetime_to_gregorian_seconds(calendar:local_time()) + 1), - ?line All = check_report(fun() -> rb:show() end,OutFile), - ?line Last = hd(All), + All = check_report(fun() -> rb:show() end,OutFile), + Last = hd(All), - ?line [_,_,_] = rb_filter([{rb_SUITE,"rb_test",re}],{Before,After},OutFile), - ?line [_,_] = rb_filter([{rb_SUITE,"rb_test",re}],{Before,Between1},OutFile), - ?line [_] = rb_filter([{rb_SUITE,"rb_test",re}],{Between2,After},OutFile), - ?line [_] = rb_filter([{rb_SUITE,rb_test_filter}],{Before,After},OutFile), - ?line [] = rb_filter([{rb_SUITE,rb_test_filter}],{Before,Between1},OutFile), - ?line [Last] = rb_filter([{rb_SUITE,rb_test_filter,no}],{Between2,After},OutFile), - ?line {_,Str} = Last, - ?line false = contains(Str,"rb_test_filter"), + [_,_,_] = rb_filter([{rb_SUITE,"rb_test",re}],{Before,After},OutFile), + [_,_] = rb_filter([{rb_SUITE,"rb_test",re}],{Before,Between1},OutFile), + [_] = rb_filter([{rb_SUITE,"rb_test",re}],{Between2,After},OutFile), + [_] = rb_filter([{rb_SUITE,rb_test_filter}],{Before,After},OutFile), + [] = rb_filter([{rb_SUITE,rb_test_filter}],{Before,Between1},OutFile), + [Last] = rb_filter([{rb_SUITE,rb_test_filter,no}],{Between2,After},OutFile), + {_,Str} = Last, + false = contains(Str,"rb_test_filter"), ok. -filter_re_no() -> filter_re_no(suite). -filter_re_no(suite) -> []; filter_re_no(Config) -> - ?line PrivDir = ?config(priv_dir,Config), - ?line OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), + PrivDir = ?config(priv_dir,Config), + OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), %% Insert some reports in the error log and start rb init_error_logs(), - ?line ok = start_rb(OutFile), + ok = start_rb(OutFile), - ?line All = check_report(fun() -> rb:show() end,OutFile), + All = check_report(fun() -> rb:show() end,OutFile), - ?line E = [_,_] = rb_filter([{rb_SUITE,"rb_test",re}],OutFile), - ?line AllButE = rb_filter([{rb_SUITE,"rb_test",re,no}],OutFile), + E = [_,_] = rb_filter([{rb_SUITE,"rb_test",re}],OutFile), + AllButE = rb_filter([{rb_SUITE,"rb_test",re,no}],OutFile), {_,AllRep} = lists:unzip(All), {_,ERep} = lists:unzip(E), {_,AllButERep} = lists:unzip(AllButE), - ?line AllButERep = AllRep -- ERep, + AllButERep = AllRep -- ERep, ok. -rescan() -> rescan(suite). -rescan(suite) -> []; rescan(Config) -> - ?line PrivDir = ?config(priv_dir,Config), - ?line OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), - + PrivDir = ?config(priv_dir,Config), + OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), + %% Start rb - ?line ok = start_rb(OutFile), + ok = start_rb(OutFile), %% Insert one more report and check that the list is longer. Note %% that there might be two more reports, since the progress report %% from starting rb_server might not be included before the rescan. - ?line AllBefore = capture(fun() -> rb:list() end), - ?line error_logger:error_report([{rb_SUITE,rb_test_rescan}]), - ?line ok = rb:rescan(), - ?line AllAfter = capture(fun() -> rb:list() end), - ?line Diff = length(AllAfter) - length(AllBefore), - ?line true = (Diff >= 1), + AllBefore = capture(fun() -> rb:list() end), + error_logger:error_report([{rb_SUITE,rb_test_rescan}]), + ok = rb:rescan(), + AllAfter = capture(fun() -> rb:list() end), + Diff = length(AllAfter) - length(AllBefore), + true = (Diff >= 1), ok. -start_stop_log() -> start_stop_log(suite). -start_stop_log(suite) -> []; start_stop_log(Config) -> - ?line PrivDir = ?config(priv_dir,Config), - ?line OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), - ?line ok = file:write_file(OutFile,[]), + PrivDir = ?config(priv_dir,Config), + OutFile = filename:join(PrivDir,"rb_SUITE_log.txt"), + ok = file:write_file(OutFile,[]), %% Start rb and check that show is printed to standard_io - ?line ok = start_rb(), - ?line StdioResult = [_|_] = capture(fun() -> rb:show(1) end), - ?line {ok,<<>>} = file:read_file(OutFile), - + ok = start_rb(), + StdioResult = [_|_] = capture(fun() -> rb:show(1) end), + {ok,<<>>} = file:read_file(OutFile), + %% Start log and check that show is printed to log and not to standad_io - ?line ok = rb:start_log(OutFile), - ?line [] = capture(fun() -> rb:show(1) end), - ?line {ok,Bin} = file:read_file(OutFile), - ?line true = (Bin =/= <<>>), + ok = rb:start_log(OutFile), + [] = capture(fun() -> rb:show(1) end), + {ok,Bin} = file:read_file(OutFile), + true = (Bin =/= <<>>), %% Stop log and check that show is printed to standard_io and not to log - ?line ok = rb:stop_log(), - ?line ok = file:write_file(OutFile,[]), - ?line StdioResult = capture(fun() -> rb:show(1) end), - ?line {ok,<<>>} = file:read_file(OutFile), + ok = rb:stop_log(), + ok = file:write_file(OutFile,[]), + StdioResult = capture(fun() -> rb:show(1) end), + {ok,<<>>} = file:read_file(OutFile), %% Test that standard_io is used if log file can not be opened - ?line ok = rb:start_log(filename:join(nonexistingdir,"newfile.txt")), - ?line StdioResult = capture(fun() -> rb:show(1) end), - ?line {ok,<<>>} = file:read_file(OutFile), + ok = rb:start_log(filename:join(nonexistingdir,"newfile.txt")), + StdioResult = capture(fun() -> rb:show(1) end), + {ok,<<>>} = file:read_file(OutFile), ok. @@ -435,7 +392,7 @@ empty_error_logs(Config) -> catch delete_content(?config(rb_dir, Config)), ok = application:start(sasl), wait_for_sasl(). - + wait_for_sasl() -> wait_for_sasl(50). wait_for_sasl(0) -> @@ -448,7 +405,7 @@ wait_for_sasl(N) -> timer:sleep(100), wait_for_sasl(N-1) end. - + start_rb(OutFile) -> do_start_rb([{start_log,OutFile}]). start_rb() -> @@ -482,20 +439,20 @@ delete_content(Dir) -> Files). init_error_logs() -> - ?line error_logger:error_report([{rb_SUITE,rb_test_error}]), - ?line error_logger:error_msg("rb_test_error_msg"), - ?line error_logger:info_report([{rb_SUITE,rb_test_info}]), - ?line error_logger:info_msg("rb_test_info_msg"), - ?line _Pid = start(), - ?line Ref = erlang:monitor(process,?MODULE), - ?line gen_server:cast(?MODULE,crash), - ?line receive {'DOWN',Ref,process,_,{rb_SUITE,rb_test_crash}} -> ok - after 2000 -> - ?t:format("Got: ~p~n",[process_info(self(),messages)]), - ?t:fail("rb_SUITE server never died") - end, - ?line erlang:demonitor(Ref), - ?line wait_for_server(), + error_logger:error_report([{rb_SUITE,rb_test_error}]), + error_logger:error_msg("rb_test_error_msg"), + error_logger:info_report([{rb_SUITE,rb_test_info}]), + error_logger:info_msg("rb_test_info_msg"), + _Pid = start(), + Ref = erlang:monitor(process,?MODULE), + gen_server:cast(?MODULE,crash), + receive {'DOWN',Ref,process,_,{rb_SUITE,rb_test_crash}} -> ok + after 2000 -> + ?t:format("Got: ~p~n",[process_info(self(),messages)]), + ?t:fail("rb_SUITE server never died") + end, + erlang:demonitor(Ref), + wait_for_server(), ok. wait_for_server() -> diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl index af2183bfff..a8e3cc3d88 100644 --- a/lib/sasl/test/release_handler_SUITE.erl +++ b/lib/sasl/test/release_handler_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011. All Rights Reserved. +%% Copyright Ericsson AB 2011-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -19,6 +19,7 @@ -module(release_handler_SUITE). -include_lib("common_test/include/ct.hrl"). +-include("test_lib.hrl"). -compile(export_all). @@ -30,6 +31,7 @@ suite() -> [{ct_hooks, [ts_install_cth]}]. init_per_suite(Config) -> + init_priv_dir(Config), application:start(sasl), Config. @@ -58,7 +60,10 @@ cases() -> [otp_2740, otp_2760, otp_5761, otp_9402, otp_9417, otp_9395_check_old_code, otp_9395_check_and_purge, otp_9395_update_many_mods, otp_9395_rm_many_mods, - instructions, eval_appup, supervisor_which_children_timeout]. + instructions, eval_appup, eval_appup_with_restart, + supervisor_which_children_timeout, + release_handler_which_releases, install_release_syntax_check, + upgrade_supervisor, upgrade_supervisor_fail, otp_9864]. groups() -> [{release,[], @@ -69,6 +74,7 @@ groups() -> {release_single,[], [ upgrade, + upgrade_restart, client1, client2 ]}, @@ -82,7 +88,7 @@ groups() -> init_per_group(release, Config) -> Dog = ?t:timetrap(?default_timeout), P1gInstall = filename:join(priv_dir(Config),p1g_install), - ok = do_create_p1g(Config,P1gInstall), + ok = create_p1g(Config,P1gInstall), ok = create_p1h(Config), ?t:timetrap_cancel(Dog); @@ -95,6 +101,7 @@ init_per_group(release_single, Config) -> %% Create some more releases to upgrade to ok = create_p1i(Config), ok = create_p2a(Config), + ok = create_p2b(Config), ?t:timetrap_cancel(Dog); @@ -155,7 +162,7 @@ end_per_group(release, Config) -> {win32,_} -> delete_all_services(); _ -> ok end, - delete_release(Config), + clean_priv_dir(Config,true), ?t:timetrap_cancel(Dog), Config; end_per_group(_GroupName, Config) -> @@ -191,7 +198,10 @@ end_per_testcase(Case, Config) -> FailDir = filename:join(SaveDir,lists:concat(["failed-",Case])), ok = filelib:ensure_dir(filename:join(FailDir,"*")), - LogDirs = filelib:wildcard(filename:join([PrivDir,"*",log])), + LogDirs = + filelib:wildcard(filename:join([PrivDir,"*",log])) ++ + filelib:wildcard(filename:join([PrivDir,"*",clients, + type1,"*",log])), lists:foreach( fun(LogDir) -> @@ -236,7 +246,7 @@ break(Config) -> ?t:break(priv_dir(Config)), ok. -%% Test upgrade and downgrade of erts +%% Test upgrade and downgrade of erts and other apps on embedded node upgrade(Conf) when is_list(Conf) -> reg_print_proc(), %% starts a printer process on test_server node ?t:format("upgrade ~p~n",[reg_print_proc]), @@ -259,54 +269,75 @@ upgrade(Conf) when is_list(Conf) -> stop_cover(TestNode), reboot_and_wait(TestNode,"install_2",[a]), - %% check that P1H is permanent, unpack and install P1I, unpack and install P2A - TestNodeInit1 = rpc:call(TestNode,erlang,whereis,[init]), + %% check that P1H is permanent, unpack and install P1I, unpack P2A ok = rpc_inst(TestNode, install_3, [PrivDir]), stop_cover(TestNode), - ok = rpc_inst(TestNode, install_3a, []), - wait_nodes_up([{TestNode,TestNodeInit1}],"install_3",[a]), + reboot_and_wait(TestNode,"install_3",[a]), - %% check that P2A is used, reboot from P1I - ok = rpc_inst(TestNode, install_4, []), + %% check that P1H is used, install P2A + TestNodeInit1 = rpc:call(TestNode,erlang,whereis,[init]), stop_cover(TestNode), - reboot_and_wait(TestNode,"install_4",[a]), + ok = rpc_inst(TestNode, install_4, []), + wait_nodes_up([{TestNode,TestNodeInit1}],"install_4",[a]), - %% check that P1I, reinstall P2A + %% check that P2A is used, then downgrade to P1I TestNodeInit2 = rpc:call(TestNode,erlang,whereis,[init]), ok = rpc_inst(TestNode, install_5, []), stop_cover(TestNode), ok = rpc_inst(TestNode, install_5a, []), wait_nodes_up([{TestNode,TestNodeInit2}],"install_5",[a]), - %% check that P2A is used, make P2A permanent + %% Check that P1I is used, then make P1I permanent and install P2A + TestNodeInit3 = rpc:call(TestNode,erlang,whereis,[init]), ok = rpc_inst(TestNode, install_6, []), stop_cover(TestNode), - reboot_and_wait(TestNode,"install_6",[a]), + ok = rpc_inst(TestNode, install_6a, []), + wait_nodes_up([{TestNode,TestNodeInit3}],"install_6",[a]), - %% check that P2A is permanent, install old P1H - TestNodeInit3 = rpc:call(TestNode,erlang,whereis,[init]), - stop_cover(TestNode), + %% check that P2A is used, then downgrade to P1H + TestNodeInit4 = rpc:call(TestNode,erlang,whereis,[init]), ok = rpc_inst(TestNode, install_7, []), - wait_nodes_up([{TestNode,TestNodeInit3}],"install_7",[a]), + stop_cover(TestNode), + ok = rpc_inst(TestNode, install_7a, []), + wait_nodes_up([{TestNode,TestNodeInit4}],"install_7",[a]), - %% check that P1H is permanent, remove P1I and P2A + %% check that P1H is used, then install P1I and check that it is permanent + %% then reinstall P2A + TestNodeInit5 = rpc:call(TestNode,erlang,whereis,[init]), ok = rpc_inst(TestNode, install_8, []), stop_cover(TestNode), - reboot_and_wait(TestNode,"install_8",[a]), + ok = rpc_inst(TestNode, install_8a, []), + wait_nodes_up([{TestNode,TestNodeInit5}],"install_8",[a]), + + %% check that P2A is used, make P2A permanent + ok = rpc_inst(TestNode, install_9, []), + stop_cover(TestNode), + reboot_and_wait(TestNode,"install_9",[a]), + + %% check that P2A is permanent, reboot to old P1H + TestNodeInit6 = rpc:call(TestNode,erlang,whereis,[init]), + stop_cover(TestNode), + ok = rpc_inst(TestNode, install_10, []), + wait_nodes_up([{TestNode,TestNodeInit6}],"install_10",[a]), + + %% check that P1H is permanent, remove P1I and P2A + ok = rpc_inst(TestNode, install_11, []), + stop_cover(TestNode), + reboot_and_wait(TestNode,"install_11",[a]), %% check that P1H is permanent, reboot old P1G - TestNodeInit4 = rpc:call(TestNode,erlang,whereis,[init]), + TestNodeInit7 = rpc:call(TestNode,erlang,whereis,[init]), stop_cover(TestNode), - ok = rpc_inst(TestNode, install_9, []), - wait_nodes_up([{TestNode,TestNodeInit4}],"install_9"), + ok = rpc_inst(TestNode, install_12, []), + wait_nodes_up([{TestNode,TestNodeInit7}],"install_12"), %% check that P1G is permanent, remove P1H - ok = rpc_inst(TestNode, install_10, []), + ok = rpc_inst(TestNode, install_13, []), stop_cover(TestNode), - reboot_and_wait(TestNode,"install_10"), + reboot_and_wait(TestNode,"install_13"), %% check that P1G is permanent - ok = rpc_inst(TestNode, install_11, []), + ok = rpc_inst(TestNode, install_14, []), ok. @@ -323,6 +354,54 @@ reboot_and_wait(Node,Tag,Apps) -> wait_nodes_up([{Node,InitPid}],Tag,Apps). +%% Test upgrade and downgrade of erts in combination with the +%% restart_emulator option to systools:make_relup. For upgrade, this +%% should cause one restart before the upgrade code, and one +%% after. For downgrade, there will be one restart only - at the end. +upgrade_restart(Conf) when is_list(Conf) -> + reg_print_proc(), %% starts a printer process on test_server node + ?t:format("upgrade_restart ~p~n",[reg_print_proc]), + PrivDir = priv_dir(Conf), + Sname = tc_sname(Conf), % nodename for use in this testcase + + %% Copy the P1G release to a directory for use in this testcase + ok = copy_installed(Conf,p1g_install,[Sname]), + + %% start the test node + [TestNode] = start_nodes(Conf,[Sname],"upgrade_restart start"), + + %% unpack and install P2B + TestNodeInit1 = rpc:call(TestNode,erlang,whereis,[init]), + ok = rpc_inst(TestNode, upgrade_restart_1, [PrivDir]), + stop_cover(TestNode), + ok = rpc_inst(TestNode, upgrade_restart_1a, []), + wait_nodes_up([{TestNode,TestNodeInit1}],"upgrade_restart_1",[a]), + + %% install P1G + case rpc_inst(TestNode, upgrade_restart_2, []) of + ok -> + ok; + {wait,TestNodeInit2a} -> + %% We catched the node too early - it was supposed to + %% restart twice, so let's wait for one more restart. + wait_nodes_up([{TestNode,TestNodeInit2a}],"upgrade_restart_2a",[]), + ok = rpc_inst(TestNode, upgrade_restart_2a, []) + end, + TestNodeInit2 = rpc:call(TestNode,erlang,whereis,[init]), + stop_cover(TestNode), + ok = rpc_inst(TestNode, upgrade_restart_2b, []), + wait_nodes_up([{TestNode,TestNodeInit2}],"upgrade_restart_2b",[]), + + %% Check that P1G is going again + ok = rpc_inst(TestNode, upgrade_restart_3, []), + + ok. + +upgrade_restart(cleanup,Config) -> + TestNode = tc_full_node_name(Config), + ok = stop_nodes([TestNode]). + + %% Test upgrade and downgrade of erts, diskless client1(Conf) when is_list(Conf) -> reg_print_proc(), %% starts a printer process on test_server node @@ -542,9 +621,51 @@ supervisor_which_children_timeout(Conf) -> ok. -supervisor_which_children_timeout(cleanup, Conf) -> +supervisor_which_children_timeout(cleanup, _Conf) -> stop_node(node_name(supervisor_which_children_timeout)). + +%% Test that check_install_release will fail for illegal relup +%% instructions, even after point of no return. +install_release_syntax_check(Conf) when is_list(Conf) -> + + S1 = [point_of_no_return, illegal_instruction], + {error,{illegal_instruction_after_point_of_no_return,illegal_instruction}} = + release_handler_1:check_script(S1,[]), + + S2 = [point_of_no_return,restart_new_emulator], + {error,{illegal_instruction_after_point_of_no_return,restart_new_emulator}} = + release_handler_1:check_script(S2,[]), + + ok. + + +%%----------------------------------------------------------------- +%% release_handler:which_releases/0 and 1 test +%%----------------------------------------------------------------- +release_handler_which_releases(Conf) -> + PrivDir = priv_dir(Conf), + Dir = filename:join(PrivDir,"release_handler_which_releases"), + DataDir = ?config(data_dir,Conf), + LibDir = filename:join([DataDir,release_handler_timeouts]), + + Rel1 = create_and_install_fake_first_release(Dir,[{dummy,"0.1",LibDir}]), + + {ok, Node} = t_start_node(release_handler_which_releases, Rel1, []), + Releases0 = rpc:call(Node, release_handler, which_releases, []), + Releases1 = rpc:call(Node, release_handler, which_releases, [permanent]), + Releases2 = rpc:call(Node, release_handler, which_releases, [old]), + + 1 = length(Releases0), + 1 = length(Releases1), + 0 = length(Releases2), + + ?t:format("release_handler:which_releases/0: ~p~n", [Releases0]), + ?t:format("release_handler:which_releases/1: ~p~n", [Releases1]), + ?t:format("release_handler:which_releases/1: ~p~n", [Releases2]), + + ok. + %%----------------------------------------------------------------- %% Ticket: OTP-2740 %% Slogan: vsn not numeric doesn't work so good in release_handling @@ -1084,6 +1205,163 @@ otp_9395_rm_many_mods(Conf) when is_list(Conf) -> otp_9395_rm_many_mods(cleanup,_Conf) -> stop_node(node_name(otp_9395_rm_many_mods)). +otp_9864(Conf) -> + %% Set some paths + PrivDir = priv_dir(Conf), + Dir = filename:join(PrivDir,"otp_9864"), + RelDir = filename:join(?config(data_dir, Conf), "app1_app2"), + LibDir1 = filename:join(RelDir, "lib1"), + LibDir2 = filename:join(RelDir, "lib2"), + + %% Create the releases + Rel1 = create_and_install_fake_first_release(Dir, + [{app1,"1.0",LibDir1}, + {app2,"1.0",LibDir1}]), + Rel2 = create_fake_upgrade_release(Dir, + "2", + [{app1,"2.0",LibDir2}, + {app2,"1.0",LibDir2}], + {[Rel1],[Rel1],[LibDir1]}), + Rel1Dir = filename:dirname(Rel1), + Rel2Dir = filename:dirname(Rel2), + + %% Start a slave node + {ok, Node} = t_start_node(otp_9864, Rel1, filename:join(Rel1Dir,"sys.config")), + + %% Unpack rel2 (make sure it does not work if an AppDir is bad) + LibDir3 = filename:join(RelDir, "lib3"), + {error, {no_such_directory, _}} = + rpc:call(Node, release_handler, set_unpacked, + [Rel2++".rel", [{app1,"2.0",LibDir2}, {app2,"1.0",LibDir3}]]), + {ok, RelVsn2} = + rpc:call(Node, release_handler, set_unpacked, + [Rel2++".rel", [{app1,"2.0",LibDir2}, {app2,"1.0",LibDir2}]]), + ok = rpc:call(Node, release_handler, install_file, + [RelVsn2, filename:join(Rel2Dir, "relup")]), + ok = rpc:call(Node, release_handler, install_file, + [RelVsn2, filename:join(Rel2Dir, "start.boot")]), + ok = rpc:call(Node, release_handler, install_file, + [RelVsn2, filename:join(Rel2Dir, "sys.config")]), + + %% Install RelVsn2 without {update_paths, true} option + {ok, RelVsn1, []} = + rpc:call(Node, release_handler, install_release, [RelVsn2]), + + %% Install RelVsn1 again + {ok, RelVsn1, []} = + rpc:call(Node, release_handler, install_release, [RelVsn1]), + + TempRel2Dir = filename:join(Dir,"releases/2"), + file:make_symlink(TempRel2Dir, filename:join(TempRel2Dir, "foo_symlink_dir")), + + %% This will fail if symlinks are not handled + ok = rpc:call(Node, release_handler, remove_release, [RelVsn2]), + + ok. + + +upgrade_supervisor(Conf) when is_list(Conf) -> + %% Set some paths + PrivDir = priv_dir(Conf), + Dir = filename:join(PrivDir,"upgrade_supervisor"), + LibDir = filename:join(?config(data_dir, Conf), "lib"), + + %% Create the releases + Lib1 = [{a,"1.0",LibDir}], + Lib2 = [{a,"9.0",LibDir}], + Rel1 = create_and_install_fake_first_release(Dir,Lib1), + Rel2 = create_fake_upgrade_release(Dir,"2",Lib2,{[Rel1],[Rel1],[LibDir]}), + Rel1Dir = filename:dirname(Rel1), + Rel2Dir = filename:dirname(Rel2), + + %% Start a slave node + {ok, Node} = t_start_node(upgrade_supervisor, Rel1, + filename:join(Rel1Dir,"sys.config")), + + %% Check path + Dir1 = filename:join([LibDir, "a-1.0"]), + Dir1 = rpc:call(Node, code, lib_dir, [a]), + ASupBeam1 = filename:join([Dir1,ebin,"a_sup.beam"]), + ASupBeam1 = rpc:call(Node, code, which, [a_sup]), + + %% Install second release, with no changed modules + {ok, RelVsn2} = rpc:call(Node, release_handler, set_unpacked, + [Rel2++".rel", Lib2]), + ok = rpc:call(Node, release_handler, install_file, + [RelVsn2, filename:join(Rel2Dir, "relup")]), + ok = rpc:call(Node, release_handler, install_file, + [RelVsn2, filename:join(Rel2Dir, "start.boot")]), + ok = rpc:call(Node, release_handler, install_file, + [RelVsn2, filename:join(Rel2Dir, "sys.config")]), + + {ok, _RelVsn1, []} = + rpc:call(Node, release_handler, install_release, [RelVsn2]), + + %% Check that libdir is changed + Dir2 = filename:join([LibDir, "a-9.0"]), + Dir2 = rpc:call(Node, code, lib_dir, [a]), + ASupBeam2 = filename:join([Dir2,ebin,"a_sup.beam"]), + ASupBeam2 = rpc:call(Node, code, which, [a_sup]), + + %% Check that the restart strategy and child spec is updated + {status, _, {module, _}, [_, _, _, _, [_,_,{data,[{"State",State}]}]]} = + rpc:call(Node,sys,get_status,[a_sup]), + {state,_,RestartStrategy,[Child],_,_,_,_,_,_} = State, + one_for_all = RestartStrategy, % changed from one_for_one + {child,_,_,_,_,brutal_kill,_,_} = Child, % changed from timeout 2000 + + ok. + +%% Check that if the supervisor fails, then the upgrade is rolled back +%% and an ok error message is returned +upgrade_supervisor_fail(Conf) when is_list(Conf) -> + %% Set some paths + PrivDir = priv_dir(Conf), + Dir = filename:join(PrivDir,"upgrade_supervisor_fail"), + LibDir = filename:join(?config(data_dir, Conf), "lib"), + + %% Create the releases + Lib1 = [{a,"1.0",LibDir}], + Lib2 = [{a,"9.1",LibDir}], + Rel1 = create_and_install_fake_first_release(Dir,Lib1), + Rel2 = create_fake_upgrade_release(Dir,"2",Lib2,{[Rel1],[Rel1],[LibDir]}), + Rel1Dir = filename:dirname(Rel1), + Rel2Dir = filename:dirname(Rel2), + + %% Start a slave node + {ok, Node} = t_start_node(upgrade_supervisor_fail, Rel1, + filename:join(Rel1Dir,"sys.config")), + + %% Check path + Dir1 = filename:join([LibDir, "a-1.0"]), + Dir1 = rpc:call(Node, code, lib_dir, [a]), + ASupBeam1 = filename:join([Dir1,ebin,"a_sup.beam"]), + ASupBeam1 = rpc:call(Node, code, which, [a_sup]), + + %% Install second release, with no changed modules + {ok, RelVsn2} = rpc:call(Node, release_handler, set_unpacked, + [Rel2++".rel", Lib2]), + ok = rpc:call(Node, release_handler, install_file, + [RelVsn2, filename:join(Rel2Dir, "relup")]), + ok = rpc:call(Node, release_handler, install_file, + [RelVsn2, filename:join(Rel2Dir, "start.boot")]), + ok = rpc:call(Node, release_handler, install_file, + [RelVsn2, filename:join(Rel2Dir, "sys.config")]), + ok = net_kernel:monitor_nodes(true), + + {error,{code_change_failed,_Pid,a_sup,_Vsn, + {error,{invalid_shutdown,brutal_kil}}}} = + rpc:call(Node, release_handler, install_release, [RelVsn2]), + + %% Check that the upgrade is terminated - normally this would mean + %% rollback, but since this testcase is very simplified the node + %% is not started with heart supervision and will therefore not be + %% restarted. So we just check that the node goes down. + receive {nodedown,Node} -> ok + after 10000 -> ct:fail(failed_upgrade_never_restarted_node) + end, + + ok. %% Test upgrade and downgrade of applications @@ -1107,6 +1385,12 @@ eval_appup(Conf) when is_list(Conf) -> App11Dir = code:lib_dir(app1), ok = gen_server:call(harry, error), + %% Read appup script + {ok,"2.0",UpScript} = release_handler:upgrade_script(app1,App12Dir), + [{load_object_code,_}, + point_of_no_return, + {load,_}] = UpScript, + %% Upgrade to app1-2.0 {ok, []} = release_handler:upgrade_app(app1, App12Dir), App12Dir = code:lib_dir(app1), @@ -1117,6 +1401,12 @@ eval_appup(Conf) when is_list(Conf) -> %% (see myrel/lib2/app1-2.0/ebin/app1.app) [{var,val2}] = ets:lookup(otp_6162, var), + %% Read appup script + {ok,DnScript} = release_handler:downgrade_script(app1,"1.0",App11Dir), + [{load_object_code,_}, + point_of_no_return, + {load,_}] = DnScript, + %% Downgrade to app1-1.0 {ok, []} = release_handler:downgrade_app(app1,"1.0",App11Dir), App11Dir = code:lib_dir(app1), @@ -1134,6 +1424,85 @@ eval_appup(Conf) when is_list(Conf) -> ok. +%% Test upgrade and downgrade of applications when appup contains +%% restart_emulator and restart_new_emulator instructions +eval_appup_with_restart(Conf) when is_list(Conf) -> + + %% Set some paths + RelDir = filename:join(?config(data_dir, Conf), "app1_app2"), + App11Dir = filename:join([RelDir, "lib1", "app1-1.0"]), + App13Dir = filename:join([RelDir, "lib3", "app1-3.0"]), %restart_emulator + App14Dir = filename:join([RelDir, "lib4", "app1-4.0"]), %restart_new_emulator + EbinDir1 = filename:join(App11Dir, "ebin"), + EbinDir3 = filename:join(App13Dir, "ebin"), + EbinDir4 = filename:join(App14Dir, "ebin"), + + %% Start app1-1.0 + code:add_patha(EbinDir1), + ok = application:start(app1), + App11Dir = code:lib_dir(app1), + + %% Read appup script + {ok,"3.0",UpScript3} = release_handler:upgrade_script(app1,App13Dir), + [{load_object_code,_}, + point_of_no_return, + {load,_}, + restart_emulator] = UpScript3, + + %% Upgrade to app1-3.0 - restart_emulator + restart_emulator = release_handler:upgrade_app(app1, App13Dir), + App13Dir = code:lib_dir(app1), + + %% Fake full upgrade to 3.0 + {ok,AppSpec} = file:consult(filename:join([App13Dir,"ebin","app1.app"])), + application_controller:change_application_data(AppSpec,[]), + + %% Read appup script + {ok,"4.0",UpScript4} = release_handler:upgrade_script(app1,App14Dir), + [restart_new_emulator,point_of_no_return] = UpScript4, + + %% Try pgrade to app1-4.0 - restart_new_emulator + {error,restart_new_emulator} = release_handler:upgrade_app(app1, App14Dir), + App13Dir = code:lib_dir(app1), + + %% Read appup script + {ok,DnScript1} = release_handler:downgrade_script(app1,"1.0",App11Dir), + [{load_object_code,_}, + point_of_no_return, + {load,_}, + restart_emulator] = DnScript1, + + %% Still running 3.0 - downgrade to app1-1.0 - restart_emulator + restart_emulator = release_handler:downgrade_app(app1,"1.0",App11Dir), + App11Dir = code:lib_dir(app1), + + ok = application:stop(app1), + ok = application:unload(app1), + true = code:del_path(EbinDir1), + + %% Start again as version 4.0 + code:add_patha(EbinDir4), + ok = application:start(app1), + App14Dir = code:lib_dir(app1), + + %% Read appup script + {ok,DnScript3} = release_handler:downgrade_script(app1,"3.0",App13Dir), + [point_of_no_return,restart_emulator] = DnScript3, + + %% Downgrade to app1-3.0 - restart_new_emulator + restart_emulator = release_handler:downgrade_app(app1,"3.0",App13Dir), + App13Dir = code:lib_dir(app1), + + ok = application:stop(app1), + ok = application:unload(app1), + + true = code:del_path(EbinDir3), + false = code:del_path(EbinDir1), + false = code:del_path(EbinDir4), + + ok. + + %% Test the example/target_system.erl module target_system(Conf) when is_list(Conf) -> PrivDir = priv_dir(Conf), @@ -1147,11 +1516,10 @@ target_system(Conf) when is_list(Conf) -> %% Create the .rel file - ErtsVsn = erlang:system_info(version), RelName = filename:join(TargetCreateDir,"ts-1.0"), RelFile = RelName++".rel", RelVsn = "R1A", - create_rel_file(RelFile,RelName,RelVsn,ErtsVsn,[{a, "1.0"}]), + create_rel_file(RelFile,RelName,RelVsn,current,[{a, "1.0"}]), %% Build the target_system module ExamplesEbin = filename:join([code:lib_dir(sasl),examples,ebin]), @@ -1179,11 +1547,13 @@ target_system(Conf) when is_list(Conf) -> code:del_path(TSPath), %% Check that all files exist in installation - true = filelib:is_dir(filename:join(TargetInstallDir,"erts-"++ErtsVsn)), + ErtsDir = app_dir(erts,current), + true = filelib:is_dir(filename:join(TargetInstallDir,ErtsDir)), LibDir = filename:join(TargetInstallDir,lib), - {ok,KernelVsn} = application:get_key(kernel,vsn), - {ok,StdlibVsn} = application:get_key(stdlib,vsn), - {ok,SaslVsn} = application:get_key(sasl,vsn), + KernelVsn = vsn(kernel,current), + StdlibVsn = vsn(stdlib,current), + SaslVsn = vsn(sasl,current), + RelFileBasename = filename:basename(RelFile), true = filelib:is_dir(filename:join(LibDir,"kernel-"++KernelVsn)), true = filelib:is_dir(filename:join(LibDir,"stdlib-"++StdlibVsn)), true = filelib:is_dir(filename:join(LibDir,"sasl-"++SaslVsn)), @@ -1191,10 +1561,10 @@ target_system(Conf) when is_list(Conf) -> RelDir = filename:join(TargetInstallDir,releases), true = filelib:is_regular(filename:join(RelDir,"RELEASES")), true = filelib:is_regular(filename:join(RelDir,"start_erl.data")), - true = filelib:is_regular(filename:join(RelDir, - filename:basename(RelFile))), + true = filelib:is_regular(filename:join(RelDir,RelFileBasename)), true = filelib:is_dir(filename:join(RelDir,RelVsn)), true = filelib:is_regular(filename:join([RelDir,RelVsn,"start.boot"])), + true = filelib:is_regular(filename:join([RelDir,RelVsn,RelFileBasename])), BinDir = filename:join(TargetInstallDir,bin), true = filelib:is_regular(filename:join(BinDir,"start.boot")), true = filelib:is_regular(filename:join(BinDir,erl)), @@ -1205,6 +1575,7 @@ target_system(Conf) when is_list(Conf) -> true = filelib:is_regular(filename:join(BinDir,to_erl)), %% Check content of files + ErtsVsn = vsn(erts,current), {ok,SED} = file:read_file(filename:join(RelDir,"start_erl.data")), [ErtsVsn,RelVsn] = string:tokens(binary_to_list(SED),"\s\n"), ok. @@ -1456,7 +1827,7 @@ copy_client(Conf,Master,Sname,Client) -> ok. -delete_release(Conf) -> +clean_priv_dir(Conf,Save) -> PrivDir = priv_dir(Conf), {ok, OrigWd} = file:get_cwd(), @@ -1466,7 +1837,7 @@ delete_release(Conf) -> {ok, Dirs} = file:list_dir(PrivDir), ?t:format("======== deleting ~p~n",[Dirs]), - ok = delete_release_os(Dirs--["save"]), + ok = clean_dirs_os(Dirs,Save), {ok,Remaining} = file:list_dir(PrivDir), ?t:format("======== remaining ~p~n",[Remaining]), @@ -1474,7 +1845,7 @@ delete_release(Conf) -> [] -> ok; _ -> - delete_release_os(Remaining), + clean_dirs_os(Remaining,Save), Remaining2 = file:list_dir(PrivDir), ?t:format("======== remaining after second try ~p~n",[Remaining2]) end, @@ -1483,22 +1854,22 @@ delete_release(Conf) -> ok. -delete_release_os(Dirs) -> +clean_dirs_os(Dirs,Save) -> case os:type() of {unix, _} -> - delete_release_unix(Dirs); + clean_dirs_unix(Dirs,Save); {win32, _} -> - delete_release_win32(Dirs); + clean_dirs_win32(Dirs,Save); Os -> test_server:fail({error, {not_yet_implemented_os, Os}}) end. -delete_release_unix([]) -> +clean_dirs_unix([],_) -> ok; -delete_release_unix(["save"|Dirs]) -> - delete_release_unix(Dirs); -delete_release_unix([Dir|Dirs]) -> +clean_dirs_unix(["save"|Dirs],Save) when Save -> + clean_dirs_unix(Dirs,Save); +clean_dirs_unix([Dir|Dirs],Save) -> Rm = string:concat("rm -rf ", Dir), ?t:format("============== COMMAND ~p~n",[Rm]), case file:list_dir(Dir) of @@ -1515,13 +1886,13 @@ delete_release_unix([Dir|Dirs]) -> ?t:format("------- ls -al ~p~n",[os:cmd("ls -al " ++ Dir)]) end, - delete_release_unix(Dirs). + clean_dirs_unix(Dirs,Save). -delete_release_win32([]) -> +clean_dirs_win32([],_) -> ok; -delete_release_win32(["save"|Dirs]) -> - delete_release_win32(Dirs); -delete_release_win32([Dir|Dirs]) -> +clean_dirs_win32(["save"|Dirs],Save) when Save -> + clean_dirs_win32(Dirs,Save); +clean_dirs_win32([Dir|Dirs],Save) -> Rm = case filelib:is_dir(Dir) of true -> @@ -1531,7 +1902,7 @@ delete_release_win32([Dir|Dirs]) -> end, ?t:format("============== COMMAND ~p~n",[Rm]), [] = os:cmd(Rm), - delete_release_win32(Dirs). + clean_dirs_win32(Dirs,Save). node_name(Sname) when is_atom(Sname) -> @@ -1657,9 +2028,17 @@ priv_dir(Conf) -> %% filename:absname(?config(priv_dir, Conf)). % Get rid of trailing slash %% Due to problem with long paths on windows => creating a new %% priv_dir under data_dir + filename:absname(filename:join(?config(data_dir, Conf),priv_dir)). + +init_priv_dir(Conf) -> Dir = filename:absname(filename:join(?config(data_dir, Conf),priv_dir)), - filelib:ensure_dir(filename:join(Dir,"*")), - Dir. + case filelib:is_dir(Dir) of + true -> + clean_priv_dir(Conf,false); + false -> + ok + end, + filelib:ensure_dir(filename:join(Dir,"*")). latest_version(Dir) -> List = filelib:wildcard(Dir ++ "*"), @@ -1694,14 +2073,22 @@ stop_print_proc() -> %% Create the first target release, vsn P1G. This release is used for %% all test cases in {group,release} -create_p1g(Conf,Sname) -> - do_create_p1g(Conf,filename:join(priv_dir(Conf),Sname)). - -do_create_p1g(Conf,TargetDir) -> - PrivDir = priv_dir(Conf), +create_p1g(Conf,TargetDir) -> DataDir = ?config(data_dir,Conf), - ErtsVsn = "4.4", - ErtsDir = "erts-"++ErtsVsn, + PrivDir = priv_dir(Conf), + ErtsDir = app_dir(erts,old), + KernelDir = app_dir(kernel,old), + StdlibDir = app_dir(stdlib,old), + + %% Fake earlier version of kernel and stdlib + SystemLib = system_lib(PrivDir), + ok = filelib:ensure_dir(filename:join(SystemLib,"*")), + KernelLib = code:lib_dir(kernel), + StdlibLib = code:lib_dir(stdlib), + ok = copy_tree(Conf,KernelLib,KernelDir,SystemLib), + ok = copy_tree(Conf,StdlibLib,StdlibDir,SystemLib), + fix_version(SystemLib,kernel), + fix_version(SystemLib,stdlib), %% Create dirs BinDir = filename:join(TargetDir,bin), @@ -1745,17 +2132,15 @@ do_create_p1g(Conf,TargetDir) -> RelFileName = filename:join(RelDir,RelName), RelFile = RelFileName ++ ".rel", ok = filelib:ensure_dir(RelFile), - LibPath = filename:join([DataDir,lib,"*",ebin]), - TarFile = create_basic_release(Conf, RelFile, RelVsn, {ErtsVsn,false}, - LibPath, [], [], [], []), + TarFile = create_basic_release(Conf,RelFile,RelVsn,{old,false}), %% Extract tar file in target directory (i.e. same directory as erts etc.) ok = erl_tar:extract(TarFile, [{cwd, TargetDir}, compressed]), %% Create start_erl.data StartErlDataFile = filename:join([ReleasesDir, "start_erl.data"]), - StartErlData = io_lib:fwrite("~s ~s~n", [ErtsVsn, RelVsn]), + StartErlData = io_lib:fwrite("~s ~s~n", [vsn(erts,old), RelVsn]), ok = file:write_file(StartErlDataFile, StartErlData), %% Create RELEASES @@ -1763,60 +2148,98 @@ do_create_p1g(Conf,TargetDir) -> ok. +fix_version(SystemLib,App) -> + FromVsn = vsn(App,current), + ToVsn = vsn(App,old), + Rootname = filename:join([SystemLib,app_dir(App,old),ebin,atom_to_list(App)]), + + AppFile = Rootname ++ ".app", + {ok,OrigApp} = file:read_file(AppFile), + ok = file:write_file(AppFile,re:replace(OrigApp,FromVsn,ToVsn, + [{return,binary}])), + AppupFile = Rootname ++ ".appup", + {ok,OrigAppup} = file:read_file(AppupFile), + ok = file:write_file(AppupFile,re:replace(OrigAppup,FromVsn,ToVsn, + [{return,binary}])). + + %% Create version P1H - which is P1G + a-1.0 %% Must have run create_p1g first!! create_p1h(Conf) -> - create_upgrade_release(Conf,"rel1","P1H",{"4.4",false},[{a,"1.0"}], - [{a,[{key2,val2}]}],{"rel0",[new_appl]}). + create_upgrade_release(Conf,"rel1","P1H",{old,false},[{a,"1.0"}], + [{a,[{key2,val2}]}],[{"rel0",[new_appl]}]). %% Create version P1I - which is P1H, but with application a upgraded to a-1.1 %% Must have run create_p1h first!! create_p1i(Conf) -> - create_upgrade_release(Conf,"rel2","P1I",{"4.4",false},[{a,"1.1"}], + create_upgrade_release(Conf,"rel2","P1I",{old,false},[{a,"1.1"}], [{a,[{key2,newval2}]}], - {"rel1",[{extra,gott}]}). + [{"rel1",[{extra,gott}]}]). %% Create version P2A - which is P1I, but with erts-<latest> %% Must have run create_p1i first!! create_p2a(Conf) -> - ErtsVsn = erlang:system_info(version), - create_upgrade_release(Conf,"rel3","P2A",{ErtsVsn,code:root_dir()}, + create_upgrade_release(Conf,"rel3","P2A",{current,code:root_dir()}, + [{a,"1.1"}],[{a,[{key2,newval2}]}], + [{"rel1",[new_emu,new_appl]},{"rel2",[new_emu]}], + [{"rel1",[old_emu,old_appl]},{"rel2",[old_emu]}]). + +%% Create version P2B - which is P2A, but with relup containing an +%% extra reboot. +%% Can be upgraded to from P1G - so must have run create_p1g first!! +create_p2b(Conf) -> + create_upgrade_release(Conf,"rel4","P2B",{current,code:root_dir()}, [{a,"1.1"}],[{a,[{key2,newval2}]}], - {"rel2",[new_emu]}). + [{"rel0",[new_emu,add_appl]}], + [{"rel0",[old_emu,rm_appl]}], + [restart_emulator]). %% Create a release tar package which can be installed on top of P1G -create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,{UpFromName,Descr}) -> +create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom) -> + create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom,[]). +create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom,DownTo) -> + create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom,DownTo,[]). +create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom0,DownTo0,RelupOpts) -> PrivDir = priv_dir(Conf), - DataDir = ?config(data_dir,Conf), - RelDir = filename:join(PrivDir,RelName), RelFileName = filename:join(RelDir,RelName), RelFile = RelFileName ++ ".rel", ok = filelib:ensure_dir(RelFile), - LibPath = filename:join([DataDir,lib,"*",ebin]), - UpFrom = [{filename:join([PrivDir,UpFromName,UpFromName]),Descr}], + UpFrom = [{filename:join([PrivDir,UpFromName,UpFromName]),Descr} || + {UpFromName,Descr} <- UpFrom0], + DownTo = [{filename:join([PrivDir,DownToName,DownToName]),Descr} || + {DownToName,Descr} <- DownTo0], - create_basic_release(Conf, RelFile, RelVsn, Erts, LibPath, - Apps, Config, UpFrom, []), + create_basic_release(Conf,RelFile,RelVsn,Erts,Apps,Config, + UpFrom,DownTo,RelupOpts), ok. %% Create .rel, .script, .boot, sys.config and tar -create_basic_release(Conf, RelFile,RelVsn,{ErtsVsn,ErtsDir},LibPath,ExtraApps,Config,UpFrom,DownTo) -> +create_basic_release(Conf,RelFile,RelVsn,{Erts,ErtsDir}) -> + create_basic_release(Conf, RelFile,RelVsn,{Erts,ErtsDir},[],[],[],[],[]). +create_basic_release(Conf,RelFile,RelVsn,{Erts,ErtsDir},ExtraApps,Config,UpFrom,DownTo,RelupOpts) -> + DataDir = ?config(data_dir,Conf), + PrivDir = priv_dir(Conf), + SystemLib = system_lib(PrivDir), + LibPath = [filename:join([SystemLib,"*",ebin]), + filename:join([DataDir,lib,"*",ebin])], + RelDir = filename:dirname(RelFile), RelFileName = filename:rootname(RelFile), %% Create .rel file - create_installer_rel_file(RelFile,RelVsn,ErtsVsn,ExtraApps), + create_installer_rel_file(RelFile,RelVsn,Erts,ExtraApps), %% Generate .script and .boot ok = systools:make_script(RelFileName, - [{path,[LibPath]}, + [{path,LibPath}, {outdir,RelDir}]), %% Generate relup - ok = systools:make_relup(RelFileName,UpFrom,DownTo,[{path,[LibPath]}, - {outdir,RelDir}]), + ok = systools:make_relup(RelFileName,UpFrom,DownTo,[{path,LibPath}, + {outdir,RelDir} | + RelupOpts]), %% Create sys.config ok = write_term_file(filename:join(RelDir,"sys.config"),Config), @@ -1824,7 +2247,7 @@ create_basic_release(Conf, RelFile,RelVsn,{ErtsVsn,ErtsDir},LibPath,ExtraApps,Co %% Create tar file (i.e. collect all lib/app-*/* and system files) ok = systools:make_tar(RelFileName, - [{path,[LibPath]}, + [{path,LibPath}, {outdir,RelDir} | case ErtsDir of false -> []; @@ -1841,18 +2264,19 @@ create_basic_release(Conf, RelFile,RelVsn,{ErtsVsn,ErtsDir},LibPath,ExtraApps,Co TarFileName. %% Create a .rel file -create_installer_rel_file(RelFile,RelVsn,ErtsVsn,ExtraApps) -> - create_rel_file(RelFile,"SASL-test",RelVsn,ErtsVsn, +create_installer_rel_file(RelFile,RelVsn,Erts,ExtraApps) -> + create_rel_file(RelFile,"SASL-test",RelVsn,Erts, [{installer,"1.0"}|ExtraApps]). -create_rel_file(RelFile,RelName,RelVsn,ErtsVsn,ExtraApps) -> - {ok,KernelVsn} = application:get_key(kernel,vsn), - {ok,StdlibVsn} = application:get_key(stdlib,vsn), - {ok,SaslVsn} = application:get_key(sasl,vsn), +create_rel_file(RelFile,RelName,RelVsn,Erts,ExtraApps) -> + ErtsVsn = vsn(erts,Erts), + KernelVsn = vsn(kernel,Erts), + StdlibVsn = vsn(stdlib,Erts), + SaslVsn = vsn(sasl,current), application:load(tools), - {ok,ToolsVsn} = application:get_key(tools,vsn), + ToolsVsn = vsn(tools,current), application:load(runtime_tools), - {ok,RuntimeToolsVsn} = application:get_key(runtime_tools,vsn), + RuntimeToolsVsn = vsn(runtime_tools,current), RelFileContent = {release, {RelName, RelVsn}, @@ -2033,7 +2457,7 @@ start_node_unix(Sname,NodeDir) -> start_node_win32(Sname,NodeDir) -> Name = atom_to_list(Sname) ++ "_P1G", - ErtsBinDir = filename:join(NodeDir,"erts-4.4/bin"), + ErtsBinDir = filename:join([NodeDir,app_dir(erts,old),"bin"]), StartErlArgs = rh_test_lib:get_start_erl_args(NodeDir), ServiceArgs = rh_test_lib:get_service_args(NodeDir, Sname, StartErlArgs), @@ -2158,7 +2582,6 @@ create_fake_release(Dir,RelName,RelVsn,AppDirs) -> RelDir = filename:join(Dir,"rel_" ++ RelVsn), Rel = filename:join([RelDir,"rel_" ++ RelVsn]), ok = filelib:ensure_dir(Rel), - ErtsVsn = erlang:system_info(version), {Apps,Paths} = lists:foldl(fun({App,Vsn,Lib},{As,Ps}) -> @@ -2168,7 +2591,7 @@ create_fake_release(Dir,RelName,RelVsn,AppDirs) -> {[],[]}, AppDirs), - create_rel_file(Rel++".rel",RelName,RelVsn,ErtsVsn,Apps), + create_rel_file(Rel++".rel",RelName,RelVsn,current,Apps), %% Generate boot scripts ok = systools:make_script(Rel,[local, @@ -2217,3 +2640,16 @@ modify_tar_win32(Conf, TarFileName) -> [ok = erl_tar:add(T,filename:join(TmpDir,F),F,[]) || F <- Fs], ok = erl_tar:close(T), ok. + +app_dir(App,Vsn) -> + atom_to_list(App) ++ "-" ++ vsn(App,Vsn). +vsn(erts,old) -> ?ertsvsn; +vsn(kernel,old) -> ?kernelvsn; +vsn(stdlib,old) -> ?stdlibvsn; +vsn(erts,current) -> erlang:system_info(version); +vsn(App,current) -> + {ok,Vsn} = application:get_key(App,vsn), + Vsn. + +system_lib(PrivDir) -> + filename:join(PrivDir,"system_lib"). diff --git a/lib/sasl/test/release_handler_SUITE_data/Makefile.src b/lib/sasl/test/release_handler_SUITE_data/Makefile.src index edb446413d..55d20aa8b6 100644 --- a/lib/sasl/test/release_handler_SUITE_data/Makefile.src +++ b/lib/sasl/test/release_handler_SUITE_data/Makefile.src @@ -5,6 +5,10 @@ P2B= \ P2B/a-2.0/ebin/a_sup.@EMULATOR@ LIB= \ + lib/a-9.1/ebin/a.@EMULATOR@ \ + lib/a-9.1/ebin/a_sup.@EMULATOR@ \ + lib/a-9.0/ebin/a.@EMULATOR@ \ + lib/a-9.0/ebin/a_sup.@EMULATOR@ \ lib/a-1.2/ebin/a.@EMULATOR@ \ lib/a-1.2/ebin/a_sup.@EMULATOR@ \ lib/a-1.1/ebin/a.@EMULATOR@ \ @@ -50,7 +54,13 @@ APP= \ app1_app2/lib2/app1-2.0/ebin/app1.@EMULATOR@ \ app1_app2/lib2/app2-1.0/ebin/app2_sup.@EMULATOR@ \ app1_app2/lib2/app2-1.0/ebin/app2_server.@EMULATOR@ \ - app1_app2/lib2/app2-1.0/ebin/app2.@EMULATOR@ + app1_app2/lib2/app2-1.0/ebin/app2.@EMULATOR@ \ + app1_app2/lib3/app1-3.0/ebin/app1_sup.@EMULATOR@ \ + app1_app2/lib3/app1-3.0/ebin/app1_server.@EMULATOR@ \ + app1_app2/lib3/app1-3.0/ebin/app1.@EMULATOR@ \ + app1_app2/lib4/app1-4.0/ebin/app1_sup.@EMULATOR@ \ + app1_app2/lib4/app1-4.0/ebin/app1_server.@EMULATOR@ \ + app1_app2/lib4/app1-4.0/ebin/app1.@EMULATOR@ OTP2740= \ otp_2740/vsn_atom.@EMULATOR@ \ @@ -95,6 +105,17 @@ lib/a-1.2/ebin/a.@EMULATOR@: lib/a-1.2/src/a.erl lib/a-1.2/ebin/a_sup.@EMULATOR@: lib/a-1.2/src/a_sup.erl erlc $(EFLAGS) -olib/a-1.2/ebin lib/a-1.2/src/a_sup.erl +lib/a-9.0/ebin/a.@EMULATOR@: lib/a-9.0/src/a.erl + erlc $(EFLAGS) -olib/a-9.0/ebin lib/a-9.0/src/a.erl +lib/a-9.0/ebin/a_sup.@EMULATOR@: lib/a-9.0/src/a_sup.erl + erlc $(EFLAGS) -olib/a-9.0/ebin lib/a-9.0/src/a_sup.erl + +lib/a-9.1/ebin/a.@EMULATOR@: lib/a-9.1/src/a.erl + erlc $(EFLAGS) -olib/a-9.1/ebin lib/a-9.1/src/a.erl +lib/a-9.1/ebin/a_sup.@EMULATOR@: lib/a-9.1/src/a_sup.erl + erlc $(EFLAGS) -olib/a-9.1/ebin lib/a-9.1/src/a_sup.erl + + lib/b-1.0/ebin/b_server.@EMULATOR@: lib/b-1.0/src/b_server.erl erlc $(EFLAGS) -olib/b-1.0/ebin lib/b-1.0/src/b_server.erl lib/b-1.0/ebin/b_lib.@EMULATOR@: lib/b-1.0/src/b_lib.erl @@ -183,6 +204,22 @@ app1_app2/lib2/app2-1.0/ebin/app2.@EMULATOR@: app1_app2/lib2/app2-1.0/src/app2.e erlc $(EFLAGS) -oapp1_app2/lib2/app2-1.0/ebin app1_app2/lib2/app2-1.0/src/app2.erl +app1_app2/lib3/app1-3.0/ebin/app1_sup.@EMULATOR@: app1_app2/lib3/app1-3.0/src/app1_sup.erl + erlc $(EFLAGS) -oapp1_app2/lib3/app1-3.0/ebin app1_app2/lib3/app1-3.0/src/app1_sup.erl +app1_app2/lib3/app1-3.0/ebin/app1_server.@EMULATOR@: app1_app2/lib3/app1-3.0/src/app1_server.erl + erlc $(EFLAGS) -oapp1_app2/lib3/app1-3.0/ebin app1_app2/lib3/app1-3.0/src/app1_server.erl +app1_app2/lib3/app1-3.0/ebin/app1.@EMULATOR@: app1_app2/lib3/app1-3.0/src/app1.erl + erlc $(EFLAGS) -oapp1_app2/lib3/app1-3.0/ebin app1_app2/lib3/app1-3.0/src/app1.erl + + +app1_app2/lib4/app1-4.0/ebin/app1_sup.@EMULATOR@: app1_app2/lib4/app1-4.0/src/app1_sup.erl + erlc $(EFLAGS) -oapp1_app2/lib4/app1-4.0/ebin app1_app2/lib4/app1-4.0/src/app1_sup.erl +app1_app2/lib4/app1-4.0/ebin/app1_server.@EMULATOR@: app1_app2/lib4/app1-4.0/src/app1_server.erl + erlc $(EFLAGS) -oapp1_app2/lib4/app1-4.0/ebin app1_app2/lib4/app1-4.0/src/app1_server.erl +app1_app2/lib4/app1-4.0/ebin/app1.@EMULATOR@: app1_app2/lib4/app1-4.0/src/app1.erl + erlc $(EFLAGS) -oapp1_app2/lib4/app1-4.0/ebin app1_app2/lib4/app1-4.0/src/app1.erl + + otp_2740/vsn_atom.@EMULATOR@: otp_2740/vsn_atom.erl erlc $(EFLAGS) -ootp_2740 otp_2740/vsn_atom.erl otp_2740/vsn_list.@EMULATOR@: otp_2740/vsn_list.erl diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/ebin/app1.app b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/ebin/app1.app new file mode 100644 index 0000000000..4adc0540c4 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/ebin/app1.app @@ -0,0 +1,9 @@ +{application, app1, + [{description, "very simple example application"}, + {id, "app1"}, + {vsn, "3.0"}, + {modules, [app1, app1_sup, app1_server]}, + {registered, [harry]}, + {applications, [kernel, stdlib, sasl]}, + {env, [{var,val2}]}, + {mod, {app1, []}}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/ebin/app1.appup b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/ebin/app1.appup new file mode 100644 index 0000000000..a5cdfe9fcc --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/ebin/app1.appup @@ -0,0 +1,4 @@ +{"3.0", + [{"1.0", [{load_module, app1_server},restart_emulator]}], + [{"1.0", [{load_module, app1_server},restart_emulator]}] +}. diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1.erl new file mode 100644 index 0000000000..f123c8f470 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1.erl @@ -0,0 +1,22 @@ +-module(app1). + +-behaviour(application). + +%% Application callbacks +-export([start/2, stop/1]). +-export([config_change/3]). + +start(_Type, _StartArgs) -> + case app1_sup:start_link() of + {ok, Pid} -> + {ok, Pid}; + Error -> + Error + end. + +stop(_State) -> + ok. + +config_change(Changed, _New, _Removed) -> + catch ets:insert(otp_6162, hd(Changed)), + ok. diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1_server.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1_server.erl new file mode 100644 index 0000000000..660d095ebf --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1_server.erl @@ -0,0 +1,35 @@ +-module(app1_server). + +-behaviour(gen_server). + +%% API +-export([start_link/0]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +start_link() -> + gen_server:start_link({local, harry}, ?MODULE, [], []). + +init([]) -> + {ok, []}. + +handle_call(error, _From, State) -> + Reply = error, + {reply, Reply, State}; +handle_call(_Request, _From, State) -> + Reply = ok, + {reply, Reply, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1_sup.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1_sup.erl new file mode 100644 index 0000000000..e6ad9b6967 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1_sup.erl @@ -0,0 +1,17 @@ +-module(app1_sup). + +-behaviour(supervisor). + +%% API +-export([start_link/0]). + +%% Supervisor callbacks +-export([init/1]). + +start_link() -> + supervisor:start_link(?MODULE, []). + +init([]) -> + AChild = {harry,{app1_server,start_link,[]}, + permanent,2000,worker,[app1_server]}, + {ok,{{one_for_all,0,1}, [AChild]}}. diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/ebin/app1.app b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/ebin/app1.app new file mode 100644 index 0000000000..243bc21f02 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/ebin/app1.app @@ -0,0 +1,9 @@ +{application, app1, + [{description, "very simple example application"}, + {id, "app1"}, + {vsn, "4.0"}, + {modules, [app1, app1_sup, app1_server]}, + {registered, [harry]}, + {applications, [kernel, stdlib, sasl]}, + {env, [{var,val2}]}, + {mod, {app1, []}}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/ebin/app1.appup b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/ebin/app1.appup new file mode 100644 index 0000000000..72535c8b34 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/ebin/app1.appup @@ -0,0 +1,4 @@ +{"4.0", + [{"3.0", [restart_new_emulator]}], + [{"3.0", [restart_new_emulator]}] +}. diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1.erl new file mode 100644 index 0000000000..f123c8f470 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1.erl @@ -0,0 +1,22 @@ +-module(app1). + +-behaviour(application). + +%% Application callbacks +-export([start/2, stop/1]). +-export([config_change/3]). + +start(_Type, _StartArgs) -> + case app1_sup:start_link() of + {ok, Pid} -> + {ok, Pid}; + Error -> + Error + end. + +stop(_State) -> + ok. + +config_change(Changed, _New, _Removed) -> + catch ets:insert(otp_6162, hd(Changed)), + ok. diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1_server.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1_server.erl new file mode 100644 index 0000000000..660d095ebf --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1_server.erl @@ -0,0 +1,35 @@ +-module(app1_server). + +-behaviour(gen_server). + +%% API +-export([start_link/0]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +start_link() -> + gen_server:start_link({local, harry}, ?MODULE, [], []). + +init([]) -> + {ok, []}. + +handle_call(error, _From, State) -> + Reply = error, + {reply, Reply, State}; +handle_call(_Request, _From, State) -> + Reply = ok, + {reply, Reply, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1_sup.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1_sup.erl new file mode 100644 index 0000000000..e6ad9b6967 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1_sup.erl @@ -0,0 +1,17 @@ +-module(app1_sup). + +-behaviour(supervisor). + +%% API +-export([start_link/0]). + +%% Supervisor callbacks +-export([init/1]). + +start_link() -> + supervisor:start_link(?MODULE, []). + +init([]) -> + AChild = {harry,{app1_server,start_link,[]}, + permanent,2000,worker,[app1_server]}, + {ok,{{one_for_all,0,1}, [AChild]}}. diff --git a/lib/sasl/test/release_handler_SUITE_data/heart_restart.bat b/lib/sasl/test/release_handler_SUITE_data/heart_restart.bat index ede1ad4ff3..ede1ad4ff3 100755..100644 --- a/lib/sasl/test/release_handler_SUITE_data/heart_restart.bat +++ b/lib/sasl/test/release_handler_SUITE_data/heart_restart.bat diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/README b/lib/sasl/test/release_handler_SUITE_data/lib/README index 639a4ca0fb..ffb8c5120b 100644 --- a/lib/sasl/test/release_handler_SUITE_data/lib/README +++ b/lib/sasl/test/release_handler_SUITE_data/lib/README @@ -8,6 +8,14 @@ a-1.2: can be upgraded to from a-1.1. No module have changed, but priv dir is added including one 'file' +a-9.0: +can be upgrade to from a-1.0 +Changes a_sup correctly - to test successful upgrade of supervisor + +a-9.1: +can be upgrade to from a-1.0 +Changes a_sup faulty - to test failing upgrade of supervisor + b-1.0: start version, includes b_lib and b_server diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup index 05db4cb541..6ef67b869e 100644 --- a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup @@ -1,3 +1,3 @@ {"1.1", [{"1.0",[{update,a,{advanced,extra_par}}]}], - []}. + [{"1.0",[{update,a,{advanced,extra_par}}]}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl index c082ad5339..1050e53f35 100644 --- a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl @@ -51,4 +51,6 @@ terminate(_Reason, _State) -> ok. code_change(1, Extra, State) -> - {ok, {state, bval}}. + {ok, {state, bval}}; +code_change({down,1},Extra,State) -> + {ok, state}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/ebin/a.app b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/ebin/a.app new file mode 100644 index 0000000000..aa436d3e8c --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/ebin/a.app @@ -0,0 +1,8 @@ +{application, a, + [{description, "A CXC 138 11"}, + {vsn, "9.0"}, + {modules, [a, a_sup]}, + {registered, [a_sup]}, + {applications, [kernel, stdlib]}, + {env, [{key1, val1}]}, + {mod, {a_sup, []}}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/ebin/a.appup b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/ebin/a.appup new file mode 100644 index 0000000000..c4071d57a3 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/ebin/a.appup @@ -0,0 +1,3 @@ +{"9.0", + [{"1.0",[{update,a_sup,{advanced,update_supervisor}}]}], + [{"1.0",[{update,a_sup,{advanced,update_supervisor}}]}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/src/a.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/src/a.erl new file mode 100644 index 0000000000..1050e53f35 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/src/a.erl @@ -0,0 +1,56 @@ +%% ``The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved via the world wide web at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. +%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +%% AB. All Rights Reserved.'' +%% +%% $Id$ +%% +-module(a). + + +-behaviour(gen_server). + +%% External exports +-export([start_link/0, a/0, b/0]). +%% Internal exports +-export([init/1, handle_call/3, handle_info/2, terminate/2, code_change/3]). + +start_link() -> gen_server:start_link({local, aa}, a, [], []). + +a() -> gen_server:call(aa, a). +b() -> gen_server:call(aa, b). + +%%----------------------------------------------------------------- +%% Callback functions from gen_server +%%----------------------------------------------------------------- +init([]) -> + process_flag(trap_exit, true), + {ok, {state, bval}}. + +handle_call(a, _From, State) -> + X = application:get_all_env(a), + {reply, X, State}; + +handle_call(b, _From, State) -> + {reply, {ok, element(2, State)}, State}. + +handle_info(_, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(1, Extra, State) -> + {ok, {state, bval}}; +code_change({down,1},Extra,State) -> + {ok, state}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/src/a_sup.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/src/a_sup.erl new file mode 100644 index 0000000000..ae1d080f58 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/src/a_sup.erl @@ -0,0 +1,37 @@ +%% ``The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved via the world wide web at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. +%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +%% AB. All Rights Reserved.'' +%% +%% $Id$ +%% +-module(a_sup). + + +-behaviour(supervisor). + +%% External exports +-export([start/2]). + +%% Internal exports +-export([init/1]). + +start(_, _) -> + supervisor:start_link({local, a_sup}, a_sup, []). + +init([]) -> + SupFlags = {one_for_all, 4, 3600}, + Config = {a, + {a, start_link, []}, + permanent, brutal_kill, worker, [a]}, + {ok, {SupFlags, [Config]}}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/ebin/a.app b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/ebin/a.app new file mode 100644 index 0000000000..5b467ec4e8 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/ebin/a.app @@ -0,0 +1,8 @@ +{application, a, + [{description, "A CXC 138 11"}, + {vsn, "9.1"}, + {modules, [a, a_sup]}, + {registered, [a_sup]}, + {applications, [kernel, stdlib]}, + {env, [{key1, val1}]}, + {mod, {a_sup, []}}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/ebin/a.appup b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/ebin/a.appup new file mode 100644 index 0000000000..efeb7f1fe3 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/ebin/a.appup @@ -0,0 +1,3 @@ +{"9.1", + [{"1.0",[{update,a_sup,{advanced,update_supervisor}}]}], + [{"1.0",[{update,a_sup,{advanced,update_supervisor}}]}]}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/src/a.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/src/a.erl new file mode 100644 index 0000000000..1050e53f35 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/src/a.erl @@ -0,0 +1,56 @@ +%% ``The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved via the world wide web at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. +%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +%% AB. All Rights Reserved.'' +%% +%% $Id$ +%% +-module(a). + + +-behaviour(gen_server). + +%% External exports +-export([start_link/0, a/0, b/0]). +%% Internal exports +-export([init/1, handle_call/3, handle_info/2, terminate/2, code_change/3]). + +start_link() -> gen_server:start_link({local, aa}, a, [], []). + +a() -> gen_server:call(aa, a). +b() -> gen_server:call(aa, b). + +%%----------------------------------------------------------------- +%% Callback functions from gen_server +%%----------------------------------------------------------------- +init([]) -> + process_flag(trap_exit, true), + {ok, {state, bval}}. + +handle_call(a, _From, State) -> + X = application:get_all_env(a), + {reply, X, State}; + +handle_call(b, _From, State) -> + {reply, {ok, element(2, State)}, State}. + +handle_info(_, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(1, Extra, State) -> + {ok, {state, bval}}; +code_change({down,1},Extra,State) -> + {ok, state}. diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/src/a_sup.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/src/a_sup.erl new file mode 100644 index 0000000000..b0597dc5c3 --- /dev/null +++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/src/a_sup.erl @@ -0,0 +1,37 @@ +%% ``The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved via the world wide web at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. +%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +%% AB. All Rights Reserved.'' +%% +%% $Id$ +%% +-module(a_sup). + + +-behaviour(supervisor). + +%% External exports +-export([start/2]). + +%% Internal exports +-export([init/1]). + +start(_, _) -> + supervisor:start_link({local, a_sup}, a_sup, []). + +init([]) -> + SupFlags = {one_for_all, 4, 3600}, + Config = {a, + {a, start_link, []}, + permanent, brutal_kil, worker, [a]}, + {ok, {SupFlags, [Config]}}. diff --git a/lib/sasl/test/sasl_SUITE.erl b/lib/sasl/test/sasl_SUITE.erl index 454095db6a..b6eaf41323 100644 --- a/lib/sasl/test/sasl_SUITE.erl +++ b/lib/sasl/test/sasl_SUITE.erl @@ -20,20 +20,21 @@ -include_lib("common_test/include/ct.hrl"). -% Default timetrap timeout (set in init_per_testcase). +%% Default timetrap timeout (set in init_per_testcase). -define(default_timeout, ?t:minutes(1)). -define(application, sasl). -% Test server specific exports +%% Test server specific exports -export([all/0,groups/0,init_per_group/2,end_per_group/2]). -export([init_per_testcase/2, end_per_testcase/2]). -% Test cases must be exported. +%% Test cases must be exported. -export([app_test/1, + appup_test/1, log_mf_h_env/1]). all() -> - [app_test, log_mf_h_env]. + [app_test, appup_test, log_mf_h_env]. groups() -> []. @@ -46,7 +47,7 @@ end_per_group(_GroupName, Config) -> init_per_testcase(_Case, Config) -> - ?line Dog=test_server:timetrap(?default_timeout), + Dog=test_server:timetrap(?default_timeout), [{watchdog, Dog}|Config]. end_per_testcase(_Case, Config) -> Dog=?config(watchdog, Config), @@ -54,9 +55,105 @@ end_per_testcase(_Case, Config) -> ok. app_test(Config) when is_list(Config) -> - ?line ?t:app_test(sasl, allow), + ?t:app_test(sasl, allow), ok. +%% Test that appup allows upgrade from/downgrade to a maximum of two +%% major releases back. +appup_test(_Config) -> + application:load(sasl), + {sasl,_,SaslVsn} = lists:keyfind(sasl,1,application:loaded_applications()), + Ebin = filename:join(code:lib_dir(sasl),ebin), + {ok,[{SaslVsn,UpFrom,DownTo}=Appup]} = + file:consult(filename:join(Ebin,"sasl.appup")), + ct:log("~p~n",[Appup]), + {OkVsns,NokVsns} = create_test_vsns(SaslVsn), + check_appup(OkVsns,UpFrom,{ok,[restart_new_emulator]}), + check_appup(OkVsns,DownTo,{ok,[restart_new_emulator]}), + check_appup(NokVsns,UpFrom,error), + check_appup(NokVsns,DownTo,error), + ok. + + +%% For sasl, the versions up to R14B03 were not according to the rule +%% used for other core applications - i.e. to change the second number +%% at major releases, the third at maintenance releases and the fourth +%% for patches - therefore test versions up to and including R16 are +%% hardcoded. +%% (All versions below are not necessarily existing.) +-define(r12_vsns,["2.1.5"]). +-define(r13_vsns,["2.1.6","2.1.7.1","2.1.9","2.1.9.1.2"]). +-define(r14_vsns,["2.1.9.2","2.1.9.2.20","2.1.9.4","2.1.10"]). +-define(r15_major,"2.2"). +-define(r16_major,"2.3"). +-define(r17_major,"2.4"). +create_test_vsns(?r15_major ++ Rest) -> + R15Vsns = + case string:tokens(Rest,".") of + [] -> []; + ["1"] -> [?r15_major]; + _ -> [?r15_major,?r15_major++".1"] + end, + OkVsns = ?r13_vsns ++ ?r14_vsns ++ R15Vsns, + NokVsns = ?r12_vsns ++ [?r15_major++",1", ?r16_major], + {OkVsns,NokVsns}; +create_test_vsns(?r16_major ++ Rest) -> + R16Vsns = + case string:tokens(Rest,".") of + [] -> []; + ["1"] -> [?r16_major]; + _ -> [?r16_major,?r16_major++".1"] + end, + OkVsns = ?r14_vsns ++ [?r15_major, ?r15_major ++ ".1.4"] ++ R16Vsns, + NokVsns = ?r13_vsns ++ [?r16_major++",1", ?r17_major], + {OkVsns,NokVsns}; +%% Normal erts case - i.e. for versions that comply to the erts standard +create_test_vsns(Current) -> + [XStr,YStr|Rest] = string:tokens(Current,"."), + X = list_to_integer(XStr), + Y = list_to_integer(YStr), + SecondMajor = vsn(X,Y-2), + SecondMinor = SecondMajor ++ ".1.3", + FirstMajor = vsn(X,Y-1), + FirstMinor = FirstMajor ++ ".57", + ThisMajor = vsn(X,Y), + This = + case Rest of + [] -> + []; + ["1"] -> + [ThisMajor]; + _ -> + ThisMinor = ThisMajor ++ ".1", + [ThisMajor,ThisMinor] + end, + OkVsns = This ++ [FirstMajor, FirstMinor, SecondMajor, SecondMinor], + + ThirdMajor = vsn(X,Y-3), + ThirdMinor = ThirdMajor ++ ".10.12", + Illegal = ThisMajor ++ ",1", + Newer1Major = vsn(X,Y+1), + Newer1Minor = Newer1Major ++ ".1", + Newer2Major = ThisMajor ++ "1", + NokVsns = [ThirdMajor,ThirdMinor, + Illegal, + Newer1Major,Newer1Minor, + Newer2Major], + {OkVsns,NokVsns}. + +vsn(X,Y) -> + integer_to_list(X) ++ "." ++ integer_to_list(Y). + +check_appup([Vsn|Vsns],Instrs,Expected) -> + case systools_relup:appup_search_for_version(Vsn, Instrs) of + Expected -> check_appup(Vsns,Instrs,Expected); + Other -> ct:fail({unexpected_result_for_vsn,Vsn,Other}) + end; +check_appup([],_,_) -> + ok. + + + %% OTP-9185 - fail sasl start if some but not all log_mf_h env vars %% are given. log_mf_h_env(Config) -> diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl index e352247d44..878d582e6b 100644 --- a/lib/sasl/test/systools_SUITE.erl +++ b/lib/sasl/test/systools_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011. All Rights Reserved. +%% Copyright Ericsson AB 2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -28,9 +28,9 @@ -module(systools_SUITE). -%-define(debug, true). +%%-define(debug, true). --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). -define(format(S, A), ok). -define(datadir, ?config(data_dir, Config)). -define(privdir, ?config(priv_dir, Config)). @@ -40,19 +40,22 @@ -export([all/0,suite/0,groups/0,init_per_group/2,end_per_group/2]). --export([ script_options/1, normal_script/1, no_mod_vsn_script/1, - wildcard_script/1, variable_script/1, - abnormal_script/1, src_tests_script/1, crazy_script/1, - warn_shadow_script/1, - included_script/1, included_override_script/1, - included_fail_script/1, included_bug_script/1, exref_script/1]). --export([ tar_options/1, normal_tar/1, no_mod_vsn_tar/1, variable_tar/1, - src_tests_tar/1, shadow_tar/1, var_tar/1, - exref_tar/1, link_tar/1, otp_9507/1]). --export([ normal_relup/1, abnormal_relup/1, no_appup_relup/1, - bad_appup_relup/1, app_start_type_relup/1, otp_3065/1]). --export([ - otp_6226/1]). +-export([script_options/1, normal_script/1, no_mod_vsn_script/1, + wildcard_script/1, variable_script/1, no_sasl_script/1, + abnormal_script/1, src_tests_script/1, crazy_script/1, + included_script/1, included_override_script/1, + included_fail_script/1, included_bug_script/1, exref_script/1, + otp_3065_circular_dependenies/1, included_and_used_sort_script/1]). +-export([tar_options/1, normal_tar/1, no_mod_vsn_tar/1, system_files_tar/1, + system_files_tar/2, invalid_system_files_tar/1, + invalid_system_files_tar/2, variable_tar/1, + src_tests_tar/1, var_tar/1, exref_tar/1, link_tar/1, + otp_9507_path_ebin/1]). +-export([normal_relup/1, restart_relup/1, abnormal_relup/1, no_sasl_relup/1, + no_appup_relup/1, bad_appup_relup/1, app_start_type_relup/1, + regexp_relup/1]). +-export([normal_hybrid/1,hybrid_no_old_sasl/1,hybrid_no_new_sasl/1]). +-export([otp_6226_outdir/1]). -export([init_per_suite/1, end_per_suite/1, init_per_testcase/2, end_per_testcase/2]). @@ -67,25 +70,27 @@ suite() -> [{ct_hooks, [ts_install_cth]}]. all() -> - [{group, script}, {group, tar}, {group, relup}, - {group, tickets}]. + [{group, script}, {group, tar}, {group, relup}, {group, hybrid}, + {group, options}]. groups() -> [{script, [], [script_options, normal_script, no_mod_vsn_script, wildcard_script, variable_script, abnormal_script, - src_tests_script, crazy_script, warn_shadow_script, + no_sasl_script, src_tests_script, crazy_script, included_script, included_override_script, included_fail_script, included_bug_script, exref_script, - otp_3065]}, + otp_3065_circular_dependenies, included_and_used_sort_script]}, {tar, [], - [tar_options, normal_tar, no_mod_vsn_tar, variable_tar, - src_tests_tar, shadow_tar, var_tar, - exref_tar, link_tar, otp_9507]}, + [tar_options, normal_tar, no_mod_vsn_tar, system_files_tar, + invalid_system_files_tar, variable_tar, + src_tests_tar, var_tar, exref_tar, link_tar, otp_9507_path_ebin]}, {relup, [], - [normal_relup, abnormal_relup, no_appup_relup, - bad_appup_relup, app_start_type_relup]}, - {tickets, [], [otp_6226]}]. + [normal_relup, restart_relup, abnormal_relup, no_sasl_relup, + no_appup_relup, bad_appup_relup, app_start_type_relup, regexp_relup + ]}, + {hybrid, [], [normal_hybrid,hybrid_no_old_sasl,hybrid_no_new_sasl]}, + {options, [], [otp_6226_outdir]}]. init_per_group(_GroupName, Config) -> Config. @@ -100,17 +105,17 @@ init_per_suite(Config) when is_list(Config) -> %% Make of copy of the data directory. DataDir = ?datadir, PrivDir = ?privdir, - ?line CopyDir = fname(PrivDir, "datacopy"), - ?line TarFile = fname(PrivDir, "datacopy.tgz"), - ?line {ok, Tar} = erl_tar:open(TarFile, [write, compressed]), - ?line ok = erl_tar:add(Tar, DataDir, CopyDir, [compressed]), - ?line ok = erl_tar:close(Tar), - ?line ok = erl_tar:extract(TarFile, [compressed]), - ?line ok = file:delete(TarFile), + CopyDir = fname(PrivDir, "datacopy"), + TarFile = fname(PrivDir, "datacopy.tgz"), + {ok, Tar} = erl_tar:open(TarFile, [write, compressed]), + ok = erl_tar:add(Tar, DataDir, CopyDir, [compressed]), + ok = erl_tar:close(Tar), + ok = erl_tar:extract(TarFile, [compressed]), + ok = file:delete(TarFile), %% Compile source files in the copy directory. - ?line Sources = filelib:wildcard(fname([CopyDir,'*','*','*','*','*.erl'])), - ?line lists:foreach(fun compile_source/1, Sources), + Sources = filelib:wildcard(fname([CopyDir,'*','*','*','*','*.erl'])), + lists:foreach(fun compile_source/1, Sources), %% To use in end_per_testcase Path = code:get_path(), @@ -141,10 +146,13 @@ init_per_testcase(link_tar, Config) -> {win32, _} -> {skip, "Skip on windows"} end; init_per_testcase(_Case, Config) -> - ?line Dog = test_server:timetrap(?default_timeout), + Dog = test_server:timetrap(?default_timeout), [{watchdog, Dog}|Config]. -end_per_testcase(_Case, Config) -> +end_per_testcase(Case, Config) -> + try apply(?MODULE,Case,[cleanup,Config]) + catch error:undef -> ok + end, Dog=?config(watchdog, Config), test_server:timetrap_cancel(Dog), case {?config(path,Config),?config(cwd,Config)} of @@ -172,502 +180,502 @@ end_per_testcase(_Case, Config) -> %% -%% make_script -%% -script_options(suite) -> []; -script_options(doc) -> - ["Check illegal script options."]; +%% make_script: Check illegal script options script_options(Config) when is_list(Config) -> - ?line {'EXIT',{{badarg,[{path,["Path",12,"Another"]}]}, _}} = - (catch systools:make_script("release", [{path,["Path",12,"Another"]}])), - ?line {'EXIT',{{badarg,[sillent]}, _}} = + {'EXIT',{{badarg,[{path,["Path",12,"Another"]}]}, _}} = + (catch systools:make_script("release", [{path,["Path",12,"Another"]}])), + {'EXIT',{{badarg,[sillent]}, _}} = (catch systools:make_script("release", [{path,["Path","Another"]},sillent])), - ?line {'EXIT',{{badarg,[locall]}, _}} = + {'EXIT',{{badarg,[locall]}, _}} = (catch systools:make_script("release", [{path,["Path","Another"]},locall])), - ?line {'EXIT',{{badarg,[src_testsxx]}, _}} = + {'EXIT',{{badarg,[src_testsxx]}, _}} = (catch systools:make_script("release", [{path,["Path"]},src_testsxx])), - ?line {'EXIT',{{badarg,[{variables, {"TEST", "/home/lib"}}]}, _}} = + {'EXIT',{{badarg,[{variables, {"TEST", "/home/lib"}}]}, _}} = (catch systools:make_script("release", [{variables, {"TEST", "/home/lib"}}])), - ?line {'EXIT',{{badarg,[{variables, [{a, b}, {"a", "b"}]}]}, _}} = + {'EXIT',{{badarg,[{variables, [{a, b}, {"a", "b"}]}]}, _}} = (catch systools:make_script("release", [{variables, [{a, b}, {"a", "b"}]}])), - ?line {'EXIT',{{badarg,[exreff]}, _}} = + {'EXIT',{{badarg,[exreff]}, _}} = (catch systools:make_script("release", [{path,["Path","Another"]},exreff])), - ?line {'EXIT',{{badarg,[{exref,["appl"]}]}, _}} = + {'EXIT',{{badarg,[{exref,["appl"]}]}, _}} = (catch systools:make_script("release", [{exref,["appl"]}])), - ?line {'EXIT',{{badarg,[{machine, "appl"}]}, _}} = + {'EXIT',{{badarg,[{machine, "appl"}]}, _}} = (catch systools:make_script("release", [{machine,"appl"}])), ok. -%% make_script -%% -normal_script(suite) -> []; -normal_script(doc) -> - ["Check that make_script handles normal case."]; +%% make_script: Check that normal case normal_script(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), - ?line PSAVE = code:get_path(), % Save path + {ok, OldDir} = file:get_cwd(), + PSAVE = code:get_path(), % Save path - ?line {LatestDir, LatestName} = create_script(latest,Config), + {LatestDir, LatestName} = create_script(latest,Config), - ?line DataDir = filename:absname(?copydir), - ?line LibDir = fname([DataDir, d_normal, lib]), - ?line P1 = fname([LibDir, 'db-2.1', ebin]), - ?line P2 = fname([LibDir, 'fe-3.1', ebin]), + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + P1 = fname([LibDir, 'db-2.1', ebin]), + P2 = fname([LibDir, 'fe-3.1', ebin]), - ?line true = code:add_patha(P1), - ?line true = code:add_patha(P2), + true = code:add_patha(P1), + true = code:add_patha(P2), - ?line ok = file:set_cwd(LatestDir), + ok = file:set_cwd(LatestDir), - ?line ok = systools:make_script(filename:basename(LatestName)), - ?line {ok, _} = read_script_file(LatestName), % Check readabillity + ok = systools:make_script(filename:basename(LatestName)), + {ok, _} = read_script_file(LatestName), % Check readabillity %% Check the same but w. silent flag - ?line {ok, _, []} = systools:make_script(LatestName, [silent]), + {ok, _, []} = systools:make_script(LatestName, [silent]), %% Use the local option - ?line ok = systools:make_script(LatestName, [local]), - ?line ok = check_script_path(LatestName), + ok = systools:make_script(LatestName, [local]), + ok = check_script_path(LatestName), %% use the path option - ?line code:set_path(PSAVE), % Restore path + code:set_path(PSAVE), % Restore path %% Mess up std path: - ?line true = code:add_patha(fname([LibDir, 'db-1.0', ebin])), - ?line true = code:add_patha(fname([LibDir, 'fe-2.1', ebin])), + true = code:add_patha(fname([LibDir, 'db-1.0', ebin])), + true = code:add_patha(fname([LibDir, 'fe-2.1', ebin])), - ?line error = systools:make_script(LatestName), %should fail - ?line ok = systools:make_script(LatestName,[{path, [P1, P2]}]), + error = systools:make_script(LatestName), %should fail + ok = systools:make_script(LatestName,[{path, [P1, P2]}]), - ?line ok = file:set_cwd(OldDir), - ?line code:set_path(PSAVE), % Restore path + ok = file:set_cwd(OldDir), + code:set_path(PSAVE), % Restore path ok. -%% make_script -%% -no_mod_vsn_script(suite) -> []; -no_mod_vsn_script(doc) -> - ["Check that make_script handles normal case.", - "Modules specified without version in .app file (db-3.1)." - "Note that this is now the normal way - i.e. systools now " - "ignores the module versions in the .app file."]; +%% make_script: +%% Modules specified without version in .app file (db-3.1). +%% Note that this is now the normal way - i.e. systools now ignores +%% the module versions in the .app file. no_mod_vsn_script(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), - ?line PSAVE = code:get_path(), % Save path + {ok, OldDir} = file:get_cwd(), + PSAVE = code:get_path(), % Save path - ?line {LatestDir, LatestName} = create_script(latest_no_mod_vsn,Config), + {LatestDir, LatestName} = create_script(latest_no_mod_vsn,Config), - ?line DataDir = filename:absname(?copydir), - ?line LibDir = fname([DataDir, d_normal, lib]), - ?line P1 = fname([LibDir, 'db-3.1', ebin]), - ?line P2 = fname([LibDir, 'fe-3.1', ebin]), + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + P1 = fname([LibDir, 'db-3.1', ebin]), + P2 = fname([LibDir, 'fe-3.1', ebin]), - ?line true = code:add_patha(P1), - ?line true = code:add_patha(P2), + true = code:add_patha(P1), + true = code:add_patha(P2), - ?line ok = file:set_cwd(LatestDir), + ok = file:set_cwd(LatestDir), - ?line ok = systools:make_script(filename:basename(LatestName)), - ?line {ok, _} = read_script_file(LatestName), % Check readabillity + ok = systools:make_script(filename:basename(LatestName)), + {ok, _} = read_script_file(LatestName), % Check readabillity %% Check the same but w. silent flag - ?line {ok, _, []} = systools:make_script(LatestName, [silent]), + {ok, _, []} = systools:make_script(LatestName, [silent]), %% Use the local option - ?line ok = systools:make_script(LatestName, [local]), - ?line ok = check_script_path(LatestName), + ok = systools:make_script(LatestName, [local]), + ok = check_script_path(LatestName), %% use the path option - ?line code:set_path(PSAVE), % Restore path + code:set_path(PSAVE), % Restore path %% Mess up std path: - ?line true = code:add_patha(fname([LibDir, 'db-1.0', ebin])), - ?line true = code:add_patha(fname([LibDir, 'fe-2.1', ebin])), + true = code:add_patha(fname([LibDir, 'db-1.0', ebin])), + true = code:add_patha(fname([LibDir, 'fe-2.1', ebin])), - ?line error = systools:make_script(LatestName), %should fail - ?line ok = systools:make_script(LatestName, - [{path, [P1, P2]}]), + error = systools:make_script(LatestName), %should fail + ok = systools:make_script(LatestName, + [{path, [P1, P2]}]), - ?line ok = file:set_cwd(OldDir), - ?line code:set_path(PSAVE), % Restore path + ok = file:set_cwd(OldDir), + code:set_path(PSAVE), % Restore path ok. -%% make_script -%% -wildcard_script(suite) -> []; -wildcard_script(doc) -> - ["Check that make_script handles wildcards in path."]; +%% make_script: Check that make_script handles wildcards in path. wildcard_script(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), + {ok, OldDir} = file:get_cwd(), - ?line {LatestDir, LatestName} = create_script(latest,Config), + {LatestDir, LatestName} = create_script(latest,Config), - ?line DataDir = filename:absname(?copydir), - ?line LibDir = fname([DataDir, d_normal, lib]), - ?line WildDir = fname([LibDir, '*', ebin]), + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + WildDir = fname([LibDir, '*', ebin]), - ?line ok = file:set_cwd(LatestDir), + ok = file:set_cwd(LatestDir), - ?line error = systools:make_script(filename:basename(LatestName)), + error = systools:make_script(filename:basename(LatestName)), - ?line ok = systools:make_script(LatestName, - [{path, [WildDir]}]), + ok = systools:make_script(LatestName, + [{path, [WildDir]}]), - ?line {ok, _} = read_script_file(LatestName), % Check readabillity + {ok, _} = read_script_file(LatestName), % Check readabillity - ?line ok = file:set_cwd(OldDir), + ok = file:set_cwd(OldDir), ok. -%% make_script -%% -variable_script(suite) -> []; -variable_script(doc) -> - ["Add own installation dependent variable in script."]; +%% make_script: Add own installation dependent variable in script. variable_script(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), + {ok, OldDir} = file:get_cwd(), - ?line {LatestDir, LatestName} = create_script(latest,Config), + {LatestDir, LatestName} = create_script(latest,Config), - ?line DataDir = filename:absname(?copydir), - ?line LibDir = fname([DataDir, d_normal, lib]), - ?line P = [fname([LibDir, 'db-2.1', ebin]), - fname([LibDir, 'fe-3.1', ebin])], + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + P = [fname([LibDir, 'db-2.1', ebin]), + fname([LibDir, 'fe-3.1', ebin])], - ?line ok = file:set_cwd(LatestDir), + ok = file:set_cwd(LatestDir), - ?line ok = systools:make_script(LatestName, - [{path, P}, - {variables, [{"TEST", LibDir}]}]), + ok = systools:make_script(LatestName, + [{path, P}, + {variables, [{"TEST", LibDir}]}]), %% Check variables - ?line ok = check_var_script_file([fname(['$TEST', 'db-2.1', ebin]), - fname(['$TEST', 'fe-3.1', ebin])], - P, - LatestName), + ok = check_var_script_file([fname(['$TEST', 'db-2.1', ebin]), + fname(['$TEST', 'fe-3.1', ebin])], + P, + LatestName), - ?line ok = file:set_cwd(OldDir), + ok = file:set_cwd(OldDir), ok. -%% make_script -%% -abnormal_script(suite) -> []; -abnormal_script(doc) -> - ["Abnormal cases."]; +%% make_script: Abnormal cases. abnormal_script(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), + {ok, OldDir} = file:get_cwd(), - ?line {LatestDir, LatestName} = create_script(latest,Config), + {LatestDir, LatestName} = create_script(latest,Config), - ?line DataDir = filename:absname(?copydir), + DataDir = filename:absname(?copydir), - ?line ok = file:set_cwd(LatestDir), - ?line LibDir = fname([DataDir, d_bad_app_vsn, lib]), - ?line P = [fname([LibDir, 'db-2.1', ebin]), - fname([LibDir, 'fe-3.1', ebin])], + ok = file:set_cwd(LatestDir), + LibDir = fname([DataDir, d_bad_app_vsn, lib]), + P = [fname([LibDir, 'db-2.1', ebin]), + fname([LibDir, 'fe-3.1', ebin])], %% Check wrong app vsn - ?line error = systools:make_script(LatestName, [{path, P}]), - ?line {error, - systools_make, - [{error_reading, {db, {no_valid_version, - {{"should be","2.1"}, - {"found file", _, "2.0"}}}}}]} = + error = systools:make_script(LatestName, [{path, P}]), + {error, + systools_make, + [{error_reading, {db, {no_valid_version, + {{"should be","2.1"}, + {"found file", _, "2.0"}}}}}]} = systools:make_script(LatestName, [silent, {path, P}]), - ?line ok = file:set_cwd(OldDir), + ok = file:set_cwd(OldDir), ok. -%% make_script -%% -src_tests_script(suite) -> []; -src_tests_script(doc) -> - ["Do not check date of object file or that source code can be found."]; +%% make_script: Create script without sasl appl. Check warning. +no_sasl_script(Config) when is_list(Config) -> + {ok, OldDir} = file:get_cwd(), + + {LatestDir, LatestName} = create_script(latest1_no_sasl,Config), + + DataDir = filename:absname(?copydir), + LibDir = [fname([DataDir, d_normal, lib])], + P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + ok = file:set_cwd(LatestDir), + + {ok, _ , [{warning,missing_sasl}]} = + systools:make_script(LatestName,[{path, P},silent]), + + {ok, _ , []} = + systools:make_script(LatestName,[{path, P},silent, no_warn_sasl]), + + ok = file:set_cwd(OldDir), + ok. + + +%% make_script: Do not check date of object file or that source code +%% can be found. src_tests_script(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), - ?line PSAVE = code:get_path(), % Save path + {ok, OldDir} = file:get_cwd(), + PSAVE = code:get_path(), % Save path - ?line {LatestDir, LatestName} = create_script(latest,Config), - ?line BootFile = LatestName ++ ".boot", + {LatestDir, LatestName} = create_script(latest,Config), + BootFile = LatestName ++ ".boot", - ?line DataDir = filename:absname(?copydir), - ?line LibDir = fname([DataDir, d_missing_src, lib]), - ?line P1 = fname([LibDir, 'db-2.1', ebin]), - ?line P2 = fname([LibDir, 'fe-3.1', ebin]), + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_missing_src, lib]), + P1 = fname([LibDir, 'db-2.1', ebin]), + P2 = fname([LibDir, 'fe-3.1', ebin]), N = [P1, P2], - ?line ok = file:set_cwd(LatestDir), + ok = file:set_cwd(LatestDir), %% Manipulate the modification date of a beam file so it seems %% older than its .erl file - ?line Erl = filename:join([P1,"..","src","db1.erl"]), - ?line {ok, FileInfo=#file_info{mtime={{Y,M,D},T}}} = file:read_file_info(Erl), - ?line Beam = filename:join(P1,"db1.beam"), - ?line ok=file:write_file_info(Beam, FileInfo#file_info{mtime={{Y-1,M,D},T}}), + Erl = filename:join([P1,"..","src","db1.erl"]), + {ok, FileInfo=#file_info{mtime={{Y,M,D},T}}} = file:read_file_info(Erl), + Beam = filename:join(P1,"db1.beam"), + ok=file:write_file_info(Beam, FileInfo#file_info{mtime={{Y-1,M,D},T}}), %% Remove a .erl file - ?line Erl2 = filename:join([P1,"..","src","db2.erl"]), - ?line file:delete(Erl2), + Erl2 = filename:join([P1,"..","src","db2.erl"]), + file:delete(Erl2), %% Then make script %% .boot file should not exist - ?line ok = file:delete(BootFile), - ?line false = filelib:is_regular(BootFile), + ok = file:delete(BootFile), + false = filelib:is_regular(BootFile), %% With warnings_as_errors and src_tests option, an error should be issued - ?line error = + error = systools:make_script(LatestName, [silent, {path, N}, src_tests, warnings_as_errors]), - ?line error = + error = systools:make_script(LatestName, [{path, N}, src_tests, warnings_as_errors]), %% due to warnings_as_errors .boot file should still not exist - ?line false = filelib:is_regular(BootFile), + false = filelib:is_regular(BootFile), %% Two warnings should be issued when src_tests is given %% 1. old object code for db1.beam %% 2. missing source code for db2.beam - ?line {ok, _, [{warning,{obj_out_of_date,_}}, - {warning,{source_not_found,_}}]} = + {ok, _, [{warning,{obj_out_of_date,_}}, + {warning,{source_not_found,_}}]} = systools:make_script(LatestName, [silent, {path, N}, src_tests]), %% .boot file should exist now - ?line true = filelib:is_regular(BootFile), + true = filelib:is_regular(BootFile), %% Without the src_tests option, no warning should be issued - ?line {ok, _, []} = + {ok, _, []} = systools:make_script(LatestName, [silent, {path, N}]), %% Check that the old no_module_tests option (from the time when %% it was default to do the src_test) is ignored - ?line {ok, _, [{warning,{obj_out_of_date,_}}, - {warning,{source_not_found,_}}]} = + {ok, _, [{warning,{obj_out_of_date,_}}, + {warning,{source_not_found,_}}]} = systools:make_script(LatestName, [silent, {path, N}, no_module_tests, src_tests]), - ?line ok = file:set_cwd(OldDir), - ?line code:set_path(PSAVE), + ok = file:set_cwd(OldDir), + code:set_path(PSAVE), ok. -%% make_script -%% -warn_shadow_script(suite) -> []; -warn_shadow_script(doc) -> - ["Check that jam file out of date warning doesn't", - "shadow bad module version error."]; -warn_shadow_script(Config) when is_list(Config) -> - %% This test has been removed since the 'vsn' attribute is - %% not used any more, starting with R6. No warning - %% 'obj_out_of_date' seemed to be generated. - true. - - -%% make_script -%% -crazy_script(suite) -> []; -crazy_script(doc) -> - ["Do the crazy cases."]; +%% make_script: Do the crazy cases. crazy_script(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), + {ok, OldDir} = file:get_cwd(), - ?line {LatestDir, LatestName} = create_script(latest, Config), + {LatestDir, LatestName} = create_script(latest, Config), - ?line DataDir = filename:absname(?copydir), - ?line LibDir = fname([DataDir, d_normal, lib]), - ?line P = [fname([LibDir, 'db-2.1', ebin]), - fname([LibDir, 'fe-3.1', ebin])], + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + P = [fname([LibDir, 'db-2.1', ebin]), + fname([LibDir, 'fe-3.1', ebin])], - ?line ok = file:set_cwd(LatestDir), + ok = file:set_cwd(LatestDir), %% Run with bad path - ?line error = systools:make_script(LatestName), - ?line {error, _, [{error_reading, _}, {error_reading, _}]} = + error = systools:make_script(LatestName), + {error, _, [{error_reading, _}, {error_reading, _}]} = systools:make_script(LatestName, [silent]), %% Run with .rel file lacking kernel - ?line {LatestDir2, LatestName2} = create_script(latest_nokernel, Config), - ?line ok = file:set_cwd(LatestDir2), + {LatestDir2, LatestName2} = create_script(latest_nokernel, Config), + ok = file:set_cwd(LatestDir2), - ?line error = systools:make_script(LatestName2), - ?line {error, _, {missing_mandatory_app,[kernel,stdlib]}} = + error = systools:make_script(LatestName2), + {error, _, {missing_mandatory_app,kernel}} = systools:make_script(LatestName2, [silent,{path,P}]), - ?line ok = file:set_cwd(OldDir), + %% Run with .rel file with non-permanent kernel + {LatestDir3, LatestName3} = create_script(latest_kernel_start_type, Config), + ok = file:set_cwd(LatestDir3), + + error = systools:make_script(LatestName3), + {error, _, {mandatory_app,kernel,load}} = + systools:make_script(LatestName3, [silent,{path,P}]), + + %% Run with .rel file with non-permanent stdlib + {LatestDir4, LatestName4} = create_script(latest_stdlib_start_type, Config), + ok = file:set_cwd(LatestDir4), + + error = systools:make_script(LatestName4), + {error, _, {mandatory_app,stdlib,load}} = + systools:make_script(LatestName4, [silent,{path,P}]), + + %% Run with .rel file lacking stdlib + {LatestDir5, LatestName5} = create_script(latest_no_stdlib, Config), + ok = file:set_cwd(LatestDir5), + + error = systools:make_script(LatestName5), + {error, _, {missing_mandatory_app,stdlib}} = + systools:make_script(LatestName5, [silent,{path,P}]), + + ok = file:set_cwd(OldDir), ok. -%% make_script -%% -included_script(suite) -> []; -included_script(doc) -> - ["Check that make_script handles generation of script", - "for applications with included applications."]; +%% make_script: Check that make_script handles generation of script +%% for applications with included applications. included_script(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), - ?line {LatestDir, LatestName} = create_include_files(inc1, Config), - ?line ok = file:set_cwd(LatestDir), - ?line ok = systools:make_script(LatestName), - ?line ok = check_include_script(LatestName, - [t1, t2, t3, t5, t4, t6], - [t1, t3, t6]), - ?line ok = file:set_cwd(OldDir), + {ok, OldDir} = file:get_cwd(), + {LatestDir, LatestName} = create_include_files(inc1, Config), + ok = file:set_cwd(LatestDir), + ok = systools:make_script(LatestName), + ok = check_include_script(LatestName, + [t1, t2, t3, t5, t4, t6], + [t1, t3, t6]), + ok = file:set_cwd(OldDir), ok. -%% make_script -%% -included_override_script(suite) -> []; -included_override_script(doc) -> - ["Check that make_script handles generation of script", - "for applications with included applications which are override by", - "the .rel file."]; +%% make_script: Check that make_script handles generation of script +%% for applications with included applications which are override by +%% the .rel file. included_override_script(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), - ?line {LatestDir, LatestName} = create_include_files(inc2, Config), - ?line ok = file:set_cwd(LatestDir), - ?line ok = systools:make_script(LatestName), - ?line ok = check_include_script(LatestName, - [t1, t2, t3, t4, t6, t5], - [t1, t3, t6, t5]), - - ?line {_, LatestName1} = create_include_files(inc3, Config), - ?line ok = systools:make_script(LatestName1), - ?line ok = check_include_script(LatestName1, - [t3, t5, t4, t6, t1, t2], - [t3, t6, t1, t2]), - - ?line {_, LatestName2} = create_include_files(inc4, Config), - ?line ok = systools:make_script(LatestName2), - ?line ok = check_include_script(LatestName2, - [t3, t4, t6, t5, t1, t2], - [t3, t6, t5, t1, t2]), - - ?line {_, LatestName3} = create_include_files(inc5, Config), - ?line ok = systools:make_script(LatestName3), - ?line ok = check_include_script(LatestName3, - [t3, t4, t6, t1, t2], - [t3, t6, t1, t2]), - - ?line ok = file:set_cwd(OldDir), + {ok, OldDir} = file:get_cwd(), + {LatestDir, LatestName} = create_include_files(inc2, Config), + ok = file:set_cwd(LatestDir), + ok = systools:make_script(LatestName), + ok = check_include_script(LatestName, + [t1, t2, t3, t4, t6, t5], + [t1, t3, t6, t5]), + + {_, LatestName1} = create_include_files(inc3, Config), + ok = systools:make_script(LatestName1), + ok = check_include_script(LatestName1, + [t3, t5, t4, t6, t1, t2], + [t3, t6, t1, t2]), + + {_, LatestName2} = create_include_files(inc4, Config), + ok = systools:make_script(LatestName2), + ok = check_include_script(LatestName2, + [t3, t4, t6, t5, t1, t2], + [t3, t6, t5, t1, t2]), + + {_, LatestName3} = create_include_files(inc5, Config), + ok = systools:make_script(LatestName3), + ok = check_include_script(LatestName3, + [t3, t4, t6, t1, t2], + [t3, t6, t1, t2]), + + ok = file:set_cwd(OldDir), ok. -%% make_script -%% -included_fail_script(suite) -> []; -included_fail_script(doc) -> - ["Check that make_script handles errors then generating", - "script with included applications."]; +%% make_script: Check that make_script handles errors then generating +%% script with included applications. included_fail_script(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), - ?line {LatestDir, LatestName} = create_include_files(inc6, Config), - ?line ok = file:set_cwd(LatestDir), - ?line {error, _, {undefined_applications,[t2]}} = + {ok, OldDir} = file:get_cwd(), + {LatestDir, LatestName} = create_include_files(inc6, Config), + ok = file:set_cwd(LatestDir), + {error, _, {undefined_applications,[t2]}} = systools:make_script(LatestName, [silent]), - ?line {_, LatestName1} = create_include_files(inc7, Config), - ?line {error, _, {duplicate_include,[{{t5,t7,_,_},{t5,t6,_,_}}]}} = + {_, LatestName1} = create_include_files(inc7, Config), + {error, _, {duplicate_include,[{{t5,t7,_,_},{t5,t6,_,_}}]}} = systools:make_script(LatestName1, [silent]), - ?line {_, LatestName3} = create_include_files(inc9, Config), - ?line {error, _, {circular_dependencies,[{t10,_},{t8,_}]}} = + {_, LatestName3} = create_include_files(inc9, Config), + {error, _, {circular_dependencies,[{t10,_},{t8,_}]}} = systools:make_script(LatestName3, [silent]), - ?line {_, LatestName4} = create_include_files(inc10, Config), - ?line {error, _, [{error_reading,{t9,{override_include,[t7]}}}]} = + {_, LatestName4} = create_include_files(inc10, Config), + {error, _, [{error_reading,{t9,{override_include,[t7]}}}]} = systools:make_script(LatestName4, [silent]), - ?line ok = file:set_cwd(OldDir), + ok = file:set_cwd(OldDir), ok. -%% make_script -%% -included_bug_script(suite) -> []; -included_bug_script(doc) -> - ["Check that make_script handles generation of script", - "with difficult dependency for included applications."]; +%% make_script: Check that make_script handles generation of script +%% with difficult dependency for included applications. included_bug_script(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), - ?line {LatestDir, LatestName} = create_include_files(inc11, Config), - ?line ok = file:set_cwd(LatestDir), - ?line ok = systools:make_script(LatestName), - ?line ok = check_include_script(LatestName, - [t13, t11, t12], - [t11, t12]), - ?line ok = file:set_cwd(OldDir), + {ok, OldDir} = file:get_cwd(), + {LatestDir, LatestName} = create_include_files(inc11, Config), + ok = file:set_cwd(LatestDir), + ok = systools:make_script(LatestName), + ok = check_include_script(LatestName, + [t13, t11, t12], + [t11, t12]), + ok = file:set_cwd(OldDir), ok. -%% make_script -%% -otp_3065(suite) -> []; -otp_3065(doc) -> - ["Circular dependencies in systools:make_script()."]; -otp_3065(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), - ?line {LatestDir, LatestName} = create_include_files(otp_3065, Config), - ?line ok = file:set_cwd(LatestDir), - ?line ok = systools:make_script(LatestName), - ?line ok = check_include_script(LatestName, - [aa12, chAts, chTraffic], - [chTraffic]), - ?line ok = file:set_cwd(OldDir), +%% make_script: Circular dependencies in systools:make_script(). +otp_3065_circular_dependenies(Config) when is_list(Config) -> + {ok, OldDir} = file:get_cwd(), + {LatestDir, LatestName} = + create_include_files(otp_3065_circular_dependenies, Config), + ok = file:set_cwd(LatestDir), + ok = systools:make_script(LatestName), + ok = check_include_script(LatestName, + [aa12, chAts, chTraffic], + [chTraffic]), + ok = file:set_cwd(OldDir), ok. +%% Test sorting of included applications and used applications +included_and_used_sort_script(Config) when is_list(Config) -> + {ok, OldDir} = file:get_cwd(), + {LatestDir1, LatestName1} = create_include_files(sort_apps, Config), + ok = file:set_cwd(LatestDir1), + ok = systools:make_script(LatestName1), + ok = check_include_script(LatestName1, + [t20,t19,t18,t17,t16,t15,t14],[t20,t19,t18,t14]), + + {LatestDir2, LatestName2} = create_include_files(sort_apps_rev, Config), + ok = file:set_cwd(LatestDir2), + ok = systools:make_script(LatestName2), + ok = check_include_script(LatestName2, + [t18,t19,t20,t15,t16,t17,t14],[t18,t19,t20,t14]), + + ok = file:set_cwd(OldDir), + ok. -%% make_script -%% -exref_script(suite) -> []; -exref_script(doc) -> - ["Check that make_script exref option works."]; + +%% make_script: Check that make_script exref option works. exref_script(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), - ?line PSAVE = code:get_path(), % Save path + {ok, OldDir} = file:get_cwd(), + PSAVE = code:get_path(), % Save path - ?line {LatestDir, LatestName} = create_script(latest,Config), + {LatestDir, LatestName} = create_script(latest,Config), - ?line DataDir = filename:absname(?copydir), - ?line LibDir = fname([DataDir, d_normal, lib]), - ?line P = [fname([LibDir, 'db-2.1', ebin]), - fname([LibDir, 'fe-3.1', ebin])], + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + P = [fname([LibDir, 'db-2.1', ebin]), + fname([LibDir, 'fe-3.1', ebin])], - ?line ok = file:set_cwd(LatestDir), + ok = file:set_cwd(LatestDir), - ?line {ok, _, _} = systools:make_script(LatestName, [{path,P}, silent]), + {ok, _, _} = systools:make_script(LatestName, [{path,P}, silent]), %% Complete exref - ?line {ok, _, W1} = + {ok, _, W1} = systools:make_script(LatestName, [exref, {path,P}, silent]), - ?line check_exref_warnings(with_db1, W1), - ?line {ok, _} = read_script_file(LatestName), % Check readabillity + check_exref_warnings(with_db1, W1), + {ok, _} = read_script_file(LatestName), % Check readabillity %% Only exref the db application. - ?line {ok, _, W2} = + {ok, _, W2} = systools:make_script(LatestName, [{exref,[db]}, {path,P}, silent]), - ?line check_exref_warnings(with_db1, W2), - ?line {ok, _} = read_script_file(LatestName), % Check readabillity + check_exref_warnings(with_db1, W2), + {ok, _} = read_script_file(LatestName), % Check readabillity %% Only exref the fe application. - ?line {ok, _, W3} = + {ok, _, W3} = systools:make_script(LatestName, [{exref,[fe]}, {path,P}, silent]), - ?line check_exref_warnings(without_db1, W3), - ?line {ok, _} = read_script_file(LatestName), % Check readabillity + check_exref_warnings(without_db1, W3), + {ok, _} = read_script_file(LatestName), % Check readabillity %% exref the db and stdlib applications. - ?line {ok, _, W4} = + {ok, _, W4} = systools:make_script(LatestName, [{exref,[db,stdlib]}, {path,P}, silent]), - ?line check_exref_warnings(with_db1, W4), - ?line {ok, _} = read_script_file(LatestName), % Check readabillity - ?line ok = file:set_cwd(OldDir), - ?line code:set_path(PSAVE), % Restore path + check_exref_warnings(with_db1, W4), + {ok, _} = read_script_file(LatestName), % Check readabillity + ok = file:set_cwd(OldDir), + code:set_path(PSAVE), % Restore path ok. check_exref_warnings(with_db1, W) -> @@ -697,11 +705,11 @@ filter({ok, W}) -> {ok, filter(W)}; filter(L) -> lists:filter(fun%({hipe_consttab,_,_}) -> false; - ({int,_,_}) -> false; - ({i,_,_}) -> false; - ({crypto,_,_}) -> false; - (_) -> true - end, + ({int,_,_}) -> false; + ({i,_,_}) -> false; + ({crypto,_,_}) -> false; + (_) -> true + end, L). get_exref1(T, [{warning, {T, Value}}|_]) -> {ok, Value}; @@ -721,197 +729,268 @@ no_hipe({ok, Value}) -> {ok, Value} end. -%% tar_options -%% -tar_options(suite) -> []; -tar_options(doc) -> - ["Check illegal tar options."]; +%% tar_options: Check illegal tar options. tar_options(Config) when is_list(Config) -> - ?line {'EXIT',{{badarg,[{path,["Path",12,"Another"]}]}, _}} = + {'EXIT',{{badarg,[{path,["Path",12,"Another"]}]}, _}} = (catch systools:make_tar("release", [{path,["Path",12,"Another"]}])), - ?line {'EXIT',{{badarg,[sillent]}, _}} = + {'EXIT',{{badarg,[sillent]}, _}} = (catch systools:make_tar("release", [{path,["Path","Another"]},sillent])), - ?line {'EXIT',{{badarg,[{dirs,["dirs"]}]}, _}} = + {'EXIT',{{badarg,[{dirs,["dirs"]}]}, _}} = (catch systools:make_tar("release", [{dirs, ["dirs"]}])), - ?line {'EXIT',{{badarg,[{erts, illegal}]}, _}} = + {'EXIT',{{badarg,[{erts, illegal}]}, _}} = (catch systools:make_tar("release", [{erts, illegal}])), - ?line {'EXIT',{{badarg,[src_testsxx]}, _}} = + {'EXIT',{{badarg,[src_testsxx]}, _}} = (catch systools:make_tar("release", [{path,["Path"]},src_testsxx])), - ?line {'EXIT',{{badarg,[{variables, [{a, b}, {"a", "b"}]}]}, _}} = + {'EXIT',{{badarg,[{variables, [{a, b}, {"a", "b"}]}]}, _}} = (catch systools:make_tar("release", [{variables, [{a, b}, {"a", "b"}]}])), - ?line {'EXIT',{{badarg,[{var_tar, illegal}]}, _}} = + {'EXIT',{{badarg,[{var_tar, illegal}]}, _}} = (catch systools:make_tar("release", [{var_tar, illegal}])), - ?line {'EXIT',{{badarg,[exreff]}, _}} = + {'EXIT',{{badarg,[exreff]}, _}} = (catch systools:make_tar("release", [{path,["Path","Another"]},exreff])), - ?line {'EXIT',{{badarg,[{exref,["appl"]}]}, _}} = + {'EXIT',{{badarg,[{exref,["appl"]}]}, _}} = (catch systools:make_tar("release", [{exref,["appl"]}])), - ?line {'EXIT',{{badarg,[{machine, "appl"}]}, _}} = + {'EXIT',{{badarg,[{machine, "appl"}]}, _}} = (catch systools:make_tar("release", [{machine,"appl"}])), ok. -%% normal_tar -%% -normal_tar(suite) -> []; -normal_tar(doc) -> - ["Check normal case"]; +%% make_tar: Check normal case normal_tar(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), + {ok, OldDir} = file:get_cwd(), - ?line {LatestDir, LatestName} = create_script(latest,Config), + {LatestDir, LatestName} = create_script(latest,Config), - ?line DataDir = filename:absname(?copydir), - ?line LibDir = fname([DataDir, d_normal, lib]), - ?line P = [fname([LibDir, 'db-2.1', ebin]), - fname([LibDir, 'fe-3.1', ebin])], + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + P = [fname([LibDir, 'db-2.1', ebin]), + fname([LibDir, 'fe-3.1', ebin])], - ?line ok = file:set_cwd(LatestDir), + ok = file:set_cwd(LatestDir), - ?line {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]), - ?line ok = systools:make_tar(LatestName, [{path, P}]), - ?line ok = check_tar(fname([lib,'db-2.1',ebin,'db.app']), LatestName), - ?line {ok, _, _} = systools:make_tar(LatestName, [{path, P}, silent]), - ?line ok = check_tar(fname([lib,'fe-3.1',ebin,'fe.app']), LatestName), + {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]), + ok = systools:make_tar(LatestName, [{path, P}]), + ok = check_tar(fname([lib,'db-2.1',ebin,'db.app']), LatestName), + {ok, _, _} = systools:make_tar(LatestName, [{path, P}, silent]), + ok = check_tar(fname([lib,'fe-3.1',ebin,'fe.app']), LatestName), - ?line ok = file:set_cwd(OldDir), + ok = file:set_cwd(OldDir), ok. -%% no_mod_vsn_tar -%% -no_mod_vsn_tar(suite) -> []; -no_mod_vsn_tar(doc) -> - ["Check normal case", - "Modules specified without version in .app file (db-3.1)." - "Note that this is now the normal way - i.e. systools now " - "ignores the module versions in the .app file."]; +%% make_tar: Modules specified without version in .app file (db-3.1). +%% Note that this is now the normal way - i.e. systools now ignores +%% the module versions in the .app file. no_mod_vsn_tar(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), + {ok, OldDir} = file:get_cwd(), - ?line {LatestDir, LatestName} = create_script(latest_no_mod_vsn,Config), + {LatestDir, LatestName} = create_script(latest_no_mod_vsn,Config), - ?line DataDir = filename:absname(?copydir), - ?line LibDir = fname([DataDir, d_normal, lib]), - ?line P = [fname([LibDir, 'db-3.1', ebin]), - fname([LibDir, 'fe-3.1', ebin])], + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + P = [fname([LibDir, 'db-3.1', ebin]), + fname([LibDir, 'fe-3.1', ebin])], - ?line ok = file:set_cwd(LatestDir), + ok = file:set_cwd(LatestDir), - ?line {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]), - ?line ok = systools:make_tar(LatestName, [{path, P}]), - ?line ok = check_tar(fname([lib,'db-3.1',ebin,'db.app']), LatestName), - ?line {ok, _, _} = systools:make_tar(LatestName, [{path, P}, silent]), - ?line ok = check_tar(fname([lib,'fe-3.1',ebin,'fe.app']), LatestName), + {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]), + ok = systools:make_tar(LatestName, [{path, P}]), + ok = check_tar(fname([lib,'db-3.1',ebin,'db.app']), LatestName), + {ok, _, _} = systools:make_tar(LatestName, [{path, P}, silent]), + ok = check_tar(fname([lib,'fe-3.1',ebin,'fe.app']), LatestName), - ?line ok = file:set_cwd(OldDir), + ok = file:set_cwd(OldDir), ok. -%% variable_tar -%% -variable_tar(suite) -> []; -variable_tar(doc) -> - ["Use variable and create separate tar (included in generated tar)."]; + +%% make_tar: Check that relup or sys.config are included if they exist +system_files_tar(Config) -> + {ok, OldDir} = file:get_cwd(), + + {LatestDir, LatestName} = create_script(latest,Config), + + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + P = [fname([LibDir, 'db-2.1', ebin]), + fname([LibDir, 'fe-3.1', ebin])], + + ok = file:set_cwd(LatestDir), + + %% Add dummy relup and sys.config + ok = file:write_file("sys.config","[].\n"), + ok = file:write_file("relup","{\"LATEST\",[],[]}.\n"), + + {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]), + ok = systools:make_tar(LatestName, [{path, P}]), + ok = check_tar(fname(["releases","LATEST","sys.config"]), LatestName), + ok = check_tar(fname(["releases","LATEST","relup"]), LatestName), + {ok, _, _} = systools:make_tar(LatestName, [{path, P}, silent]), + ok = check_tar(fname(["releases","LATEST","sys.config"]), LatestName), + ok = check_tar(fname(["releases","LATEST","relup"]), LatestName), + + ok = file:set_cwd(OldDir), + + ok. + +system_files_tar(cleanup,Config) -> + Dir = ?privdir, + file:delete(filename:join(Dir,"sys.config")), + file:delete(filename:join(Dir,"relup")), + ok. + + +%% make_tar: Check that make_tar fails if relup or sys.config exist +%% but do not have valid content +invalid_system_files_tar(Config) -> + {ok, OldDir} = file:get_cwd(), + + {LatestDir, LatestName} = create_script(latest,Config), + + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + P = [fname([LibDir, 'db-2.1', ebin]), + fname([LibDir, 'fe-3.1', ebin])], + + ok = file:set_cwd(LatestDir), + + {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]), + + %% Add dummy relup and sys.config - faulty sys.config + ok = file:write_file("sys.config","[]\n"), %!!! syntax error - missing '.' + ok = file:write_file("relup","{\"LATEST\",[],[]}.\n"), + + error = systools:make_tar(LatestName, [{path, P}]), + {error,_,{tar_error,{add,"sys.config",[{error,_}]}}} = + systools:make_tar(LatestName, [{path, P}, silent]), + + %% Add dummy relup and sys.config - faulty sys.config + ok = file:write_file("sys.config","[x,y].\n"), %!!! faulty format + ok = file:write_file("relup","{\"LATEST\",[],[]}.\n"), + + error = systools:make_tar(LatestName, [{path, P}]), + {error,_,{tar_error,{add,"sys.config",[invalid_format]}}} = + systools:make_tar(LatestName, [{path, P}, silent]), + + %% Add dummy relup and sys.config - faulty relup + ok = file:write_file("sys.config","[]\n"), + ok = file:write_file("relup","{\"LATEST\"\n"), %!!! syntax error - truncated + + error = systools:make_tar(LatestName, [{path, P}]), + {error,_,{tar_error,{add,"relup",[{error,_}]}}} = + systools:make_tar(LatestName, [{path, P}, silent]), + + %% Add dummy relup and sys.config - faulty relup + ok = file:write_file("sys.config","[]\n"), + ok = file:write_file("relup","[].\n"), %!!! faulty format + + error = systools:make_tar(LatestName, [{path, P}]), + {error,_,{tar_error,{add,"relup",[invalid_format]}}} = + systools:make_tar(LatestName, [{path, P}, silent]), + + ok = file:set_cwd(OldDir), + + ok. + +invalid_system_files_tar(cleanup,Config) -> + Dir = ?privdir, + file:delete(filename:join(Dir,"sys.config")), + file:delete(filename:join(Dir,"relup")), + ok. + + +%% make_tar: Use variable and create separate tar (included in generated tar). variable_tar(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), + {ok, OldDir} = file:get_cwd(), - ?line {LatestDir, LatestName} = create_script(latest,Config), + {LatestDir, LatestName} = create_script(latest,Config), - ?line DataDir = filename:absname(?copydir), - ?line LibDir = fname([DataDir, d_normal, lib]), - ?line P = [fname([LibDir, 'db-2.1', ebin]), - fname([LibDir, 'fe-3.1', ebin])], + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + P = [fname([LibDir, 'db-2.1', ebin]), + fname([LibDir, 'fe-3.1', ebin])], - ?line ok = file:set_cwd(LatestDir), + ok = file:set_cwd(LatestDir), - ?line {ok, _, _} = systools:make_script(LatestName, - [silent, - {path, P}, - {variables,[{"TEST", LibDir}]}]), + {ok, _, _} = systools:make_script(LatestName, + [silent, + {path, P}, + {variables,[{"TEST", LibDir}]}]), - ?line ok = systools:make_tar(LatestName, [{path, P}, - {variables,[{"TEST", LibDir}]}]), - ?line ok = check_var_tar("TEST", LatestName), + ok = systools:make_tar(LatestName, [{path, P}, + {variables,[{"TEST", LibDir}]}]), + ok = check_var_tar("TEST", LatestName), - ?line {ok, _, _} = systools:make_tar(LatestName, - [{path, P}, silent, - {variables,[{"TEST", LibDir}]}]), - ?line ok = check_var_tar("TEST", LatestName), + {ok, _, _} = systools:make_tar(LatestName, + [{path, P}, silent, + {variables,[{"TEST", LibDir}]}]), + ok = check_var_tar("TEST", LatestName), - ?line ok = file:set_cwd(OldDir), + ok = file:set_cwd(OldDir), ok. -%% link_tar -%% -link_tar(suite) -> []; -link_tar(doc) -> - ["Check that symlinks in applications are handled correctly"]; +%% make_tar: Check that symlinks in applications are handled correctly. link_tar(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), + {ok, OldDir} = file:get_cwd(), - ?line {LatestDir, LatestName} = create_script(latest,Config), + {LatestDir, LatestName} = create_script(latest,Config), - ?line DataDir = filename:absname(?copydir), - ?line LibDir = fname([DataDir, d_links, lib]), - ?line P = [fname([LibDir, 'db-2.1', ebin]), - fname([LibDir, 'fe-3.1', ebin])], + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_links, lib]), + P = [fname([LibDir, 'db-2.1', ebin]), + fname([LibDir, 'fe-3.1', ebin])], %% Make some links - ?line Db1Erl = fname(['db-2.1',src,'db1.erl']), - ?line NormalDb1Erl = fname([DataDir,d_normal,lib,Db1Erl]), - ?line LinkDb1Erl = fname([LibDir, Db1Erl]), - ?line ok = file:make_symlink(NormalDb1Erl, LinkDb1Erl), - ?line Db1Beam = fname(['db-2.1',ebin,'db1.beam']), - ?line NormalDb1Beam = fname([DataDir,d_normal,lib,Db1Beam]), - ?line LinkDb1Beam = fname([LibDir, Db1Beam]), - ?line ok = file:make_symlink(NormalDb1Beam, LinkDb1Beam), - ?line FeApp = fname(['fe-3.1',ebin,'fe.app']), - ?line NormalFeApp = fname([DataDir,d_normal,lib,FeApp]), - ?line LinkFeApp = fname([LibDir, FeApp]), - ?line ok = file:make_symlink(NormalFeApp, LinkFeApp), - + Db1Erl = fname(['db-2.1',src,'db1.erl']), + NormalDb1Erl = fname([DataDir,d_normal,lib,Db1Erl]), + LinkDb1Erl = fname([LibDir, Db1Erl]), + ok = file:make_symlink(NormalDb1Erl, LinkDb1Erl), + Db1Beam = fname(['db-2.1',ebin,'db1.beam']), + NormalDb1Beam = fname([DataDir,d_normal,lib,Db1Beam]), + LinkDb1Beam = fname([LibDir, Db1Beam]), + ok = file:make_symlink(NormalDb1Beam, LinkDb1Beam), + FeApp = fname(['fe-3.1',ebin,'fe.app']), + NormalFeApp = fname([DataDir,d_normal,lib,FeApp]), + LinkFeApp = fname([LibDir, FeApp]), + ok = file:make_symlink(NormalFeApp, LinkFeApp), + %% Create the tar and check that the linked files are included as %% regular files - ?line ok = file:set_cwd(LatestDir), - - ?line {ok,_,[]} = systools:make_script(LatestName, [{path, P},silent]), - - ?line {ok, _, []} = systools:make_tar(LatestName, [{path, P}, silent]), - ?line ok = check_tar_regular(?privdir, - [fname([lib,FeApp]), - fname([lib,Db1Beam])], - LatestName), - - ?line {ok, _, []} = systools:make_tar(LatestName, [{path, P}, silent, - {dirs, [src]}]), - ?line ok = check_tar_regular(?privdir, - [fname([lib,FeApp]), - fname([lib,Db1Beam]), - fname([lib,Db1Erl])], - LatestName), - - ?line ok = file:set_cwd(OldDir), + ok = file:set_cwd(LatestDir), + + {ok,_,[]} = systools:make_script(LatestName, [{path, P},silent]), + + {ok, _, []} = systools:make_tar(LatestName, [{path, P}, silent]), + ok = check_tar_regular(?privdir, + [fname([lib,FeApp]), + fname([lib,Db1Beam])], + LatestName), + + {ok, _, []} = systools:make_tar(LatestName, [{path, P}, silent, + {dirs, [src]}]), + ok = check_tar_regular(?privdir, + [fname([lib,FeApp]), + fname([lib,Db1Beam]), + fname([lib,Db1Erl])], + LatestName), + + ok = file:set_cwd(OldDir), ok. -%% src_tests_tar -%% -src_tests_tar(suite) -> []; -src_tests_tar(doc) -> - ["Do not check date of object file or that source code can be found."]; +%% make_tar: Do not check date of object file or that source code can be found. src_tests_tar(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), + {ok, OldDir} = file:get_cwd(), - ?line {LatestDir, LatestName} = create_script(latest,Config), + {LatestDir, LatestName} = create_script(latest,Config), - ?line DataDir = filename:absname(?copydir), - ?line LibDir = fname([DataDir, d_missing_src, lib]), - ?line P1 = fname([LibDir, 'db-2.1', ebin]), - ?line P2 = fname([LibDir, 'fe-3.1', ebin]), + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_missing_src, lib]), + P1 = fname([LibDir, 'db-2.1', ebin]), + P2 = fname([LibDir, 'fe-3.1', ebin]), P = [P1, P2], - ?line ok = file:set_cwd(LatestDir), + ok = file:set_cwd(LatestDir), %% Manipulate the modification date of a beam file so it seems %% older than the .erl file @@ -921,282 +1000,308 @@ src_tests_tar(Config) when is_list(Config) -> ok = file:write_file_info(Beam, FileInfo#file_info{mtime={{Y-1,M,D},T}}), %% Remove a .erl file - ?line Erl2 = filename:join([P1,"..","src","db2.erl"]), - ?line file:delete(Erl2), + Erl2 = filename:join([P1,"..","src","db2.erl"]), + file:delete(Erl2), - ?line ok = systools:make_script(LatestName, [{path, P}]), + ok = systools:make_script(LatestName, [{path, P}]), %% Then make tar - two warnings should be issued when %% src_tests is given %% 1. old object code for db1.beam %% 2. missing source code for db2.beam - ?line {ok, _, [{warning,{obj_out_of_date,_}}, - {warning,{source_not_found,_}}]} = + {ok, _, [{warning,{obj_out_of_date,_}}, + {warning,{source_not_found,_}}]} = systools:make_tar(LatestName, [{path, P}, silent, {dirs, [src]}, src_tests]), - ?line ok = check_tar(fname([lib,'db-2.1',src,'db1.erl']), LatestName), + ok = check_tar(fname([lib,'db-2.1',src,'db1.erl']), LatestName), %% Without the src_tests option, no warning should be issued - ?line {ok, _, []} = systools:make_tar(LatestName, [{path, P}, silent, - {dirs, [src]}]), - ?line ok = check_tar(fname([lib,'db-2.1',src,'db1.erl']), LatestName), + {ok, _, []} = systools:make_tar(LatestName, [{path, P}, silent, + {dirs, [src]}]), + ok = check_tar(fname([lib,'db-2.1',src,'db1.erl']), LatestName), %% Check that the old no_module_tests option (from the time when %% it was default to do the src_test) is ignored - ?line {ok, _, [{warning,{obj_out_of_date,_}}, - {warning,{source_not_found,_}}]} = + {ok, _, [{warning,{obj_out_of_date,_}}, + {warning,{source_not_found,_}}]} = systools:make_tar(LatestName, [{path, P}, silent, {dirs, [src]}, no_module_tests, src_tests]), - ?line ok = check_tar(fname([lib,'db-2.1',src,'db1.erl']), LatestName), - - ?line ok = file:set_cwd(OldDir), - ok. + ok = check_tar(fname([lib,'db-2.1',src,'db1.erl']), LatestName), -%% shadow_tar -%% -shadow_tar(suite) -> []; -shadow_tar(doc) -> - ["Check that jam file out of date warning doesn't", - "shadow bad module version error."]; -shadow_tar(Config) when is_list(Config) -> - % This test has been commented out since the 'vsn' attribute is not used - % any more, starting with R6. No warning 'obj_out_of_date' seemed to be - % generated. - true; -shadow_tar(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), - ?line PSAVE = code:get_path(), % Save path - - ?line {LatestDir, LatestName} = create_script(latest,Config), - - ?line DataDir = filename:absname(?copydir), - ?line LibDir = fname([DataDir, 'd_bad_mod+warn', lib]), - ?line P = [fname([LibDir, 'db-2.1', ebin]), - fname([LibDir, 'fe-3.1', ebin])], - - ?line ok = file:set_cwd(LatestDir), - - ?line {error, _, _} = systools:make_tar(LatestName, [{path, P}, silent]), - ?line {error, _, _} = systools:make_tar(LatestName, [{path, P}, silent, - {dirs, [src]}]), - ?line ok = file:set_cwd(OldDir), - ?line code:set_path(PSAVE), + ok = file:set_cwd(OldDir), ok. -%% var_tar -%% -var_tar(suite) -> []; -var_tar(doc) -> - ["Check that make_tar handles generation and placement of tar", - "files for variables outside the main tar file.", - "Test the {var_tar, include | ownfile | omit} option."]; +%% make_tar: Check that make_tar handles generation and placement of +%% tar files for variables outside the main tar file. +%% Test the {var_tar, include | ownfile | omit} optio. var_tar(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), - ?line PSAVE = code:get_path(), % Save path + {ok, OldDir} = file:get_cwd(), + PSAVE = code:get_path(), % Save path - ?line {LatestDir, LatestName} = create_script(latest,Config), + {LatestDir, LatestName} = create_script(latest,Config), - ?line DataDir = filename:absname(?copydir), - ?line LibDir = fname([DataDir, d_normal, lib]), - ?line P = [fname([LibDir, 'db-2.1', ebin]), - fname([LibDir, 'fe-3.1', ebin])], + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + P = [fname([LibDir, 'db-2.1', ebin]), + fname([LibDir, 'fe-3.1', ebin])], - ?line ok = file:set_cwd(LatestDir), + ok = file:set_cwd(LatestDir), - ?line {ok, _, _} = systools:make_script(LatestName, - [silent, - {path, P}, - {variables,[{"TEST", LibDir}]}]), + {ok, _, _} = systools:make_script(LatestName, + [silent, + {path, P}, + {variables,[{"TEST", LibDir}]}]), - ?line ok = systools:make_tar(LatestName, [{path, P}, - {var_tar, ownfile}, - {variables,[{"TEST", LibDir}]}]), + ok = systools:make_tar(LatestName, [{path, P}, + {var_tar, ownfile}, + {variables,[{"TEST", LibDir}]}]), - ?line true = exists_tar_file("TEST"), %% Also removes the file ! - ?line {error, {not_generated, _}} = check_var_tar("TEST", LatestName), + true = exists_tar_file("TEST"), %% Also removes the file ! + {error, {not_generated, _}} = check_var_tar("TEST", LatestName), - ?line ok = systools:make_tar(LatestName, [{path, P}, - {var_tar, omit}, - {variables,[{"TEST", LibDir}]}]), + ok = systools:make_tar(LatestName, [{path, P}, + {var_tar, omit}, + {variables,[{"TEST", LibDir}]}]), - ?line {error, {not_generated, _}} = check_var_tar("TEST", LatestName), - ?line false = exists_tar_file("TEST"), + {error, {not_generated, _}} = check_var_tar("TEST", LatestName), + false = exists_tar_file("TEST"), - ?line ok = systools:make_tar(LatestName, [{path, P}, - {var_tar, include}, - {variables,[{"TEST", LibDir}]}]), + ok = systools:make_tar(LatestName, [{path, P}, + {var_tar, include}, + {variables,[{"TEST", LibDir}]}]), - ?line ok = check_var_tar("TEST", LatestName), - ?line false = exists_tar_file("TEST"), + ok = check_var_tar("TEST", LatestName), + false = exists_tar_file("TEST"), - ?line ok = file:set_cwd(OldDir), - ?line code:set_path(PSAVE), + ok = file:set_cwd(OldDir), + code:set_path(PSAVE), ok. -%% exref_tar -%% -exref_tar(suite) -> []; -exref_tar(doc) -> - ["Check exref option."]; +%% make_tar: Check exref option. exref_tar(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), + {ok, OldDir} = file:get_cwd(), - ?line {LatestDir, LatestName} = create_script(latest,Config), + {LatestDir, LatestName} = create_script(latest,Config), - ?line DataDir = filename:absname(?copydir), - ?line LibDir = fname([DataDir, d_normal, lib]), - ?line P = [fname([LibDir, 'db-2.1', ebin]), - fname([LibDir, 'fe-3.1', ebin])], + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + P = [fname([LibDir, 'db-2.1', ebin]), + fname([LibDir, 'fe-3.1', ebin])], - ?line ok = file:set_cwd(LatestDir), + ok = file:set_cwd(LatestDir), - ?line {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]), + {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]), %% Complete exref - ?line {ok, _, W1} = + {ok, _, W1} = systools:make_tar(LatestName, [exref, {path, P}, silent]), - ?line check_exref_warnings(with_db1, W1), - ?line ok = check_tar(fname([lib,'db-2.1',ebin,'db.app']), LatestName), + check_exref_warnings(with_db1, W1), + ok = check_tar(fname([lib,'db-2.1',ebin,'db.app']), LatestName), %% Only exref the db application. - ?line {ok, _, W2} = + {ok, _, W2} = systools:make_tar(LatestName, [{exref, [db]}, {path, P}, silent]), - ?line check_exref_warnings(with_db1, W2), - ?line ok = check_tar(fname([lib,'fe-3.1',ebin,'fe.app']), LatestName), + check_exref_warnings(with_db1, W2), + ok = check_tar(fname([lib,'fe-3.1',ebin,'fe.app']), LatestName), %% Only exref the fe application. - ?line {ok, _, W3} = + {ok, _, W3} = systools:make_tar(LatestName, [{exref, [fe]}, {path, P}, silent]), - ?line check_exref_warnings(without_db1, W3), - ?line ok = check_tar(fname([lib,'db-2.1',ebin,'db.app']), LatestName), + check_exref_warnings(without_db1, W3), + ok = check_tar(fname([lib,'db-2.1',ebin,'db.app']), LatestName), %% exref the db and stdlib applications. - ?line {ok, _, W4} = + {ok, _, W4} = systools:make_tar(LatestName, [{exref, [db, stdlib]}, {path, P}, silent]), - ?line check_exref_warnings(with_db1, W4), - ?line ok = check_tar(fname([lib,'fe-3.1',ebin,'fe.app']), LatestName), + check_exref_warnings(with_db1, W4), + ok = check_tar(fname([lib,'fe-3.1',ebin,'fe.app']), LatestName), - ?line ok = file:set_cwd(OldDir), + ok = file:set_cwd(OldDir), ok. -%% otp_9507 -%% -otp_9507(suite) -> []; -otp_9507(doc) -> - ["make_tar failed when path given as just 'ebin'."]; -otp_9507(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), +%% make_tar: OTP-9507 - make_tar failed when path given as just 'ebin'. +otp_9507_path_ebin(Config) when is_list(Config) -> + {ok, OldDir} = file:get_cwd(), - ?line {LatestDir, LatestName} = create_script(latest_small,Config), + {LatestDir, LatestName} = create_script(latest_small,Config), - ?line DataDir = filename:absname(?copydir), - ?line LibDir = fname([DataDir, d_normal, lib]), - ?line FeDir = fname([LibDir, 'fe-3.1']), + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + FeDir = fname([LibDir, 'fe-3.1']), - ?line ok = file:set_cwd(FeDir), + ok = file:set_cwd(FeDir), RelName = fname([LatestDir,LatestName]), - ?line P1 = ["./ebin", - fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], - ?line {ok, _, _} = systools:make_script(RelName, [silent, {path, P1}]), - ?line ok = systools:make_tar(RelName, [{path, P1}]), - ?line Content1 = tar_contents(RelName), + P1 = ["./ebin", + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + {ok, _, _} = systools:make_script(RelName, [silent, {path, P1}]), + ok = systools:make_tar(RelName, [{path, P1}]), + Content1 = tar_contents(RelName), - ?line P2 = ["ebin", - fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + P2 = ["ebin", + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], %% Tickets solves the following line - it used to fail with %% {function_clause,[{filename,join,[[]]},...} - ?line ok = systools:make_tar(RelName, [{path, P2}]), - ?line Content2 = tar_contents(RelName), + ok = systools:make_tar(RelName, [{path, P2}]), + Content2 = tar_contents(RelName), true = (Content1 == Content2), - ?line ok = file:set_cwd(OldDir), + ok = file:set_cwd(OldDir), ok. -%% The relup stuff. -%% -%% - - -%% make_relup -%% -normal_relup(suite) -> []; -normal_relup(doc) -> - ["Check normal case"]; +%% make_relup: Check normal case normal_relup(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), + {ok, OldDir} = file:get_cwd(), - ?line {LatestDir,LatestName} = create_script(latest0,Config), - ?line {_LatestDir1,LatestName1} = create_script(latest1,Config), - ?line {_LatestDir2,LatestName2} = create_script(latest2,Config), + {LatestDir,LatestName} = create_script(latest0,Config), + {_LatestDir1,LatestName1} = create_script(latest1,Config), + {_LatestDir2,LatestName2} = create_script(latest2,Config), - ?line DataDir = filename:absname(?copydir), - ?line LibDir = [fname([DataDir, d_normal, lib])], - ?line P = [fname([LibDir, '*', ebin]), - fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + DataDir = filename:absname(?copydir), + LibDir = [fname([DataDir, d_normal, lib])], + P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], - ?line ok = file:set_cwd(LatestDir), - - %% OTP-2561: Check that the option 'restart_emulator' generates a - %% "restart_new_emulator" instruction. - ?line {ok, _ , _, []} = - systools:make_relup(LatestName, [LatestName1], [LatestName1], - [{path, P},restart_emulator,silent]), - ?line ok = check_relup([{db, "2.1"}], [{db, "1.0"}]), - ?line ok = check_restart_emulator(), + ok = file:set_cwd(LatestDir), %% This is the ultra normal case - ?line ok = systools:make_relup(LatestName, [LatestName1], [LatestName1], - [{path, P}]), - ?line ok = check_relup([{db, "2.1"}], [{db, "1.0"}]), - ?line {ok, _, _, []} = + ok = systools:make_relup(LatestName, [LatestName1], [LatestName1], + [{path, P}]), + ok = check_relup([{db, "2.1"}], [{db, "1.0"}]), + {ok, _, _, []} = systools:make_relup(LatestName, [LatestName1], [LatestName1], [{path, P}, silent]), - ?line ok = check_relup([{db, "2.1"}], [{db, "1.0"}]), + ok = check_relup([{db, "2.1"}], [{db, "1.0"}]), %% file should not be written if warnings_as_errors is enabled. %% delete before running tests. - ?line ok = file:delete("relup"), + ok = file:delete("relup"), %% Check that warnings are treated as errors - ?line error = + error = systools:make_relup(LatestName, [LatestName2], [LatestName1], [{path, P}, warnings_as_errors]), - ?line error = + error = systools:make_relup(LatestName, [LatestName2], [LatestName1], [{path, P}, silent, warnings_as_errors]), %% relup file should not exist - ?line false = filelib:is_regular("relup"), + false = filelib:is_regular("relup"), %% Check that warnings get through - ?line ok = systools:make_relup(LatestName, [LatestName2], [LatestName1], - [{path, P}]), - ?line ok = check_relup([{fe, "3.1"}, {db, "2.1"}], [{db, "1.0"}]), - ?line {ok, _, _, [{erts_vsn_changed, _}]} = + ok = systools:make_relup(LatestName, [LatestName2], [LatestName1], + [{path, P}]), + ok = check_relup([{fe, "3.1"}, {db, "2.1"}], [{db, "1.0"}]), + {ok, _, _, [pre_R15_emulator_upgrade,{erts_vsn_changed, _}]} = systools:make_relup(LatestName, [LatestName2], [LatestName1], [{path, P}, silent]), - ?line ok = check_relup([{fe, "3.1"}, {db, "2.1"}], [{db, "1.0"}]), + ok = check_relup([{fe, "3.1"}, {db, "2.1"}], [{db, "1.0"}]), %% relup file should exist now - ?line true = filelib:is_regular("relup"), + true = filelib:is_regular("relup"), + + ok = file:set_cwd(OldDir), + ok. + + +%% make_relup: Test relup which includes emulator restart. +restart_relup(Config) when is_list(Config) -> + {ok, OldDir} = file:get_cwd(), + + {LatestDir,LatestName} = create_script(latest0,Config), + {_LatestDir1,LatestName1} = create_script(latest1,Config), + {_LatestDir0CurrErts,LatestName0CurrErts} = + create_script(latest0_current_erts,Config), + {_CurrentAllDir,CurrentAllName} = create_script(current_all,Config), + {_CurrentAllFutErtsDir,CurrentAllFutErtsName} = + create_script(current_all_future_erts,Config), + {_CurrentAllFutSaslDir,CurrentAllFutSaslName} = + create_script(current_all_future_sasl,Config), - ?line ok = file:set_cwd(OldDir), + DataDir = filename:absname(?copydir), + LibDir = [fname([DataDir, d_normal, lib])], + P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin]), + fname([DataDir, lib, 'sasl-9.9', ebin])], + + ok = file:set_cwd(LatestDir), + + %% OTP-2561: Check that the option 'restart_emulator' generates a + %% "restart_emulator" instruction. + {ok, _ , _, []} = + systools:make_relup(LatestName, [LatestName1], [LatestName1], + [{path, P},restart_emulator,silent]), + ok = check_relup([{db, "2.1"}], [{db, "1.0"}]), + ok = check_restart_emulator(), + + + %% Pre-R15 to Post-R15 upgrade + {ok, _ , _, Ws} = + systools:make_relup(LatestName0CurrErts, + [LatestName1], + [LatestName1], + [{path, P},silent]), + ok = check_relup([{db,"2.1"}], [{db, "1.0"}]), + ok = check_pre_to_post_r15_restart_emulator(), + ok = check_pre_to_post_r15_warnings(Ws), + + + %% Check that new sasl version generates a restart_new_emulator + %% instruction + {ok, _ , _, []} = + systools:make_relup(CurrentAllFutSaslName, + [CurrentAllName], + [CurrentAllName], + [{path, P},silent]), + ok = check_relup([{fe, "3.1"}], []), + ok = check_restart_emulator_diff_coreapp(), + + + %% Check that new erts version generates a restart_new_emulator + %% instruction, if FromSaslVsn >= R15SaslVsn + %% (One erts_vsn_changed warning for upgrade and one for downgrade) + {ok, _ , _, [{erts_vsn_changed,_},{erts_vsn_changed,_}]} = + systools:make_relup(CurrentAllFutErtsName, + [CurrentAllName], + [CurrentAllName], + [{path, P},silent]), + ok = check_relup([{fe, "3.1"}], []), + ok = check_restart_emulator_diff_coreapp(), + + + %% Check that new erts version generates a restart_new_emulator + %% instruction, and can be combined with restart_emulator opt. + %% (One erts_vsn_changed warning for upgrade and one for downgrade) + {ok, _ , _, [{erts_vsn_changed,_},{erts_vsn_changed,_}]} = + systools:make_relup(CurrentAllFutErtsName, + [CurrentAllName], + [CurrentAllName], + [{path, P},restart_emulator,silent]), + ok = check_relup([{fe, "3.1"}], []), + ok = check_restart_emulator(), + ok = check_restart_emulator_diff_coreapp(), + + ok = file:set_cwd(OldDir), ok. @@ -1216,295 +1321,558 @@ check_relup(UpVsnL, DnVsnL) -> [{App, Vsn} || {load_object_code,{App,Vsn,_}} <- Dn]), ok. +check_relup_up_only(UpVsnL) -> + {ok, [{_V1, [{_, _, Up}], []}]} = file:consult(relup), + [] = foldl(fun(X, Acc) -> + true = lists:member(X, Acc), + lists:delete(X, Acc) end, + UpVsnL, + [{App, Vsn} || {load_object_code,{App,Vsn,_}} <- Up]), + ok. + check_restart_emulator() -> {ok, [{_V1, [{_, _, Up}], [{_, _, Dn}]}]} = file:consult(relup), + restart_emulator = lists:last(Up), + restart_emulator = lists:last(Dn), + ok. + +check_restart_emulator_up_only() -> + {ok, [{_V1, [{_, _, Up}], []}]} = file:consult(relup), + restart_emulator = lists:last(Up), + ok. + +check_restart_emulator_diff_coreapp() -> + {ok, [{_V1, [{_, _, Up}], [{_, _, Dn}]}]} = file:consult(relup), + [restart_new_emulator|_] = Up, + restart_emulator = lists:last(Dn), + ok. + +check_pre_to_post_r15_restart_emulator() -> + {ok, [{_V1, [{_, _, Up}], [{_, _, Dn}]}]} = file:consult(relup), restart_new_emulator = lists:last(Up), - restart_new_emulator = lists:last(Dn), + restart_emulator = lists:last(Dn), ok. -%% make_relup -%% -no_appup_relup(suite) -> []; -no_appup_relup(doc) -> - ["Check that appup files may be missing, but only if we don't need them."]; +check_pre_to_post_r15_warnings(Ws) -> + true = lists:member(pre_R15_emulator_upgrade,Ws), + ok. + +%% make_relup: Check that appup files may be missing, but only if we +%% don't need them. no_appup_relup(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), + {ok, OldDir} = file:get_cwd(), - ?line {LatestDir,LatestName} = create_script(latest_small,Config), - ?line {_LatestDir0,LatestName0} = create_script(latest_small0,Config), - ?line {_LatestDir1,LatestName1} = create_script(latest_small1,Config), + {LatestDir,LatestName} = create_script(latest_small,Config), + {_LatestDir0,LatestName0} = create_script(latest_small0,Config), + {_LatestDir1,LatestName1} = create_script(latest_small1,Config), - ?line DataDir = filename:absname(?copydir), - ?line P1 = [fname([DataDir, d_no_appup, lib, 'fe-3.1', ebin]), - fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + DataDir = filename:absname(?copydir), - ?line ok = file:set_cwd(LatestDir), + ok = file:set_cwd(LatestDir), %% Check that appup might be missing - ?line ok = + P1 = [fname([DataDir, d_no_appup, lib, 'fe-3.1', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + ok = systools:make_relup(LatestName, [LatestName], [], [{path, P1}]), - ?line {ok,_, _, []} = + {ok,_, _, []} = systools:make_relup(LatestName, [LatestName], [], [silent, {path, P1}]), %% Check that appup might NOT be missing when we need it - ?line error = - systools:make_relup(LatestName, [LatestName0], [], [{path, P1}]), - ?line {error,_,{file_problem, {_,{error,{open,_,_}}}}} = + P2 = [fname([DataDir, d_no_appup, lib, 'fe-3.1', ebin]), + fname([DataDir, d_no_appup, lib, 'fe-2.1', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + error = + systools:make_relup(LatestName, [LatestName0], [], [{path, P2}]), + {error,_,{file_problem, {_,{error,{open,_,_}}}}} = systools:make_relup(LatestName, [], [LatestName0], - [silent, {path, P1}]), + [silent, {path, P2}]), %% Check that appups missing vsn traps - ?line P2 = [fname([DataDir, d_no_appup, lib, 'fe-2.1', ebin]), - fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], - - ?line error = - systools:make_relup(LatestName0, [LatestName1], [], [{path, P2}]), - ?line {error,_,{no_relup, _, _, _}} = + P3 = [fname([DataDir, d_no_appup, lib, 'fe-2.1', ebin]), + fname([DataDir, d_no_appup, lib, 'fe-500.18.7', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + error = + systools:make_relup(LatestName0, [LatestName1], [], [{path, P3}]), + {error,_,{no_relup, _, _, _}} = systools:make_relup(LatestName0, [], [LatestName1], - [silent, {path, P2}]), + [silent, {path, P3}]), - ?line ok = file:set_cwd(OldDir), + ok = file:set_cwd(OldDir), ok. -%% make_relup -%% -bad_appup_relup(suite) -> []; -bad_appup_relup(doc) -> - ["Check that badly written appup files are detected"]; +%% make_relup: Check that badly written appup files are detected. bad_appup_relup(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), + {ok, OldDir} = file:get_cwd(), - ?line {LatestDir,LatestName} = create_script(latest_small,Config), - ?line {_LatestDir0,LatestName0} = create_script(latest_small0,Config), + {LatestDir,LatestName} = create_script(latest_small,Config), + {_LatestDir0,LatestName0} = create_script(latest_small0,Config), - ?line DataDir = filename:absname(?copydir), - ?line N2 = [fname([DataDir, d_bad_appup, lib, 'fe-3.1', ebin]), - fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + DataDir = filename:absname(?copydir), + N2 = [fname([DataDir, d_bad_appup, lib, 'fe-3.1', ebin]), + fname([DataDir, d_bad_appup, lib, 'fe-2.1', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], - ?line ok = file:set_cwd(LatestDir), + ok = file:set_cwd(LatestDir), %% Check that bad appup is trapped - ?line error = + error = systools:make_relup(LatestName, [LatestName0], [], [{path, N2}]), - ?line {error,_,{file_problem, {_, {error, {parse,_, _}}}}} = + {error,_,{file_problem, {_, {error, {parse,_, _}}}}} = systools:make_relup(LatestName, [], [LatestName0], [silent, {path, N2}]), - ?line ok = file:set_cwd(OldDir), + ok = file:set_cwd(OldDir), ok. -%% make_relup -%% -abnormal_relup(suite) -> []; -abnormal_relup(doc) -> - ["Check some abnormal cases"]; +%% make_relup: Check some abnormal cases. abnormal_relup(Config) when is_list(Config) -> - ?line {ok, OldDir} = file:get_cwd(), + {ok, OldDir} = file:get_cwd(), - ?line {LatestDir,LatestName} = create_script(latest0,Config), - ?line {_LatestDir1,LatestName1} = create_script(latest1,Config), + {LatestDir,LatestName} = create_script(latest0,Config), + {_LatestDir1,LatestName1} = create_script(latest1,Config), %% Check wrong app vsn - ?line DataDir = filename:absname(?copydir), - ?line P = [fname([DataDir, d_bad_app_vsn, lib, 'db-2.1', ebin]), - fname([DataDir, d_bad_app_vsn, lib, 'fe-3.1', ebin]), - fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], - - ?line ok = file:set_cwd(LatestDir), - - ?line error = systools:make_relup(LatestName, [LatestName1], [LatestName1], - [{path, P}]), - ?line R0 = systools:make_relup(LatestName, [LatestName1], [LatestName1], - [silent, {path, P}]), - ?line {error,systools_make, - [{error_reading,{db,{no_valid_version, - {{"should be","2.1"}, - {"found file", _, "2.0"}}}}}]} = R0, - ?line ok = file:set_cwd(OldDir), + DataDir = filename:absname(?copydir), + P = [fname([DataDir, d_bad_app_vsn, lib, 'db-2.1', ebin]), + fname([DataDir, d_bad_app_vsn, lib, 'fe-3.1', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + ok = file:set_cwd(LatestDir), + + error = systools:make_relup(LatestName, [LatestName1], [LatestName1], + [{path, P}]), + R0 = systools:make_relup(LatestName, [LatestName1], [LatestName1], + [silent, {path, P}]), + {error,systools_make, + [{error_reading,{db,{no_valid_version, + {{"should be","2.1"}, + {"found file", _, "2.0"}}}}}]} = R0, + ok = file:set_cwd(OldDir), ok. -%% Check that application start type is used in relup -app_start_type_relup(suite) -> - []; -app_start_type_relup(doc) -> - ["Release upgrade file with various application start types"]; +%% make_relup: Check relup can not be created is sasl is not in rel file. +no_sasl_relup(Config) when is_list(Config) -> + {ok, OldDir} = file:get_cwd(), + {Dir1,Name1} = create_script(latest1_no_sasl,Config), + {_Dir2,Name2} = create_script(latest1,Config), + + DataDir = filename:absname(?copydir), + LibDir = [fname([DataDir, d_normal, lib])], + P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + ok = file:set_cwd(Dir1), + + error = systools:make_relup(Name2, [Name1], [Name1], [{path, P}]), + R1 = systools:make_relup(Name2, [Name1], [Name1],[silent, {path, P}]), + {error,systools_relup,{missing_sasl,_}} = R1, + + error = systools:make_relup(Name1, [Name2], [Name2], [{path, P}]), + R2 = systools:make_relup(Name1, [Name2], [Name2],[silent, {path, P}]), + {error,systools_relup,{missing_sasl,_}} = R2, + + ok = file:set_cwd(OldDir), + ok. + + +%% make_relup: Check that application start type is used in relup app_start_type_relup(Config) when is_list(Config) -> - ?line PrivDir = ?config(priv_dir, Config), - ?line {Dir1,Name1} = create_script(latest_app_start_type1,Config), - ?line {Dir2,Name2} = create_script(latest_app_start_type2,Config), - ?line Release1 = filename:join(Dir1,Name1), - ?line Release2 = filename:join(Dir2,Name2), - - ?line {ok, Release2Relup, systools_relup, []} = systools:make_relup(Release2, [Release1], [Release1], [{outdir, PrivDir}, silent]), - ?line {"2", [{"1",[], UpInstructions}], [{"1",[], DownInstructions}]} = Release2Relup, + PrivDir = ?config(priv_dir, Config), + {Dir1,Name1} = create_script(latest_app_start_type1,Config), + {Dir2,Name2} = create_script(latest_app_start_type2,Config), + Release1 = filename:join(Dir1,Name1), + Release2 = filename:join(Dir2,Name2), + + {ok, Release2Relup, systools_relup, []} = systools:make_relup(Release2, [Release1], [Release1], [{outdir, PrivDir}, silent]), + {"LATEST_APP_START_TYPE2", + [{"LATEST_APP_START_TYPE1",[], UpInstructions}], + [{"LATEST_APP_START_TYPE1",[], DownInstructions}]} = Release2Relup, %% ?t:format("Up: ~p",[UpInstructions]), %% ?t:format("Dn: ~p",[DownInstructions]), - ?line [{load_object_code, {mnesia, _, _}}, - {load_object_code, {sasl, _, _}}, - {load_object_code, {webtool, _, _}}, - {load_object_code, {snmp, _, _}}, - {load_object_code, {xmerl, _, _}}, - point_of_no_return - | UpInstructionsT] = UpInstructions, - ?line true = lists:member({apply,{application,start,[mnesia,permanent]}}, UpInstructionsT), - ?line true = lists:member({apply,{application,start,[sasl,transient]}}, UpInstructionsT), - ?line true = lists:member({apply,{application,start,[webtool,temporary]}}, UpInstructionsT), - ?line true = lists:member({apply,{application,load,[snmp]}}, UpInstructionsT), - ?line false = lists:any(fun({apply,{application,_,[xmerl|_]}}) -> true; (_) -> false end, UpInstructionsT), - ?line [point_of_no_return | DownInstructionsT] = DownInstructions, - ?line true = lists:member({apply,{application,stop,[mnesia]}}, DownInstructionsT), - ?line true = lists:member({apply,{application,stop,[sasl]}}, DownInstructionsT), - ?line true = lists:member({apply,{application,stop,[webtool]}}, DownInstructionsT), - ?line true = lists:member({apply,{application,stop,[snmp]}}, DownInstructionsT), - ?line true = lists:member({apply,{application,stop,[xmerl]}}, DownInstructionsT), - ?line true = lists:member({apply,{application,unload,[mnesia]}}, DownInstructionsT), - ?line true = lists:member({apply,{application,unload,[sasl]}}, DownInstructionsT), - ?line true = lists:member({apply,{application,unload,[webtool]}}, DownInstructionsT), - ?line true = lists:member({apply,{application,unload,[snmp]}}, DownInstructionsT), - ?line true = lists:member({apply,{application,unload,[xmerl]}}, DownInstructionsT), + [{load_object_code, {mnesia, _, _}}, + {load_object_code, {runtime_tools, _, _}}, + {load_object_code, {webtool, _, _}}, + {load_object_code, {snmp, _, _}}, + {load_object_code, {xmerl, _, _}}, + point_of_no_return + | UpInstructionsT] = UpInstructions, + true = lists:member({apply,{application,start,[mnesia,permanent]}}, UpInstructionsT), + true = lists:member({apply,{application,start,[runtime_tools,transient]}}, UpInstructionsT), + true = lists:member({apply,{application,start,[webtool,temporary]}}, UpInstructionsT), + true = lists:member({apply,{application,load,[snmp]}}, UpInstructionsT), + false = lists:any(fun({apply,{application,_,[xmerl|_]}}) -> true; (_) -> false end, UpInstructionsT), + [point_of_no_return | DownInstructionsT] = DownInstructions, + true = lists:member({apply,{application,stop,[mnesia]}}, DownInstructionsT), + true = lists:member({apply,{application,stop,[runtime_tools]}}, DownInstructionsT), + true = lists:member({apply,{application,stop,[webtool]}}, DownInstructionsT), + true = lists:member({apply,{application,stop,[snmp]}}, DownInstructionsT), + true = lists:member({apply,{application,stop,[xmerl]}}, DownInstructionsT), + true = lists:member({apply,{application,unload,[mnesia]}}, DownInstructionsT), + true = lists:member({apply,{application,unload,[runtime_tools]}}, DownInstructionsT), + true = lists:member({apply,{application,unload,[webtool]}}, DownInstructionsT), + true = lists:member({apply,{application,unload,[snmp]}}, DownInstructionsT), + true = lists:member({apply,{application,unload,[xmerl]}}, DownInstructionsT), + ok. + + +%% make_relup: Check that regexp can be used in .appup for UpFromVsn +%% and DownToVsn. +regexp_relup(Config) -> + {ok, OldDir} = file:get_cwd(), + + {LatestDir,LatestName} = create_script(latest_small,Config), + {_LatestDir0,LatestName0} = create_script(latest_small0,Config), + {_LatestDir1,LatestName1} = create_script(latest_small2,Config), + + DataDir = filename:absname(?copydir), + P = [fname([DataDir, d_regexp_appup, lib, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + ok = file:set_cwd(LatestDir), + + %% Upgrade fe 2.1 -> 3.1, and downgrade 2.1 -> 3.1 + %% Shall match the first entry if fe-3.1 appup. + {ok, _, _, []} = + systools:make_relup(LatestName, [LatestName0], [LatestName0], + [{path, P}, silent]), + ok = check_relup([{fe, "3.1"}], [{fe, "2.1"}]), + + %% Upgrade fe 2.1.1 -> 3.1 + %% Shall match the second entry in fe-3.1 appup. Have added a + %% restart_emulator instruction there to distinguish it from + %% the first entry... + {ok, _, _, []} = + systools:make_relup(LatestName, [LatestName1], [], [{path, P}, silent]), + ok = check_relup_up_only([{fe, "3.1"}]), + ok = check_restart_emulator_up_only(), + + %% Attempt downgrade fe 3.1 -> 2.1.1 + %% Shall not match any entry!! + {error,systools_relup,{no_relup,_,_,_}} = + systools:make_relup(LatestName, [], [LatestName1], [{path, P}, silent]), + + ok = file:set_cwd(OldDir), + + ok. + + +%% make_hybrid_boot: Normal case. +%% For upgrade of erts - create a boot file which is a hybrid between +%% old and new release - i.e. starts erts, kernel, stdlib, sasl from +%% new release, all other apps from old release. +normal_hybrid(Config) -> + {ok, OldDir} = file:get_cwd(), + {Dir1,Name1} = create_script(latest1,Config), + {_Dir2,Name2} = create_script(current_all,Config), + + DataDir = filename:absname(?copydir), + LibDir = [fname([DataDir, d_normal, lib])], + P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + ok = file:set_cwd(Dir1), + + {ok, _ , []} = systools:make_script(Name1,[{path, P},silent]), + {ok, _ , []} = systools:make_script(Name2,[{path, P},silent]), + {ok,Boot1} = file:read_file(Name1 ++ ".boot"), + {ok,Boot2} = file:read_file(Name2 ++ ".boot"), + + ok = file:set_cwd(OldDir), + + BasePaths = {"testkernelpath","teststdlibpath","testsaslpath"}, + {ok,Hybrid} = systools_make:make_hybrid_boot("tmp_vsn",Boot1,Boot2, + BasePaths, [dummy,args]), + + {script,{"Test release","tmp_vsn"},Script} = binary_to_term(Hybrid), + ct:log("~p.~n",[Script]), + + %% Check that all paths to base apps are replaced by paths from BaseLib + Boot1Str = io_lib:format("~p~n",[binary_to_term(Boot1)]), + HybridStr = io_lib:format("~p~n",[binary_to_term(Hybrid)]), + ReOpts = [global,{capture,first,list},unicode], + {match,OldKernelMatch} = re:run(Boot1Str,"kernel-[0-9\.]+",ReOpts), + {match,OldStdlibMatch} = re:run(Boot1Str,"stdlib-[0-9\.]+",ReOpts), + {match,OldSaslMatch} = re:run(Boot1Str,"sasl-[0-9\.]+",ReOpts), + + nomatch = re:run(HybridStr,"kernel-[0-9\.]+",ReOpts), + nomatch = re:run(HybridStr,"stdlib-[0-9\.]+",ReOpts), + nomatch = re:run(HybridStr,"sasl-[0-9\.]+",ReOpts), + {match,NewKernelMatch} = re:run(HybridStr,"testkernelpath",ReOpts), + {match,NewStdlibMatch} = re:run(HybridStr,"teststdlibpath",ReOpts), + {match,NewSaslMatch} = re:run(HybridStr,"testsaslpath",ReOpts), + + NewKernelN = length(NewKernelMatch), + NewKernelN = length(OldKernelMatch), + NewStdlibN = length(NewStdlibMatch), + NewStdlibN = length(OldStdlibMatch), + NewSaslN = length(NewSaslMatch), + NewSaslN = length(OldSaslMatch), + + %% Check that application load instruction has correct versions + Apps = application:loaded_applications(), + {_,_,KernelVsn} = lists:keyfind(kernel,1,Apps), + {_,_,StdlibVsn} = lists:keyfind(stdlib,1,Apps), + {_,_,SaslVsn} = lists:keyfind(sasl,1,Apps), + + [KernelInfo] = [I || {kernelProcess,application_controller, + {application_controller,start, + [{application,kernel,I}]}} <- Script], + [StdlibInfo] = [I || {apply, + {application,load, + [{application,stdlib,I}]}} <- Script], + [SaslInfo] = [I || {apply, + {application,load, + [{application,sasl,I}]}} <- Script], + + {vsn,KernelVsn} = lists:keyfind(vsn,1,KernelInfo), + {vsn,StdlibVsn} = lists:keyfind(vsn,1,StdlibInfo), + {vsn,SaslVsn} = lists:keyfind(vsn,1,SaslInfo), + + %% Check that new_emulator_upgrade call is added + [_,{apply,{release_handler,new_emulator_upgrade,[dummy,args]}}|_] = + lists:reverse(Script), + + %% Check that db-1.0 and fe-3.1 are used (i.e. vsns from old release) + %% And that fe is in there (it exists in old rel but not in new) + {match,DbMatch} = re:run(HybridStr,"db-[0-9\.]+",ReOpts), + {match,[_|_]=FeMatch} = re:run(HybridStr,"fe-[0-9\.]+",ReOpts), + true = lists:all(fun(["db-1.0"]) -> true; + (_) -> false + end, + DbMatch), + true = lists:all(fun(["fe-3.1"]) -> true; + (_) -> false + end, + FeMatch), + + %% Check that script has same length as old script, plus one (the + %% new_emulator_upgrade apply) + {_,_,Old} = binary_to_term(Boot1), + OldLength = length(Old), + NewLength = length(Script), + NewLength = OldLength + 1, + + ok. + +%% make_hybrid_boot: No sasl in from-release. +%% Check that systools_make:make_hybrid_boot fails with a meaningful +%% error message if the FromBoot does not include the sasl +%% application. +hybrid_no_old_sasl(Config) -> + {ok, OldDir} = file:get_cwd(), + {Dir1,Name1} = create_script(latest1_no_sasl,Config), + {_Dir2,Name2} = create_script(current_all,Config), + + DataDir = filename:absname(?copydir), + LibDir = [fname([DataDir, d_normal, lib])], + P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + ok = file:set_cwd(Dir1), + + {ok, _ , [{warning,missing_sasl}]} = + systools:make_script(Name1,[{path, P},silent]), + {ok, _ , []} = systools:make_script(Name2,[{path, P},silent]), + {ok,Boot1} = file:read_file(Name1 ++ ".boot"), + {ok,Boot2} = file:read_file(Name2 ++ ".boot"), + + BasePaths = {"testkernelpath","teststdlibpath","testsaslpath"}, + {error,{app_not_replaced,sasl}} = + systools_make:make_hybrid_boot("tmp_vsn",Boot1,Boot2, + BasePaths,[dummy,args]), + + ok = file:set_cwd(OldDir), + ok. + + +%% make_hybrid_boot: No sasl in to-release. +%% Check that systools_make:make_hybrid_boot fails with a meaningful +%% error message if the ToBoot does not include the sasl +%% application. +hybrid_no_new_sasl(Config) -> + {ok, OldDir} = file:get_cwd(), + {Dir1,Name1} = create_script(latest1,Config), + {_Dir2,Name2} = create_script(current_all_no_sasl,Config), + + DataDir = filename:absname(?copydir), + LibDir = [fname([DataDir, d_normal, lib])], + P = [fname([LibDir, '*', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], + + ok = file:set_cwd(Dir1), + + {ok, _ , []} = systools:make_script(Name1,[{path, P},silent]), + {ok, _ , [{warning,missing_sasl}]} = + systools:make_script(Name2,[{path, P},silent]), + {ok,Boot1} = file:read_file(Name1 ++ ".boot"), + {ok,Boot2} = file:read_file(Name2 ++ ".boot"), + + BasePaths = {"testkernelpath","teststdlibpath","testsaslpath"}, + {error,{app_not_found,sasl}} = + systools_make:make_hybrid_boot("tmp_vsn",Boot1,Boot2, + BasePaths,[dummy,args]), + + ok = file:set_cwd(OldDir), ok. -otp_6226(suite) -> - []; -otp_6226(doc) -> - ["{outdir,Dir} option for systools:make_script()"]; -otp_6226(Config) when is_list(Config) -> + +%% options: {outdir,Dir} option +otp_6226_outdir(Config) when is_list(Config) -> PrivDir = ?privdir, - ?line {ok, OldDir} = file:get_cwd(), + {ok, OldDir} = file:get_cwd(), + + {LatestDir, LatestName} = create_script(latest0,Config), + {_LatestDir, LatestName1} = create_script(latest1,Config), - ?line {LatestDir, LatestName} = create_script(latest0,Config), - ?line {_LatestDir, LatestName1} = create_script(latest1,Config), + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + P = [fname([LibDir, 'db-2.1', ebin]), + fname([LibDir, 'db-1.0', ebin]), + fname([LibDir, 'fe-3.1', ebin]), + fname([DataDir, lib, kernel, ebin]), + fname([DataDir, lib, stdlib, ebin]), + fname([DataDir, lib, sasl, ebin])], - ?line DataDir = filename:absname(?copydir), - ?line LibDir = fname([DataDir, d_normal, lib]), - ?line P = [fname([LibDir, 'db-2.1', ebin]), - fname([LibDir, 'db-1.0', ebin]), - fname([LibDir, 'fe-3.1', ebin]), - fname([DataDir, lib, kernel, ebin]), - fname([DataDir, lib, stdlib, ebin])], + ok = file:set_cwd(LatestDir), - ?line ok = file:set_cwd(LatestDir), - %% Create an outdir1 directory - ?line ok = file:make_dir("outdir1"), + ok = file:make_dir("outdir1"), %% ==== Now test systools:make_script ==== %% a) badarg - ?line {'EXIT', {{badarg,[{outdir,outdir1}]}, _}} = + {'EXIT', {{badarg,[{outdir,outdir1}]}, _}} = (catch systools:make_script(LatestName, [{outdir,outdir1}, {path,P},silent])), %% b) absolute path Outdir1 = filename:join(PrivDir, "outdir1"), - ?line {ok,_,[]} = systools:make_script(LatestName, [{outdir,Outdir1}, - {path,P},silent]), - ?line Script1 = filename:join(Outdir1, LatestName ++ ".script"), - ?line Boot1 = filename:join(Outdir1, LatestName ++ ".boot"), - ?line true = filelib:is_file(Script1), - ?line true = filelib:is_file(Boot1), - ?line ok = file:delete(Script1), - ?line ok = file:delete(Boot1), + {ok,_,[]} = systools:make_script(LatestName, [{outdir,Outdir1}, + {path,P},silent]), + Script1 = filename:join(Outdir1, LatestName ++ ".script"), + Boot1 = filename:join(Outdir1, LatestName ++ ".boot"), + true = filelib:is_file(Script1), + true = filelib:is_file(Boot1), + ok = file:delete(Script1), + ok = file:delete(Boot1), %% c) relative path - ?line {ok,_,[]} = systools:make_script(LatestName, [{outdir,"./outdir1"}, - {path,P},silent]), - ?line true = filelib:is_file(Script1), - ?line true = filelib:is_file(Boot1), - ?line ok = file:delete(Script1), - ?line ok = file:delete(Boot1), + {ok,_,[]} = systools:make_script(LatestName, [{outdir,"./outdir1"}, + {path,P},silent]), + true = filelib:is_file(Script1), + true = filelib:is_file(Boot1), + ok = file:delete(Script1), + ok = file:delete(Boot1), %% d) absolute but incorrect path - ?line Outdir2 = filename:join(PrivDir, "outdir2"), - ?line Script2 = filename:join(Outdir2, LatestName ++ ".script"), - ?line {error,_,{open,Script2,_}} = + Outdir2 = filename:join(PrivDir, "outdir2"), + Script2 = filename:join(Outdir2, LatestName ++ ".script"), + {error,_,{open,Script2,_}} = systools:make_script(LatestName, [{outdir,Outdir2},{path,P},silent]), %% e) relative but incorrect path - ?line {error,_,{open,_,_}} = + {error,_,{open,_,_}} = systools:make_script(LatestName, [{outdir,"./outdir2"},{path,P},silent]), %% f) with .rel in another directory than cwd - ?line ok = file:set_cwd(Outdir1), - ?line {ok,_,[]} = systools:make_script(filename:join(PrivDir, LatestName), - [{outdir,"."},{path,P},silent]), - ?line true = filelib:is_file(LatestName ++ ".script"), - ?line true = filelib:is_file(LatestName ++ ".boot"), - ?line ok = file:delete(LatestName ++ ".script"), - ?line ok = file:delete(LatestName ++ ".boot"), - ?line ok = file:set_cwd(LatestDir), + ok = file:set_cwd(Outdir1), + {ok,_,[]} = systools:make_script(filename:join(PrivDir, LatestName), + [{outdir,"."},{path,P},silent]), + true = filelib:is_file(LatestName ++ ".script"), + true = filelib:is_file(LatestName ++ ".boot"), + ok = file:delete(LatestName ++ ".script"), + ok = file:delete(LatestName ++ ".boot"), + ok = file:set_cwd(LatestDir), %% ==== Now test systools:make_tar ===== - ?line {ok,_,[]} = systools:make_script(LatestName, [{path,P},silent]), + {ok,_,[]} = systools:make_script(LatestName, [{path,P},silent]), %% a) badarg - ?line {'EXIT', {{badarg, [{outdir,outdir1}]}, _}} = + {'EXIT', {{badarg, [{outdir,outdir1}]}, _}} = (catch systools:make_tar(LatestName,[{outdir,outdir1},{path,P},silent])), %% b) absolute path - ?line {ok,_,[]} = systools:make_tar(LatestName, [{outdir,Outdir1}, - {path,P},silent]), - ?line Tar1 = filename:join(Outdir1,LatestName++".tar.gz"), - ?line true = filelib:is_file(Tar1), - ?line ok = file:delete(Tar1), + {ok,_,[]} = systools:make_tar(LatestName, [{outdir,Outdir1}, + {path,P},silent]), + Tar1 = filename:join(Outdir1,LatestName++".tar.gz"), + true = filelib:is_file(Tar1), + ok = file:delete(Tar1), %% c) relative path - ?line {ok,_,[]} = systools:make_tar(LatestName, [{outdir,"./outdir1"}, - {path,P},silent]), - ?line true = filelib:is_file(Tar1), - ?line ok = file:delete(Tar1), + {ok,_,[]} = systools:make_tar(LatestName, [{outdir,"./outdir1"}, + {path,P},silent]), + true = filelib:is_file(Tar1), + ok = file:delete(Tar1), %% d) absolute but incorrect path - ?line Tar2 = filename:join(Outdir2,LatestName++".tar.gz"), - ?line {error,_,{tar_error,{open,Tar2,{Tar2,enoent}}}} = + Tar2 = filename:join(Outdir2,LatestName++".tar.gz"), + {error,_,{tar_error,{open,Tar2,{Tar2,enoent}}}} = systools:make_tar(LatestName, [{outdir,Outdir2},{path,P},silent]), - + %% e) relative but incorrect path - ?line {error,_,{tar_error,{open,_,_}}} = - systools:make_tar(LatestName, [{outdir,"./outdir2"},{path,P},silent]), + {error,_,{tar_error,{open,_,_}}} = + systools:make_tar(LatestName, [{outdir,"./outdir2"},{path,P},silent]), %% f) with .rel in another directory than cwd - ?line ok = file:set_cwd(Outdir1), - ?line {ok,_,[]} = systools:make_tar(filename:join(PrivDir, LatestName), - [{outdir,"."},{path,P},silent]), - ?line true = filelib:is_file(Tar1), - ?line ok = file:set_cwd(LatestDir), + ok = file:set_cwd(Outdir1), + {ok,_,[]} = systools:make_tar(filename:join(PrivDir, LatestName), + [{outdir,"."},{path,P},silent]), + true = filelib:is_file(Tar1), + ok = file:set_cwd(LatestDir), %% ===== Now test systools:make_relup ===== %% a) badarg - ?line {'EXIT', {{badarg, [{outdir,outdir1}]}, _}} = + {'EXIT', {{badarg, [{outdir,outdir1}]}, _}} = (catch systools:make_relup(LatestName,[LatestName1],[LatestName1], [{outdir,outdir1}, {path,P},silent])), %% b) absolute path Relup = filename:join(Outdir1, "relup"), - ?line {ok,_,_,[]} = systools:make_relup(LatestName,[LatestName1],[LatestName1], - [{outdir,Outdir1}, - {path,P},silent]), - ?line true = filelib:is_file(Relup), - ?line ok = file:delete(Relup), - + {ok,_,_,[]} = systools:make_relup(LatestName,[LatestName1],[LatestName1], + [{outdir,Outdir1}, + {path,P},silent]), + true = filelib:is_file(Relup), + ok = file:delete(Relup), + %% c) relative path - ?line {ok,_,_,[]} = systools:make_relup(LatestName,[LatestName1],[LatestName1], - [{outdir,"./outdir1"}, - {path,P},silent]), - ?line true = filelib:is_file(Relup), - ?line ok = file:delete(Relup), - + {ok,_,_,[]} = systools:make_relup(LatestName,[LatestName1],[LatestName1], + [{outdir,"./outdir1"}, + {path,P},silent]), + true = filelib:is_file(Relup), + ok = file:delete(Relup), + %% d) absolute but incorrect path - ?line {error,_,{file_problem,{"relup",enoent}}} = + {error,_,{file_problem,{"relup",enoent}}} = systools:make_relup(LatestName,[LatestName1],[LatestName1], [{outdir,Outdir2},{path,P},silent]), - + %% e) relative but incorrect path - ?line {error,_,{file_problem,{"relup",enoent}}} = + {error,_,{file_problem,{"relup",enoent}}} = systools:make_relup(LatestName,[LatestName1],[LatestName1], [{outdir,"./outdir2"},{path,P},silent]), @@ -1513,7 +1881,7 @@ otp_6226(Config) when is_list(Config) -> %% cwd, not in the same directory as the .rel file -- %% Change back to previous working directory - ?line ok = file:set_cwd(OldDir), + ok = file:set_cwd(OldDir), ok. @@ -1536,7 +1904,7 @@ check_var_script_file(VarDirs, NoExistDirs, RelName) -> AllPaths = lists:append(lists:map(fun({path, P}) -> P; (_) -> [] end, - ListOfThings)), + ListOfThings)), case lists:filter(fun(VarDir) -> lists:member(VarDir, AllPaths) end, VarDirs) of VarDirs -> @@ -1561,7 +1929,7 @@ check_include_script(RelName, ExpectedLoad, ExpectedStart) -> [App || {apply,{application,load,[{application,App,_}]}} <- ListOfThings, App=/=kernel, App=/=stdlib], - + if ActualLoad =:= ExpectedLoad -> ok; true -> test_server:fail({bad_load_order, ActualLoad, ExpectedLoad}) end, @@ -1636,7 +2004,7 @@ check_tar_regular(PrivDir, Files, RelName) -> NotThere -> {error,{erroneous_tar_file,tar_name(RelName),NotThere}} end. - + delete_tree(Dir) -> case filelib:is_dir(Dir) of true -> @@ -1656,534 +2024,582 @@ tar_name(Name) -> Name ++ ".tar.gz". create_script(latest,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 3\", \"LATEST\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"~s\"}, {stdlib, \"~s\"}, \n" - " {db, \"2.1\"}, {fe, \"3.1\"}]}.\n", - [KernelVer,StdlibVer]), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps(current) ++ [{db,"2.1"},{fe,"3.1"}], + do_create_script(latest,Config,"4.4",Apps); create_script(latest_no_mod_vsn,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 3\", \"LATESTNOMOD\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"~s\"}, {stdlib, \"~s\"}, \n" - " {db, \"3.1\"}, {fe, \"3.1\"}]}.\n", - [KernelVer,StdlibVer]), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps(current) ++ [{db,"3.1"},{fe,"3.1"}], + do_create_script(latest_no_mod_vsn,Config,"4.4",Apps); create_script(latest0,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-1'), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 2\", \"LATEST0\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {db, \"2.1\"}, {fe, \"3.1\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{db,"2.1"},{fe,"3.1"}], + do_create_script(latest0,Config,"4.4",Apps); +create_script(latest0_current_erts,Config) -> + Apps = core_apps("1.0") ++ [{db,"2.1"},{fe,"3.1"}], + do_create_script(latest0_current_erts,Config,current,Apps); create_script(latest1,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 2\", \"LATEST1\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {db, \"1.0\"}, {fe, \"3.1\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{db,"1.0"},{fe,"3.1"}], + do_create_script(latest1,Config,"4.4",Apps); +create_script(latest1_no_sasl,Config) -> + Apps = [{kernel,"1.0"},{stdlib,"1.0"},{db,"1.0"},{fe,"3.1"}], + do_create_script(latest1_no_sasl,Config,"4.4",Apps); create_script(latest2,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-2'), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 1\", \"LATEST2\"}, \n" - " {erts, \"4.3\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {db, \"1.0\"}, {fe, \"2.1\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{db,"1.0"},{fe,"2.1"}], + do_create_script(latest2,Config,"4.3",Apps); create_script(latest_small,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-small'), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 2\", \"LATEST_SMALL\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {fe, \"3.1\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{fe,"3.1"}], + do_create_script(latest_small,Config,"4.4",Apps); create_script(latest_small0,Config) -> %Differs in fe vsn - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-small0'), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 2\", \"LATEST_SMALL0\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {fe, \"2.1\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{fe,"2.1"}], + do_create_script(latest_small0,Config,"4.4",Apps); create_script(latest_small1,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-small1'), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 2\", \"LATEST_SMALL1\"}, \n" - " {erts, \"4.4\"}, \n" - " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n" - " {fe, \"500.18.7\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps("1.0") ++ [{fe,"500.18.7"}], + do_create_script(latest_small1,Config,"4.4",Apps); +create_script(latest_small2,Config) -> + Apps = core_apps("1.0") ++ [{fe,"2.1.1"}], + do_create_script(latest_small2,Config,"4.4",Apps); create_script(latest_nokernel,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, 'latest-nokernel'), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line io:format(Fd, - "{release, {\"Test release 3\", \"LATEST_NOKERNEL\"}, \n" - " {erts, \"4.4\"}, \n" - " [{db, \"2.1\"}, {fe, \"3.1\"}]}.\n", - []), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = [{db,"2.1"},{fe,"3.1"}], + do_create_script(latest_nokernel,Config,"4.4",Apps); +create_script(latest_kernel_start_type,Config) -> + Apps = [{kernel,"1.0",load},{stdlib,"1.0"},{db,"2.1"},{fe,"3.1"}], + do_create_script(latest_kernel_start_type,Config,"4.4",Apps); +create_script(latest_stdlib_start_type,Config) -> + Apps = [{kernel,"1.0"},{stdlib,"1.0",load},{db,"2.1"},{fe,"3.1"}], + do_create_script(latest_stdlib_start_type,Config,"4.4",Apps); +create_script(latest_no_stdlib,Config) -> + Apps = [{kernel,"1.0"},{db,"2.1"},{fe,"3.1"}], + do_create_script(latest_no_stdlib,Config,"4.4",Apps); create_script(latest_app_start_type1,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest_app_start_type1), - ?line ErtsVer = erlang:system_info(version), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line RelfileContent = - {release,{"Test release", "1"}, - {erts,ErtsVer}, - [{kernel,KernelVer}, - {stdlib,StdlibVer}]}, - ?line io:format(Fd,"~p.~n",[RelfileContent]), - ?line ok = file:close(Fd), - {filename:dirname(Name), filename:basename(Name)}; + Apps = core_apps(current), + do_create_script(latest_app_start_type1,Config,current,Apps); create_script(latest_app_start_type2,Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, latest_app_start_type2), - ?line ErtsVer = erlang:system_info(version), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), - ?line OtherApps = [{mnesia,permanent}, - {sasl,transient}, - {webtool,temporary}, - {snmp,load}, - {xmerl,none}], - ?line lists:foreach(fun({App,_}) -> application:load(App) end, - OtherApps), - ?line Loaded = application:loaded_applications(), - ?line OtherAppsRel = - lists:map(fun({App,StartType}) -> - {_,_,Ver} = lists:keyfind(App,1,Loaded), - {App,Ver,StartType} - end, - OtherApps), - ?line {ok,Fd} = file:open(Name++".rel",write), - ?line RelfileContent = - {release,{"Test release", "2"}, - {erts,ErtsVer}, - [{kernel,KernelVer}, - {stdlib,StdlibVer} | OtherAppsRel]}, - ?line io:format(Fd,"~p.~n",[RelfileContent]), - ?line ok = file:close(Fd), + OtherApps = [{mnesia,current,permanent}, + {runtime_tools,current,transient}, + {webtool,current,temporary}, + {snmp,current,load}, + {xmerl,current,none}], + Apps = core_apps(current) ++ OtherApps, + do_create_script(latest_app_start_type2,Config,current,Apps); +create_script(current_all_no_sasl,Config) -> + Apps = [{kernel,current},{stdlib,current},{db,"2.1"},{fe,"3.1"}], + do_create_script(current_all_no_sasl,Config,current,Apps); +create_script(current_all,Config) -> + Apps = core_apps(current) ++ [{db,"2.1"}], + do_create_script(current_all,Config,current,Apps); +create_script(current_all_future_erts,Config) -> + Apps = core_apps(current) ++ [{db,"2.1"},{fe,"3.1"}], + do_create_script(current_all_future_erts,Config,"99.99",Apps); +create_script(current_all_future_sasl,Config) -> + Apps = [{kernel,current},{stdlib,current},{sasl,"9.9"},{db,"2.1"},{fe,"3.1"}], + do_create_script(current_all_future_sasl,Config,current,Apps). + + +do_create_script(Id,Config,ErtsVsn,AppVsns) -> + PrivDir = ?privdir, + Name = fname(PrivDir, Id), + {ok,Fd} = file:open(Name++".rel",write), + RelfileContent = + {release,{"Test release", string:to_upper(atom_to_list(Id))}, + {erts,erts_vsn(ErtsVsn)}, + app_vsns(AppVsns)}, + io:format(Fd,"~p.~n",[RelfileContent]), + ok = file:close(Fd), {filename:dirname(Name), filename:basename(Name)}. +core_apps(Vsn) -> + [{App,Vsn} || App <- [kernel,stdlib,sasl]]. + +app_vsns(AppVsns) -> + [{App,app_vsn(App,Vsn)} || {App,Vsn} <- AppVsns] ++ + [{App,app_vsn(App,Vsn),Type} || {App,Vsn,Type} <- AppVsns]. +app_vsn(App,current) -> + application:load(App), + {ok,Vsn} = application:get_key(App,vsn), + Vsn; +app_vsn(_App,Vsn) -> + Vsn. + +erts_vsn(current) -> erlang:system_info(version); +erts_vsn(Vsn) -> Vsn. + + create_include_files(inc1, Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, inc1), + PrivDir = ?privdir, + Name = fname(PrivDir, inc1), create_apps(PrivDir), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + Apps = application_controller:which_applications(), + {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\n" - " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" - ++ StdlibVer ++ "\"},\n" - " {t6, \"1.0\"}, {t5, \"1.0\"}, \n" - " {t4, \"1.0\"}, {t3, \"1.0\"}, {t2, \"1.0\"}, \n" - " {t1, \"1.0\"}]}.\n", + " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" + ++ StdlibVer ++ "\"},\n" + " {t6, \"1.0\"}, {t5, \"1.0\"}, \n" + " {t4, \"1.0\"}, {t3, \"1.0\"}, {t2, \"1.0\"}, \n" + " {t1, \"1.0\"}]}.\n", file:write_file(Name ++ ".rel", list_to_binary(Rel)), {filename:dirname(Name), filename:basename(Name)}; create_include_files(inc2, Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, inc2), + PrivDir = ?privdir, + Name = fname(PrivDir, inc2), create_apps(PrivDir), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + Apps = application_controller:which_applications(), + {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), %% t6 does not include t5 ! Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\n" - " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" - ++ StdlibVer ++ "\"},\n" - " {t6, \"1.0\", [t4]}, {t5, \"1.0\"}, \n" - " {t4, \"1.0\"}, {t3, \"1.0\"}, {t2, \"1.0\"}, \n" - " {t1, \"1.0\"}]}.\n", + " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" + ++ StdlibVer ++ "\"},\n" + " {t6, \"1.0\", [t4]}, {t5, \"1.0\"}, \n" + " {t4, \"1.0\"}, {t3, \"1.0\"}, {t2, \"1.0\"}, \n" + " {t1, \"1.0\"}]}.\n", file:write_file(Name ++ ".rel", list_to_binary(Rel)), {filename:dirname(Name), filename:basename(Name)}; create_include_files(inc3, Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, inc3), + PrivDir = ?privdir, + Name = fname(PrivDir, inc3), create_apps(PrivDir), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + Apps = application_controller:which_applications(), + {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), %% t3 does not include t2 ! Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\n" - " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" - ++ StdlibVer ++ "\"},\n" - " {t6, \"1.0\"}, {t5, \"1.0\"}, \n" - " {t4, \"1.0\"}, {t3, \"1.0\", []}, {t2, \"1.0\"}, \n" - " {t1, \"1.0\"}]}.\n", + " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" + ++ StdlibVer ++ "\"},\n" + " {t6, \"1.0\"}, {t5, \"1.0\"}, \n" + " {t4, \"1.0\"}, {t3, \"1.0\", []}, {t2, \"1.0\"}, \n" + " {t1, \"1.0\"}]}.\n", file:write_file(Name ++ ".rel", list_to_binary(Rel)), {filename:dirname(Name), filename:basename(Name)}; create_include_files(inc4, Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, inc4), + PrivDir = ?privdir, + Name = fname(PrivDir, inc4), create_apps(PrivDir), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + Apps = application_controller:which_applications(), + {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), %% t3 does not include t2 ! %% t6 does not include t5 ! Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\n" - " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" - ++ StdlibVer ++ "\"},\n" - " {t6, \"1.0\", [t4]}, {t5, \"1.0\"}, \n" - " {t4, \"1.0\"}, {t3, \"1.0\", []}, {t2, \"1.0\"}, \n" - " {t1, \"1.0\"}]}.\n", + " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" + ++ StdlibVer ++ "\"},\n" + " {t6, \"1.0\", [t4]}, {t5, \"1.0\"}, \n" + " {t4, \"1.0\"}, {t3, \"1.0\", []}, {t2, \"1.0\"}, \n" + " {t1, \"1.0\"}]}.\n", file:write_file(Name ++ ".rel", list_to_binary(Rel)), {filename:dirname(Name), filename:basename(Name)}; create_include_files(inc5, Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, inc5), + PrivDir = ?privdir, + Name = fname(PrivDir, inc5), create_apps(PrivDir), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + Apps = application_controller:which_applications(), + {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), %% t6 does not include t5 ! %% exclude t5. Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\n" - " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" - ++ StdlibVer ++ "\"},\n" - " {t6, \"1.0\", [t4]}, \n" - " {t4, \"1.0\"}, {t3, \"1.0\", []}, {t2, \"1.0\"}, \n" - " {t1, \"1.0\"}]}.\n", + " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" + ++ StdlibVer ++ "\"},\n" + " {t6, \"1.0\", [t4]}, \n" + " {t4, \"1.0\"}, {t3, \"1.0\", []}, {t2, \"1.0\"}, \n" + " {t1, \"1.0\"}]}.\n", file:write_file(Name ++ ".rel", list_to_binary(Rel)), {filename:dirname(Name), filename:basename(Name)}; create_include_files(inc6, Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, inc6), + PrivDir = ?privdir, + Name = fname(PrivDir, inc6), create_apps(PrivDir), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + Apps = application_controller:which_applications(), + {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), %% t3 does include non existing t2 ! Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\n" - " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" - ++ StdlibVer ++ "\"},\n" - " {t6, \"1.0\"}, {t5, \"1.0\"}, \n" - " {t4, \"1.0\"}, {t3, \"1.0\"}, \n" - " {t1, \"1.0\"}]}.\n", + " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" + ++ StdlibVer ++ "\"},\n" + " {t6, \"1.0\"}, {t5, \"1.0\"}, \n" + " {t4, \"1.0\"}, {t3, \"1.0\"}, \n" + " {t1, \"1.0\"}]}.\n", file:write_file(Name ++ ".rel", list_to_binary(Rel)), {filename:dirname(Name), filename:basename(Name)}; create_include_files(inc7, Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, inc7), + PrivDir = ?privdir, + Name = fname(PrivDir, inc7), create_apps(PrivDir), create_app(t7, PrivDir), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + Apps = application_controller:which_applications(), + {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), %% t7 and t6 does include t5 ! Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\n" - " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" - ++ StdlibVer ++ "\"},\n" - " {t7, \"1.0\"}, {t6, \"1.0\"}, {t5, \"1.0\"}, \n" - " {t4, \"1.0\"}, {t3, \"1.0\"}, {t2, \"1.0\"}, \n" - " {t1, \"1.0\"}]}.\n", + " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" + ++ StdlibVer ++ "\"},\n" + " {t7, \"1.0\"}, {t6, \"1.0\"}, {t5, \"1.0\"}, \n" + " {t4, \"1.0\"}, {t3, \"1.0\"}, {t2, \"1.0\"}, \n" + " {t1, \"1.0\"}]}.\n", file:write_file(Name ++ ".rel", list_to_binary(Rel)), {filename:dirname(Name), filename:basename(Name)}; create_include_files(inc8, Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, inc8), + PrivDir = ?privdir, + Name = fname(PrivDir, inc8), create_circular_apps(PrivDir), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + Apps = application_controller:which_applications(), + {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), %% t8 uses t9 and t10 includes t9 ! Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\n" - " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" - ++ StdlibVer ++ "\"},\n" - " {t8, \"1.0\"}, {t9, \"1.0\"}, {t10, \"1.0\"}]}.\n", + " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" + ++ StdlibVer ++ "\"},\n" + " {t8, \"1.0\"}, {t9, \"1.0\"}, {t10, \"1.0\"}]}.\n", file:write_file(Name ++ ".rel", list_to_binary(Rel)), {filename:dirname(Name), filename:basename(Name)}; create_include_files(inc9, Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, inc9), + PrivDir = ?privdir, + Name = fname(PrivDir, inc9), create_circular_apps(PrivDir), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + Apps = application_controller:which_applications(), + {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), %% t8 uses t9, t9 uses t10 and t10 includes t8 ==> circular !! Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\n" - " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" - ++ StdlibVer ++ "\"},\n" - " {t8, \"1.0\"}, {t9, \"1.0\"}, {t10, \"1.0\", [t8]}]}.\n", + " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" + ++ StdlibVer ++ "\"},\n" + " {t8, \"1.0\"}, {t9, \"1.0\"}, {t10, \"1.0\", [t8]}]}.\n", file:write_file(Name ++ ".rel", list_to_binary(Rel)), {filename:dirname(Name), filename:basename(Name)}; create_include_files(inc10, Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, inc10), + PrivDir = ?privdir, + Name = fname(PrivDir, inc10), create_circular_apps(PrivDir), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + Apps = application_controller:which_applications(), + {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), %% t9 tries to include not specified (in .app file) application ! Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\n" - " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" - ++ StdlibVer ++ "\"},\n" - " {t8, \"1.0\"}, {t9, \"1.0\", [t7]}, {t10, \"1.0\"}]}.\n", + " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" + ++ StdlibVer ++ "\"},\n" + " {t8, \"1.0\"}, {t9, \"1.0\", [t7]}, {t10, \"1.0\"}]}.\n", file:write_file(Name ++ ".rel", list_to_binary(Rel)), {filename:dirname(Name), filename:basename(Name)}; create_include_files(inc11, Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, inc11), + PrivDir = ?privdir, + Name = fname(PrivDir, inc11), create_apps2(PrivDir), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + Apps = application_controller:which_applications(), + {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\n" - " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" - ++ StdlibVer ++ "\"},\n" - " {t11, \"1.0\"}, \n" - " {t12, \"1.0\"}, \n" - " {t13, \"1.0\"}]}.\n", + " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" + ++ StdlibVer ++ "\"},\n" + " {t11, \"1.0\"}, \n" + " {t12, \"1.0\"}, \n" + " {t13, \"1.0\"}]}.\n", file:write_file(Name ++ ".rel", list_to_binary(Rel)), {filename:dirname(Name), filename:basename(Name)}; -create_include_files(otp_3065, Config) -> - ?line PrivDir = ?privdir, - ?line Name = fname(PrivDir, otp_3065), +create_include_files(otp_3065_circular_dependenies, Config) -> + PrivDir = ?privdir, + Name = fname(PrivDir, otp_3065_circular_dependenies), create_apps_3065(PrivDir), - ?line Apps = application_controller:which_applications(), - ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), - ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + Apps = application_controller:which_applications(), + {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\n" - " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" - ++ StdlibVer ++ "\"},\n" - " {chAts, \"1.0\"}, {aa12, \"1.0\"}, \n" - " {chTraffic, \"1.0\"}]}.\n", + " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" + ++ StdlibVer ++ "\"},\n" + " {chAts, \"1.0\"}, {aa12, \"1.0\"}, \n" + " {chTraffic, \"1.0\"}]}.\n", + file:write_file(Name ++ ".rel", list_to_binary(Rel)), + {filename:dirname(Name), filename:basename(Name)}; + +create_include_files(sort_apps, Config) -> + PrivDir = ?privdir, + Name = fname(PrivDir, sort_apps), + create_sort_apps(PrivDir), + + Apps = application_controller:which_applications(), + {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + + Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\n" + " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" + ++ StdlibVer ++ "\"},\n" + " {t14, \"1.0\"}, \n" + " {t20, \"1.0\"}, \n" + " {t19, \"1.0\"}, \n" + " {t18, \"1.0\"}, \n" + " {t17, \"1.0\"}, \n" + " {t16, \"1.0\"}, \n" + " {t15, \"1.0\"}]}.\n", + file:write_file(Name ++ ".rel", list_to_binary(Rel)), + {filename:dirname(Name), filename:basename(Name)}; + +create_include_files(sort_apps_rev, Config) -> + PrivDir = ?privdir, + Name = fname(PrivDir, sort_apps_rev), + create_sort_apps(PrivDir), + + Apps = application_controller:which_applications(), + {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), + {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), + + Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\n" + " [{kernel, \"" ++ KernelVer ++ "\"}, {stdlib, \"" + ++ StdlibVer ++ "\"},\n" + " {t14, \"1.0\"}, \n" + " {t18, \"1.0\"}, \n" + " {t19, \"1.0\"}, \n" + " {t20, \"1.0\"}, \n" + " {t15, \"1.0\"}, \n" + " {t16, \"1.0\"}, \n" + " {t17, \"1.0\"}]}.\n", file:write_file(Name ++ ".rel", list_to_binary(Rel)), {filename:dirname(Name), filename:basename(Name)}. + create_apps(Dir) -> T1 = "{application, t1,\n" - " [{vsn, \"1.0\"},\n" - " {description, \"test\"},\n" - " {modules, []},\n" - " {applications, [kernel, stdlib]},\n" - " {registered, []}]}.\n", + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, [kernel, stdlib]},\n" + " {registered, []}]}.\n", file:write_file(fname(Dir, 't1.app'), list_to_binary(T1)), T2 = "{application, t2,\n" - " [{vsn, \"1.0\"},\n" - " {description, \"test\"},\n" - " {modules, []},\n" - " {applications, [t1]},\n" - " {registered, []}]}.\n", + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, [t1]},\n" + " {registered, []}]}.\n", file:write_file(fname(Dir, 't2.app'), list_to_binary(T2)), T3 = "{application, t3,\n" - " [{vsn, \"1.0\"},\n" - " {description, \"test\"},\n" - " {modules, []},\n" - " {applications, []},\n" - " {included_applications, [t2]},\n" - " {registered, []}]}.\n", + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, [t2]},\n" + " {registered, []}]}.\n", file:write_file(fname(Dir, 't3.app'), list_to_binary(T3)), T4 = "{application, t4,\n" - " [{vsn, \"1.0\"},\n" - " {description, \"test\"},\n" - " {modules, []},\n" - " {applications, [t3]},\n" - " {included_applications, []},\n" - " {registered, []}]}.\n", + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, [t3]},\n" + " {included_applications, []},\n" + " {registered, []}]}.\n", file:write_file(fname(Dir, 't4.app'), list_to_binary(T4)), T5 = "{application, t5,\n" - " [{vsn, \"1.0\"},\n" - " {description, \"test\"},\n" - " {modules, []},\n" - " {applications, [t3]},\n" - " {included_applications, []},\n" - " {registered, []}]}.\n", + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, [t3]},\n" + " {included_applications, []},\n" + " {registered, []}]}.\n", file:write_file(fname(Dir, 't5.app'), list_to_binary(T5)), T6 = "{application, t6,\n" - " [{vsn, \"1.0\"},\n" - " {description, \"test\"},\n" - " {modules, []},\n" - " {applications, []},\n" - " {included_applications, [t4, t5]},\n" - " {registered, []}]}.\n", + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, [t4, t5]},\n" + " {registered, []}]}.\n", file:write_file(fname(Dir, 't6.app'), list_to_binary(T6)). create_app(t7, Dir) -> T7 = "{application, t7,\n" - " [{vsn, \"1.0\"},\n" - " {description, \"test\"},\n" - " {modules, []},\n" - " {applications, []},\n" - " {included_applications, [t5]},\n" - " {registered, []}]}.\n", + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, [t5]},\n" + " {registered, []}]}.\n", file:write_file(fname(Dir, 't7.app'), list_to_binary(T7)). create_circular_apps(Dir) -> T8 = "{application, t8,\n" - " [{vsn, \"1.0\"},\n" - " {description, \"test\"},\n" - " {modules, []},\n" - " {applications, [t9]},\n" - " {included_applications, []},\n" - " {registered, []}]}.\n", + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, [t9]},\n" + " {included_applications, []},\n" + " {registered, []}]}.\n", file:write_file(fname(Dir, 't8.app'), list_to_binary(T8)), T9 = "{application, t9,\n" - " [{vsn, \"1.0\"},\n" - " {description, \"test\"},\n" - " {modules, []},\n" - " {applications, [t10]},\n" - " {included_applications, []},\n" - " {registered, []}]}.\n", + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, [t10]},\n" + " {included_applications, []},\n" + " {registered, []}]}.\n", file:write_file(fname(Dir, 't9.app'), list_to_binary(T9)), T10 = "{application, t10,\n" - " [{vsn, \"1.0\"},\n" - " {description, \"test\"},\n" - " {modules, []},\n" - " {applications, []},\n" - " {included_applications, [t8, t9]},\n" - " {registered, []}]}.\n", + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, [t8, t9]},\n" + " {registered, []}]}.\n", file:write_file(fname(Dir, 't10.app'), list_to_binary(T10)). create_apps2(Dir) -> T11 = "{application, t11,\n" - " [{vsn, \"1.0\"},\n" - " {description, \"test\"},\n" - " {modules, []},\n" - " {applications, []},\n" - " {included_applications, [t13]},\n" - " {registered, []}]}.\n", + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, [t13]},\n" + " {registered, []}]}.\n", file:write_file(fname(Dir, 't11.app'), list_to_binary(T11)), T12 = "{application, t12,\n" - " [{vsn, \"1.0\"},\n" - " {description, \"test\"},\n" - " {modules, []},\n" - " {applications, [t11]},\n" - " {registered, []}]}.\n", + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, [t11]},\n" + " {registered, []}]}.\n", file:write_file(fname(Dir, 't12.app'), list_to_binary(T12)), T13 = "{application, t13,\n" - " [{vsn, \"1.0\"},\n" - " {description, \"test\"},\n" - " {modules, []},\n" - " {applications, []},\n" - " {included_applications, []},\n" - " {registered, []}]}.\n", + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, []},\n" + " {registered, []}]}.\n", file:write_file(fname(Dir, 't13.app'), list_to_binary(T13)). create_apps_3065(Dir) -> T11 = "{application, chTraffic,\n" - " [{vsn, \"1.0\"},\n" - " {description, \"test\"},\n" - " {modules, []},\n" - " {applications, []},\n" - " {included_applications, [chAts]},\n" - " {registered, []}]}.\n", + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, [chAts]},\n" + " {registered, []}]}.\n", file:write_file(fname(Dir, 'chTraffic.app'), list_to_binary(T11)), T12 = "{application, chAts,\n" - " [{vsn, \"1.0\"},\n" - " {description, \"test\"},\n" - " {modules, []},\n" - " {applications, []},\n" - " {included_applications, [aa12]},\n" - " {registered, []}]}.\n", + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, [aa12]},\n" + " {registered, []}]}.\n", file:write_file(fname(Dir, 'chAts.app'), list_to_binary(T12)), T13 = "{application, aa12,\n" - " [{vsn, \"1.0\"},\n" - " {description, \"test\"},\n" - " {modules, []},\n" - " {applications, [chAts]},\n" - " {included_applications, []},\n" - " {registered, []}]}.\n", + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, [chAts]},\n" + " {included_applications, []},\n" + " {registered, []}]}.\n", file:write_file(fname(Dir, 'aa12.app'), list_to_binary(T13)). +create_sort_apps(Dir) -> + T14 = "{application, t14,\n" + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, [t18,t20,t19]},\n" + " {included_applications, [t15,t17,t16]},\n" + " {registered, []}]}.\n", + file:write_file(fname(Dir, 't14.app'), list_to_binary(T14)), + + T15 = "{application, t15,\n" + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, []},\n" + " {registered, []}]}.\n", + file:write_file(fname(Dir, 't15.app'), list_to_binary(T15)), + + T16 = "{application, t16,\n" + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, []},\n" + " {registered, []}]}.\n", + file:write_file(fname(Dir, 't16.app'), list_to_binary(T16)), + + T17 = "{application, t17,\n" + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, []},\n" + " {registered, []}]}.\n", + file:write_file(fname(Dir, 't17.app'), list_to_binary(T17)), + + T18 = "{application, t18,\n" + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, []},\n" + " {registered, []}]}.\n", + file:write_file(fname(Dir, 't18.app'), list_to_binary(T18)), + + T19 = "{application, t19,\n" + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, []},\n" + " {registered, []}]}.\n", + file:write_file(fname(Dir, 't19.app'), list_to_binary(T19)), + + T20 = "{application, t20,\n" + " [{vsn, \"1.0\"},\n" + " {description, \"test\"},\n" + " {modules, []},\n" + " {applications, []},\n" + " {included_applications, []},\n" + " {registered, []}]}.\n", + file:write_file(fname(Dir, 't20.app'), list_to_binary(T20)). + fname(N) -> filename:join(N). diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-2.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-2.1/ebin/fe.app new file mode 100644 index 0000000000..3cb0b0c2cf --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-2.1/ebin/fe.app @@ -0,0 +1,7 @@ +{application, fe, + [{description, "ERICSSON NR FOR FE"}, + {vsn, "2.1"}, + {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {registered, []}, + {applications, []}, + {mod, {fe1, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-500.18.7/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-500.18.7/ebin/fe.app new file mode 100644 index 0000000000..3a5c0ddd9b --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-500.18.7/ebin/fe.app @@ -0,0 +1,7 @@ +{application, fe, + [{description, "ERICSSON NR FOR FE"}, + {vsn, "500.18.7"}, + {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {registered, []}, + {applications, []}, + {mod, {fe1, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1.1/ebin/fe.app new file mode 100644 index 0000000000..c7ba1dfe91 --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1.1/ebin/fe.app @@ -0,0 +1,8 @@ +{application, fe, + [{description, "ERICSSON NR FOR FE"}, + {vsn, "2.1.1"}, + {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {registered, []}, + {applications, []}, + {env, []}, + {start, {fe2, start, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1/ebin/fe.app new file mode 100644 index 0000000000..47ea248720 --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1/ebin/fe.app @@ -0,0 +1,8 @@ +{application, fe, + [{description, "ERICSSON NR FOR FE"}, + {vsn, "2.1"}, + {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {registered, []}, + {applications, []}, + {env, []}, + {start, {fe2, start, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.app new file mode 100644 index 0000000000..0696e2494c --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.app @@ -0,0 +1,7 @@ +{application, fe, + [{description, "ERICSSON NR FOR FE"}, + {vsn, "3.1"}, + {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]}, + {registered, []}, + {applications, []}, + {mod, {fe1, []}}]}. diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.appup b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.appup new file mode 100644 index 0000000000..6b99c47e53 --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.appup @@ -0,0 +1,28 @@ +%% -*- erlang -*- +%% Release upgrade script for fe (front end) +%% + +{ + "3.1", + %% Upgrade from: + [ + {<<"2\\.[0-9]+">>, % matches 2.X in full length and 2.X.Y... only partly + [{update, fe1, soft, soft_purge, soft_purge, []}, + {update, fe2, soft, soft_purge, soft_purge, [fe1]}, + {update, fe3, {advanced, extra}, soft_purge, soft_purge, [fe1, fe2]} + ]}, + {<<"2(\\.[0-9]+)+">>, % matches 2.X.Y... in full length + [{update, fe1, soft, soft_purge, soft_purge, []}, + {update, fe2, soft, soft_purge, soft_purge, [fe1]}, + {update, fe3, {advanced, extra}, soft_purge, soft_purge,[fe1, fe2]}, + restart_emulator]} + ], + + %% Downgrade to: + [ + {<<"2\\.[0-9]+">>, % matches 2.X in full length and 2.X.Y... only partly + [{update, fe2, soft, soft_purge, soft_purge, []}, + {update, fe3, {advanced, extra}, soft_purge, soft_purge, [fe2]} + ]} + ] +}. diff --git a/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.app b/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.app new file mode 100644 index 0000000000..3bcc1a4619 --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.app @@ -0,0 +1,6 @@ +{application, sasl, + [{description, "FAKE FUTURE SASL"}, + {vsn, "9.9"}, + {modules, []}, + {registered, []}, + {applications, []}]}. diff --git a/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.appup b/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.appup new file mode 100644 index 0000000000..cff0c69b6e --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.appup @@ -0,0 +1,12 @@ +%% +%% Fake release upgrade script for sasl +%% + +{ + "9.9", + [{<<".+">>,[restart_new_emulator]} + ], + + [{<<".+">>,[restart_new_emulator]} + ] +}. diff --git a/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.app b/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.app new file mode 100644 index 0000000000..aaeb37fa4d --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.app @@ -0,0 +1,6 @@ +{application, sasl, + [{description, "FAKE SASL"}, + {vsn, "1.0"}, + {modules, []}, + {registered, []}, + {applications, []}]}. diff --git a/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.appup b/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.appup new file mode 100644 index 0000000000..796a1e7368 --- /dev/null +++ b/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.appup @@ -0,0 +1,12 @@ +%% +%% Fake release upgrade script for sasl +%% + +{ + "1.0", + [ + ], + + [ + ] +}. diff --git a/lib/sasl/test/systools_rc_SUITE.erl b/lib/sasl/test/systools_rc_SUITE.erl index bb93f38fa7..bd4aa9e7a7 100644 --- a/lib/sasl/test/systools_rc_SUITE.erl +++ b/lib/sasl/test/systools_rc_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010. All Rights Reserved. +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -18,17 +18,18 @@ %% -module(systools_rc_SUITE). --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). -include_lib("sasl/src/systools.hrl"). -export([all/0,groups/0,init_per_group/2,end_per_group/2, - syntax_check/1, translate/1, translate_app/1]). + syntax_check/1, translate/1, translate_app/1, + translate_emulator_restarts/1]). %%----------------------------------------------------------------- %% erl -compile systools_rc_SUITE @i ../src/ @i ../../test_server/include/ %% c(systools_rc_SUITE, [{i, "../src"}, {i, "../../test_server/include"}]). %%----------------------------------------------------------------- all() -> - [syntax_check, translate, translate_app]. + [syntax_check, translate, translate_app, translate_emulator_restarts]. groups() -> []. @@ -40,7 +41,6 @@ end_per_group(_GroupName, Config) -> Config. -syntax_check(suite) -> []; syntax_check(Config) when is_list(Config) -> PreApps = [#application{name = test, @@ -68,8 +68,8 @@ syntax_check(Config) when is_list(Config) -> {update, baz, 5000, soft, brutal_purge, brutal_purge, []}, {add_module, new_mod}, {remove_application, snmp} - ], - ?line {ok, _} = systools_rc:translate_scripts([S1], Apps, PreApps), + ], + {ok, _} = systools_rc:translate_scripts([S1], Apps, PreApps), S2 = [ {apply, {m, f, [a]}}, {load_object_code, {tst, "1.0", [new_mod]}}, @@ -87,42 +87,42 @@ syntax_check(Config) when is_list(Config) -> {sync_nodes, id1, {m, f, [a]}}, {sync_nodes, id2, [cp1, cp2]}, {apply, {m,f,[a]}}, - restart_new_emulator - ], - ?line {ok, _} = systools_rc:translate_scripts([S2], Apps, []), + restart_new_emulator, + restart_emulator + ], + {ok, _} = systools_rc:translate_scripts([S2], Apps, []), S3 = [{apply, {m, f, a}}], - ?line {error, _, _} = systools_rc:translate_scripts([S3], Apps, []), + {error, _, _} = systools_rc:translate_scripts([S3], Apps, []), S3_1 = [{apply, {m, 3, a}}], - ?line {error, _, _} = systools_rc:translate_scripts([S3_1], Apps, []), + {error, _, _} = systools_rc:translate_scripts([S3_1], Apps, []), S4 = [{apply, {m, f}}], - ?line {error, _, _} = systools_rc:translate_scripts([S4], Apps, []), + {error, _, _} = systools_rc:translate_scripts([S4], Apps, []), S5 = [{load_object_code, hej}], - ?line {error, _, _} = systools_rc:translate_scripts([S5], Apps, []), + {error, _, _} = systools_rc:translate_scripts([S5], Apps, []), S6 = [{load_object_code, {342, "1.0", [foo]}}], - ?line {error, _, _} = systools_rc:translate_scripts([S6], Apps, []), + {error, _, _} = systools_rc:translate_scripts([S6], Apps, []), S7 = [{load_object_code, {tets, "1.0", foo}}], - ?line {error, _, _} = systools_rc:translate_scripts([S7], Apps, []), + {error, _, _} = systools_rc:translate_scripts([S7], Apps, []), S8 = [{suspend, [m1]}, point_of_no_return], - ?line {error, _, _} = systools_rc:translate_scripts([S8], Apps, []), + {error, _, _} = systools_rc:translate_scripts([S8], Apps, []), S9 = [{update, ba, {advanced, extra}, brutal_purge, brutal_purge, []}], - ?line {error, _, _} = systools_rc:translate_scripts([S9], Apps, []), + {error, _, _} = systools_rc:translate_scripts([S9], Apps, []), S10 = [{update, bar, {advanced, extra}, brutal_purge, brutal_purge, [baz]}], - ?line {error, _, _} = systools_rc:translate_scripts([S10], Apps, []), + {error, _, _} = systools_rc:translate_scripts([S10], Apps, []), S11 = [{update, bar, {advanced, extra}, brutal_purge, brutal_purge, [ba]}], - ?line {error, _, _} = systools_rc:translate_scripts([S11], Apps, []), + {error, _, _} = systools_rc:translate_scripts([S11], Apps, []), S12 = [{update, bar, advanced, brutal_purge, brutal_purge, []}], - ?line {error, _, _} = systools_rc:translate_scripts([S12], Apps, []), + {error, _, _} = systools_rc:translate_scripts([S12], Apps, []), S13 = [{update, bar, {advanced, extra}, rutal_purge, brutal_purge, [ba]}], - ?line {error, _, _} = systools_rc:translate_scripts([S13], Apps, []), + {error, _, _} = systools_rc:translate_scripts([S13], Apps, []), S14 = [{update, bar, {advanced, extra}, brutal_purge, rutal_purge, [ba]}], - ?line {error, _, _} = systools_rc:translate_scripts([S14], Apps, []), + {error, _, _} = systools_rc:translate_scripts([S14], Apps, []), S15 = [{update, bar, {advanced, extra}, brutal_purge, brutal_purge, ba}], - ?line {error, _, _} = systools_rc:translate_scripts([S15], Apps, []), + {error, _, _} = systools_rc:translate_scripts([S15], Apps, []), S16 = [{code_change, [module]}], - ?line {error, _, _} = systools_rc:translate_scripts([S16], Apps, []), - ?line ok. + {error, _, _} = systools_rc:translate_scripts([S16], Apps, []), + ok. -translate(suite) -> []; translate(Config) when is_list(Config) -> Apps = [#application{name = test, @@ -134,170 +134,170 @@ translate(Config) when is_list(Config) -> mod = {sasl, []}}], %% Simple translation (1) Up1 = [{update, foo, soft, soft_purge, soft_purge, []}], - ?line {ok, X1} = systools_rc:translate_scripts([Up1], Apps, []), - ?line [{load_object_code, {test,"1.0",[foo]}}, - point_of_no_return, - {suspend,[foo]}, - {load,{foo,soft_purge,soft_purge}}, - {resume,[foo]}] = X1, + {ok, X1} = systools_rc:translate_scripts([Up1], Apps, []), + [{load_object_code, {test,"1.0",[foo]}}, + point_of_no_return, + {suspend,[foo]}, + {load,{foo,soft_purge,soft_purge}}, + {resume,[foo]}] = X1, %% Simple translation (2) Up2 = [{update, foo, {advanced, extra}, soft_purge, soft_purge, []}], - ?line {ok, X2} = systools_rc:translate_scripts([Up2], Apps, []), - ?line [{load_object_code, {test,"1.0",[foo]}}, - point_of_no_return, - {suspend,[foo]}, - {load,{foo,soft_purge,soft_purge}}, - {code_change, up, [{foo, extra}]}, - {resume,[foo]}] = X2, - - ?line {ok, X22} = systools_rc:translate_scripts(dn,[Up2], Apps, []), - ?line [{load_object_code, {test,"1.0",[foo]}}, - point_of_no_return, - {suspend,[foo]}, - {code_change, down, [{foo, extra}]}, - {load,{foo,soft_purge,soft_purge}}, - {resume,[foo]}] = X22, + {ok, X2} = systools_rc:translate_scripts([Up2], Apps, []), + [{load_object_code, {test,"1.0",[foo]}}, + point_of_no_return, + {suspend,[foo]}, + {load,{foo,soft_purge,soft_purge}}, + {code_change, up, [{foo, extra}]}, + {resume,[foo]}] = X2, + + {ok, X22} = systools_rc:translate_scripts(dn,[Up2], Apps, []), + [{load_object_code, {test,"1.0",[foo]}}, + point_of_no_return, + {suspend,[foo]}, + {code_change, down, [{foo, extra}]}, + {load,{foo,soft_purge,soft_purge}}, + {resume,[foo]}] = X22, Up2a = [{update, foo, static, default, {advanced,extra}, soft_purge, soft_purge, []}], - ?line {ok, X2a} = systools_rc:translate_scripts([Up2a], Apps, []), - ?line [{load_object_code, {test,"1.0",[foo]}}, - point_of_no_return, - {suspend,[foo]}, - {load,{foo,soft_purge,soft_purge}}, - {code_change, up, [{foo, extra}]}, - {resume,[foo]}] = X2a, - - ?line {ok, X22a} = systools_rc:translate_scripts(dn,[Up2a], Apps, []), - ?line [{load_object_code, {test,"1.0",[foo]}}, - point_of_no_return, - {suspend,[foo]}, - {load,{foo,soft_purge,soft_purge}}, - {code_change, down, [{foo, extra}]}, - {resume,[foo]}] = X22a, + {ok, X2a} = systools_rc:translate_scripts([Up2a], Apps, []), + [{load_object_code, {test,"1.0",[foo]}}, + point_of_no_return, + {suspend,[foo]}, + {load,{foo,soft_purge,soft_purge}}, + {code_change, up, [{foo, extra}]}, + {resume,[foo]}] = X2a, + + {ok, X22a} = systools_rc:translate_scripts(dn,[Up2a], Apps, []), + [{load_object_code, {test,"1.0",[foo]}}, + point_of_no_return, + {suspend,[foo]}, + {load,{foo,soft_purge,soft_purge}}, + {code_change, down, [{foo, extra}]}, + {resume,[foo]}] = X22a, %% Simple dependency (1) Up3 = [{update, foo, soft, soft_purge, soft_purge, [bar]}, {update, bar, soft, soft_purge, soft_purge, []}], - ?line {ok, X31} = systools_rc:translate_scripts([Up3], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,bar]}}, - point_of_no_return, - {suspend,[foo,bar]}, - {load,{bar,soft_purge,soft_purge}}, - {load,{foo,soft_purge,soft_purge}}, - {resume,[bar,foo]}] = X31, - ?line {ok, X32} = systools_rc:translate_scripts(dn,[Up3], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,bar]}}, - point_of_no_return, - {suspend,[foo,bar]}, - {load,{foo,soft_purge,soft_purge}}, - {load,{bar,soft_purge,soft_purge}}, - {resume,[bar,foo]}] = X32, + {ok, X31} = systools_rc:translate_scripts([Up3], Apps, []), + [{load_object_code,{test,"1.0",[foo,bar]}}, + point_of_no_return, + {suspend,[foo,bar]}, + {load,{bar,soft_purge,soft_purge}}, + {load,{foo,soft_purge,soft_purge}}, + {resume,[bar,foo]}] = X31, + {ok, X32} = systools_rc:translate_scripts(dn,[Up3], Apps, []), + [{load_object_code,{test,"1.0",[foo,bar]}}, + point_of_no_return, + {suspend,[foo,bar]}, + {load,{foo,soft_purge,soft_purge}}, + {load,{bar,soft_purge,soft_purge}}, + {resume,[bar,foo]}] = X32, Up3a = [{update, foo, static, default, soft, soft_purge, soft_purge, [bar]}, {update, bar, static, default, soft, soft_purge, soft_purge, []}], - ?line {ok, X3a1} = systools_rc:translate_scripts([Up3a], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,bar]}}, - point_of_no_return, - {suspend,[foo, bar]}, - {load,{bar,soft_purge,soft_purge}}, - {load,{foo,soft_purge,soft_purge}}, - {resume,[bar,foo]}] = X3a1, - ?line {ok, X3a2} = systools_rc:translate_scripts(dn,[Up3a], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,bar]}}, - point_of_no_return, - {suspend,[foo,bar]}, - {load,{foo,soft_purge,soft_purge}}, - {load,{bar,soft_purge,soft_purge}}, - {resume,[bar,foo]}] = X3a2, + {ok, X3a1} = systools_rc:translate_scripts([Up3a], Apps, []), + [{load_object_code,{test,"1.0",[foo,bar]}}, + point_of_no_return, + {suspend,[foo, bar]}, + {load,{bar,soft_purge,soft_purge}}, + {load,{foo,soft_purge,soft_purge}}, + {resume,[bar,foo]}] = X3a1, + {ok, X3a2} = systools_rc:translate_scripts(dn,[Up3a], Apps, []), + [{load_object_code,{test,"1.0",[foo,bar]}}, + point_of_no_return, + {suspend,[foo,bar]}, + {load,{foo,soft_purge,soft_purge}}, + {load,{bar,soft_purge,soft_purge}}, + {resume,[bar,foo]}] = X3a2, %% Simple dependency (2) Up4 = [{update, foo, soft, soft_purge, soft_purge, [bar]}, {update, bar, {advanced, []}, soft_purge, soft_purge, []}], - ?line {ok, X4} = systools_rc:translate_scripts(up,[Up4], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,bar]}}, - point_of_no_return, - {suspend,[foo,bar]}, - {load,{bar,soft_purge,soft_purge}}, - {load,{foo,soft_purge,soft_purge}}, - {code_change,up,[{bar,[]}]}, - {resume,[bar,foo]}] = X4, - - ?line {ok, X42} = systools_rc:translate_scripts(dn,[Up4], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,bar]}}, - point_of_no_return, - {suspend,[foo,bar]}, - {code_change,down,[{bar,[]}]}, - {load,{foo,soft_purge,soft_purge}}, - {load,{bar,soft_purge,soft_purge}}, - {resume,[bar,foo]}] = X42, + {ok, X4} = systools_rc:translate_scripts(up,[Up4], Apps, []), + [{load_object_code,{test,"1.0",[foo,bar]}}, + point_of_no_return, + {suspend,[foo,bar]}, + {load,{bar,soft_purge,soft_purge}}, + {load,{foo,soft_purge,soft_purge}}, + {code_change,up,[{bar,[]}]}, + {resume,[bar,foo]}] = X4, + + {ok, X42} = systools_rc:translate_scripts(dn,[Up4], Apps, []), + [{load_object_code,{test,"1.0",[foo,bar]}}, + point_of_no_return, + {suspend,[foo,bar]}, + {code_change,down,[{bar,[]}]}, + {load,{foo,soft_purge,soft_purge}}, + {load,{bar,soft_purge,soft_purge}}, + {resume,[bar,foo]}] = X42, Up4a = [{update, foo, soft, soft_purge, soft_purge, [bar]}, {update, bar, static, infinity, {advanced, []}, soft_purge, soft_purge, []}], - ?line {ok, X4a} = systools_rc:translate_scripts(up,[Up4a], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,bar]}}, - point_of_no_return, - {suspend,[foo,{bar,infinity}]}, - {load,{bar,soft_purge,soft_purge}}, - {load,{foo,soft_purge,soft_purge}}, - {code_change,up,[{bar,[]}]}, - {resume,[bar,foo]}] = X4a, - - ?line {ok, X42a} = systools_rc:translate_scripts(dn,[Up4a], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,bar]}}, - point_of_no_return, - {suspend,[foo,{bar,infinity}]}, - {load,{foo,soft_purge,soft_purge}}, - {load,{bar,soft_purge,soft_purge}}, - {code_change,down,[{bar,[]}]}, - {resume,[bar,foo]}] = X42a, + {ok, X4a} = systools_rc:translate_scripts(up,[Up4a], Apps, []), + [{load_object_code,{test,"1.0",[foo,bar]}}, + point_of_no_return, + {suspend,[foo,{bar,infinity}]}, + {load,{bar,soft_purge,soft_purge}}, + {load,{foo,soft_purge,soft_purge}}, + {code_change,up,[{bar,[]}]}, + {resume,[bar,foo]}] = X4a, + + {ok, X42a} = systools_rc:translate_scripts(dn,[Up4a], Apps, []), + [{load_object_code,{test,"1.0",[foo,bar]}}, + point_of_no_return, + {suspend,[foo,{bar,infinity}]}, + {load,{foo,soft_purge,soft_purge}}, + {load,{bar,soft_purge,soft_purge}}, + {code_change,down,[{bar,[]}]}, + {resume,[bar,foo]}] = X42a, Up4b = [{update, foo, soft, soft_purge, soft_purge, [bar]}, {update, bar, dynamic, infinity, {advanced, []}, soft_purge, soft_purge, []}], - ?line {ok, X4b} = systools_rc:translate_scripts(up,[Up4b], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,bar]}}, - point_of_no_return, - {suspend,[foo,{bar,infinity}]}, - {load,{bar,soft_purge,soft_purge}}, - {load,{foo,soft_purge,soft_purge}}, - {code_change,up,[{bar,[]}]}, - {resume,[bar,foo]}] = X4b, - - ?line {ok, X42b} = systools_rc:translate_scripts(dn,[Up4b], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,bar]}}, - point_of_no_return, - {suspend,[foo,{bar,infinity}]}, - {code_change,down,[{bar,[]}]}, - {load,{foo,soft_purge,soft_purge}}, - {load,{bar,soft_purge,soft_purge}}, - {resume,[bar,foo]}] = X42b, + {ok, X4b} = systools_rc:translate_scripts(up,[Up4b], Apps, []), + [{load_object_code,{test,"1.0",[foo,bar]}}, + point_of_no_return, + {suspend,[foo,{bar,infinity}]}, + {load,{bar,soft_purge,soft_purge}}, + {load,{foo,soft_purge,soft_purge}}, + {code_change,up,[{bar,[]}]}, + {resume,[bar,foo]}] = X4b, + + {ok, X42b} = systools_rc:translate_scripts(dn,[Up4b], Apps, []), + [{load_object_code,{test,"1.0",[foo,bar]}}, + point_of_no_return, + {suspend,[foo,{bar,infinity}]}, + {code_change,down,[{bar,[]}]}, + {load,{foo,soft_purge,soft_purge}}, + {load,{bar,soft_purge,soft_purge}}, + {resume,[bar,foo]}] = X42b, %% More complex dependency Up5 = [{update, foo, soft, soft_purge, soft_purge, [bar, baz]}, {update, bar, {advanced, []}, soft_purge, soft_purge, []}, {update, baz, {advanced, baz}, soft_purge, soft_purge, [bar]}], - ?line {ok, X5} = systools_rc:translate_scripts([Up5], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,baz,bar]}}, - point_of_no_return, - {suspend,[foo,baz,bar]}, - {load,{bar,soft_purge,soft_purge}}, - {load,{baz,soft_purge,soft_purge}}, - {load,{foo,soft_purge,soft_purge}}, - {code_change,up,[{baz,baz},{bar,[]}]}, - {resume,[bar,baz,foo]}] = X5, - - ?line {ok, X52} = systools_rc:translate_scripts(dn,[Up5], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,baz,bar]}}, - point_of_no_return, - {suspend,[foo,baz,bar]}, - {code_change,down,[{baz,baz},{bar,[]}]}, - {load,{foo,soft_purge,soft_purge}}, - {load,{baz,soft_purge,soft_purge}}, - {load,{bar,soft_purge,soft_purge}}, - {resume,[bar,baz,foo]}] = X52, + {ok, X5} = systools_rc:translate_scripts([Up5], Apps, []), + [{load_object_code,{test,"1.0",[foo,baz,bar]}}, + point_of_no_return, + {suspend,[foo,baz,bar]}, + {load,{bar,soft_purge,soft_purge}}, + {load,{baz,soft_purge,soft_purge}}, + {load,{foo,soft_purge,soft_purge}}, + {code_change,up,[{baz,baz},{bar,[]}]}, + {resume,[bar,baz,foo]}] = X5, + + {ok, X52} = systools_rc:translate_scripts(dn,[Up5], Apps, []), + [{load_object_code,{test,"1.0",[foo,baz,bar]}}, + point_of_no_return, + {suspend,[foo,baz,bar]}, + {code_change,down,[{baz,baz},{bar,[]}]}, + {load,{foo,soft_purge,soft_purge}}, + {load,{baz,soft_purge,soft_purge}}, + {load,{bar,soft_purge,soft_purge}}, + {resume,[bar,baz,foo]}] = X52, Up5a = [{update, foo, dynamic, infinity, soft, soft_purge, soft_purge, [bar, baz]}, @@ -305,26 +305,26 @@ translate(Config) when is_list(Config) -> soft_purge, []}, {update, baz, dynamic, default, {advanced, baz}, soft_purge, soft_purge, [bar]}], - ?line {ok, X5a} = systools_rc:translate_scripts([Up5a], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,baz,bar]}}, - point_of_no_return, - {suspend,[{foo,infinity},baz,{bar,7000}]}, - {load,{bar,soft_purge,soft_purge}}, - {load,{baz,soft_purge,soft_purge}}, - {load,{foo,soft_purge,soft_purge}}, - {code_change,up,[{baz,baz}, {bar,[]}]}, - {resume,[bar,baz,foo]}] = X5a, - - ?line {ok, X52a} = systools_rc:translate_scripts(dn,[Up5a], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,baz,bar]}}, - point_of_no_return, - {suspend,[{foo,infinity},baz,{bar,7000}]}, - {code_change,down,[{baz,baz}]}, - {load,{foo,soft_purge,soft_purge}}, - {load,{baz,soft_purge,soft_purge}}, - {load,{bar,soft_purge,soft_purge}}, - {code_change,down,[{bar,[]}]}, - {resume,[bar,baz,foo]}] = X52a, + {ok, X5a} = systools_rc:translate_scripts([Up5a], Apps, []), + [{load_object_code,{test,"1.0",[foo,baz,bar]}}, + point_of_no_return, + {suspend,[{foo,infinity},baz,{bar,7000}]}, + {load,{bar,soft_purge,soft_purge}}, + {load,{baz,soft_purge,soft_purge}}, + {load,{foo,soft_purge,soft_purge}}, + {code_change,up,[{baz,baz}, {bar,[]}]}, + {resume,[bar,baz,foo]}] = X5a, + + {ok, X52a} = systools_rc:translate_scripts(dn,[Up5a], Apps, []), + [{load_object_code,{test,"1.0",[foo,baz,bar]}}, + point_of_no_return, + {suspend,[{foo,infinity},baz,{bar,7000}]}, + {code_change,down,[{baz,baz}]}, + {load,{foo,soft_purge,soft_purge}}, + {load,{baz,soft_purge,soft_purge}}, + {load,{bar,soft_purge,soft_purge}}, + {code_change,down,[{bar,[]}]}, + {resume,[bar,baz,foo]}] = X52a, Up5b = [{update, foo, dynamic, infinity, soft, soft_purge, soft_purge, [bar, baz]}, @@ -332,65 +332,65 @@ translate(Config) when is_list(Config) -> soft_purge, []}, {update, baz, static, default, {advanced, baz}, soft_purge, soft_purge, [bar]}], - ?line {ok, X5b} = systools_rc:translate_scripts([Up5b], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,baz,bar]}}, - point_of_no_return, - {suspend,[{foo,infinity},baz,{bar,7000}]}, - {load,{bar,soft_purge,soft_purge}}, - {load,{baz,soft_purge,soft_purge}}, - {load,{foo,soft_purge,soft_purge}}, - {code_change,up,[{baz,baz},{bar,[]}]}, - {resume,[bar,baz,foo]}] = X5b, - - ?line {ok, X52b} = systools_rc:translate_scripts(dn,[Up5b], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,baz,bar]}}, - point_of_no_return, - {suspend,[{foo,infinity},baz,{bar,7000}]}, - {code_change,down,[{bar,[]}]}, - {load,{foo,soft_purge,soft_purge}}, - {load,{baz,soft_purge,soft_purge}}, - {load,{bar,soft_purge,soft_purge}}, - {code_change,down,[{baz,baz}]}, - {resume,[bar,baz,foo]}] = X52b, + {ok, X5b} = systools_rc:translate_scripts([Up5b], Apps, []), + [{load_object_code,{test,"1.0",[foo,baz,bar]}}, + point_of_no_return, + {suspend,[{foo,infinity},baz,{bar,7000}]}, + {load,{bar,soft_purge,soft_purge}}, + {load,{baz,soft_purge,soft_purge}}, + {load,{foo,soft_purge,soft_purge}}, + {code_change,up,[{baz,baz},{bar,[]}]}, + {resume,[bar,baz,foo]}] = X5b, + + {ok, X52b} = systools_rc:translate_scripts(dn,[Up5b], Apps, []), + [{load_object_code,{test,"1.0",[foo,baz,bar]}}, + point_of_no_return, + {suspend,[{foo,infinity},baz,{bar,7000}]}, + {code_change,down,[{bar,[]}]}, + {load,{foo,soft_purge,soft_purge}}, + {load,{baz,soft_purge,soft_purge}}, + {load,{bar,soft_purge,soft_purge}}, + {code_change,down,[{baz,baz}]}, + {resume,[bar,baz,foo]}] = X52b, %% Simple circular dependency (1) Up6 = [{update, foo, soft, soft_purge, soft_purge, [bar]}, {update, bar, soft, soft_purge, soft_purge, [foo]}], - ?line {ok, X61} = systools_rc:translate_scripts([Up6], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,bar]}}, - point_of_no_return, - {suspend,[foo,bar]}, - {load,{bar,soft_purge,soft_purge}}, - {load,{foo,soft_purge,soft_purge}}, - {resume,[bar,foo]}] = X61, - ?line {ok, X62} = systools_rc:translate_scripts(dn,[Up6], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,bar]}}, - point_of_no_return, - {suspend,[foo,bar]}, - {load,{foo,soft_purge,soft_purge}}, - {load,{bar,soft_purge,soft_purge}}, - {resume,[bar,foo]}] = X62, + {ok, X61} = systools_rc:translate_scripts([Up6], Apps, []), + [{load_object_code,{test,"1.0",[foo,bar]}}, + point_of_no_return, + {suspend,[foo,bar]}, + {load,{bar,soft_purge,soft_purge}}, + {load,{foo,soft_purge,soft_purge}}, + {resume,[bar,foo]}] = X61, + {ok, X62} = systools_rc:translate_scripts(dn,[Up6], Apps, []), + [{load_object_code,{test,"1.0",[foo,bar]}}, + point_of_no_return, + {suspend,[foo,bar]}, + {load,{foo,soft_purge,soft_purge}}, + {load,{bar,soft_purge,soft_purge}}, + {resume,[bar,foo]}] = X62, %% Simple circular dependency (2) Up7 = [{update, foo, soft, soft_purge, soft_purge, [bar, baz]}, {update, bar, soft, soft_purge, soft_purge, [foo]}, {update, baz, soft, soft_purge, soft_purge, [bar]}], - ?line {ok, X71} = systools_rc:translate_scripts([Up7], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,bar,baz]}}, - point_of_no_return, - {suspend,[foo,bar,baz]}, - {load,{baz,soft_purge,soft_purge}}, - {load,{bar,soft_purge,soft_purge}}, - {load,{foo,soft_purge,soft_purge}}, - {resume,[baz, bar, foo]}] = X71, - ?line {ok, X72} = systools_rc:translate_scripts(dn,[Up7], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,bar,baz]}}, - point_of_no_return, - {suspend,[foo,bar,baz]}, - {load,{foo,soft_purge,soft_purge}}, - {load,{bar,soft_purge,soft_purge}}, - {load,{baz,soft_purge,soft_purge}}, - {resume,[baz,bar,foo]}] = X72, + {ok, X71} = systools_rc:translate_scripts([Up7], Apps, []), + [{load_object_code,{test,"1.0",[foo,bar,baz]}}, + point_of_no_return, + {suspend,[foo,bar,baz]}, + {load,{baz,soft_purge,soft_purge}}, + {load,{bar,soft_purge,soft_purge}}, + {load,{foo,soft_purge,soft_purge}}, + {resume,[baz, bar, foo]}] = X71, + {ok, X72} = systools_rc:translate_scripts(dn,[Up7], Apps, []), + [{load_object_code,{test,"1.0",[foo,bar,baz]}}, + point_of_no_return, + {suspend,[foo,bar,baz]}, + {load,{foo,soft_purge,soft_purge}}, + {load,{bar,soft_purge,soft_purge}}, + {load,{baz,soft_purge,soft_purge}}, + {resume,[baz,bar,foo]}] = X72, %% Complex circular dependencies, check only order %% @@ -400,20 +400,20 @@ translate(Config) when is_list(Config) -> {update, z, soft, soft_purge, soft_purge, [x]}, {update, bar, soft, soft_purge, soft_purge, [baz]}, {update, baz, soft, soft_purge, soft_purge, [bar]}], - ?line {ok, X8} = systools_rc:translate_scripts([Up8], Apps, []), - ?line {value, {suspend, Order}} = lists:keysearch(suspend, 1, X8), - ?line Rest = case lists:reverse(Order) of - [bar, baz | R] -> R; - [baz, bar | R] -> R - end, - ?line case Rest of - [y, z, x, foo] -> ok; - [y, x, z, foo] -> ok; - [foo, y, z, x] -> ok; - [foo, y, x, z] -> ok; - [y, foo, z, x] -> ok; - [y, foo, x, z] -> ok - end, + {ok, X8} = systools_rc:translate_scripts([Up8], Apps, []), + {value, {suspend, Order}} = lists:keysearch(suspend, 1, X8), + Rest = case lists:reverse(Order) of + [bar, baz | R] -> R; + [baz, bar | R] -> R + end, + case Rest of + [y, z, x, foo] -> ok; + [y, x, z, foo] -> ok; + [foo, y, z, x] -> ok; + [foo, y, x, z] -> ok; + [y, foo, z, x] -> ok; + [y, foo, x, z] -> ok + end, %% Check that order among other instructions isn't changed Up9 = [{update, foo, soft, soft_purge, soft_purge, [baz]}, @@ -428,13 +428,12 @@ translate(Config) when is_list(Config) -> {apply, {m, f, [5]}}, {update, baz, soft, soft_purge, soft_purge, [bar]}, {apply, {m, f, [6]}}], - ?line {ok, X9} = systools_rc:translate_scripts([Up9], Apps, []), + {ok, X9} = systools_rc:translate_scripts([Up9], Apps, []), Other2 = [X || {apply, {m, f, [X]}} <- X9], - ?line [1,2,3,4,5,6] = lists:sort(Other2), - ?line ok. + [1,2,3,4,5,6] = lists:sort(Other2), + ok. -translate_app(suite) -> []; translate_app(Config) when is_list(Config) -> PreApps = [#application{name = test, @@ -459,30 +458,112 @@ translate_app(Config) when is_list(Config) -> %% Simple translation (1) Up1 = [{add_module, foo}, {add_module, bar}], - ?line {ok, X1} = systools_rc:translate_scripts([Up1], Apps, []), - ?line [{load_object_code,{test,"1.0",[foo,bar]}}, - point_of_no_return, - {load,{foo,brutal_purge,brutal_purge}}, - {load,{bar,brutal_purge,brutal_purge}}] = X1, + {ok, X1} = systools_rc:translate_scripts([Up1], Apps, []), + [{load_object_code,{test,"1.0",[foo,bar]}}, + point_of_no_return, + {load,{foo,brutal_purge,brutal_purge}}, + {load,{bar,brutal_purge,brutal_purge}}] = X1, %% Simple translation (2) Up2 = [{add_application, test}], - ?line {ok, X2} = systools_rc:translate_scripts([Up2], Apps, []), -io:format("X2=~p~n", [X2]), - ?line [{load_object_code,{test,"1.0",[foo,bar,baz]}}, - point_of_no_return, - {load,{foo,brutal_purge,brutal_purge}}, - {load,{bar,brutal_purge,brutal_purge}}, - {load,{baz,brutal_purge,brutal_purge}}, - {apply,{application,start,[test,permanent]}}] = X2, + {ok, X2} = systools_rc:translate_scripts([Up2], Apps, []), + io:format("X2=~p~n", [X2]), + [{load_object_code,{test,"1.0",[foo,bar,baz]}}, + point_of_no_return, + {load,{foo,brutal_purge,brutal_purge}}, + {load,{bar,brutal_purge,brutal_purge}}, + {load,{baz,brutal_purge,brutal_purge}}, + {apply,{application,start,[test,permanent]}}] = X2, %% Simple translation (3) Up3 = [{remove_application, pelle}], - ?line {ok, X3} = systools_rc:translate_scripts([Up3], Apps, PreApps), - ?line [point_of_no_return, - {apply,{application,stop,[pelle]}}, - {remove,{pelle,brutal_purge,brutal_purge}}, - {remove,{kalle,brutal_purge,brutal_purge}}, - {purge,[pelle,kalle]}, - {apply,{application,unload,[pelle]}}] = X3, - ?line ok. + {ok, X3} = systools_rc:translate_scripts([Up3], Apps, PreApps), + [point_of_no_return, + {apply,{application,stop,[pelle]}}, + {remove,{pelle,brutal_purge,brutal_purge}}, + {remove,{kalle,brutal_purge,brutal_purge}}, + {purge,[pelle,kalle]}, + {apply,{application,unload,[pelle]}}] = X3, + ok. + + +translate_emulator_restarts(_Config) -> + Apps = + [#application{name = test, + description = "TEST", + vsn = "1.0", + modules = [{foo,1},{bar,1},{baz,1}], + regs = [], + mod = {sasl, []}}, + #application{name = test, + description = "TEST2", + vsn = "1.0", + modules = [{x,1},{y,1},{z,1}], + regs = [], + mod = {sasl, []}}], + %% restart_new_emulator + Up1 = [{update, foo, soft, soft_purge, soft_purge, []},restart_new_emulator], + {ok, X1} = systools_rc:translate_scripts([Up1], Apps, []), + [restart_new_emulator, + {load_object_code, {test,"1.0",[foo]}}, + point_of_no_return, + {suspend,[foo]}, + {load,{foo,soft_purge,soft_purge}}, + {resume,[foo]}] = X1, + + %% restart_emulator + Up2 = [{update, foo, soft, soft_purge, soft_purge, []},restart_emulator], + {ok, X2} = systools_rc:translate_scripts([Up2], Apps, []), + [{load_object_code, {test,"1.0",[foo]}}, + point_of_no_return, + {suspend,[foo]}, + {load,{foo,soft_purge,soft_purge}}, + {resume,[foo]}, + restart_emulator] = X2, + + %% restart_emulator + restart_new_emulator + Up3 = [{update, foo, soft, soft_purge, soft_purge, []}, + restart_emulator, + restart_new_emulator], + {ok, X3} = systools_rc:translate_scripts([Up3], Apps, []), + [restart_new_emulator, + {load_object_code, {test,"1.0",[foo]}}, + point_of_no_return, + {suspend,[foo]}, + {load,{foo,soft_purge,soft_purge}}, + {resume,[foo]}, + restart_emulator] = X3, + + %% restart_emulator + restart_new_emulator + Up4a = [{update, foo, soft, soft_purge, soft_purge, []}, + restart_emulator, + restart_new_emulator], + Up4b = [restart_new_emulator, + {update, x, soft, soft_purge, soft_purge, []}, + restart_emulator, + restart_emulator], + {ok, X4} = systools_rc:translate_scripts([Up4a,Up4b], Apps, []), + [restart_new_emulator, + {load_object_code, {test,"1.0",[foo,x]}}, + point_of_no_return, + {suspend,[foo]}, + {load,{foo,soft_purge,soft_purge}}, + {resume,[foo]}, + {suspend,[x]}, + {load,{x,soft_purge,soft_purge}}, + {resume,[x]}, + restart_emulator] = X4, + + %% only restart_new_emulator + Up5 = [restart_new_emulator], + {ok, X5} = systools_rc:translate_scripts([Up5], Apps, []), + [restart_new_emulator, + point_of_no_return] = X5, + + %% only restart_emulator + Up6 = [restart_emulator], + {ok, X6} = systools_rc:translate_scripts([Up6], Apps, []), + [point_of_no_return, + restart_emulator] = X6, + + ok. diff --git a/lib/sasl/test/test_lib.hrl b/lib/sasl/test/test_lib.hrl new file mode 100644 index 0000000000..eeef721647 --- /dev/null +++ b/lib/sasl/test/test_lib.hrl @@ -0,0 +1,3 @@ +-define(ertsvsn,"4.4"). +-define(kernelvsn,"2.14.3"). +-define(stdlibvsn,"1.17.3"). diff --git a/lib/sasl/vsn.mk b/lib/sasl/vsn.mk index 2db134af48..6e9e2c9ff8 100644 --- a/lib/sasl/vsn.mk +++ b/lib/sasl/vsn.mk @@ -1 +1 @@ -SASL_VSN = 2.1.10 +SASL_VSN = 2.2.1 |