aboutsummaryrefslogtreecommitdiffstats
path: root/lib/sasl/test
diff options
context:
space:
mode:
authorLukas Larsson <[email protected]>2011-05-18 16:21:34 +0200
committerLukas Larsson <[email protected]>2011-05-18 16:21:34 +0200
commit15426ac367eed736c165a5bdbb1c051a87944f68 (patch)
treefcabce7847168a8416600fe35f94a411a5f73d6e /lib/sasl/test
parent4cd0717b717803ce8f03a12de4bf89f452ed1df7 (diff)
parentf44bbb331fb517e989d4d906b7f63ec110bbbc18 (diff)
downloadotp-15426ac367eed736c165a5bdbb1c051a87944f68.tar.gz
otp-15426ac367eed736c165a5bdbb1c051a87944f68.tar.bz2
otp-15426ac367eed736c165a5bdbb1c051a87944f68.zip
Merge branch 'dev' of super:otp into dev
* 'dev' of super:otp: (166 commits) Corrected documentation error and added examples to Users Guide In TLS 1.1, failure to properly close a connection no longer requires that a session not be resumed. This is a change from TLS 1.0 to conform with widespread implementation practice. Erlang ssl will now in TLS 1.0 conform to the widespread implementation practice instead of the specification to avoid performance issues. Add escript to bootstrap/bin Remove unused variable warning in inet_res Remove unused variable in epmd_port Remove compiler warnings in inet_drv Add SASL test suite Allow same module name in multiple applications if explicitely excluded Fix bugs concerning the option report_missing_types Fix default encoding in SAX parser. re: remove gratuitous "it " in manpage Spelling in (backward *compatibility*) comment. Improve erl_docgen's support for Dialyzer specs and types dialyzer warning on mnesia_tm Add documentation text about majority checking add mnesia_majority_test suite where_to_wlock optimization + change_table_majority/2 bug in mnesia_tm:needs_majority/2 optimize sticky_lock maj. check check majority for sticky locks ...
Diffstat (limited to 'lib/sasl/test')
-rw-r--r--lib/sasl/test/.gitignore5
-rw-r--r--lib/sasl/test/Makefile91
-rw-r--r--lib/sasl/test/alarm_handler_SUITE.erl179
-rw-r--r--lib/sasl/test/installer.erl778
-rw-r--r--lib/sasl/test/overload_SUITE.erl175
-rw-r--r--lib/sasl/test/rb_SUITE.erl606
-rw-r--r--lib/sasl/test/release_handler_SUITE.erl1651
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/Makefile.src108
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/ebin/a.app8
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/src/a.erl47
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/src/a_sup.erl37
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app1-1.0/ebin/app1.app9
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app1-1.0/src/app1.erl22
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app1-1.0/src/app1_server.erl32
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app1-1.0/src/app1_sup.erl17
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app2-1.0/ebin/app2.app9
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app2-1.0/src/app2.erl17
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app2-1.0/src/app2_server.erl32
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app2-1.0/src/app2_sup.erl17
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app1-2.0/ebin/app1.app9
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app1-2.0/ebin/app1.appup4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app1-2.0/src/app1.erl22
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app1-2.0/src/app1_server.erl35
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app1-2.0/src/app1_sup.erl17
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app2-1.0/ebin/app2.app9
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app2-1.0/src/app2.erl17
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app2-1.0/src/app2_server.erl32
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app2-1.0/src/app2_sup.erl17
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/c/aa.erl41
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/c/b.erl38
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/c/c.app8
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/c/c_sup.erl40
-rwxr-xr-xlib/sasl/test/release_handler_SUITE_data/clients/start_cli138
-rwxr-xr-xlib/sasl/test/release_handler_SUITE_data/clients/start_cli237
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/ebin/a.app8
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/src/a.app8
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/src/a.erl49
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/src/a_sup.erl37
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.app8
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup3
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl54
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a_sup.erl37
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/installer-1.0/ebin/installer.app6
l---------lib/sasl/test/release_handler_SUITE_data/lib/installer-1.0/src/installer.erl1
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_atom.erl26
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_list.erl26
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_numeric.erl26
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_string.erl26
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_tuple.erl26
-rwxr-xr-xlib/sasl/test/release_handler_SUITE_data/start29
l---------lib/sasl/test/release_handler_SUITE_data/target_system.erl1
-rw-r--r--lib/sasl/test/sasl.cover2
-rw-r--r--lib/sasl/test/sasl.spec1
-rw-r--r--lib/sasl/test/sasl_SUITE.erl98
-rw-r--r--lib/sasl/test/systools_SUITE.erl2112
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/ebin/db.app8
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/ebin/db.appup20
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/src/db1.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/src/db2.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/ebin/fe.app8
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/ebin/fe.appup27
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/src/fe1.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/src/fe2.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/src/fe3.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-3.1/ebin/fe.app7
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-3.1/ebin/fe.appup27
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/ebin/db.app8
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/ebin/db.appup20
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/src/db1.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/src/db2.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/ebin/fe.app8
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/ebin/fe.appup27
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/src/fe1.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/src/fe2.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/src/fe3.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/ebin/db.app8
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/ebin/db.appup20
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/src/db2.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/src/db3.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_links/lib/fe-3.1/ebin/fe.appup27
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_links/lib/fe-3.1/src/fe1.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_links/lib/fe-3.1/src/fe2.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_links/lib/fe-3.1/src/fe3.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/ebin/db.app8
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/ebin/db.appup20
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/src/db1.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/src/db2.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/ebin/fe.app8
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/ebin/fe.appup27
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/src/fe1.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/src/fe2.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/src/fe3.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-2.1/ebin/fe.app8
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-2.1/ebin/fe.appup27
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-3.1/ebin/fe.app7
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.0/ebin/db.app8
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.0/src/db1.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.0/src/db2.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.1/ebin/db.app8
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.1/src/db1.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.1/src/db2.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/ebin/db.app7
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/ebin/db.appup20
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/src/db1.erl13
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/src/db2.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/db-3.1/ebin/db.app7
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/db-3.1/ebin/db.appup20
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/db-3.1/src/db1.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/db-3.1/src/db2.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1.1/ebin/fe.app8
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1.1/src/fe1.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1.1/src/fe2.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1.1/src/fe3.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1/ebin/fe.app8
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1/src/fe1.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1/src/fe2.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1/src/fe3.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/ebin/fe.app7
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/ebin/fe.appup27
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/src/fe1.erl7
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/src/fe2.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/src/fe3.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/lib/kernel/ebin/kernel.app6
-rw-r--r--lib/sasl/test/systools_SUITE_data/lib/kernel/ebin/kernel.appup12
-rw-r--r--lib/sasl/test/systools_SUITE_data/lib/stdlib/ebin/stdlib.app6
-rw-r--r--lib/sasl/test/systools_SUITE_data/lib/stdlib/ebin/stdlib.appup12
-rw-r--r--lib/sasl/test/systools_rc_SUITE.erl488
127 files changed, 7842 insertions, 0 deletions
diff --git a/lib/sasl/test/.gitignore b/lib/sasl/test/.gitignore
new file mode 100644
index 0000000000..76e706b874
--- /dev/null
+++ b/lib/sasl/test/.gitignore
@@ -0,0 +1,5 @@
+#
+# Don't ignore *.beam files in any sub-directory.
+#
+
+!*.beam
diff --git a/lib/sasl/test/Makefile b/lib/sasl/test/Makefile
new file mode 100644
index 0000000000..ad08c8136b
--- /dev/null
+++ b/lib/sasl/test/Makefile
@@ -0,0 +1,91 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 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%
+#
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+MODULES= \
+ sasl_SUITE \
+ alarm_handler_SUITE \
+ installer \
+ release_handler_SUITE \
+ systools_SUITE \
+ systools_rc_SUITE \
+ overload_SUITE \
+ rb_SUITE
+
+ERL_FILES= $(MODULES:%=%.erl)
+
+TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+INSTALL_PROGS= $(TARGET_FILES)
+
+EMAKEFILE=Emakefile
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/sasl_test
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ERL_MAKE_FLAGS +=
+ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/test_server/include \
+ -I$(ERL_TOP)/lib/sasl/src
+
+EBIN = .
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+make_emakefile:
+ $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make'\
+ > $(EMAKEFILE)
+ $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES)\
+ >> $(EMAKEFILE)
+
+tests debug opt: make_emakefile
+ erl $(ERL_MAKE_FLAGS) -make
+
+clean:
+ rm -f $(EMAKEFILE)
+ rm -f $(TARGET_FILES)
+ rm -f core
+
+docs:
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+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 -f -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
new file mode 100644
index 0000000000..a98e8c9c67
--- /dev/null
+++ b/lib/sasl/test/alarm_handler_SUITE.erl
@@ -0,0 +1,179 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+%%
+-module(alarm_handler_SUITE).
+
+-include_lib("test_server/include/test_server.hrl").
+
+%%-----------------------------------------------------------------
+%% We will add an own alarm handler in order to verify that the
+%% alarm_handler deliver the expected events.
+%%-----------------------------------------------------------------
+
+-export([init_per_suite/1, end_per_suite/1, all/0,groups/0,
+ init_per_group/2,end_per_group/2,
+ set_alarm/1, clear_alarm/1, swap/1]).
+
+-export([init/1, handle_event/2, handle_call/2, handle_info/2,
+ terminate/2]).
+
+
+init_per_suite(Config) ->
+ application:start(sasl),
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+all() ->
+ [set_alarm, clear_alarm, swap].
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+
+
+%%-----------------------------------------------------------------
+
+set_alarm(suite) -> [];
+set_alarm(Config) when is_list(Config) ->
+ ?line 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),
+ reported(set_alarm, Alarm1),
+ ?line ok = alarm_handler:set_alarm(Alarm2),
+ reported(set_alarm, Alarm2),
+ ?line ok = alarm_handler:set_alarm(Alarm3),
+ reported(set_alarm, Alarm3),
+
+ ?line [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(),
+
+ test_server:messages_get(),
+ ?line 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()),
+ 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),
+ test_server:messages_get(),
+
+ ?line ok = alarm_handler:clear_alarm(alarm1),
+ reported(clear_alarm, alarm1),
+ ?line ok = alarm_handler:clear_alarm("alarm2"),
+ reported(clear_alarm, "alarm2"),
+ ?line ok = alarm_handler:clear_alarm({alarm3}),
+ reported(clear_alarm, {alarm3}),
+ ?line [] = alarm_handler:get_alarms(),
+
+ ?line 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,
+ 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),
+ Alarms = [Alarm3, Alarm2, Alarm1],
+ reported(swap_alarms, Alarms),
+
+ %% get_alarms is only valid with the default handler installed.
+ ?line {error, _} = alarm_handler:get_alarms(),
+
+ ?line my_yes = gen_event:delete_handler(alarm_handler,
+ ?MODULE, []),
+ ?line gen_event:add_handler(alarm_handler, alarm_handler, []),
+ ok;
+ _ ->
+ alarm_handler:clear_alarm(alarm1),
+ alarm_handler:clear_alarm("alarm2"),
+ alarm_handler:clear_alarm({alarm3}),
+ ok
+ end.
+
+%%-----------------------------------------------------------------
+%% Check that the alarm has been received.
+%%-----------------------------------------------------------------
+reported(Tag, Data) ->
+ receive
+ {Tag, Data} ->
+ test_server:messages_get(),
+ ok
+ after 1000 ->
+ test_server:fail(no_alarm_received)
+ end.
+
+%%-----------------------------------------------------------------
+%% The error_logger handler (gen_event behaviour).
+%% Sends a notification to the Tester process about the events
+%% generated by the Tester process.
+%%-----------------------------------------------------------------
+init(Tester) when is_pid(Tester) ->
+ {ok, Tester};
+init({Tester, {alarm_handler,Alarms}}) -> % Swap from default handler.
+ Tester ! {swap_alarms, Alarms},
+ {ok, Tester}.
+
+handle_event({set_alarm, Alarm}, Tester) ->
+ Tester ! {set_alarm, Alarm},
+ {ok, Tester};
+handle_event({clear_alarm, AlarmId}, Tester) ->
+ Tester ! {clear_alarm, AlarmId},
+ {ok, Tester};
+handle_event(_Event, Tester) ->
+ {ok, Tester}.
+
+handle_info(_, Tester) ->
+ {ok, Tester}.
+
+handle_call(_Query, Tester) -> {ok, {error, bad_query}, Tester}.
+
+terminate(_Reason, _Tester) ->
+ my_yes.
diff --git a/lib/sasl/test/installer.erl b/lib/sasl/test/installer.erl
new file mode 100644
index 0000000000..a114c4b5c9
--- /dev/null
+++ b/lib/sasl/test/installer.erl
@@ -0,0 +1,778 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+%%
+
+-module(installer).
+
+%%-compile(export_all).
+-export([install_1/2]).
+-export([install_2/1]).
+-export([install_3/2]).
+-export([install_3a/1]).
+-export([install_4/1]).
+-export([install_5/1]).
+-export([install_5a/1]).
+-export([install_6/1]).
+-export([install_7/1]).
+-export([install_8/1]).
+-export([install_9/1]).
+-export([install_10/1]).
+-export([install_11/1]).
+-export([client1_1/4]).
+-export([client2/3]).
+-export([stop/1]).
+-export([unpack_p1h/2]).
+-export([permanent_p1h/1]).
+-export([reg_proc/1]).
+-export([registered_loop/1]).
+
+-define(print(List), {rh_print, TestNode} ! {print, {?MODULE, ?LINE}, List}).
+-define(print_line(Line,List), {rh_print, TestNode} ! {print, {?MODULE, Line}, List}).
+-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_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)).
+
+
+install_1(TestNode,PrivDir) ->
+ ?print([TestNode]),
+ ?print(["install_1 start"]),
+
+ % Unpack and install P1H
+ {ok, "P1H"} = unpack_release(PrivDir,"rel1"),
+ ?print(["unpack_release P1H ok"]),
+ ?check_release("P1H",unpacked,["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_running_app(a,"1.0"),
+ X = a:a(),
+ ?print(["X", X]),
+ {key2, val2} = lists:keyfind(key2, 1, X),
+ {key1, val1} = lists:keyfind(key1, 1, X),
+ ?print(["install_1 end OK"]),
+ ok.
+ % release_handler_SUITE will reboot this node now!
+
+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"]),
+ {ok,"P1G",[new_appl]} = release_handler:install_release("P1H"),
+ ?print(["install_2 install_release ok"]),
+ ?check_release("P1H",current,["a-1.0"]),
+ ?check_running_app(a,"1.0"),
+ ok = release_handler:make_permanent("P1H").
+ % 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"]),
+ 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"]),
+ {ok,"P1H",[{extra, gott}]} = release_handler:check_install_release("P1I"),
+ {error,_} = release_handler:check_install_release("P1J"),
+ {ok,"P1H",[{extra, gott}]} = release_handler:install_release("P1I"),
+ ?print(["install_3 install_release P1I ok"]),
+ ?check_release("P1I",current,["a-1.1"]),
+ ?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(),
+
+ % Unpack and install P2A
+ {ok, "P2A"} = unpack_release(PrivDir,"rel3"),
+ ?print(["install_3 unpack_release P2A ok"]),
+ ?check_release("P2A",unpacked,["a-1.1"]),
+ {ok, "P1I", [new_emu]} = release_handler:check_install_release("P2A"),
+ ok = release_handler:make_permanent("P1I"),
+ ?print(["install_3 make_permanent P1I ok"]),
+ ?check_release("P1I",permanent,["a-1.1"]),
+ ok.
+
+install_3a(TestNode) ->
+ {ok, "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_3 P2A installed"]),
+ ok.
+
+
+
+install_4(TestNode) ->
+ ?print(["install_4 start"]),
+
+ % Check that P2A is in use.
+ ?check_release("P2A",current,["a-1.1"]),
+ ?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_SUITE will reboot this node now!
+
+install_5(TestNode) ->
+ ?print(["install_5 start"]),
+
+ % Check that P1I is used
+ {ok, "P1I", [new_emu]} = release_handler:check_install_release("P2A"),
+ ok.
+
+install_5a(TestNode) ->
+ % Install P2A again
+ {ok, "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"]),
+ ok.
+
+install_6(TestNode) ->
+ ?print(["install_6 start"]),
+
+ % Check that P2A is used
+ ?check_release("P2A",current,["a-1.1"]),
+ ?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").
+ % release_handler_SUITE will reboot this node now!
+
+
+install_7(TestNode) ->
+ ?print(["install_7 start"]),
+
+ % Check that P2A is used
+ ?check_release("P2A",permanent,["a-1.1"]),
+
+ % Install old P1H
+ ok = release_handler:reboot_old_release("P1H"),
+ ok.
+
+install_8(TestNode) ->
+ ?print(["install_8 start"]),
+
+ % Check that P1H is permanent
+ ?check_release("P1H",permanent,["a-1.0"]),
+ X = a:a(),
+ {key2, val2} = lists:keyfind(key2, 1, X),
+ {key1, val1} = lists:keyfind(key1, 1, X),
+
+ %% Remove P1I and P2A and check that a-1.1 and erts-<latest> are removed
+ ok = release_handler:remove_release("P2A"),
+ ok = release_handler:remove_release("P1I"),
+ {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),
+ ok.
+ % release_handler_SUITE will reboot this node now!
+
+install_9(TestNode) ->
+ ?print(["install_9 start"]),
+
+ % Check that P1H is permanent
+ ?check_release("P1H",permanent,["a-1.0"]),
+ X = a:a(),
+ {key2, val2} = lists:keyfind(key2, 1, X),
+ {key1, val1} = lists:keyfind(key1, 1, X),
+
+ % Install old P1G
+ ok = release_handler:reboot_old_release("P1G"),
+ ok.
+
+install_10(TestNode) ->
+ ?print(["install_10 start"]),
+
+ % Check that P1G is permanent
+ ?check_release("P1G",permanent,[]),
+ ?check_release("P1H",old,["a-1.0"]),
+
+ %% Remove P1H and check that both versions of application a is removed
+ ok = release_handler:remove_release("P1H"),
+ {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),
+ ok.
+ % release_handler_SUITE will reboot this node now!
+
+install_11(TestNode) ->
+ ?print(["install_11 start"]),
+
+ % Check that P1G is permanent
+ ?check_release("P1G",permanent,[]),
+ ok.
+
+
+
+%%-----------------------------------------------------------------
+%% This test starts a client node which uses this node as master
+%% for the release_handler.
+%% The client node runs all tests as in installer/1 test case.
+%% Thus, the client node will be rebooted several times.
+%% The to_erl /tmp/NODENAME@HOSTNAME/ command can be used to connect
+%% to the client node.
+%% run_erl logs for the client can be found in the directory:
+%% code:root_dir() ++ "/clients/type1/NODENAME@HOSTNAME/log
+%%-----------------------------------------------------------------
+
+
+client1_1(TestNode,PrivDir,MasterDir,ClientSname) ->
+ TestHost = test_host(),
+ ?print(["client1_1 start"]),
+
+ {ok,IP} = inet:getaddr(TestHost,inet),
+ erl_boot_server:start([IP]),
+
+ ok = net_kernel:monitor_nodes(true),
+ Node = start_client(TestNode,ClientSname),
+ trace_disallowed_calls(Node),
+
+ %% Check env var for SASL on client node
+ SaslEnv = rpc:call(Node, application, get_all_env, [sasl]),
+ {_,CliDir} = lists:keyfind(client_directory,1,SaslEnv),
+ {_,[Master]} = lists:keyfind(masters,1,SaslEnv),
+ {_,StartCli} = lists:keyfind(start_prg,1,SaslEnv),
+ Root = code:root_dir(),
+ true = (CliDir =:= filename:join([Root,"clients","type1",Node])),
+ true = (StartCli =:= filename:join([CliDir,"bin","start"])),
+ true = (Master =:= node()),
+
+ %% Unpack P1H on master
+ {ok, "P1H"} = unpack_release(PrivDir,"rel1"),
+
+ %% Unpack and install P1H on client
+ P1HDir = filename:join([Root, "releases", "P1H"]),
+
+ %% The AppDirs argument (last arg to set_unpacked) below is really
+ %% not necessary, it could just be [] since the path is the same
+ %% 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.
+ %% (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"]),
+
+ ok = rpc:call(Node, release_handler, install_file,
+ ["P1H", filename:join(P1HDir, "start.boot")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ ["P1H", filename:join(P1HDir, "sys.config")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ ["P1H", filename:join(P1HDir, "relup")]),
+ ?print([{release_handler_state, Node},
+ rpc:call(Node, sys, get_status, [release_handler])]),
+
+ {ok,"P1G",[new_appl]} =
+ rpc:call(Node, release_handler, check_install_release, ["P1H"]),
+
+ {ok,"P1G",[new_appl]} =
+ rpc:call(Node, release_handler, install_release, ["P1H"]),
+
+ 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(),
+ reboot(TestNode,Node),
+ trace_disallowed_calls(Node),
+
+ client1_2(TestNode,PrivDir,Node).
+
+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"]),
+
+ {ok,"P1G",[new_appl]} =
+ rpc:call(Node, release_handler, install_release, ["P1H"]),
+ ?check_release_client(Node,"P1H",current,["a-1.0"]),
+ ?check_running_app_client(Node,a,"1.0"),
+
+ ok = rpc:call(Node, release_handler, make_permanent, ["P1H"]),
+
+ check_disallowed_calls(),
+ reboot(TestNode,Node),
+ trace_disallowed_calls(Node),
+
+ client1_3(TestNode,PrivDir,Node).
+
+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),
+
+ %% Unpack P1I on master
+ {ok, "P1I"} = unpack_release(PrivDir,"rel2"),
+
+ MasterRoot = code:root_dir(),
+
+ %% Unpack and install P1I on client
+ P1IDir = filename:join([MasterRoot, "releases", "P1I"]),
+ {ok, "P1I"} = rpc:call(Node, release_handler, set_unpacked,
+ [filename:join(P1IDir, "rel2.rel"),[]]),
+
+ ?check_release_client(Node,"P1I",unpacked,["a-1.1"]),
+
+ ok = rpc:call(Node, release_handler, install_file,
+ ["P1I", filename:join(P1IDir, "start.boot")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ ["P1I", filename:join(P1IDir, "sys.config")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ ["P1I", filename:join(P1IDir, "relup")]),
+
+ {ok,"P1H",[{extra, gott}]} =
+ rpc:call(Node, release_handler, check_install_release, ["P1I"]),
+ {error,_} = rpc:call(Node, release_handler, check_install_release, ["P1J"]),
+ {ok,"P1H",[{extra, gott}]} =
+ rpc:call(Node, release_handler, install_release, ["P1I"]),
+
+ ?check_running_app_client(Node,a,"1.1"),
+ X2 = rpc:call(Node, a, a, []),
+ {key2, newval2} = lists:keyfind(key2, 1, X2),
+ {key1, val1} = lists:keyfind(key1, 1, X2),
+ {ok, bval} = rpc:call(Node, a, b, []),
+
+ %% Unpack P2A on master
+ {ok, "P2A"} = unpack_release(PrivDir,"rel3"),
+
+ %% Unpack and install P2A on client
+ P2ADir = filename:join([MasterRoot, "releases", "P2A"]),
+ {ok, "P2A"} =
+ rpc:call(Node, release_handler, set_unpacked,
+ [filename:join(P2ADir, "rel3.rel"),[]]),
+
+ ok = rpc:call(Node, release_handler, install_file,
+ ["P2A", filename:join(P2ADir, "start.boot")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ ["P2A", filename:join(P2ADir, "sys.config")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ ["P2A", filename:join(P2ADir, "relup")]),
+
+ {ok, "P1I", [new_emu]} =
+ rpc:call(Node, release_handler, check_install_release, ["P2A"]),
+ ok = rpc:call(Node, release_handler, make_permanent, ["P1I"]),
+ ?check_release_client(Node,"P1I",permanent,["a-1.1"]),
+
+ %% since the install_release below reboot the node...
+ check_disallowed_calls(),
+ cover_client(TestNode,Node,stop_cover),
+
+ {ok, "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_4(TestNode,Node) ->
+ ?print(["client1_4 start"]),
+
+ %% Check that P2A is in use.
+ ?check_release_client(Node,"P2A",current,["a-1.1"]),
+ ?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),
+ trace_disallowed_calls(Node),
+
+ client1_5(TestNode,Node).
+
+client1_5(TestNode,Node) ->
+ ?print(["client1_5 start"]),
+
+ %% Check that P1I is used
+ {ok, "P1I", [new_emu]} =
+ rpc:call(Node, release_handler, check_install_release, ["P2A"]),
+
+ %% since the install_release below will reboot the node...
+ check_disallowed_calls(),
+ cover_client(TestNode,Node,stop_cover),
+
+ %% Install P2A again
+ {ok, "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_6(TestNode,Node) ->
+ ?print(["client1_6 start"]),
+
+ %% Check that P2A is used
+ ?check_release_client(Node,"P2A",current,["a-1.1"]),
+ ?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, []),
+
+ %% Make P2A permanent
+ ok = rpc:call(Node, release_handler, make_permanent, ["P2A"]),
+
+ %% Reboot from P2A
+ check_disallowed_calls(),
+ reboot(TestNode,Node),
+ trace_disallowed_calls(Node),
+
+ client1_7(TestNode,Node).
+
+client1_7(TestNode,Node) ->
+ ?print(["client1_7 start"]),
+
+ %% Check that P2A is used
+ ?check_release_client(Node,"P2A",permanent,["a-1.1"]),
+
+ %% since the reboot_old_release below will reboot the node
+ check_disallowed_calls(),
+ cover_client(TestNode,Node,stop_cover),
+
+ %% Install old P1H
+ rpc:call(Node, release_handler, reboot_old_release, ["P1H"]),
+ %% We are rebooted.
+ check_reboot(TestNode,Node),
+ trace_disallowed_calls(Node),
+
+ client1_8(TestNode,Node).
+
+client1_8(TestNode,Node) ->
+ ?print(["client1_8 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),
+
+ %% Remove P1I and P2I from client
+ ok = rpc:call(Node, release_handler, set_removed, ["P2A"]),
+ ok = rpc:call(Node, release_handler, set_removed, ["P1I"]),
+
+ 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.
+ 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),
+
+ %% since the reboot_old_release below will reboot the node
+ check_disallowed_calls(),
+ cover_client(TestNode,Node,stop_cover),
+
+ %% Install old P1G
+ rpc:call(Node, release_handler, reboot_old_release, ["P1G"]),
+ %% We are rebooted.
+ check_reboot(TestNode,Node),
+ trace_disallowed_calls(Node),
+
+ client1_10(TestNode,Node).
+
+client1_10(TestNode,Node) ->
+ ?print(["client1_10 start"]),
+
+ %% Check that P1G is permanent
+ ?check_release_client(Node,"P1G",permanent,[]),
+ ?check_release_client(Node,"P1H",old,["a-1.0"]),
+ {error,client_node} = rpc:call(Node,release_handler,remove_release,["P1H"]),
+ ok = rpc:call(Node, release_handler, set_removed, ["P1H"]),
+
+ check_disallowed_calls(),
+ reboot(TestNode,Node),
+ trace_disallowed_calls(Node),
+
+ client1_11(TestNode,Node).
+
+client1_11(TestNode,Node) ->
+ ?print(["client1_11 start"]),
+
+ %% Check that P1G is permanent
+ ?check_release_client(Node,"P1G",permanent,[]),
+
+ check_disallowed_calls(),
+ stop_client(TestNode,Node), %% TEST IS OK !!
+ net_kernel:monitor_nodes(false),
+
+ ok = release_handler:remove_release("P2A"),
+ ok = release_handler:remove_release("P1I"),
+ ok = release_handler:remove_release("P1H"),
+ ok.
+
+%% Start tracing of the file module on the client node. This module
+%% shall never be called, since
+%% 1) the node is a client from the release_handler's point of view,
+%% so all file access should be done via rpc calls to the master
+%% 2) it is started with erl_prim_loader loader set to 'inet' so all
+%% code loading should be done via the inet to the master
+%% (OTP-9142)
+%% This function is called each time the client node is started and to
+%% check if a call has been made, call check_disallowed_node/0
+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,[]]).
+
+check_disallowed_calls() ->
+ receive
+ Trace when element(1,Trace)==trace ->
+ exit({disallowed_function_call,Trace})
+ after 0 ->
+ ok
+ end.
+
+start_client(TestNode,Client) ->
+ {Start, Node} = do_start_client(Client,test_host()),
+ Cmd = lists:concat(["env NODENAME=",Client," ",
+ filename:join(code:root_dir(), Start)]),
+ ?print([{start_client,Client},Cmd]),
+ Res = os:cmd(Cmd),
+ ?print([{start_client,result},Res]),
+ receive
+ {nodeup, Node} ->
+ wait_started(TestNode,Node)
+ after 30000 ->
+ ?print([{start_client,failed,Node},net_adm:ping(Node)]),
+ ?fail({"can not start", Node})
+ end.
+
+do_start_client(Client, Host) ->
+ Node = list_to_atom(lists:concat([Client,"@",Host])),
+ Start = filename:join(["clients", "type1", Node, "bin", "start"]),
+ {Start, Node}.
+
+reboot(TestNode,Node) ->
+ cover_client(TestNode,Node,stop_cover),
+ rpc:call(Node, init, reboot, []),
+ check_reboot(TestNode,Node).
+
+%% This way of checking that the node is rebooted will only work if
+%% the nodes are automatically re-connected after the reboot. This
+%% happens for master/client (when sasl is started on the client).
+check_reboot(TestNode,Node) ->
+ receive
+ {nodedown, Node} ->
+ receive
+ {nodeup, Node} -> wait_started(TestNode,Node)
+ after 30000 ->
+ ?fail({Node, "not rebooted",net_adm:ping(Node)})
+ end
+ after 30000 ->
+ ?fail({Node, "not closing down",net_adm:ping(Node)})
+ end.
+
+stop_client(TestNode,Node) ->
+ cover_client(TestNode,Node,stop_cover),
+ rpc:call(Node, init, stop, []),
+ receive
+ {nodedown, Node} -> ok
+ after 30000 ->
+ ?fail({Node, "not stopping"})
+ end.
+
+wait_started(TestNode,Node) ->
+ case rpc:call(Node, init, get_status, []) of
+ {started, _} ->
+ cover_client(TestNode,Node,start_cover),
+ Node;
+ _ ->
+ timer:sleep(1000),
+ wait_started(TestNode,Node)
+ end.
+
+cover_client(TestNode,Node,Func) ->
+ R = rpc:call(TestNode,release_handler_SUITE,Func,[Node]),
+ ?print([{Func,Node,R}]).
+
+
+%%-----------------------------------------------------------------
+%% This test starts a client node which uses this node as master
+%% for the release_handler.
+%% The client node has the name cli2@HOSTNAME.
+%% The client node is not allowed to do ANY release updates
+%% as it also have another (non-existing) master node.
+%%
+%% The to_erl /tmp/cli2@HOSTNAME/ command can be used to connect
+%% to the client node.
+%% run_erl logs for the client can be found in the directory:
+%% code:root_dir() ++ "/clients/type1/cli2@HOSTNAME/log
+%%-----------------------------------------------------------------
+client2(TestNode,PrivDir,ClientSname) ->
+ TestHost = test_host(),
+ ?print(["client2 start"]),
+
+ %% Clean up if previous test case failed
+ release_handler:remove_release("P1H"),
+
+ ok = net_kernel:monitor_nodes(true),
+ Node = start_client(TestNode,ClientSname),
+
+ %% Check env var for SASL on client node
+ ?print([{sasl_env, Node}, rpc:call(Node, application, get_all_env, [sasl])]),
+ SaslEnv = rpc:call(Node, application, get_all_env, [sasl]),
+ {_,CliDir} = lists:keyfind(client_directory,1,SaslEnv),
+ {_,[Master,Master2]} = lists:keyfind(masters,1,SaslEnv),
+ {_,StartCli} = lists:keyfind(start_prg,1,SaslEnv),
+ Root = code:root_dir(),
+ true = (CliDir =:= filename:join([Root,"clients","type1",Node])),
+ true = (StartCli =:= filename:join([CliDir,"bin","start"])),
+ true = (Master =:= node()),
+ true = (Master2 =:= list_to_atom("master2@"++TestHost)),
+
+ {ok, "P1H"} = unpack_release(PrivDir,"rel1"),
+
+ {error,{bad_masters,[Master2]}} =
+ rpc:call(Node, release_handler, set_unpacked,
+ [filename:join([Root, "releases", "P1H", "rel1.rel"]),[]]),
+
+ {error,{no_such_release,"P1H"}} =
+ rpc:call(Node, release_handler, check_install_release, ["P1H"]),
+
+ stop_client(TestNode,Node), %% TEST IS OK !!
+ net_kernel:monitor_nodes(false),
+
+ release_handler:remove_release("P1H"),
+ ok.
+
+
+stop(Now) ->
+ %% The timestamp is only used for debugging. It is printed by
+ %% release_handler_SUITE also.
+ R = init:stop(),
+ erlang:display({init_stop,Now,R}),
+ R.
+
+unpack_p1h(TestNode,PrivDir) ->
+ {ok, "P1H"} = unpack_release(PrivDir,"rel1"),
+ ?check_release("P1H",unpacked,["a-1.0"]),
+ ok.
+
+permanent_p1h(TestNode) ->
+ ?check_release("P1H",unpacked,["a-1.0"]),
+ {ok,"P1G",[new_appl]} = release_handler:install_release("P1H"),
+ ?check_release("P1H",current,["a-1.0"]),
+ ok = release_handler:make_permanent("P1H"),
+ ?check_release("P1H",permanent,["a-1.0"]),
+ ok.
+
+
+reg_proc(Name) ->
+ catch unregister(Name),
+ Pid = spawn_link(?MODULE, registered_loop, [Name]),
+ global:register_name(Name, Pid),
+ ok.
+
+registered_loop(_Name) ->
+ receive
+ kill ->
+ exit(killed)
+ end.
+
+check_release(TestNode,Node,Vsn,Status,Apps,Line) ->
+ case rpc:call(Node,release_handler,which_releases,[]) of
+ {badrpc,_}=Error ->
+ ?fail_line(Line,{check_release,Node,Vsn,Status,Error});
+ Rels ->
+ ?print_line(Line,["check_release:", 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_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),
+ ok
+ end.
+
+test_host() ->
+ {ok,Host} = inet:gethostname(),
+ Host.
+
+unpack_release(PrivDir,Rel) ->
+ copy(filename:join([PrivDir,Rel,Rel++".tar.gz"]),
+ filename:join(code:root_dir(),releases)),
+ release_handler:unpack_release(Rel).
+
+copy(Src, DestDir) ->
+ Dest = filename:join(DestDir, filename:basename(Src)),
+ {ok,_} = file:copy(Src, Dest),
+ ok.
+
diff --git a/lib/sasl/test/overload_SUITE.erl b/lib/sasl/test/overload_SUITE.erl
new file mode 100644
index 0000000000..92b1aaed6e
--- /dev/null
+++ b/lib/sasl/test/overload_SUITE.erl
@@ -0,0 +1,175 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+%%
+
+-module(overload_SUITE).
+-include("test_server.hrl").
+
+-compile(export_all).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all() -> [info, set_config_data, set_env_vars, request, timeout].
+all(suite) -> all().
+
+init_per_testcase(_Case,Config) ->
+ restart_sasl(),
+ Config.
+
+end_per_testcase(Case,Config) ->
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
+ 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.
+
+%%%-----------------------------------------------------------------
+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),
+ 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),
+ ok.
+set_env_vars(cleanup,_Config) ->
+ application:unset_env(sasl,overload_max_intensity),
+ application:unset_env(sasl,overload_weight),
+ 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]),
+
+ %% 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,
+
+ %% 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,
+
+ %% 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,
+ ok.
+
+%%%-----------------------------------------------------------------
+timeout(suite) -> [];
+timeout(_Config) ->
+ ?line overload:set_config_data(0.8, 1),
+ ?line _N = do_many_requests(0),
+
+ %% Check that the overload alarm is raised
+ ?line [{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(),
+
+ %% 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(),
+
+ ok.
+
+
+%%%-----------------------------------------------------------------
+%%% INTERNAL FUNCTIONS
+
+%%%-----------------------------------------------------------------
+%%% Call overload:request/0 up to 30 times with the given time delay
+%%% between. Stop when 'reject' is returned.
+do_many_requests(T) ->
+ 30 - do_requests(30,T).
+
+do_requests(0,_) ->
+ ?t:fail(never_rejected);
+do_requests(N,T) ->
+ case overload:request() of
+ accept ->
+ timer:sleep(T),
+ do_requests(N-1,T);
+ reject ->
+ N
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Restart the sasl application
+restart_sasl() ->
+ application:stop(sasl),
+ application:start(sasl),
+ ok.
+
+%%%-----------------------------------------------------------------
+%%% Check that max_intensity and weight is set as expected
+check_info(MI,W,Info) ->
+ case {lists:keyfind(max_intensity,1,Info), lists:keyfind(weight,1,Info)} of
+ {{_,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
new file mode 100644
index 0000000000..b53c382609
--- /dev/null
+++ b/lib/sasl/test/rb_SUITE.erl
@@ -0,0 +1,606 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+%%
+
+-module(rb_SUITE).
+-include("test_server.hrl").
+
+-compile(export_all).
+
+-define(SUP,rb_SUITE_sup).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+all() ->
+ no_group_cases() ++ [{group,running_error_logger}].
+
+no_group_cases() ->
+ [help,
+ start_error_stop].
+
+groups() ->
+ [{running_error_logger,[shuffle],[show,
+ list,
+ rescan,
+ start_stop_log,
+ grep,
+ filter_filter,
+ filter_date,
+ filter_filter_and_date,
+ filter_re_no
+ ]}].
+
+
+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),
+ NewConfig = [{rb_dir,RbDir}|Config],
+ reset_sasl(NewConfig),
+ NewConfig.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(running_error_logger,Config) ->
+ install_mf_h(Config).
+
+end_per_group(running_error_logger,Config) ->
+ remove_mf_h(Config).
+
+init_per_testcase(_Case,Config) ->
+ case whereis(?SUP) of
+ undefined -> ok;
+ Pid -> kill(Pid)
+ end,
+ empty_error_logs(Config),
+ Config.
+
+kill(Pid) ->
+ Ref = erlang:monitor(process,Pid),
+ exit(Pid,kill),
+ receive {'DOWN', Ref, process, Pid, _Info} -> ok end.
+
+end_per_testcase(Case,Config) ->
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
+ ok.
+
+
+%%%-----------------------------------------------------------------
+
+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),
+ ok.
+
+
+start_error_stop() -> start_error_stop(suite).
+start_error_stop(suite) -> [];
+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.
+
+
+%% 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.
+
+remove_mf_h(_Config) ->
+ ok.
+
+
+
+show() -> show(suite).
+show(suite) -> [];
+show(Config) ->
+ ?line PrivDir = ?config(priv_dir,Config),
+ ?line 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),
+
+ %% Show all reports
+ ?line 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),
+
+ %% 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}"),
+
+ ok.
+
+list() -> list(suite).
+list(suite) -> [];
+list(Config) ->
+ ?line PrivDir = ?config(priv_dir,Config),
+ ?line 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}] =
+ sort_list(capture(fun() -> rb:list(crash_report) end)),
+ ?line [{error,EM}] =
+ sort_list(capture(fun() -> rb:list(error) end)),
+ ?line [{error_report,ER}] =
+ sort_list(capture(fun() -> rb:list(error_report) end)),
+ ?line [{info_msg,IM}] =
+ sort_list(capture(fun() -> rb:list(info_msg) end)),
+ ?line [{info_report,IR}] =
+ sort_list(capture(fun() -> rb:list(info_report) end)),
+ ?line [{progress,P}] =
+ sort_list(capture(fun() -> rb:list(progress) end)),
+ ?line [{supervisor_report,SR}] =
+ sort_list(capture(fun() -> rb:list(supervisor_report) end)),
+
+ ok.
+
+
+grep() -> grep(suite).
+grep(suite) -> [];
+grep(Config) ->
+ ?line PrivDir = ?config(priv_dir,Config),
+ ?line 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.
+
+
+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"),
+
+ %% Insert some reports in the error log and start rb
+ init_error_logs(),
+ ?line ok = start_rb(OutFile),
+
+ ?line 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),
+
+ {_,AllRep} = lists:unzip(All),
+ {_,ERRep} = lists:unzip(ER),
+ {_,AllButERRep} = lists:unzip(AllButER),
+ ?line 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"),
+
+
+ %% Insert some reports in the error log and start rb
+ init_error_logs(),
+ Between1 = calendar:local_time(),
+ timer:sleep(1000),
+ Between2 = calendar:local_time(),
+ ?line ok = start_rb(OutFile),
+
+ ?line All = check_report(fun() -> rb:show() end,OutFile),
+
+ Before = calendar:gregorian_seconds_to_datetime(
+ 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),
+
+ %%?t:format("~p~n",[All]),
+ ?line AllButLast = [{N-1,R} || {N,R} <- tl(All)],
+ ?line AllButLast = rb_filter([],{Before,Between1},OutFile),
+
+ ?line Last = hd(All),
+ ?line [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"),
+
+
+ %% Insert some reports in the error log and start rb
+ init_error_logs(),
+ 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),
+
+ Before = calendar:gregorian_seconds_to_datetime(
+ 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),
+
+ ?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"),
+
+ 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"),
+
+ %% Insert some reports in the error log and start rb
+ init_error_logs(),
+ ?line ok = start_rb(OutFile),
+
+ ?line 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),
+
+ {_,AllRep} = lists:unzip(All),
+ {_,ERep} = lists:unzip(E),
+ {_,AllButERep} = lists:unzip(AllButE),
+ ?line 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"),
+
+ %% Start rb
+ ?line 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),
+
+ 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,[]),
+
+ %% 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),
+
+ %% 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 =/= <<>>),
+
+ %% 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),
+
+ %% 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.
+
+
+%%%-----------------------------------------------------------------
+%%% INTERNAL FUNCTIONS
+
+restart_sasl() ->
+ application:stop(sasl),
+ ok = application:start(sasl),
+ wait_for_sasl().
+
+reset_sasl(Config) ->
+ application:unset_env(sasl,error_logger_mf_dir),
+ application:unset_env(sasl,error_logger_mf_maxbytes),
+ application:unset_env(sasl,error_logger_mf_maxfiles),
+ empty_error_logs(Config).
+
+empty_error_logs(Config) ->
+ application:stop(sasl),
+ 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) ->
+ ?t:fail("sasl application did not start within 5 seconds");
+wait_for_sasl(N) ->
+ case lists:keymember(sasl,1,application:which_applications()) of
+ true ->
+ ok;
+ false ->
+ timer:sleep(100),
+ wait_for_sasl(N-1)
+ end.
+
+start_rb(OutFile) ->
+ do_start_rb([{start_log,OutFile}]).
+start_rb() ->
+ do_start_rb([]).
+
+do_start_rb(Opts) ->
+ {ok,Pid} = rb:start(Opts),
+
+ %% Wait for process to started, then wait a little bit more
+ sys:get_status(Pid),
+ timer:sleep(500),
+
+ %% Make sure printouts (e.g. from rb:list(), come to the test log,
+ %% and that they can be captured.
+ group_leader(group_leader(),Pid),
+ ok.
+
+
+delete_tree(Dir) ->
+ case filelib:is_dir(Dir) of
+ true ->
+ delete_content(Dir),
+ file:del_dir(Dir);
+ false ->
+ ok = file:delete(Dir)
+ end.
+
+delete_content(Dir) ->
+ {ok,Files} = file:list_dir(Dir),
+ lists:foreach(fun(File) -> delete_tree(filename:join(Dir,File)) end,
+ 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(),
+ ok.
+
+wait_for_server() ->
+ case whereis(?MODULE) of
+ undefined ->
+ wait_for_server();
+ Pid ->
+ timer:sleep(100), % allow the supervisor report to be written
+ Pid
+ end.
+
+capture(Fun) ->
+ ?t:capture_start(),
+ ok = Fun(),
+ timer:sleep(1000),
+ ?t:capture_stop(),
+ string:tokens(lists:append(?t:capture_get()),"\n").
+
+
+rb_filter(Filter,OutFile) ->
+ check_report(fun() -> rb:filter(Filter) end, OutFile).
+rb_filter(Filter,Dates,OutFile) ->
+ check_report(fun() -> rb:filter(Filter,Dates) end, OutFile).
+
+
+%% This function first empties the given report file, then executes
+%% the fun and returns a list of {N,Report}, where Report is a report
+%% read from the file and N is an integer. The newest report has the
+%% lowest number.
+%% If the fun was a call to rb:show() (i.e. with no arguments), then
+%% the numbering (N) will be the same as rb's own numbering (as shown
+%% by rb:list()).
+check_report(Fun,File) ->
+ file:delete(File),
+ rb:rescan([{start_log,File}]),
+ ok = Fun(),
+ {ok,Bin} = file:read_file(File),
+ Reports = split_reports(binary_to_list(Bin),[],[]),
+ lists:zip(lists:seq(1,length(Reports)),Reports).
+
+-define(report_header_line,"\n===============================================================================\n").
+split_reports([],Report,Reports) ->
+ add_report(Report,Reports);
+split_reports(Text,Report,Reports) ->
+ case Text of
+ ?report_header_line++Rest ->
+ {Heading,PrevReport} = lists:splitwith(fun($\n) -> false;
+ (_) -> true
+ end,
+ Report),
+ split_reports(Rest,
+ ?report_header_line++Heading,
+ add_report(PrevReport,Reports));
+ [Ch|Rest] ->
+ split_reports(Rest,[Ch|Report],Reports)
+ end.
+
+add_report(Report,Reports) ->
+ case string:strip(Report,both,$\n) of
+ [] -> Reports;
+ Report1 -> [lists:reverse(Report1)|Reports]
+ end.
+
+%% Returns true if Substr is a substring of Str.
+contains(Str,Substr) ->
+ 0 =/= string:str(Str,Substr).
+
+%% Sort the result of rb_list after report type
+sort_list(List) ->
+ sort_list(List,dict:new()).
+sort_list([H|T],D) ->
+ case re:run(H,"\s+[0-9]+\s+([a-z_]+)",[{capture,all_but_first,list}]) of
+ nomatch ->
+ sort_list(T,D);
+ {match,[TypeStr]} ->
+ sort_list(T,dict:append(list_to_atom(TypeStr),H,D))
+ end;
+sort_list([],D) ->
+ lists:sort(dict:to_list(D)).
+
+
+%%%-----------------------------------------------------------------
+%%% A dummy supervisor and gen_server used for creating crash- and
+%%% supervisor reports
+start() ->
+ {ok,Pid} =
+ supervisor:start_link({local, ?SUP}, ?MODULE, i_am_supervisor),
+ unlink(Pid),
+ Pid.
+start_server() ->
+ gen_server:start_link({local, ?MODULE}, ?MODULE, i_am_server, []).
+init(i_am_server) ->
+ {ok, state};
+init(i_am_supervisor) ->
+ AChild = {?SUP,{?MODULE,start_server,[]},
+ permanent,2000,worker,[?MODULE]},
+ {ok,{{one_for_all,1,1}, [AChild]}}.
+handle_call(_Request, _From, State) ->
+ Reply = ok,
+ {reply, Reply, State}.
+handle_cast(crash, State) ->
+ exit({rb_SUITE,rb_test_crash}),
+ {noreply, State}.
+handle_info(_Info, State) ->
+ {noreply, State}.
+terminate(_Reason, _State) ->
+ ok.
+
diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl
new file mode 100644
index 0000000000..efa775f344
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE.erl
@@ -0,0 +1,1651 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+%%
+-module(release_handler_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+
+-compile(export_all).
+
+% Default timetrap timeout (set in init_per_testcase).
+%-define(default_timeout, ?t:minutes(40)).
+-define(default_timeout, ?t:minutes(10)).
+
+suite() ->
+ [{ct_hooks, [ts_install_cth]}].
+
+init_per_suite(Config) ->
+ application:start(sasl),
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+all() ->
+ case os:type() of
+ {unix, _} -> unix_cases();
+ {win32, _} -> win32_cases()
+ end.
+
+unix_cases() ->
+ RunErl = filename:join([code:root_dir(),"bin","run_erl"]),
+ RunErlCases = case filelib:is_file(RunErl) of
+ true -> [{group, release}];
+ false -> [no_run_erl]
+ end,
+ [target_system] ++ RunErlCases ++ cases().
+
+win32_cases() ->
+ cases().
+
+%% Cases that can be run on all platforms
+cases() ->
+ [otp_2740, otp_2760, otp_5761, instructions, eval_appup].
+
+groups() ->
+ [{release,[],
+ [
+ {group,release_single},
+ {group,release_gg}
+ ]},
+ {release_single,[],
+ [
+ upgrade,
+ client1,
+ client2
+ ]},
+ {release_gg,[],
+ [
+ upgrade_gg
+ ]}].
+
+%% {group,release}
+%% Top group for all cases using run_erl
+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_p1h(Config),
+ ?t:timetrap_cancel(Dog);
+
+%% {group,release_single}
+%% Subgroup of {group,release}, contains all cases that are not
+%% related to global_group
+init_per_group(release_single, Config) ->
+ Dog = ?t:timetrap(?default_timeout),
+
+ %% Create some more releases to upgrade to
+ ok = create_p1i(Config),
+ ok = create_p2a(Config),
+
+ ?t:timetrap_cancel(Dog);
+
+%% {group,release_gg}
+%% Subgroup of {group,release}. global_group tests.
+init_per_group(release_gg, Config0) ->
+ Config = [{sname_prefix,release_gg}|Config0],
+
+ PrivDir = priv_dir(Config),
+ Dog = ?t:timetrap(?default_timeout),
+
+ reg_print_proc(), %% starts a printer process on this node
+
+ Snames = [Gg1Sname,Gg2Sname,Gg3Sname,Gg4Sname,Gg5Sname,Gg6Sname] =
+ gg_node_snames(Config),
+
+ %% kill all possible nodes which are to be used
+ ok = stop_nodes([node_name(Sname) || Sname <- Snames]),
+
+ %% For gg1, gg3, gg4 and gg5: create a target system running
+ %% P1G, and with P1H unpacked.
+ %% For gg2 and gg6: create a target system running P1H.
+ %% Use gg2 for unpacking and permanenting P1H.
+ ok = copy_installed(Config,p1g_install,[Gg2Sname]),
+ InstallNode = unpack_p1h(Config,Gg2Sname),
+ ok = copy_installed(Config,Gg2Sname,[Gg1Sname,Gg3Sname,Gg4Sname,Gg5Sname]),
+ ok = permanent_p1h(InstallNode),
+ ok = stop_nodes([InstallNode]),
+ ok = copy_installed(Config,Gg2Sname,[Gg6Sname]),
+
+ %% Replace the sys.config files
+ %% The reason for not creating the releases with these configs in
+ %% the first place (create_p1g, create_p1h) is that then the
+ %% InstallNode (gg2) will be very slow started since it will try
+ %% to synch with the other nodes in the global group.
+ %% Also, the rpc call for installing the P1H release (in
+ %% permanent_p1h/1) would return {rpc,nodedown} due to change of
+ %% global groups.
+ lists:foreach(
+ fun(Sname) ->
+ ReleasesDir = filename:join([PrivDir,Sname,"releases"]),
+ write_term_file(filename:join([ReleasesDir,"P1G","sys.config"]),
+ gg_config([Gg1Sname,Gg3Sname,Gg4Sname,Gg5Sname])),
+ write_term_file(filename:join([ReleasesDir,"P1H","sys.config"]),
+ gg_config([Gg1Sname,Gg2Sname,Gg4Sname,
+ Gg5Sname,Gg6Sname]))
+ end,
+ Snames),
+
+ ?t:timetrap_cancel(Dog),
+ [{snames,Snames}|Config].
+
+
+end_per_group(release, Config) ->
+ Dog = ?t:timetrap(?default_timeout),
+ stop_print_proc(),
+ delete_release(Config),
+ ?t:timetrap_cancel(Dog),
+ Config;
+end_per_group(_GroupName, Config) ->
+ Config.
+
+
+init_per_testcase(Case, Config0) ->
+ Dog = test_server:timetrap(?default_timeout),
+ Config = [{sname_prefix,Case},{watchdog, Dog}|Config0],
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
+ ?t:format("~n======= init_per_testcase done =======~n",[]),
+ Config.
+
+end_per_testcase(Case, Config) ->
+ ?t:format("~n======= start end_per_testcase =======~n",[]),
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+
+ %% DEBUG
+ case ?config(tc_status,Config) of
+ ok ->
+ ok;
+ _Fail ->
+ %% save logs from master and client nodes
+ PrivDir = priv_dir(Config),
+ SaveDir = filename:join(PrivDir,save),
+ FailDir = filename:join(SaveDir,lists:concat(["failed-",Case])),
+ ok = filelib:ensure_dir(filename:join(FailDir,"*")),
+
+ LogDirs = filelib:wildcard(filename:join([PrivDir,"*",log])),
+
+ lists:foreach(
+ fun(LogDir) ->
+ ["log",Sname|_] = lists:reverse(filename:split(LogDir)),
+ copy_tree(Config,LogDir,Sname,FailDir)
+ end,
+ LogDirs),
+
+ case filelib:is_file("sasl_erl_crash.dump") of
+ true ->
+ copy_file("sasl_erl_crash.dump",FailDir);
+ _ ->
+ ok
+ end
+
+ end,
+ %% End DEBUG
+
+ %% Remove any remaining sasl_erl_crash.dump
+ %% These can occur when a new master@<host> is started, before
+ %% the old usage of the name is unregistered, causing the node to
+ %% terminate. (This has no effect on the test case, as the node is
+ %% immediately restarted by heart and the test cases wait until
+ %% the node is actually up and running -- see wait_nodes_up/2)
+ file:delete("sasl_erl_crash.dump"),
+
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
+ ok.
+
+gg_node_snames(Config) ->
+ [tc_sname(Config,X) || X <- [gg1,gg2,gg3,gg4,gg5,gg6]].
+
+
+%%%-----------------------------------------------------------------
+%%% TEST CASES
+
+
+%% Executed instead of release group when no run_erl program exists
+no_run_erl(Config) when is_list(Config) ->
+ {comment, "No run_erl program"}.
+
+
+
+%% Test upgrade and downgrade of erts
+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]),
+ 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 start"),
+
+ %% unpack and install P1H
+ ok = rpc_inst(TestNode, install_1, [PrivDir]),
+ stop_cover(TestNode),
+ reboot_and_wait(TestNode,"install_1"),
+
+ %% reinstall P1H and make it permanent
+ ok = rpc_inst(TestNode, install_2, []),
+ 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]),
+ ok = rpc_inst(TestNode, install_3, [PrivDir]),
+ stop_cover(TestNode),
+ ok = rpc_inst(TestNode, install_3a, []),
+ wait_nodes_up([{TestNode,TestNodeInit1}],"install_3",[a]),
+
+ %% check that P2A is used, reboot from P1I
+ ok = rpc_inst(TestNode, install_4, []),
+ stop_cover(TestNode),
+ reboot_and_wait(TestNode,"install_4",[a]),
+
+ %% check that P1I, reinstall P2A
+ 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
+ ok = rpc_inst(TestNode, install_6, []),
+ stop_cover(TestNode),
+ reboot_and_wait(TestNode,"install_6",[a]),
+
+ %% check that P2A is permanent, install old P1H
+ TestNodeInit3 = rpc:call(TestNode,erlang,whereis,[init]),
+ stop_cover(TestNode),
+ ok = rpc_inst(TestNode, install_7, []),
+ wait_nodes_up([{TestNode,TestNodeInit3}],"install_7",[a]),
+
+ %% check that P1H is permanent, remove P1I and P2A
+ ok = rpc_inst(TestNode, install_8, []),
+ stop_cover(TestNode),
+ reboot_and_wait(TestNode,"install_8",[a]),
+
+ %% check that P1H is permanent, reboot old P1G
+ TestNodeInit4 = rpc:call(TestNode,erlang,whereis,[init]),
+ stop_cover(TestNode),
+ ok = rpc_inst(TestNode, install_9, []),
+ wait_nodes_up([{TestNode,TestNodeInit4}],"install_9"),
+
+ %% check that P1G is permanent, remove P1H
+ ok = rpc_inst(TestNode, install_10, []),
+ stop_cover(TestNode),
+ reboot_and_wait(TestNode,"install_10"),
+
+ %% check that P1G is permanent
+ ok = rpc_inst(TestNode, install_11, []),
+
+ ok.
+
+upgrade(cleanup,Config) ->
+ TestNode = tc_full_node_name(Config),
+ ok = stop_nodes([TestNode]).
+
+reboot_and_wait(Node,Tag) ->
+ reboot_and_wait(Node,Tag,[]).
+
+reboot_and_wait(Node,Tag,Apps) ->
+ InitPid = rpc:call(Node,erlang,whereis,[init]),
+ ok = rpc:call(Node,init,reboot,[]),
+ wait_nodes_up([{Node,InitPid}],Tag,Apps).
+
+
+%% Test upgrade and downgrade of erts, diskless
+client1(Conf) when is_list(Conf) ->
+ reg_print_proc(), %% starts a printer process on test_server node
+ PrivDir = priv_dir(Conf),
+ Master = tc_sname(Conf,master),
+ Client = tc_sname(Conf,client),
+ MasterDir = filename:join(PrivDir,Master),
+
+ %% Copy the P1G release to a directory for use in this testcase
+ ok = copy_installed(Conf,p1g_install,[Master]),
+ ok = copy_client(Conf,Master,Client,"start_cli1"),
+
+ %% start the master node
+ [TestNode] = start_nodes(Conf,[Master],"client1"),
+
+ ok = rpc_inst(TestNode, client1_1, [PrivDir,MasterDir,Client]),
+
+ ok.
+
+client1(cleanup,Config) ->
+ MasterNode = tc_full_node_name(Config,master),
+ ClientNode = tc_full_node_name(Config,client),
+ ok = stop_nodes([MasterNode,ClientNode]).
+
+
+
+%% Test diskless release handling when illegal master node
+client2(Conf) when is_list(Conf) ->
+ reg_print_proc(), %% starts a printer process on test_server node
+ PrivDir = priv_dir(Conf),
+ Master = tc_sname(Conf,master),
+ Client = tc_sname(Conf,client),
+
+ %% Copy the P1G release to a directory for use in this testcase
+ ok = copy_installed(Conf,p1g_install,[Master]),
+ ok = copy_client(Conf,Master,Client,"start_cli2"),
+
+ %% start the master node
+ [TestNode] = start_nodes(Conf,[Master],"client2"),
+
+ ok = rpc_inst(TestNode, client2, [PrivDir,Client]),
+
+ ok.
+
+client2(cleanup,Config) ->
+ MasterNode = tc_full_node_name(Config,master),
+ ClientNode = tc_full_node_name(Config,client),
+ ok = stop_nodes([MasterNode,ClientNode]).
+
+
+
+%% Test instructions _not_ tested by the installer module.
+instructions(Conf) when is_list(Conf) ->
+ DataDir = ?config(data_dir, Conf),
+
+ Dir = filename:join(DataDir, "c"),
+ true = code:add_path(Dir),
+ check_bstate("no", []),
+ ok = application:start(c),
+ ok = wait_for(bb),
+ check_bstate("first", []),
+ FirstBB = whereis(bb),
+
+ case whereis(cc) of
+ Pid when is_pid(Pid) -> ok;
+ _ -> ?t:fail("cc not started")
+ end,
+
+ %% Stop and start cc process
+ S1 = [point_of_no_return,
+ {stop, [aa]},
+ {apply, {?MODULE, no_cc, []}},
+ {start, [aa]}],
+ {ok, _} = release_handler_1:eval_script(S1, [], []),
+
+ case whereis(cc) of
+ Pid2 when is_pid(Pid2) -> ok;
+ _ -> ?t:fail("cc not started")
+ end,
+
+ %% Make bb run old version of b.
+ S2 = [point_of_no_return,
+ {remove, {b, soft_purge, soft_purge}}],
+ {ok, [{b, soft_purge}]} = release_handler_1:eval_script(S2, [], []),
+ check_bstate("first", [FirstBB]),
+
+ false = code:is_loaded(b),
+ {error,{old_processes,b}} = release_handler_1:eval_script(S2,[],[]),
+ check_bstate("first", [FirstBB]),
+
+ %% Let supervisor restart bb with new code
+ S3 = [point_of_no_return,
+ {purge, [b]}],
+ {ok, []} = release_handler_1:eval_script(S3, [], []),
+ ok = wait_for(bb),
+ check_bstate("second", []),
+ SecondBB = whereis(bb),
+
+ if
+ SecondBB =:= FirstBB -> ?t:fail("bb not killed");
+ true -> ok
+ end,
+
+ %% Restart bb yet another time
+ ok = application:stop(c),
+ ok = application:start(c),
+ ok = wait_for(bb),
+ check_bstate("third", []),
+ ThirdBB = whereis(bb),
+
+ case ThirdBB of
+ _ when is_pid(ThirdBB) -> ok;
+ undefined -> ?t:fail("bb not started")
+ end,
+
+ %% Make bb run old version of b.
+ %%c:l(b),
+ check_bstate("third", []),
+ false = code:purge(b),
+ check_bstate("third", []),
+ {module,b} = code:load_file(b),
+ check_bstate("third", [ThirdBB]),
+
+ %% Let supervisor restart bb yet another time
+ S4 = [point_of_no_return,
+ {remove, {b, brutal_purge, soft_purge}}],
+ {ok, HopefullyEmpty} = release_handler_1:eval_script(S4, [], []),
+ ok = wait_for(bb),
+ FourthBB = whereis(bb),
+
+ case HopefullyEmpty of
+ [{b, soft_purge}] ->
+ %% The process managed to start between purge and delete
+ check_bstate("fourth", [FourthBB]);
+ [] ->
+ %% The process started after delete
+ check_bstate("fourth", [])
+ end,
+
+ application:stop(c),
+ check_bstate("no", []),
+ ok.
+
+instructions(cleanup,Conf) ->
+ application:stop(c),
+ really_del_code([aa,b,c_sup]),
+ code:del_path(filename:join(?config(data_dir,Conf), "c")),
+ ok.
+
+really_del_code(Mods) ->
+ lists:foreach(fun(Mod) ->
+ code:purge(Mod), % remove old code
+ code:delete(Mod),% make current code old
+ code:purge(Mod) % remove old code
+ end,
+ Mods).
+
+check_bstate(Slogan,ExpectedProcs) ->
+ BB = whereis(bb),
+ ActualProcs = lists:sort([P || P <- processes(),
+ erlang:check_process_code(P, b)]),
+ ExpectedProcs2 = lists:sort(ExpectedProcs),
+ ?t:format("check_bstate:~n~p~n~p~n",
+ [{"bb process", Slogan, BB},
+ {"Processes running old b code", ActualProcs}]),
+ if
+ Slogan =:= "no", BB =/= undefined ->
+ ?t:fail("instructions failed; process bb is running");
+ Slogan =/= "no", BB =:= undefined ->
+ ?t:fail("instructions failed; process bb is not running");
+ ExpectedProcs2 =:= [], ActualProcs =/= ExpectedProcs2 ->
+ ?t:fail("instructions failed; old b processes are running");
+ ActualProcs =/= ExpectedProcs2 ->
+ ?t:fail("instructions failed; wrong number of old b processes are running");
+ true ->
+ ok
+ end.
+
+wait_for(Name) ->
+ case whereis(Name) of
+ undefined ->
+ timer:sleep(100),
+ wait_for(Name);
+ Pid when is_pid(Pid) ->
+ ok
+ end.
+
+no_cc() ->
+ case whereis(cc) of
+ Pid when is_pid(Pid) -> ?t:fail("cc not stopped");
+ _ -> ok
+ end.
+
+
+
+%%%-----------------------------------------------------------------
+%%% Testing of reported bugs and other tickets.
+%%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-2740
+%% Slogan: vsn not numeric doesn't work so good in release_handling
+%%-----------------------------------------------------------------
+%% Test vsn.
+otp_2740(Conf) ->
+ DataDir = ?config(data_dir, Conf),
+ Dir = filename:join(DataDir, "otp_2740"),
+ true = code:add_path(Dir),
+
+ {module, vsn_numeric} = c:l(vsn_numeric),
+ {module, vsn_tuple} = c:l(vsn_tuple),
+ {module, vsn_list} = c:l(vsn_list),
+ {module, vsn_atom} = c:l(vsn_atom),
+ {module, vsn_string} = c:l(vsn_string),
+
+ 231894 = release_handler_1:get_current_vsn(vsn_numeric),
+ {tuple,["of",terms]} = release_handler_1:get_current_vsn(vsn_tuple),
+ [list,"of",{some,terms}] = release_handler_1:get_current_vsn(vsn_list),
+ atom = release_handler_1:get_current_vsn(vsn_atom),
+ "a string" = release_handler_1:get_current_vsn(vsn_string),
+
+ true = code:del_path(Dir),
+ ok.
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-2760
+%% Slogan: when an application is removed from a node it is not unloaded
+%%-----------------------------------------------------------------
+%% Test that when an application is removed from a node it is also unloaded.
+otp_2760(Conf) ->
+ PrivDir = priv_dir(Conf),
+ Dir = filename:join(PrivDir,"otp_2760"),
+ DataDir = ?config(data_dir,Conf),
+ LibDir = filename:join([DataDir,app1_app2,lib1]),
+
+ Rel1 = create_and_install_fake_first_release(Dir,[{app1,"1.0",LibDir}]),
+ Rel2 = create_fake_upgrade_release(Dir,"after",[],{Rel1,Rel1,[LibDir]}),
+ Rel2Dir = filename:dirname(Rel2),
+
+ %% Start a node with Rel1.boot and check that the app1 module is loaded
+ {ok, Node} = t_start_node(otp_2760, Rel1, []),
+ {file, _} = rpc:call(Node, code, is_loaded, [app1]),
+
+ %% Execute the relup script and check that app1 is unloaded
+ {ok, [{"after", [{_Rel1Vsn, _Descr, Script}], _}]} =
+ file:consult(filename:join(Rel2Dir, "relup")),
+ {ok, []} = rpc:call(Node, release_handler_1, eval_script,
+ [Script, [], []]),
+ false = rpc:call(Node, code, is_loaded, [app1]),
+
+ true = stop_node(Node),
+ ok.
+
+%% Test upgrade using other filesystem than the defined in OTP and
+%% option {update_paths, true}
+otp_5761(Conf) when is_list(Conf) ->
+
+ %% In the following test case, the release upgrade is somewhat
+ %% simplified (since it is not this procedure in itself we want to
+ %% test, but that application code directories are set correctly.)
+ %% Existing Erlang release is used as base, instead of creating
+ %% a new one.
+
+ %% Set some paths
+ PrivDir = priv_dir(Conf),
+ Dir = filename:join(PrivDir,"otp_5761"),
+ 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_5761, Rel1, filename:join(Rel1Dir,"sys.config")),
+
+ %% Bind some variable names that will be used in patternmatching below
+ App11Dir = filename:join([LibDir1, "app1-1.0"]),
+ App12Dir = filename:join([LibDir2, "app1-2.0"]),
+ App2aDir = filename:join([LibDir1, "app2-1.0"]),
+ App2bDir = filename:join([LibDir2, "app2-1.0"]),
+
+ %% Make sure correct code paths are used
+ App11Dir = rpc:call(Node, code, lib_dir, [app1]),
+ App2aDir = rpc:call(Node, code, lib_dir, [app2]),
+
+ %% 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]),
+ App12Dir = rpc:call(Node, code, lib_dir, [app1]),
+ App2aDir = rpc:call(Node, code, lib_dir, [app2]),
+
+ %% Install RelVsn1 again
+ {ok, RelVsn1, []} =
+ rpc:call(Node, release_handler, install_release, [RelVsn1]),
+
+ %% Install RelVsn2 with {update_paths, true} option
+ {ok, RelVsn1, []} =
+ rpc:call(Node, release_handler, install_release,
+ [RelVsn2, [{update_paths, true}]]),
+ App12Dir = rpc:call(Node, code, lib_dir, [app1]),
+ App2bDir = rpc:call(Node, code, lib_dir, [app2]),
+
+ %% Install RelVsn1 again
+ {ok, RelVsn1, []} =
+ rpc:call(Node, release_handler, install_release,
+ [RelVsn1, [{update_paths, true}]]),
+ App11Dir = rpc:call(Node, code, lib_dir, [app1]),
+ App2aDir = rpc:call(Node, code, lib_dir, [app2]),
+
+ %% Stop the slave node
+ true = stop_node(Node),
+ ok.
+
+%% Test upgrade and downgrade of applications
+eval_appup(Conf) when is_list(Conf) ->
+
+ %% OTP-6162
+ %% Create an ETS table which is updated by app1 if there is any
+ %% change made to the application configuration parameter 'var'
+ %% (see config_change/3 in myrel/lib1|2/app1-1|2.0/src/app1.erl)
+ ets:new(otp_6162, [set, public, named_table]),
+
+ %% Set some paths
+ RelDir = filename:join(?config(data_dir, Conf), "app1_app2"),
+ App11Dir = filename:join([RelDir, "lib1", "app1-1.0"]),
+ App12Dir = filename:join([RelDir, "lib2", "app1-2.0"]),
+ EbinDir = filename:join(App11Dir, "ebin"),
+
+ %% Start app1-1.0
+ code:add_patha(EbinDir),
+ ok = application:start(app1),
+ App11Dir = code:lib_dir(app1),
+ ok = gen_server:call(harry, error),
+
+ %% Upgrade to app1-2.0
+ {ok, []} = release_handler:upgrade_app(app1, App12Dir),
+ App12Dir = code:lib_dir(app1),
+ error = gen_server:call(harry, error),
+
+ %% OTP-6162
+ %% Value of config parameter 'var' should now be 'val2'
+ %% (see myrel/lib2/app1-2.0/ebin/app1.app)
+ [{var,val2}] = ets:lookup(otp_6162, var),
+
+ %% Downgrade to app1-1.0
+ {ok, []} = release_handler:downgrade_app(app1,"1.0",App11Dir),
+ App11Dir = code:lib_dir(app1),
+ ok = gen_server:call(harry, error),
+
+ %% OTP-6162
+ %% Value of config parameter 'var' should now be 'val1'
+ %% (see myrel/lib1/app1-1.0/ebin/app1.app)
+ [{var,val1}] = ets:lookup(otp_6162, var),
+
+ ok = application:stop(app1),
+ ok = application:unload(app1),
+
+ true = code:del_path(EbinDir),
+ ok.
+
+
+%% Test the example/target_system.erl module
+target_system(Conf) when is_list(Conf) ->
+ PrivDir = priv_dir(Conf),
+ DataDir = ?config(data_dir,Conf),
+
+ TargetCreateDir = filename:join([PrivDir,"target_system","create"]),
+ TargetInstallDir = filename:join([PrivDir,"target_system","install"]),
+
+ ok = filelib:ensure_dir(filename:join(TargetCreateDir,"xx")),
+ ok = filelib:ensure_dir(filename:join(TargetInstallDir,"xx")),
+
+
+ %% 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"}]),
+
+ %% Build the target_system module
+ ExamplesEbin = filename:join([code:lib_dir(sasl),examples,ebin]),
+ TSPath =
+ case filelib:is_file(filename:join(ExamplesEbin,"target_system.beam")) of
+ true ->
+ ExamplesEbin;
+ false ->
+ {ok,_} =
+ compile:file(filename:join(DataDir,"target_system.erl"),
+ [{outdir,TargetCreateDir}]),
+ TargetCreateDir
+ end,
+ code:add_path(TSPath),
+
+ %% Create the release
+ target_system:create(RelName,[{path,[filename:join([DataDir,
+ lib,
+ "a-1.0",
+ ebin])]}]),
+
+ %% Install the release
+ target_system:install(RelName,TargetInstallDir),
+
+ code:del_path(TSPath),
+
+ %% Check that all files exist in installation
+ true = filelib:is_dir(filename:join(TargetInstallDir,"erts-"++ErtsVsn)),
+ 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),
+ 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)),
+ true = filelib:is_dir(filename:join(LibDir,"a-1.0")),
+ 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_dir(filename:join(RelDir,RelVsn)),
+ true = filelib:is_regular(filename:join([RelDir,RelVsn,"start.boot"])),
+ BinDir = filename:join(TargetInstallDir,bin),
+ true = filelib:is_regular(filename:join(BinDir,"start.boot")),
+ true = filelib:is_regular(filename:join(BinDir,erl)),
+ true = filelib:is_regular(filename:join(BinDir,start_erl)),
+ true = filelib:is_regular(filename:join(BinDir,start)),
+ true = filelib:is_regular(filename:join(BinDir,epmd)),
+ true = filelib:is_regular(filename:join(BinDir,run_erl)),
+ true = filelib:is_regular(filename:join(BinDir,to_erl)),
+
+ %% Check content of files
+ {ok,SED} = file:read_file(filename:join(RelDir,"start_erl.data")),
+ [ErtsVsn,RelVsn] = string:tokens(binary_to_list(SED),"\s\n"),
+ ok.
+
+
+
+%%%=================================================================
+%%% Testing global groups.
+%%%=================================================================
+
+%% This test case involves P1G and P1H with the sys.config as
+%% specified in gg_config/1. The test case checks that the global
+%% group information is correct before and after the upgrade and also
+%% after terminating one of the nodes. The flow is as follows:
+%% 1. Start all four nodes of global group gg1 with P1G
+%% 2. Terminate one of the nodes, and upgrade the others to P1H. P1H
+%% config adds to more nodes to the global group.
+%% 3. Start the two remaining nodes with P1H
+upgrade_gg(Conf) ->
+ [Gg1Sname,Gg2Sname,Gg3Sname,Gg4Sname,Gg5Sname,Gg6Sname] =
+ ?config(snames,Conf),
+
+ %% start gg1, gg3, gg4, gg5 and check that global group info is ok
+ Nodes1 = [Gg1,Gg3,Gg4,Gg5] =
+ start_nodes(Conf,[Gg1Sname,Gg3Sname,Gg4Sname,Gg5Sname],"upgrade_gg"),
+
+ %% Give some time to synch nodes, then check global group info.
+ timer:sleep(1000),
+ [check_gg_info(Node,Nodes1,[],Nodes1--[Node]) || Node <- Nodes1],
+
+ %% register a process on each of the nodes
+ ok = rpc:call(Gg1, installer, reg_proc, [reg1]),
+ ok = rpc:call(Gg3, installer, reg_proc, [reg3]),
+ ok = rpc:call(Gg4, installer, reg_proc, [reg4]),
+ ok = rpc:call(Gg5, installer, reg_proc, [reg5]),
+ are_names_reg_gg(Gg1, [reg1, reg3, reg4, reg5]),
+
+ %% Stop gg3, then upgrade gg1, gg4 and gg5 to P1H
+ ok = stop_nodes([Gg3]),
+
+ ok = install_release_changed_gg(Gg1,"P1H"),
+ ok = install_release_changed_gg(Gg4,"P1H"),
+ ok = install_release_changed_gg(Gg5,"P1H"),
+
+ %% Check global group info
+ Gg2 = node_name(Gg2Sname),
+ Gg6 = node_name(Gg6Sname),
+ Nodes2 = [Gg1,Gg4,Gg5],
+ [check_gg_info(Node,Nodes2,[Gg2,Gg6],Nodes2--[Node]) || Node <- Nodes2],
+
+ %% start gg2 and gg6
+ [Gg2,Gg6] = start_nodes(Conf,[Gg2Sname,Gg6Sname],"upgrade_gg start gg2/gg6"),
+
+ %% reg proc on each of the nodes
+ ok = rpc:call(Gg2, installer, reg_proc, [reg2]),
+ ok = rpc:call(Gg6, installer, reg_proc, [reg6]),
+ are_names_reg_gg(Gg1, [reg1, reg2, reg4, reg5, reg6]),
+
+ %% Check global group info
+ Nodes3 = [Gg1,Gg2,Gg4,Gg5,Gg6],
+ [check_gg_info(Node,Nodes3,[],Nodes3--[Node]) || Node <- Nodes3],
+
+ ok.
+
+upgrade_gg(cleanup,Config) ->
+ Snames = ?config(snames,Config),
+ NodeNames = [node_name(Sname) || Sname <- Snames],
+ ok = stop_nodes(NodeNames).
+
+
+
+
+%%%=================================================================
+%%% Misceleaneous functions
+%%%=================================================================
+stop_nodes(Nodes) ->
+ ?t:format("Stopping nodes: ~p~n",[Nodes]),
+ Running =
+ lists:foldl(fun(Node,Acc) ->
+ Now = now(),
+ stop_cover(Node),
+ case rpc:call(Node,installer,stop,[Now]) of
+ {badrpc,nodedown} ->
+ Acc;
+ Other ->
+ ?t:format("Stop ~p(~p): ~p~n",
+ [Node,Now,Other]),
+ [Node|Acc]
+ end
+ end, [], Nodes),
+ wait_nodes_down(Running).
+
+
+wait_nodes_down(Nodes) ->
+ ?t:format( "wait_nodes_down ~p:",[Nodes]),
+ wait_nodes_down(Nodes, 30).
+
+wait_nodes_down(Nodes, 0) ->
+ test_server:fail({error, {"could not kill nodes", Nodes}});
+wait_nodes_down(Nodes, N) ->
+ Fun = fun(Node, A) ->
+ case net_adm:ping(Node) of
+ pong ->
+ ?t:format( " net_adm:ping(~p) = pong", [Node]),
+ [Node|A];
+ pang ->
+ ?t:format( " net_adm:ping(~p) = pang", [Node]),
+ A
+ end
+ end,
+ Pang = lists:foldl(Fun, [], Nodes),
+ case Pang of
+ [] ->
+ ?t:format("",[]),
+ ok;
+ _ ->
+ timer:sleep(1000),
+ wait_nodes_down(Pang, N-1)
+ end.
+
+
+
+wait_nodes_up(Nodes, Tag) ->
+ wait_nodes_up(Nodes, Tag, []).
+
+wait_nodes_up(Nodes0, Tag, Apps) ->
+ ?t:format("wait_nodes_up(~p, ~p, ~p):",[Nodes0, Tag, Apps]),
+ Nodes = fix_nodes(Nodes0),
+ wait_nodes_up(Nodes, Tag, lists:umerge(Apps,[kernel,stdlib,sasl]), 30).
+
+fix_nodes([{Node,InitPid}|Nodes]) ->
+ [{Node,InitPid} | fix_nodes(Nodes)];
+fix_nodes([Node|Nodes]) ->
+ [{Node,fake_init_pid} | fix_nodes(Nodes)];
+fix_nodes([]) ->
+ [].
+
+wait_nodes_up(Nodes, Tag, Apps, 0) ->
+ test_server:fail({error, {"nodes not started", Nodes, Tag, Apps}});
+wait_nodes_up(Nodes, Tag, Apps, N) ->
+ Fun =
+ fun(NodeInfo={Node,OldInitPid}, A) ->
+ case rpc:call(Node, application, which_applications, []) of
+ {badrpc, nodedown} ->
+ ?t:format( " ~p = {badarg, nodedown}",[Node]),
+ [NodeInfo | A];
+ List when is_list(List)->
+ ?t:format( " ~p = [~p]",[Node, List]),
+ case lists:all(fun(App) ->
+ lists:keymember(App,1,List)
+ end, Apps) of
+ true ->
+ case rpc:call(Node,erlang,whereis,[init]) of
+ OldInitPid ->
+ [NodeInfo | A];
+ _ ->
+ start_cover(Node),
+ A
+ end;
+ false ->
+ [NodeInfo | A]
+ end
+ end
+ end,
+ Pang = lists:foldl(Fun,[],Nodes),
+ case Pang of
+ [] ->
+ ?t:format("",[]),
+ ok;
+ _ ->
+ timer:sleep(1000),
+ wait_nodes_up(Pang, Tag, Apps, N-1)
+ end.
+
+
+
+
+are_names_reg_gg(Node, Names) ->
+ ?t:format( "are_names_reg_gg ~p~n",[Names]),
+ are_names_reg_gg(Node, Names, 30).
+
+are_names_reg_gg(Node, Names, N) ->
+ case lists:sort(rpc:call(Node, global, registered_names, [])) of
+ Names ->
+ ok;
+ Regs when N > 0 ->
+ timer:sleep(1000),
+ ?t:format( "are_names_reg_gg Regs ~p~n",[Regs]),
+ are_names_reg_gg(Node, Names, N-1);
+ Regs ->
+ ?t:fail({error, {"Names not registered",
+ {{"should :", Names},
+ {"was :", Regs}}}})
+ end.
+
+
+
+t_start_node(Name, Boot, SysConfig) ->
+ Args =
+ case Boot of
+ [] -> [];
+ _ -> " -boot " ++ Boot
+ end ++
+ case SysConfig of
+ [] -> [];
+ _ -> " -config " ++ SysConfig
+ end,
+ test_server:start_node(Name, slave, [{args, Args}]).
+
+stop_node(Node) ->
+ ?t:stop_node(Node).
+
+
+copy_client(Conf,Master,Sname,StartScript) ->
+ io:format("copy_client(Conf)"),
+
+ DataDir = ?config(data_dir, Conf),
+ MasterDir = filename:join(priv_dir(Conf),Master),
+
+ {ok,Host} = inet:gethostname(),
+ {ok,IpTuple} = inet:getaddr(Host,inet),
+ IpAddr = inet_parse:ntoa(IpTuple),
+
+ CliNode = node_name(Sname),
+
+ Cli = filename:join([MasterDir, "clients", "type1", CliNode]),
+ ok = filelib:ensure_dir(filename:join([Cli,"bin","."])),
+ ok = filelib:ensure_dir(filename:join([Cli,"releases","."])),
+ ok = filelib:ensure_dir(filename:join([Cli,"log","."])),
+
+ P1GOrig = filename:join([MasterDir, "releases", "P1G"]),
+ ok = copy_tree(Conf,P1GOrig,filename:join(Cli,"releases")),
+
+ ok = subst_file(filename:join([DataDir, "clients", StartScript]),
+ filename:join([Cli,"bin","start"]),
+ [{"ROOT",MasterDir},
+ {"MASTER",atom_to_list(Master)},
+ {"IPADDR",IpAddr}],
+ [{chmod,8#0755}]),
+
+ StartErlData = filename:join([MasterDir, "releases", "start_erl.data"]),
+ CliRelDir = filename:join([Cli, "releases"]),
+ copy_file(StartErlData, CliRelDir),
+
+ RR = filename:join([MasterDir, "releases", "RELEASES"]),
+ copy_file(RR, CliRelDir),
+
+ ok.
+
+
+delete_release(Conf) ->
+ PrivDir = priv_dir(Conf),
+
+ {ok, OrigWd} = file:get_cwd(),
+
+ ok = file:set_cwd(PrivDir),
+ ?t:format("======== current dir ~p~n",[PrivDir]),
+ {ok, Dirs} = file:list_dir(PrivDir),
+ ?t:format("======== deleting ~p~n",[Dirs]),
+
+ ok = delete_release_os(Dirs),
+ ?t:format("======== remaining ~p~n",[file:list_dir(PrivDir)]),
+ ok = file:set_cwd(OrigWd),
+ ok.
+
+
+delete_release_os(Dirs) ->
+ case os:type() of
+ {unix, _} ->
+ delete_release_unix(Dirs);
+ {win32, _} ->
+ delete_release_win32(Dirs);
+ Os ->
+ test_server:fail({error, {not_yet_implemented_os, Os}})
+ end.
+
+
+delete_release_unix([]) ->
+ ok;
+delete_release_unix(["save"|Dirs]) ->
+ delete_release_unix(Dirs);
+delete_release_unix([Dir|Dirs]) ->
+ Rm = string:concat("rm -rf ", Dir),
+ ?t:format("============== COMMAND ~p~n",[Rm]),
+ case file:list_dir(Dir) of
+ {error, enotdir} ->
+ ok;
+ X ->
+ ?t:format("------- Dir ~p~n ~p~n",[Dir, X])
+ end,
+ case os:cmd(Rm) of
+ [] ->
+ ?t:format("------- Result of COMMAND ~p~n",[ok]);
+ Y ->
+ ?t:format("!!!!!!! delete ERROR Dir ~p Error ~p~n",[Dir, Y]),
+ ?t:format("------- ls -al ~p~n",[os:cmd("ls -al " ++ Dir)])
+ end,
+
+ delete_release_unix(Dirs).
+
+delete_release_win32([]) ->
+ ok;
+delete_release_win32(["save"|Dirs]) ->
+ delete_release_win32(Dirs);
+delete_release_win32([Dir|Dirs]) ->
+ Rm = string:concat("rmdir /s ", Dir),
+ [] = os:cmd(Rm),
+ delete_release_win32(Dirs).
+
+
+node_name(Sname) when is_atom(Sname) ->
+ {ok,Host} = inet:gethostname(),
+ list_to_atom(atom_to_list(Sname) ++ "@" ++ Host).
+
+copy_file(Src, Dest) ->
+ copy_file(Src, Dest, []).
+copy_file(Src, Dest, Opts) ->
+ case file:copy(Src,Dest) of
+ {ok,_} ->
+ preserve(Src,Dest,Opts),
+ chmod(Dest,Opts),
+ ok;
+ {error,eisdir} ->
+ NewDest = filename:join(Dest, filename:basename(Src)),
+ case file:copy(Src,NewDest) of
+ {ok,_} ->
+ preserve(Src,NewDest,Opts),
+ chmod(NewDest,Opts);
+ {error,Reason} ->
+ copy_error(Src,Dest,Reason)
+ end;
+ {error,Reason} ->
+ copy_error(Src,Dest,Reason)
+ end.
+
+preserve(Src,Dest,Opts) ->
+ case lists:member(preserve, Opts) of
+ true ->
+ {ok, FileInfo} = file:read_file_info(Src),
+ ok = file:write_file_info(Dest, FileInfo);
+ false ->
+ ok
+ end.
+
+chmod(Dest,Opts) ->
+ case lists:keyfind(chmod,1,Opts) of
+ {chmod,Mode} ->
+ ok = file:change_mode(Dest, Mode);
+ false ->
+ ok
+ end.
+
+
+
+copy_error(Src, Dest, Reason) ->
+ io:format("Copy ~s to ~s failed: ~s\n",
+ [Src,Dest,file:format_error(Reason)]),
+ ?t:fail(file_copy_failed).
+
+copy_tree(Conf, Src, DestDir) ->
+ case catch copy_tree(Conf, Src, filename:basename(Src), DestDir) of
+ ok ->
+ ok;
+ {'EXIT', {{badmatch,Error},_Stack}} ->
+ %% Most probably, an erl_tar call has failed.
+ %% Known to happen on some platforms (symbolic_link_too_long)
+ Error;
+ {'EXIT', Reason} ->
+ {error, Reason}
+ end.
+
+copy_tree(Conf, Src, NewName, DestDir) ->
+ PrivDir = priv_dir(Conf),
+ TempTarName = filename:join(PrivDir, "temp_tar_file.tar"),
+ %% Not compressing tar file here since that would increase test
+ %% suite time by almost 100%, and the tar file is deleted
+ %% imediately anyway.
+ {ok,Tar} = erl_tar:open(TempTarName, [write]),
+ ok = erl_tar:add(Tar, Src, NewName, []),
+ ok = erl_tar:close(Tar),
+ ok = erl_tar:extract(TempTarName, [{cwd,DestDir}]),
+ ok = file:delete(TempTarName),
+ ok.
+
+%% subst_file(Src, Dest, Vars)
+%% Src = Dest = string(), filename and path
+%% Vars = [{Var, Val}]
+%% Var = Val = string()
+%% Substitute all occurrences of %Var% for Val in Src, using the list
+%% of variables in Vars. Result is written to Dest.
+%%
+subst_file(Src, Dest, Vars) ->
+ subst_file(Src, Dest, Vars, []).
+subst_file(Src, Dest, Vars, Opts) ->
+ {ok, Bin} = file:read_file(Src),
+ Conts = binary_to_list(Bin),
+ NConts = subst(Conts, Vars),
+ ok = file:write_file(Dest, NConts),
+ preserve(Src,Dest,Opts),
+ chmod(Dest,Opts).
+
+subst(Str, Vars) ->
+ subst(Str, Vars, []).
+
+subst([$%, C| Rest], Vars, Result) when $A =< C, C =< $Z ->
+ subst_var([C| Rest], Vars, Result, []);
+subst([$%, C| Rest], Vars, Result) when $a =< C, C =< $z ->
+ subst_var([C| Rest], Vars, Result, []);
+subst([$%, C| Rest], Vars, Result) when C == $_ ->
+ subst_var([C| Rest], Vars, Result, []);
+subst([C| Rest], Vars, Result) ->
+ subst(Rest, Vars, [C| Result]);
+subst([], _Vars, Result) ->
+ lists:reverse(Result).
+
+subst_var([$%| Rest], Vars, Result, VarAcc) ->
+ Key = lists:reverse(VarAcc),
+ case lists:keysearch(Key, 1, Vars) of
+ {value, {Key, Value}} ->
+ subst(Rest, Vars, lists:reverse(Value, Result));
+ false ->
+ subst(Rest, Vars, [$%| VarAcc ++ [$%| Result]])
+ end;
+subst_var([C| Rest], Vars, Result, VarAcc) ->
+ subst_var(Rest, Vars, Result, [C| VarAcc]);
+subst_var([], Vars, Result, VarAcc) ->
+ subst([], Vars, [VarAcc ++ [$%| Result]]).
+
+
+priv_dir(Conf) ->
+ filename:absname(?config(priv_dir, Conf)). % Get rid of trailing slash
+
+latest_version(Dir) ->
+ List = filelib:wildcard(Dir ++ "*"),
+ lists:last(lists:sort(List)).
+
+%% A printer process which receives messages from other nodes and
+%% prints in the log
+reg_print_proc() ->
+ catch unregister(rh_print),
+ Pid = spawn_link(?MODULE, rh_print, []),
+ register(rh_print, Pid),
+ ok.
+
+rh_print() ->
+ receive
+ {print, {Module,Line}, [H|T]} ->
+ ?t:format("=== ~p:~p - ~p",[Module,Line,H]),
+ lists:foreach(fun(Term) -> ?t:format(" ~p",[Term]) end, T),
+ ?t:format("",[]),
+ rh_print();
+ kill ->
+ exit(normal)
+ end.
+
+stop_print_proc() ->
+ case whereis(rh_print) of %%removes the printer process
+ undefined ->
+ ok;
+ Pid when is_pid(Pid) ->
+ rh_print ! kill
+ end.
+
+%% 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),
+ DataDir = ?config(data_dir,Conf),
+ ErtsVsn = "4.4",
+ ErtsDir = "erts-"++ErtsVsn,
+
+ %% Create dirs
+ BinDir = filename:join(TargetDir,bin),
+ ReleasesDir = filename:join(TargetDir,releases),
+ LogDir = filename:join(TargetDir,log),
+ ok = filelib:ensure_dir(filename:join(BinDir,"*")),
+ ok = filelib:ensure_dir(filename:join(ReleasesDir,"*")),
+ ok = filelib:ensure_dir(filename:join(LogDir,"*")),
+
+ %% Copy stuff
+ ErtsLatest = latest_version(filename:join(code:root_dir(),"erts")),
+ ok = copy_tree(Conf, ErtsLatest, ErtsDir, TargetDir),
+ ErtsBinDir = filename:join([TargetDir,ErtsDir,bin]),
+ copy_file(filename:join([ErtsBinDir, "epmd"]), BinDir, [preserve]),
+ copy_file(filename:join([ErtsBinDir, "run_erl"]), BinDir, [preserve]),
+ copy_file(filename:join([ErtsBinDir, "to_erl"]), BinDir, [preserve]),
+
+ copy_file(filename:join(DataDir, "../installer.beam"),
+ filename:join([DataDir,lib,"installer-1.0",ebin])),
+
+ %% Create .rel, .script and .boot files
+ RelName = "rel0",
+ RelVsn = "P1G",
+ RelDir = filename:join(PrivDir,RelName),
+ RelFileName = filename:join(RelDir,RelName),
+ RelFile = RelFileName ++ ".rel",
+ ok = filelib:ensure_dir(RelFile),
+ LibPath = filename:join([DataDir,lib,"*",ebin]),
+
+ TarFile = create_basic_release(RelFile, RelVsn, {ErtsVsn,false},
+ LibPath, [], [], [], []),
+
+ %% 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]),
+ ok = file:write_file(StartErlDataFile, StartErlData),
+
+ %% Create RELEASES
+ ok = release_handler:create_RELEASES(TargetDir,ReleasesDir,RelFile,[]),
+
+ %% Create start_erl
+ ok = subst_file(filename:join([ErtsBinDir,"start_erl.src"]),
+ filename:join([BinDir,"start_erl"]),
+ [{"EMU","beam"}],
+ [{chmod,8#0755}]),
+
+ %% Create start script
+ %% Using a customized start script from DataDir where some options
+ %% (heart and nodename) are added compared to the start.src in the
+ %% erlang distribution.
+ ok = subst_file(filename:join(DataDir, "start"),
+ filename:join([BinDir, "start"]),
+ [{"ROOT",TargetDir}],
+ [preserve]),
+ ok.
+
+%% 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 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"}],
+ [{a,[{key2,newval2}]}],
+ {"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()},
+ [{a,"1.1"}],[{a,[{key2,newval2}]}],
+ {"rel2",[new_emu]}).
+
+%% Create a release tar package which can be installed on top of P1G
+create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,{UpFromName,Descr}) ->
+ 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}],
+
+ create_basic_release(RelFile, RelVsn, Erts, LibPath,
+ Apps, Config, UpFrom, []),
+ ok.
+
+%% Create .rel, .script, .boot, sys.config and tar
+create_basic_release(RelFile,RelVsn,{ErtsVsn,ErtsDir},LibPath,ExtraApps,Config,UpFrom,DownTo) ->
+ RelDir = filename:dirname(RelFile),
+ RelFileName = filename:rootname(RelFile),
+
+ %% Create .rel file
+ create_installer_rel_file(RelFile,RelVsn,ErtsVsn,ExtraApps),
+
+ %% Generate .script and .boot
+ ok = systools:make_script(RelFileName,
+ [{path,[LibPath]},
+ {outdir,RelDir}]),
+
+ %% Generate relup
+ ok = systools:make_relup(RelFileName,UpFrom,DownTo,[{path,[LibPath]},
+ {outdir,RelDir}]),
+
+ %% Create sys.config
+ ok = write_term_file(filename:join(RelDir,"sys.config"),Config),
+
+
+ %% Create tar file (i.e. collect all lib/app-*/* and system files)
+ ok = systools:make_tar(RelFileName,
+ [{path,[LibPath]},
+ {outdir,RelDir} |
+ case ErtsDir of
+ false -> [];
+ _ -> [{erts,ErtsDir}]
+ end]),
+
+ RelFileName ++ ".tar.gz".
+
+%% Create a .rel file
+create_installer_rel_file(RelFile,RelVsn,ErtsVsn,ExtraApps) ->
+ create_rel_file(RelFile,"SASL-test",RelVsn,ErtsVsn,
+ [{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),
+ application:load(tools),
+ {ok,ToolsVsn} = application:get_key(tools,vsn),
+ application:load(runtime_tools),
+ {ok,RuntimeToolsVsn} = application:get_key(runtime_tools,vsn),
+
+ RelFileContent = {release,
+ {RelName, RelVsn},
+ {erts, ErtsVsn},
+ [{kernel, KernelVsn},
+ {stdlib, StdlibVsn},
+ {sasl, SaslVsn},
+ {runtime_tools, RuntimeToolsVsn},
+ {tools, ToolsVsn} |
+ ExtraApps]},
+ ok = write_term_file(RelFile,RelFileContent).
+
+%% Insert a term in a file, which can be read with file:consult/1.
+write_term_file(File,Term) ->
+ ok = file:write_file(File,io_lib:format("~p.~n",[Term])).
+
+
+%% Check that global group info is correct
+check_gg_info(Node,OtherAlive,OtherDead,Synced) ->
+ GGI = rpc:call(Node, global_group, info, []),
+ GI = rpc:call(Node, global, info,[]),
+ try do_check_gg_info(OtherAlive,OtherDead,Synced,GGI,GI)
+ catch _:E ->
+ ?t:format("~ncheck_gg_info failed for ~p: ~p~nwhen GGI was: ~p~n"
+ "and GI was: ~p~n",
+ [Node,E,GGI,GI]),
+ ?t:fail("check_gg_info failed")
+ end.
+
+do_check_gg_info(OtherAlive,OtherDead,Synced,GGI,GI) ->
+ {_,gg1} = lists:keyfind(own_group_name,1,GGI),
+ {_,synced} = lists:keyfind(state,1,GGI),
+ {_,AllNodes} = lists:keyfind(own_group_nodes,1,GGI),
+ true = lists:sort(AllNodes) =:= lists:sort(OtherAlive++OtherDead),
+ {_,[]} = lists:keyfind(sync_error,1,GGI),
+ {_,[{gg2,[_,_]}]} = lists:keyfind(other_groups,1,GGI),
+
+ %% There is a known bug in global_group (OTP-9177) which causes
+ %% the following to fail every now and then:
+ %% {_,SyncedNodes} = lists:keyfind(synced_nodes,1,GGI),
+ %% true = lists:sort(SyncedNodes) =:= lists:sort(Synced),
+ %% {_,NoContact} = lists:keyfind(no_contact,1,GGI),
+ %% true = lists:sort(NoContact) =:= lists:sort(OtherDead),
+
+ %% Therefore we use global:info instead for this part
+ {state,_,_,SyncedNodes,_,_,_,_,_,_,_} = GI,
+ true = lists:sort(SyncedNodes) =:= lists:sort(Synced),
+
+ %% .. and we only check that all OtherDead are listed as
+ %% no_contact (due to th bug there might be more nodes in this
+ %% list)
+ {_,NoContact} = lists:keyfind(no_contact,1,GGI),
+ true =
+ lists:sort(OtherDead) =:=
+ lists:sort([NC || NC <- NoContact,lists:member(NC,OtherDead)]),
+
+ ok.
+
+%% Return the configuration (to be inserted in sys.config) for global group tests
+gg_config(Snames) ->
+ Nodes = [node_name(Sname) || Sname <- Snames],
+ [{kernel, [{sync_nodes_optional, Nodes},
+ {sync_nodes_timeout, 10000},
+ {global_groups,
+ [{gg1, Nodes},
+ {gg2, [node_name(Sname) || Sname <- [ggq,ggw]]}]}]},
+ {a, [{key2, val2}]}].
+
+%% Start a node with short name SnameStr, and unpack P1H
+unpack_p1h(Conf,Sname) ->
+ PrivDir = priv_dir(Conf),
+ [Node] = start_nodes(Conf,[Sname],"create_p1h"),
+ ok = rpc_inst(Node, unpack_p1h, [PrivDir]),
+ Node.
+
+%% On the given node, install P1H and make it permanent
+%% This function is to be called after unpack_p1h/2, with the same node.
+permanent_p1h(Node) ->
+ ok = rpc_inst(Node, permanent_p1h, []).
+
+%% For each node in ToNodes, create a target installation which is
+%% indentical to the target installation for FromNode.
+copy_installed(Conf,FromNode,ToNodes) ->
+ PrivDir = priv_dir(Conf),
+ DataDir = ?config(data_dir,Conf),
+ lists:foreach(
+ fun(Node) ->
+ ok = copy_tree(Conf,filename:join(PrivDir,FromNode),Node,PrivDir),
+ NodeDir = filename:join(PrivDir,Node),
+ ok = subst_file(filename:join(DataDir, "start"),
+ filename:join([NodeDir, "bin", "start"]),
+ [{"ROOT",NodeDir}]),
+ LogDir = filename:join(NodeDir,log),
+ {ok,Logs} = file:list_dir(LogDir),
+ lists:foreach(fun(Log) ->
+ file:delete(filename:join(LogDir,Log))
+ end,
+ Logs)
+ end,
+ ToNodes).
+
+start_nodes(Conf,Snames,Tag) ->
+ PrivDir = priv_dir(Conf),
+ Nodes =
+ lists:map(
+ fun(Sname) ->
+ NodeDir = filename:join(PrivDir,Sname),
+ Node = node_name(Sname),
+
+ Script = filename:join([NodeDir,"bin","start"]),
+ Cmd = "env NODENAME="++atom_to_list(Sname) ++ " " ++ Script,
+ %% {ok,StartFile} = file:read_file(Cmd),
+ %% io:format("~s:\n~s~n~n",[Start,binary_to_list(StartFile)]),
+ Res = os:cmd(Cmd),
+ io:format("Start ~p: ~p~n=>\t~p~n", [Sname,Cmd,Res]),
+ Node
+ end,
+ Snames),
+ wait_nodes_up(Nodes,Tag),
+ Nodes.
+
+tc_sname(Config) ->
+ tc_sname(Config,"").
+tc_sname(Config,Fix) when is_atom(Fix) ->
+ tc_sname(Config,atom_to_list(Fix));
+tc_sname(Config,Fix) when is_list(Fix) ->
+ list_to_atom(
+ atom_to_list(?MODULE)
+ ++ "-" ++ atom_to_list(?config(sname_prefix, Config)) ++
+ case Fix of
+ "" -> "";
+ _ -> "-" ++ Fix
+ end).
+
+tc_full_node_name(Config) ->
+ tc_full_node_name(Config,"").
+tc_full_node_name(Config,Fix) ->
+ node_name(tc_sname(Config,Fix)).
+
+
+%% When installing a release for which the sys.config includes added
+%% or changed global group(s), this node (test_sever@host) will be
+%% disconnected from the test node (Node) by global_group.erl. This
+%% will cause the rpc:call to terminate with {badrpc,nodedown} even if
+%% the installation succeeds. This function installs the release,
+%% accepts the faulty return value and then checks if the release was
+%% successfully installed.
+install_release_changed_gg(Node,RelVsn) ->
+ stop_cover(Node),
+ {badrpc,nodedown} = rpc:call(Node,release_handler,install_release,[RelVsn]),
+ timer:sleep(100),
+ wait_installed(Node,RelVsn,4).
+
+wait_installed(Node,RelVsn,0) ->
+ ?t:fail("install_release_changed_gg failed for " ++ RelVsn ++
+ " on " ++ atom_to_list(Node));
+wait_installed(Node,RelVsn,N) ->
+ Rels = rpc:call(Node,release_handler,which_releases,[]),
+ case lists:keyfind(RelVsn, 2, Rels) of
+ {"SASL-test", RelVsn, _Libs, current} ->
+ start_cover(Node),
+ ok;
+ _ ->
+ timer:sleep(500),
+ wait_installed(Node,RelVsn,N-1)
+ end.
+
+%% Start/stop cover measurements on the given node
+start_cover(Node) ->
+ cover_fun(Node,start).
+stop_cover(Node) ->
+ cover_fun(Node,stop).
+
+cover_fun(Node,Func) ->
+ case ?t:is_cover() of
+ true ->
+ cover:Func(Node);
+ false ->
+ ok
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Create a fake release ....
+
+%% This function will create and install a release build on the
+%% current running OTP release. It includes kernel, stdlib and sasl,
+%% and possibly other applications if they are listed in AppDirs =
+%% [{App,Vsn,LibDir}]
+create_and_install_fake_first_release(Dir,AppDirs) ->
+ %% Create the first release
+ {RelName,RelVsn} = init:script_id(),
+ {Rel,_} = create_fake_release(Dir,RelName,RelVsn,AppDirs),
+ ReleasesDir = filename:join(Dir, "releases"),
+ RelDir = filename:dirname(Rel),
+
+ %% And install it
+ RelVsnDir = filename:join(ReleasesDir, RelVsn),
+ ok = filelib:ensure_dir(filename:join(RelVsnDir,"*")),
+
+ ok = copy_file(Rel++".rel",RelVsnDir),
+ ok = copy_file(Rel++".boot",filename:join(RelVsnDir, "start.boot")),
+ ok = copy_file(filename:join(RelDir,"sys.config"),RelVsnDir),
+
+ ok = release_handler:create_RELEASES(code:root_dir(),
+ ReleasesDir,
+ Rel++".rel",
+ AppDirs),
+
+ Rel.
+
+%% This function create a new release, including a relup file. It can
+%% be upgraded to from the release created by
+%% create_and_install_fake_first_release/2. Unpack first by calls to
+%% release_handler:set_unpacked and release_handler:install_file.
+create_fake_upgrade_release(Dir,RelVsn,AppDirs,{UpFrom,DownTo,ExtraLibs}) ->
+ %% Create a new release
+ {RelName,_} = init:script_id(),
+ {Rel,Paths} = create_fake_release(Dir,RelName,RelVsn,AppDirs),
+ RelDir = filename:dirname(Rel),
+
+ %% And a relup file so it can be upgraded to
+ RelupPath = Paths ++ [filename:join([Lib,"*","ebin"]) || Lib <- ExtraLibs],
+ ok = systools:make_relup(Rel,[UpFrom],[DownTo],
+ [{path,RelupPath},
+ {outdir,RelDir}]),
+
+ Rel.
+
+
+create_fake_release(Dir,RelName,RelVsn,AppDirs) ->
+ %% Create .rel files
+ 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}) ->
+ {[{App,Vsn}|As],
+ lists:umerge([filename:join([Lib,"*",ebin])],Ps)}
+ end,
+ {[],[]},
+ AppDirs),
+
+ create_rel_file(Rel++".rel",RelName,RelVsn,ErtsVsn,Apps),
+
+ %% Generate boot scripts
+ ok = systools:make_script(Rel,[local,
+ {path, Paths},
+ {outdir,RelDir}]),
+ ok = copy_file(Rel++".boot", filename:join(RelDir,"start.boot")),
+
+ %% Use an own 'releases' directory - we don't want to change the
+ %% contents of $OTP_ROOT/releases
+ %% Inform SASL about this via sys.config
+ ReleasesDir = filename:join(Dir, "releases"),
+ Config = [{sasl,[{releases_dir,ReleasesDir}]}],
+ ok = write_term_file(filename:join(RelDir,"sys.config"), Config),
+
+ {Rel,Paths}.
+
+
+rpc_inst(Node,Func,Args) ->
+ rpc:call(Node,installer,Func,[node()|Args]).
diff --git a/lib/sasl/test/release_handler_SUITE_data/Makefile.src b/lib/sasl/test/release_handler_SUITE_data/Makefile.src
new file mode 100644
index 0000000000..85e25fdc2f
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/Makefile.src
@@ -0,0 +1,108 @@
+EFLAGS=+debug_info
+
+P2B= \
+ P2B/a-2.0/ebin/a.beam \
+ P2B/a-2.0/ebin/a_sup.beam
+
+LIB= \
+ lib/a-1.1/ebin/a.beam \
+ lib/a-1.1/ebin/a_sup.beam \
+ lib/a-1.0/ebin/a.beam \
+ lib/a-1.0/ebin/a_sup.beam \
+
+APP= \
+ app1_app2/lib1/app1-1.0/ebin/app1_sup.@EMULATOR@ \
+ app1_app2/lib1/app1-1.0/ebin/app1_server.@EMULATOR@ \
+ app1_app2/lib1/app1-1.0/ebin/app1.@EMULATOR@ \
+ app1_app2/lib1/app2-1.0/ebin/app2_sup.@EMULATOR@ \
+ app1_app2/lib1/app2-1.0/ebin/app2_server.@EMULATOR@ \
+ app1_app2/lib1/app2-1.0/ebin/app2.@EMULATOR@ \
+ app1_app2/lib2/app1-2.0/ebin/app1_sup.@EMULATOR@ \
+ app1_app2/lib2/app1-2.0/ebin/app1_server.@EMULATOR@ \
+ 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@
+
+OTP2740= \
+ otp_2740/vsn_atom.@EMULATOR@ \
+ otp_2740/vsn_list.@EMULATOR@ \
+ otp_2740/vsn_numeric.@EMULATOR@ \
+ otp_2740/vsn_tuple.@EMULATOR@ \
+ otp_2740/vsn_string.@EMULATOR@
+
+C= \
+ c/aa.@EMULATOR@ \
+ c/b.@EMULATOR@ \
+ c/c_sup.@EMULATOR@
+
+
+all: $(P2B) $(LIB) $(APP) $(OTP2740) $(C)
+
+P2B/a-2.0/ebin/a.@EMULATOR@: P2B/a-2.0/src/a.erl
+ erlc $(EFLAGS) -oP2B/a-2.0/ebin P2B/a-2.0/src/a.erl
+P2B/a-2.0/ebin/a_sup.@EMULATOR@: P2B/a-2.0/src/a_sup.erl
+ erlc $(EFLAGS) -oP2B/a-2.0/ebin P2B/a-2.0/src/a_sup.erl
+
+
+lib/a-1.0/ebin/a.@EMULATOR@: lib/a-1.0/src/a.erl
+ erlc $(EFLAGS) -olib/a-1.0/ebin lib/a-1.0/src/a.erl
+lib/a-1.0/ebin/a_sup.@EMULATOR@: lib/a-1.0/src/a_sup.erl
+ erlc $(EFLAGS) -olib/a-1.0/ebin lib/a-1.0/src/a_sup.erl
+
+
+lib/a-1.1/ebin/a.@EMULATOR@: lib/a-1.1/src/a.erl
+ erlc $(EFLAGS) -olib/a-1.1/ebin lib/a-1.1/src/a.erl
+lib/a-1.1/ebin/a_sup.@EMULATOR@: lib/a-1.1/src/a_sup.erl
+ erlc $(EFLAGS) -olib/a-1.1/ebin lib/a-1.1/src/a_sup.erl
+
+
+app1_app2/lib1/app1-1.0/ebin/app1_sup.@EMULATOR@: app1_app2/lib1/app1-1.0/src/app1_sup.erl
+ erlc $(EFLAGS) -oapp1_app2/lib1/app1-1.0/ebin app1_app2/lib1/app1-1.0/src/app1_sup.erl
+app1_app2/lib1/app1-1.0/ebin/app1_server.@EMULATOR@: app1_app2/lib1/app1-1.0/src/app1_server.erl
+ erlc $(EFLAGS) -oapp1_app2/lib1/app1-1.0/ebin app1_app2/lib1/app1-1.0/src/app1_server.erl
+app1_app2/lib1/app1-1.0/ebin/app1.@EMULATOR@: app1_app2/lib1/app1-1.0/src/app1.erl
+ erlc $(EFLAGS) -oapp1_app2/lib1/app1-1.0/ebin app1_app2/lib1/app1-1.0/src/app1.erl
+
+
+app1_app2/lib1/app2-1.0/ebin/app2_sup.@EMULATOR@: app1_app2/lib1/app2-1.0/src/app2_sup.erl
+ erlc $(EFLAGS) -oapp1_app2/lib1/app2-1.0/ebin app1_app2/lib1/app2-1.0/src/app2_sup.erl
+app1_app2/lib1/app2-1.0/ebin/app2_server.@EMULATOR@: app1_app2/lib1/app2-1.0/src/app2_server.erl
+ erlc $(EFLAGS) -oapp1_app2/lib1/app2-1.0/ebin app1_app2/lib1/app2-1.0/src/app2_server.erl
+app1_app2/lib1/app2-1.0/ebin/app2.@EMULATOR@: app1_app2/lib1/app2-1.0/src/app2.erl
+ erlc $(EFLAGS) -oapp1_app2/lib1/app2-1.0/ebin app1_app2/lib1/app2-1.0/src/app2.erl
+
+
+app1_app2/lib2/app1-2.0/ebin/app1_sup.@EMULATOR@: app1_app2/lib2/app1-2.0/src/app1_sup.erl
+ erlc $(EFLAGS) -oapp1_app2/lib2/app1-2.0/ebin app1_app2/lib2/app1-2.0/src/app1_sup.erl
+app1_app2/lib2/app1-2.0/ebin/app1_server.@EMULATOR@: app1_app2/lib2/app1-2.0/src/app1_server.erl
+ erlc $(EFLAGS) -oapp1_app2/lib2/app1-2.0/ebin app1_app2/lib2/app1-2.0/src/app1_server.erl
+app1_app2/lib2/app1-2.0/ebin/app1.@EMULATOR@: app1_app2/lib2/app1-2.0/src/app1.erl
+ erlc $(EFLAGS) -oapp1_app2/lib2/app1-2.0/ebin app1_app2/lib2/app1-2.0/src/app1.erl
+
+
+app1_app2/lib2/app2-1.0/ebin/app2_sup.@EMULATOR@: app1_app2/lib2/app2-1.0/src/app2_sup.erl
+ erlc $(EFLAGS) -oapp1_app2/lib2/app2-1.0/ebin app1_app2/lib2/app2-1.0/src/app2_sup.erl
+app1_app2/lib2/app2-1.0/ebin/app2_server.@EMULATOR@: app1_app2/lib2/app2-1.0/src/app2_server.erl
+ erlc $(EFLAGS) -oapp1_app2/lib2/app2-1.0/ebin app1_app2/lib2/app2-1.0/src/app2_server.erl
+app1_app2/lib2/app2-1.0/ebin/app2.@EMULATOR@: app1_app2/lib2/app2-1.0/src/app2.erl
+ erlc $(EFLAGS) -oapp1_app2/lib2/app2-1.0/ebin app1_app2/lib2/app2-1.0/src/app2.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
+ erlc $(EFLAGS) -ootp_2740 otp_2740/vsn_list.erl
+otp_2740/vsn_numeric.@EMULATOR@: otp_2740/vsn_numeric.erl
+ erlc $(EFLAGS) -ootp_2740 otp_2740/vsn_numeric.erl
+otp_2740/vsn_tuple.@EMULATOR@: otp_2740/vsn_tuple.erl
+ erlc $(EFLAGS) -ootp_2740 otp_2740/vsn_tuple.erl
+otp_2740/vsn_string.@EMULATOR@: otp_2740/vsn_string.erl
+ erlc $(EFLAGS) -ootp_2740 otp_2740/vsn_string.erl
+
+c/aa.@EMULATOR@: c/aa.erl
+ erlc $(EFLAGS) -oc c/aa.erl
+c/b.@EMULATOR@: c/b.erl
+ erlc $(EFLAGS) -oc c/b.erl
+c/c_sup.@EMULATOR@: c/c_sup.erl
+ erlc $(EFLAGS) -oc c/c_sup.erl
diff --git a/lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/ebin/a.app b/lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/ebin/a.app
new file mode 100644
index 0000000000..200cfcfe47
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/ebin/a.app
@@ -0,0 +1,8 @@
+{application, a,
+ [{description, "A CXC 138 11"},
+ {vsn, "2.0"},
+ {modules, [{a, 1}, {a_sup,1}]},
+ {registered, [a_sup]},
+ {applications, [kernel, stdlib]},
+ {env, [{key1, val1}]},
+ {mod, {a_sup, []}}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/src/a.erl b/lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/src/a.erl
new file mode 100644
index 0000000000..cfe38b55ce
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/src/a.erl
@@ -0,0 +1,47 @@
+%% ``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]).
+%% Internal exports
+-export([init/1, handle_call/3, handle_info/2, terminate/2]).
+
+start_link() -> gen_server:start_link({local, aa}, a, [], []).
+
+a() -> gen_server:call(aa, a).
+
+%%-----------------------------------------------------------------
+%% Callback functions from gen_server
+%%-----------------------------------------------------------------
+init([]) ->
+ process_flag(trap_exit, true),
+ {ok, state}.
+
+handle_call(a, _From, State) ->
+ X = application:get_all_env(a),
+ {reply, X, State}.
+
+handle_info(_, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
diff --git a/lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/src/a_sup.erl b/lib/sasl/test/release_handler_SUITE_data/P2B/a-2.0/src/a_sup.erl
new file mode 100644
index 0000000000..a141c1767b
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/P2B/a-2.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_one, 4, 3600},
+ Config = {a,
+ {a, start_link, []},
+ permanent, 2000, worker, [a]},
+ {ok, {SupFlags, [Config]}}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app1-1.0/ebin/app1.app b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app1-1.0/ebin/app1.app
new file mode 100644
index 0000000000..0489cb2595
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app1-1.0/ebin/app1.app
@@ -0,0 +1,9 @@
+{application, app1,
+ [{description, "very simple example application"},
+ {id, "app1"},
+ {vsn, "1.0"},
+ {modules, [app1, app1_sup, app1_server]},
+ {registered, [harry]},
+ {applications, [kernel, stdlib, sasl]},
+ {env, [{var,val1}]},
+ {mod, {app1, []}}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app1-1.0/src/app1.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app1-1.0/src/app1.erl
new file mode 100644
index 0000000000..f123c8f470
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app1-1.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/lib1/app1-1.0/src/app1_server.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app1-1.0/src/app1_server.erl
new file mode 100644
index 0000000000..9b49e772cc
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app1-1.0/src/app1_server.erl
@@ -0,0 +1,32 @@
+-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(_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/lib1/app1-1.0/src/app1_sup.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app1-1.0/src/app1_sup.erl
new file mode 100644
index 0000000000..e6ad9b6967
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app1-1.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/lib1/app2-1.0/ebin/app2.app b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app2-1.0/ebin/app2.app
new file mode 100644
index 0000000000..d48018cbda
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app2-1.0/ebin/app2.app
@@ -0,0 +1,9 @@
+{application, app2,
+ [{description, "very simple example application"},
+ {id, "app2"},
+ {vsn, "1.0"},
+ {modules, [app2, app2_sup, app2_server]},
+ {registered, [ginny]},
+ {applications, [kernel, stdlib, sasl]},
+ {env, []},
+ {mod, {app2, []}}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app2-1.0/src/app2.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app2-1.0/src/app2.erl
new file mode 100644
index 0000000000..a41c39730c
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app2-1.0/src/app2.erl
@@ -0,0 +1,17 @@
+-module(app2).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+start(_Type, _StartArgs) ->
+ case app2_sup:start_link() of
+ {ok, Pid} ->
+ {ok, Pid};
+ Error ->
+ Error
+ end.
+
+stop(_State) ->
+ ok.
diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app2-1.0/src/app2_server.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app2-1.0/src/app2_server.erl
new file mode 100644
index 0000000000..d8440230ff
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app2-1.0/src/app2_server.erl
@@ -0,0 +1,32 @@
+-module(app2_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, ginny}, ?MODULE, [], []).
+
+init([]) ->
+ {ok, []}.
+
+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/lib1/app2-1.0/src/app2_sup.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app2-1.0/src/app2_sup.erl
new file mode 100644
index 0000000000..80b0952d4b
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib1/app2-1.0/src/app2_sup.erl
@@ -0,0 +1,17 @@
+-module(app2_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+start_link() ->
+ supervisor:start_link(?MODULE, []).
+
+init([]) ->
+ AChild = {ginny,{app2_server,start_link,[]},
+ permanent,2000,worker,[app2_server]},
+ {ok,{{one_for_all,0,1}, [AChild]}}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app1-2.0/ebin/app1.app b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app1-2.0/ebin/app1.app
new file mode 100644
index 0000000000..3c65adfbb3
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app1-2.0/ebin/app1.app
@@ -0,0 +1,9 @@
+{application, app1,
+ [{description, "very simple example application"},
+ {id, "app1"},
+ {vsn, "2.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/lib2/app1-2.0/ebin/app1.appup b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app1-2.0/ebin/app1.appup
new file mode 100644
index 0000000000..e5e0cbda0e
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app1-2.0/ebin/app1.appup
@@ -0,0 +1,4 @@
+{"2.0",
+ [{"1.0", [{load_module, app1_server}]}],
+ [{"1.0", [{load_module, app1_server}]}]
+}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app1-2.0/src/app1.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app1-2.0/src/app1.erl
new file mode 100644
index 0000000000..f123c8f470
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app1-2.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/lib2/app1-2.0/src/app1_server.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app1-2.0/src/app1_server.erl
new file mode 100644
index 0000000000..660d095ebf
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app1-2.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/lib2/app1-2.0/src/app1_sup.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app1-2.0/src/app1_sup.erl
new file mode 100644
index 0000000000..e6ad9b6967
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app1-2.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/lib2/app2-1.0/ebin/app2.app b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app2-1.0/ebin/app2.app
new file mode 100644
index 0000000000..d48018cbda
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app2-1.0/ebin/app2.app
@@ -0,0 +1,9 @@
+{application, app2,
+ [{description, "very simple example application"},
+ {id, "app2"},
+ {vsn, "1.0"},
+ {modules, [app2, app2_sup, app2_server]},
+ {registered, [ginny]},
+ {applications, [kernel, stdlib, sasl]},
+ {env, []},
+ {mod, {app2, []}}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app2-1.0/src/app2.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app2-1.0/src/app2.erl
new file mode 100644
index 0000000000..a41c39730c
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app2-1.0/src/app2.erl
@@ -0,0 +1,17 @@
+-module(app2).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+start(_Type, _StartArgs) ->
+ case app2_sup:start_link() of
+ {ok, Pid} ->
+ {ok, Pid};
+ Error ->
+ Error
+ end.
+
+stop(_State) ->
+ ok.
diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app2-1.0/src/app2_server.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app2-1.0/src/app2_server.erl
new file mode 100644
index 0000000000..d8440230ff
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app2-1.0/src/app2_server.erl
@@ -0,0 +1,32 @@
+-module(app2_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, ginny}, ?MODULE, [], []).
+
+init([]) ->
+ {ok, []}.
+
+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/lib2/app2-1.0/src/app2_sup.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app2-1.0/src/app2_sup.erl
new file mode 100644
index 0000000000..80b0952d4b
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib2/app2-1.0/src/app2_sup.erl
@@ -0,0 +1,17 @@
+-module(app2_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+start_link() ->
+ supervisor:start_link(?MODULE, []).
+
+init([]) ->
+ AChild = {ginny,{app2_server,start_link,[]},
+ permanent,2000,worker,[app2_server]},
+ {ok,{{one_for_all,0,1}, [AChild]}}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/c/aa.erl b/lib/sasl/test/release_handler_SUITE_data/c/aa.erl
new file mode 100644
index 0000000000..1c853c85b2
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/c/aa.erl
@@ -0,0 +1,41 @@
+%% ``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(aa).
+
+
+-behaviour(gen_server).
+
+%% External exports
+-export([start_link/0]).
+%% Internal exports
+-export([init/1, handle_info/2, terminate/2]).
+
+start_link() -> gen_server:start_link({local, cc}, aa, [], []).
+
+%%-----------------------------------------------------------------
+%% Callback functions from gen_server
+%%-----------------------------------------------------------------
+init([]) ->
+ process_flag(trap_exit, true),
+ {ok, state}.
+
+handle_info(_, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
diff --git a/lib/sasl/test/release_handler_SUITE_data/c/b.erl b/lib/sasl/test/release_handler_SUITE_data/c/b.erl
new file mode 100644
index 0000000000..d8426a515e
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/c/b.erl
@@ -0,0 +1,38 @@
+%% ``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(b).
+
+
+%% External exports
+-export([start_link/0]).
+%% Internal exports
+-export([init/0]).
+
+start_link() -> {ok, proc_lib:spawn_link(b, init, [])}.
+
+%%-----------------------------------------------------------------
+%% Callback functions from gen_server
+%%-----------------------------------------------------------------
+init() ->
+ register(bb, self()),
+ loop().
+
+loop() ->
+ receive
+ hej -> ok
+ end.
diff --git a/lib/sasl/test/release_handler_SUITE_data/c/c.app b/lib/sasl/test/release_handler_SUITE_data/c/c.app
new file mode 100644
index 0000000000..908a94cf2d
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/c/c.app
@@ -0,0 +1,8 @@
+{application, c,
+ [{description, "C CXC 138 11"},
+ {vsn, "1.0"},
+ {modules, [b, {aa, 1}, {c_sup,1}]},
+ {registered, [cc,bb,c_sup]},
+ {applications, [kernel, stdlib]},
+ {env, [{key1, val1}]},
+ {mod, {c_sup, []}}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/c/c_sup.erl b/lib/sasl/test/release_handler_SUITE_data/c/c_sup.erl
new file mode 100644
index 0000000000..069eb3b99b
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/c/c_sup.erl
@@ -0,0 +1,40 @@
+%% ``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(c_sup).
+
+
+-behaviour(supervisor).
+
+%% External exports
+-export([start/2]).
+
+%% Internal exports
+-export([init/1]).
+
+start(_, _) ->
+ supervisor:start_link({local, c_sup}, c_sup, []).
+
+init([]) ->
+ SupFlags = {one_for_one, 4, 3600},
+ Config1 = {c,
+ {aa, start_link, []},
+ permanent, 2000, worker, [aa]},
+ Config2 = {b,
+ {b, start_link, []},
+ permanent, 2000, worker, [b]},
+ {ok, {SupFlags, [Config1, Config2]}}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/clients/start_cli1 b/lib/sasl/test/release_handler_SUITE_data/clients/start_cli1
new file mode 100755
index 0000000000..ee3d8c97cf
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/clients/start_cli1
@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# This program invokes the erlang emulator by calling run_erl.
+# It should only be used at an embedded target system.
+# It should be modified to give the correct flags to erl (via start_erl),
+# e.g -mode embedded -sname XXX
+#
+# Usage: start [Data]
+#
+
+if [ "x${NODENAME}" = "x" ]
+then
+ echo "ERROR: Variable \$NODENAME is not set!!"
+ exit 1
+fi
+
+TESTHOST=`hostname | sed 's/[.].*//'`
+IPADDR=%IPADDR%
+
+ROOTDIR=%ROOT%
+CLIENTDIR=$ROOTDIR/clients/type1/$NODENAME@$TESTHOST
+
+RELDIR=$CLIENTDIR/releases
+
+# Note that this scripts is modified an copied to $CLIENTDIR/bin/start
+# in release_handler_SUITE:copy_client - therefore HEART_COMMAND is as follows:
+HEART_COMMAND=$CLIENTDIR/bin/start
+HW_WD_DISABLE=true
+export HW_WD_DISABLE HEART_COMMAND
+
+START_ERL_DATA=${1:-$RELDIR/start_erl.data}
+
+if [ ! -d /tmp/$NODENAME@$TESTHOST ]
+then
+ mkdir /tmp/$NODENAME@$TESTHOST
+fi
+
+$ROOTDIR/bin/run_erl /tmp/$NODENAME@$TESTHOST/ $CLIENTDIR/log "exec $ROOTDIR/bin/start_erl $ROOTDIR $RELDIR $START_ERL_DATA -heart -sname $NODENAME -sasl start_prg \\\"$CLIENTDIR/bin/start\\\" masters \[\\'%MASTER%@$TESTHOST\\'\] client_directory \\\"$CLIENTDIR\\\" -loader inet -id $NODENAME -hosts $IPADDR" > $CLIENTDIR/log/run_erl.out 2>&1 &
diff --git a/lib/sasl/test/release_handler_SUITE_data/clients/start_cli2 b/lib/sasl/test/release_handler_SUITE_data/clients/start_cli2
new file mode 100755
index 0000000000..88912cf884
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/clients/start_cli2
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# This program invokes the erlang emulator by calling run_erl.
+# It should only be used at an embedded target system.
+# It should be modified to give the correct flags to erl (via start_erl),
+# e.g -mode embedded -sname XXX
+#
+# Usage: start [Data]
+#
+
+if [ "x${NODENAME}" = "x" ]
+then
+ echo "ERROR: Variable \$NODENAME is not set!!"
+ exit 1
+fi
+
+TESTHOST=`hostname | sed 's/[.].*//'`
+
+ROOTDIR=%ROOT%
+CLIENTDIR=$ROOTDIR/clients/type1/$NODENAME@$TESTHOST
+
+RELDIR=$CLIENTDIR/releases
+
+# Note that this scripts is modified an copied to $CLIENTDIR/bin/start
+# in release_handler_SUITE:copy_client - therefore HEART_COMMAND is as follows:
+HEART_COMMAND=$CLIENTDIR/bin/start
+HW_WD_DISABLE=true
+export HW_WD_DISABLE HEART_COMMAND
+
+START_ERL_DATA=${1:-$RELDIR/start_erl.data}
+
+if [ ! -d /tmp/$NODENAME@$TESTHOST ]
+then
+ mkdir /tmp/$NODENAME@$TESTHOST
+fi
+
+$ROOTDIR/bin/run_erl /tmp/$NODENAME@$TESTHOST/ $CLIENTDIR/log "exec $ROOTDIR/bin/start_erl $ROOTDIR $RELDIR $START_ERL_DATA -heart -sname $NODENAME -sasl start_prg \\\"$CLIENTDIR/bin/start\\\" masters \[\\'%MASTER%@$TESTHOST\\',\\'master2@$TESTHOST\\'\] client_directory \\\"$CLIENTDIR\\\"" > /dev/null 2>&1 &
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/ebin/a.app b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/ebin/a.app
new file mode 100644
index 0000000000..e938137f67
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/ebin/a.app
@@ -0,0 +1,8 @@
+{application, a,
+ [{description, "A CXC 138 11"},
+ {vsn, "1.0"},
+ {modules, [{a, 1}, {a_sup,1}]},
+ {registered, [a_sup]},
+ {applications, [kernel, stdlib]},
+ {env, [{key1, val1}]},
+ {mod, {a_sup, []}}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/src/a.app b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/src/a.app
new file mode 100644
index 0000000000..e938137f67
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/src/a.app
@@ -0,0 +1,8 @@
+{application, a,
+ [{description, "A CXC 138 11"},
+ {vsn, "1.0"},
+ {modules, [{a, 1}, {a_sup,1}]},
+ {registered, [a_sup]},
+ {applications, [kernel, stdlib]},
+ {env, [{key1, val1}]},
+ {mod, {a_sup, []}}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/src/a.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/src/a.erl
new file mode 100644
index 0000000000..bb500bed69
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/src/a.erl
@@ -0,0 +1,49 @@
+%% ``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).
+
+-vsn(1).
+
+%% External exports
+-export([start_link/0, a/0]).
+%% Internal exports
+-export([init/1, handle_call/3, handle_info/2, terminate/2]).
+
+start_link() -> gen_server:start_link({local, aa}, a, [], []).
+
+a() -> gen_server:call(aa, a).
+
+%%-----------------------------------------------------------------
+%% Callback functions from gen_server
+%%-----------------------------------------------------------------
+init([]) ->
+ process_flag(trap_exit, true),
+ {ok, state}.
+
+handle_call(a, _From, State) ->
+ X = application:get_all_env(a),
+ {reply, X, State}.
+
+handle_info(_, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/src/a_sup.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.0/src/a_sup.erl
new file mode 100644
index 0000000000..a141c1767b
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.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_one, 4, 3600},
+ Config = {a,
+ {a, start_link, []},
+ permanent, 2000, worker, [a]},
+ {ok, {SupFlags, [Config]}}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.app b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.app
new file mode 100644
index 0000000000..1c3053b2fa
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.app
@@ -0,0 +1,8 @@
+{application, a,
+ [{description, "A CXC 138 11"},
+ {vsn, "1.1"},
+ {modules, [{a, 2}, {a_sup,1}]},
+ {registered, [a_sup]},
+ {applications, [kernel, stdlib]},
+ {env, [{key1, val1}]},
+ {mod, {a_sup, []}}]}.
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
new file mode 100644
index 0000000000..05db4cb541
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup
@@ -0,0 +1,3 @@
+{"1.1",
+ [{"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
new file mode 100644
index 0000000000..c082ad5339
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl
@@ -0,0 +1,54 @@
+%% ``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}}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a_sup.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a_sup.erl
new file mode 100644
index 0000000000..a141c1767b
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.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_one, 4, 3600},
+ Config = {a,
+ {a, start_link, []},
+ permanent, 2000, worker, [a]},
+ {ok, {SupFlags, [Config]}}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/installer-1.0/ebin/installer.app b/lib/sasl/test/release_handler_SUITE_data/lib/installer-1.0/ebin/installer.app
new file mode 100644
index 0000000000..6f77317f6a
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/installer-1.0/ebin/installer.app
@@ -0,0 +1,6 @@
+{application, installer,
+ [{description, "Installer application"},
+ {vsn, "1.0"},
+ {modules, [{installer, 1}]},
+ {registered, []},
+ {applications, [kernel, stdlib, sasl]}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/installer-1.0/src/installer.erl b/lib/sasl/test/release_handler_SUITE_data/lib/installer-1.0/src/installer.erl
new file mode 120000
index 0000000000..c2f93b822d
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/installer-1.0/src/installer.erl
@@ -0,0 +1 @@
+../../../../installer.erl \ No newline at end of file
diff --git a/lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_atom.erl b/lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_atom.erl
new file mode 100644
index 0000000000..883688c231
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_atom.erl
@@ -0,0 +1,26 @@
+%% ``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(vsn_atom).
+
+-vsn(atom).
+
+-export([ok/0]).
+
+ok() ->
+ ok.
diff --git a/lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_list.erl b/lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_list.erl
new file mode 100644
index 0000000000..34c38307ba
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_list.erl
@@ -0,0 +1,26 @@
+%% ``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(vsn_list).
+
+-vsn([list, "of", {some, terms}]).
+
+-export([ok/0]).
+
+ok() ->
+ ok.
diff --git a/lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_numeric.erl b/lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_numeric.erl
new file mode 100644
index 0000000000..6bf52753fd
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_numeric.erl
@@ -0,0 +1,26 @@
+%% ``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(vsn_numeric).
+
+-vsn(231894).
+
+-export([ok/0]).
+
+ok() ->
+ ok.
diff --git a/lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_string.erl b/lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_string.erl
new file mode 100644
index 0000000000..aa430a0bb3
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_string.erl
@@ -0,0 +1,26 @@
+%% ``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(vsn_string).
+
+-vsn("a string").
+
+-export([ok/0]).
+
+ok() ->
+ ok.
diff --git a/lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_tuple.erl b/lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_tuple.erl
new file mode 100644
index 0000000000..3ff1018994
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/otp_2740/vsn_tuple.erl
@@ -0,0 +1,26 @@
+%% ``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(vsn_tuple).
+
+-vsn({tuple, ["of", terms]}).
+
+-export([ok/0]).
+
+ok() ->
+ ok.
diff --git a/lib/sasl/test/release_handler_SUITE_data/start b/lib/sasl/test/release_handler_SUITE_data/start
new file mode 100755
index 0000000000..45e526c15f
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/start
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# This program invokes the erlang emulator by calling run_erl.
+# It should only be used at an embedded target system.
+# It should be modified to give the correct flags to erl (via start_erl),
+# e.g -mode embedded -sname XXX
+#
+# Usage: start [Data]
+#
+ROOTDIR=%ROOT%
+
+if [ "x${NODENAME}" = "x" ]
+then
+ echo "ERROR: Variable \$NODENAME is not set!!"
+ exit 1
+fi
+
+if [ -z "$RELDIR" ]
+then
+ RELDIR=$ROOTDIR/releases
+fi
+
+HEART_COMMAND=$ROOTDIR/bin/start
+HW_WD_DISABLE=true
+export HW_WD_DISABLE HEART_COMMAND
+
+START_ERL_DATA=${1:-$RELDIR/start_erl.data}
+
+$ROOTDIR/bin/run_erl /tmp/ $ROOTDIR/log "exec $ROOTDIR/bin/start_erl $ROOTDIR $RELDIR $START_ERL_DATA -heart -sname $NODENAME" > $ROOTDIR/log/run_erl.out 2>&1 &
diff --git a/lib/sasl/test/release_handler_SUITE_data/target_system.erl b/lib/sasl/test/release_handler_SUITE_data/target_system.erl
new file mode 120000
index 0000000000..4d36c59632
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/target_system.erl
@@ -0,0 +1 @@
+../../examples/src/target_system.erl \ No newline at end of file
diff --git a/lib/sasl/test/sasl.cover b/lib/sasl/test/sasl.cover
new file mode 100644
index 0000000000..d19d3d0180
--- /dev/null
+++ b/lib/sasl/test/sasl.cover
@@ -0,0 +1,2 @@
+{incl_app,sasl,details}.
+
diff --git a/lib/sasl/test/sasl.spec b/lib/sasl/test/sasl.spec
new file mode 100644
index 0000000000..f3de90c9aa
--- /dev/null
+++ b/lib/sasl/test/sasl.spec
@@ -0,0 +1 @@
+{suites,"../sasl_test",all}.
diff --git a/lib/sasl/test/sasl_SUITE.erl b/lib/sasl/test/sasl_SUITE.erl
new file mode 100644
index 0000000000..454095db6a
--- /dev/null
+++ b/lib/sasl/test/sasl_SUITE.erl
@@ -0,0 +1,98 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+%%
+-module(sasl_SUITE).
+-include_lib("common_test/include/ct.hrl").
+
+
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(1)).
+-define(application, sasl).
+
+% 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.
+-export([app_test/1,
+ log_mf_h_env/1]).
+
+all() ->
+ [app_test, log_mf_h_env].
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog=test_server:timetrap(?default_timeout),
+ [{watchdog, Dog}|Config].
+end_per_testcase(_Case, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+app_test(Config) when is_list(Config) ->
+ ?line ?t:app_test(sasl, allow),
+ ok.
+
+%% OTP-9185 - fail sasl start if some but not all log_mf_h env vars
+%% are given.
+log_mf_h_env(Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ LogDir = filename:join(PrivDir,sasl_SUITE_log_dir),
+ ok = file:make_dir(LogDir),
+ application:stop(sasl),
+ SaslEnv = application:get_all_env(sasl),
+ lists:foreach(fun({E,_V}) -> application:unset_env(sasl,E) end, SaslEnv),
+
+ ok = application:set_env(sasl,error_logger_mf_dir,LogDir),
+ match_error(missing_config,application:start(sasl)),
+
+ ok = application:set_env(sasl,error_logger_mf_maxbytes,"xx"),
+ match_error(bad_config,application:start(sasl)),
+
+ ok = application:set_env(sasl,error_logger_mf_maxbytes,50000),
+ match_error(missing_config,application:start(sasl)),
+
+ ok = application:set_env(sasl,error_logger_mf_maxfiles,"xx"),
+ match_error(bad_config,application:start(sasl)),
+
+ ok = application:set_env(sasl,error_logger_mf_maxfiles,2),
+ ok = application:unset_env(sasl,error_logger_mf_dir),
+ match_error(missing_config,application:start(sasl)),
+
+ ok = application:set_env(sasl,error_logger_mf_dir,xx),
+ match_error(bad_config,application:start(sasl)),
+
+ ok = application:set_env(sasl,error_logger_mf_dir,LogDir),
+ ok = application:start(sasl).
+
+
+%%-----------------------------------------------------------------
+%% Internal
+match_error(Expected,{error,{bad_return,{_,{'EXIT',{Expected,{sasl,_}}}}}}) ->
+ ok;
+match_error(Expected,Actual) ->
+ ?t:fail({unexpected_return,Expected,Actual}).
diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl
new file mode 100644
index 0000000000..9190b111ef
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE.erl
@@ -0,0 +1,2112 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+%%
+%%
+%% Test suite for the systools module.
+%%
+%% The systools module is a wrapper for a number of modules that
+%% handle large parts of the release building functionality
+%% (e.g. checking app files, building a tar file, building
+%% release upgrad scripts.
+%%
+
+
+-module(systools_SUITE).
+
+%-define(debug, true).
+
+-include_lib("test_server/include/test_server.hrl").
+-define(format(S, A), ok).
+-define(datadir, ?config(data_dir, Config)).
+-define(privdir, ?config(priv_dir, Config)).
+-define(copydir, ?config(copy_dir, Config)).
+
+-include_lib("kernel/include/file.hrl").
+
+-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]).
+-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([init_per_suite/1, end_per_suite/1,
+ init_per_testcase/2, end_per_testcase/2]).
+
+-import(lists, [foldl/3]).
+
+-define(default_timeout, ?t:minutes(20)).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+suite() ->
+ [{ct_hooks, [ts_install_cth]}].
+
+all() ->
+ [{group, script}, {group, tar}, {group, relup},
+ {group, tickets}].
+
+groups() ->
+ [{script, [],
+ [script_options, normal_script, no_mod_vsn_script,
+ wildcard_script, variable_script, abnormal_script,
+ src_tests_script, crazy_script, warn_shadow_script,
+ included_script, included_override_script,
+ included_fail_script, included_bug_script, exref_script,
+ otp_3065]},
+ {tar, [],
+ [tar_options, normal_tar, no_mod_vsn_tar, variable_tar,
+ src_tests_tar, shadow_tar, var_tar,
+ exref_tar, link_tar]},
+ {relup, [],
+ [normal_relup, abnormal_relup, no_appup_relup,
+ bad_appup_relup, app_start_type_relup]},
+ {tickets, [], [otp_6226]}].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+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),
+
+ %% Compile source files in the copy directory.
+ ?line Sources = filelib:wildcard(fname([CopyDir,'*','*','*','*','*.erl'])),
+ ?line lists:foreach(fun compile_source/1, Sources),
+
+ %% To use in end_per_testcase
+ Path = code:get_path(),
+ {ok,Cwd} = file:get_cwd(),
+
+ [{copy_dir, CopyDir}, {cwd,Cwd}, {path,Path} | Config].
+
+compile_source(File) ->
+ %% The compiler will no longer create a Beam file
+ %% with a module name that does not match the output
+ %% file, so we must compile to a binary and write
+ %% the output file ourselves.
+ U = filename:dirname(filename:dirname(File)),
+ Base = filename:rootname(filename:basename(File)),
+ OutFile = filename:join([U,"ebin",Base++".beam"]),
+ OutFileTemp = OutFile ++ "#",
+ {ok,_,Code} = compile:file(File, [binary]),
+ ok = file:write_file(OutFileTemp, Code),
+ file:rename(OutFileTemp, OutFile).
+
+end_per_suite(Conf) when is_list(Conf) ->
+ %% Nothing.
+ Conf.
+
+init_per_testcase(link_tar, Config) ->
+ case os:type() of
+ {unix, _} -> init_per_testcase(dummy, Config);
+ {win32, _} -> {skip, "Skip on windows"}
+ end;
+init_per_testcase(_Case, Config) ->
+ ?line Dog = test_server:timetrap(?default_timeout),
+ [{watchdog, Dog}|Config].
+
+end_per_testcase(_Case, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ case {?config(path,Config),?config(cwd,Config)} of
+ {undefined,undefined} ->
+ ok;
+ {Path,Cwd} ->
+ true = code:set_path(Path),
+ ok = file:set_cwd(Cwd)
+ end,
+ ok.
+
+
+
+%% Usage:
+%% systools:make_script("RelName")
+%% Make a boot file from RelName.rel.
+%% Generates RelName.{script,boot}
+%% systools:make_tar("RelName")
+%% Make a release package from RelName.rel.
+%% Generates RelName.tar,Z
+%% systools:script2boot(File)
+%% File.script -> File.boot
+%% systools:make_relup("Target", ["UpFromRel"...], ["DownToRel"...], Opts)
+%% Gather all appup scripts to the relup file
+%%
+
+
+%% make_script
+%%
+script_options(suite) -> [];
+script_options(doc) ->
+ ["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]}, _}} =
+ (catch systools:make_script("release",
+ [{path,["Path","Another"]},sillent])),
+ ?line {'EXIT',{{badarg,[locall]}, _}} =
+ (catch systools:make_script("release",
+ [{path,["Path","Another"]},locall])),
+ ?line {'EXIT',{{badarg,[src_testsxx]}, _}} =
+ (catch systools:make_script("release",
+ [{path,["Path"]},src_testsxx])),
+ ?line {'EXIT',{{badarg,[{variables, {"TEST", "/home/lib"}}]}, _}} =
+ (catch systools:make_script("release",
+ [{variables, {"TEST", "/home/lib"}}])),
+ ?line {'EXIT',{{badarg,[{variables, [{a, b}, {"a", "b"}]}]}, _}} =
+ (catch systools:make_script("release",
+ [{variables, [{a, b}, {"a", "b"}]}])),
+ ?line {'EXIT',{{badarg,[exreff]}, _}} =
+ (catch systools:make_script("release",
+ [{path,["Path","Another"]},exreff])),
+ ?line {'EXIT',{{badarg,[{exref,["appl"]}]}, _}} =
+ (catch systools:make_script("release", [{exref,["appl"]}])),
+ ?line {'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."];
+normal_script(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_normal, lib]),
+ ?line P1 = fname([LibDir, 'db-2.1', ebin]),
+ ?line P2 = fname([LibDir, 'fe-3.1', ebin]),
+
+ ?line true = code:add_patha(P1),
+ ?line true = code:add_patha(P2),
+
+ ?line ok = file:set_cwd(LatestDir),
+
+ ?line ok = systools:make_script(filename:basename(LatestName)),
+ ?line {ok, _} = read_script_file(LatestName), % Check readabillity
+
+ %% Check the same but w. silent flag
+ ?line {ok, _, []} = systools:make_script(LatestName, [silent]),
+
+ %% Use the local option
+ ?line ok = systools:make_script(LatestName, [local]),
+ ?line ok = check_script_path(LatestName),
+
+ %% use the path option
+ ?line 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])),
+
+ ?line error = systools:make_script(LatestName), %should fail
+ ?line ok = systools:make_script(LatestName,[{path, [P1, P2]}]),
+
+ ?line ok = file:set_cwd(OldDir),
+ ?line 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."];
+no_mod_vsn_script(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+ ?line PSAVE = code:get_path(), % Save path
+
+ ?line {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]),
+
+ ?line true = code:add_patha(P1),
+ ?line true = code:add_patha(P2),
+
+ ?line ok = file:set_cwd(LatestDir),
+
+ ?line ok = systools:make_script(filename:basename(LatestName)),
+ ?line {ok, _} = read_script_file(LatestName), % Check readabillity
+
+ %% Check the same but w. silent flag
+ ?line {ok, _, []} = systools:make_script(LatestName, [silent]),
+
+ %% Use the local option
+ ?line ok = systools:make_script(LatestName, [local]),
+ ?line ok = check_script_path(LatestName),
+
+ %% use the path option
+ ?line 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])),
+
+ ?line error = systools:make_script(LatestName), %should fail
+ ?line ok = systools:make_script(LatestName,
+ [{path, [P1, P2]}]),
+
+ ?line ok = file:set_cwd(OldDir),
+ ?line code:set_path(PSAVE), % Restore path
+ ok.
+
+
+%% make_script
+%%
+wildcard_script(suite) -> [];
+wildcard_script(doc) ->
+ ["Check that make_script handles wildcards in path."];
+wildcard_script(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+
+ ?line {LatestDir, LatestName} = create_script(latest,Config),
+
+ ?line DataDir = filename:absname(?copydir),
+ ?line LibDir = fname([DataDir, d_normal, lib]),
+ ?line WildDir = fname([LibDir, '*', ebin]),
+
+ ?line ok = file:set_cwd(LatestDir),
+
+ ?line error = systools:make_script(filename:basename(LatestName)),
+
+ ?line ok = systools:make_script(LatestName,
+ [{path, [WildDir]}]),
+
+ ?line {ok, _} = read_script_file(LatestName), % Check readabillity
+
+ ?line ok = file:set_cwd(OldDir),
+ ok.
+
+
+%% make_script
+%%
+variable_script(suite) -> [];
+variable_script(doc) ->
+ ["Add own installation dependent variable in script."];
+variable_script(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+
+ ?line {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])],
+
+ ?line ok = file:set_cwd(LatestDir),
+
+ ?line 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),
+
+ ?line ok = file:set_cwd(OldDir),
+ ok.
+
+%% make_script
+%%
+abnormal_script(suite) -> [];
+abnormal_script(doc) ->
+ ["Abnormal cases."];
+abnormal_script(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+
+ ?line {LatestDir, LatestName} = create_script(latest,Config),
+
+ ?line 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])],
+
+ %% 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"}}}}}]} =
+ systools:make_script(LatestName, [silent, {path, P}]),
+
+ ?line 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."];
+src_tests_script(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_missing_src, lib]),
+ ?line P1 = fname([LibDir, 'db-2.1', ebin]),
+ ?line P2 = fname([LibDir, 'fe-3.1', ebin]),
+ N = [P1, P2],
+
+ ?line 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}}),
+
+ %% Remove a .erl file
+ ?line Erl2 = filename:join([P1,"..","src","db2.erl"]),
+ ?line file:delete(Erl2),
+
+ %% Then make script - 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,_}}]} =
+ systools:make_script(LatestName, [silent, {path, N}, src_tests]),
+
+ %% Without the src_tests option, no warning should be issued
+ ?line {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,_}}]} =
+ systools:make_script(LatestName, [silent,
+ {path, N},
+ no_module_tests,
+ src_tests]),
+
+ ?line ok = file:set_cwd(OldDir),
+ ?line 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."];
+crazy_script(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+
+ ?line {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])],
+
+ ?line ok = file:set_cwd(LatestDir),
+
+ %% Run with bad path
+ ?line error = systools:make_script(LatestName),
+ ?line {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),
+
+ ?line error = systools:make_script(LatestName2),
+ ?line {error, _, {missing_mandatory_app,[kernel,stdlib]}} =
+ systools:make_script(LatestName2, [silent,{path,P}]),
+
+ ?line 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."];
+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.
+
+%% 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."];
+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.
+
+%% make_script
+%%
+included_fail_script(suite) -> [];
+included_fail_script(doc) ->
+ ["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]}} =
+ systools:make_script(LatestName, [silent]),
+
+ ?line {_, LatestName1} = create_include_files(inc7, Config),
+ ?line {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,_}]}} =
+ systools:make_script(LatestName3, [silent]),
+
+ ?line {_, LatestName4} = create_include_files(inc10, Config),
+ ?line {error, _, [{error_reading,{t9,{override_include,[t7]}}}]} =
+ systools:make_script(LatestName4, [silent]),
+
+ ?line 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."];
+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.
+
+
+%% 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),
+ ok.
+
+
+%% make_script
+%%
+exref_script(suite) -> [];
+exref_script(doc) ->
+ ["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
+
+ ?line {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])],
+
+ ?line ok = file:set_cwd(LatestDir),
+
+ ?line {ok, _, _} = systools:make_script(LatestName, [{path,P}, silent]),
+
+ %% Complete exref
+ ?line {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
+
+ %% Only exref the db application.
+ ?line {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
+
+ %% Only exref the fe application.
+ ?line {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
+
+ %% exref the db and stdlib applications.
+ ?line {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
+ ok.
+
+check_exref_warnings(with_db1, W) ->
+ case get_exref(undef, W) of
+ {ok, [{db2,non_existing_func,0},
+ {fe2,non_existing_func,0},
+ {lists,non_existing_func,1}]} ->
+ ok;
+ {ok, L} ->
+ test_server:fail({exref_warning_undef, L});
+ _E ->
+ test_server:fail({bad_undef,_E})
+ end;
+check_exref_warnings(without_db1, W) ->
+ case get_exref(undef, W) of
+ false ->
+ ok;
+ {ok, L} ->
+ test_server:fail({exref_warning_undef, L})
+ end.
+
+get_exref(undef, W) -> filter(no_hipe(get_exref1(exref_undef, W))).
+
+filter(false) ->
+ false;
+filter({ok, W}) ->
+ {ok, filter(W)};
+filter(L) ->
+ lists:filter(fun%({hipe_consttab,_,_}) -> false;
+ ({int,_,_}) -> false;
+ ({i,_,_}) -> false;
+ ({crypto,_,_}) -> false;
+ (_) -> true
+ end,
+ L).
+
+get_exref1(T, [{warning, {T, Value}}|_]) -> {ok, Value};
+get_exref1(T, [_|W]) -> get_exref1(T, W);
+get_exref1(_, []) -> false.
+
+no_hipe(false) ->
+ false;
+no_hipe({ok, Value}) ->
+ case erlang:system_info(hipe_architecture) of
+ undefined ->
+ Hipe = "hipe",
+ Fun = fun({M,_,_}) -> not lists:prefix(Hipe, atom_to_list(M)) end,
+ NewValue = lists:filter(Fun, Value),
+ {ok, NewValue};
+ _Arch ->
+ {ok, Value}
+ end.
+
+%% tar_options
+%%
+tar_options(suite) -> [];
+tar_options(doc) ->
+ ["Check illegal tar options."];
+tar_options(Config) when is_list(Config) ->
+ ?line {'EXIT',{{badarg,[{path,["Path",12,"Another"]}]}, _}} =
+ (catch systools:make_tar("release", [{path,["Path",12,"Another"]}])),
+ ?line {'EXIT',{{badarg,[sillent]}, _}} =
+ (catch systools:make_tar("release",
+ [{path,["Path","Another"]},sillent])),
+ ?line {'EXIT',{{badarg,[{dirs,["dirs"]}]}, _}} =
+ (catch systools:make_tar("release", [{dirs, ["dirs"]}])),
+ ?line {'EXIT',{{badarg,[{erts, illegal}]}, _}} =
+ (catch systools:make_tar("release", [{erts, illegal}])),
+ ?line {'EXIT',{{badarg,[src_testsxx]}, _}} =
+ (catch systools:make_tar("release",
+ [{path,["Path"]},src_testsxx])),
+ ?line {'EXIT',{{badarg,[{variables, [{a, b}, {"a", "b"}]}]}, _}} =
+ (catch systools:make_tar("release",
+ [{variables, [{a, b}, {"a", "b"}]}])),
+ ?line {'EXIT',{{badarg,[{var_tar, illegal}]}, _}} =
+ (catch systools:make_tar("release", [{var_tar, illegal}])),
+ ?line {'EXIT',{{badarg,[exreff]}, _}} =
+ (catch systools:make_tar("release",
+ [{path,["Path","Another"]},exreff])),
+ ?line {'EXIT',{{badarg,[{exref,["appl"]}]}, _}} =
+ (catch systools:make_tar("release", [{exref,["appl"]}])),
+ ?line {'EXIT',{{badarg,[{machine, "appl"}]}, _}} =
+ (catch systools:make_tar("release", [{machine,"appl"}])),
+ ok.
+
+
+%% normal_tar
+%%
+normal_tar(suite) -> [];
+normal_tar(doc) ->
+ ["Check normal case"];
+normal_tar(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+
+ ?line {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])],
+
+ ?line 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),
+
+ ?line 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."];
+no_mod_vsn_tar(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+
+ ?line {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])],
+
+ ?line 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),
+
+ ?line ok = file:set_cwd(OldDir),
+ ok.
+
+%% variable_tar
+%%
+variable_tar(suite) -> [];
+variable_tar(doc) ->
+ ["Use variable and create separate tar (included in generated tar)."];
+variable_tar(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+
+ ?line {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])],
+
+ ?line ok = file:set_cwd(LatestDir),
+
+ ?line {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),
+
+ ?line {ok, _, _} = systools:make_tar(LatestName,
+ [{path, P}, silent,
+ {variables,[{"TEST", LibDir}]}]),
+ ?line ok = check_var_tar("TEST", LatestName),
+
+ ?line ok = file:set_cwd(OldDir),
+ ok.
+
+%% link_tar
+%%
+link_tar(suite) -> [];
+link_tar(doc) ->
+ ["Check that symlinks in applications are handled correctly"];
+link_tar(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+
+ ?line {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])],
+
+ %% 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),
+
+ %% 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.
+
+%% 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."];
+src_tests_tar(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+
+ ?line {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]),
+ P = [P1, P2],
+
+ ?line ok = file:set_cwd(LatestDir),
+
+ %% Manipulate the modification date of a beam file so it seems
+ %% older than the .erl file
+ 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),
+
+ ?line 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,_}}]} =
+ systools:make_tar(LatestName, [{path, P}, silent,
+ {dirs, [src]},
+ src_tests]),
+ ?line 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),
+
+ %% 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,_}}]} =
+ 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.
+
+%% 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.
+
+
+%% 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."];
+var_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_normal, lib]),
+ ?line P = [fname([LibDir, 'db-2.1', ebin]),
+ fname([LibDir, 'fe-3.1', ebin])],
+
+ ?line ok = file:set_cwd(LatestDir),
+
+ ?line {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}]}]),
+
+ ?line true = exists_tar_file("TEST"), %% Also removes the file !
+ ?line {error, {not_generated, _}} = check_var_tar("TEST", LatestName),
+
+ ?line 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"),
+
+ ?line 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"),
+
+ ?line ok = file:set_cwd(OldDir),
+ ?line code:set_path(PSAVE),
+ ok.
+
+
+%% exref_tar
+%%
+exref_tar(suite) -> [];
+exref_tar(doc) ->
+ ["Check exref option."];
+exref_tar(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+
+ ?line {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])],
+
+ ?line ok = file:set_cwd(LatestDir),
+
+ ?line {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]),
+
+ %% Complete exref
+ ?line {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),
+
+ %% Only exref the db application.
+ ?line {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),
+
+ %% Only exref the fe application.
+ ?line {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),
+
+ %% exref the db and stdlib applications.
+ ?line {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),
+
+ ?line ok = file:set_cwd(OldDir),
+ ok.
+
+%% The relup stuff.
+%%
+%%
+
+
+%% make_relup
+%%
+normal_relup(suite) -> [];
+normal_relup(doc) ->
+ ["Check normal case"];
+normal_relup(Config) when is_list(Config) ->
+ ?line {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),
+
+ ?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])],
+
+ ?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(),
+
+ %% 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, _, _, []} =
+ systools:make_relup(LatestName, [LatestName1], [LatestName1],
+ [{path, P}, silent]),
+ ?line ok = check_relup([{db, "2.1"}], [{db, "1.0"}]),
+
+ %% 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, _}]} =
+ systools:make_relup(LatestName, [LatestName2], [LatestName1],
+ [{path, P}, silent]),
+ ?line ok = check_relup([{fe, "3.1"}, {db, "2.1"}], [{db, "1.0"}]),
+
+ ?line ok = file:set_cwd(OldDir),
+ ok.
+
+
+%% This test fails if wrong version numbers are seen in the relup file
+%% or if any application is missing. This was triggered by OTP-1360.
+check_relup(UpVsnL, DnVsnL) ->
+ {ok, [{_V1, [{_, _, Up}], [{_, _, Dn}]}]} = 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]),
+ [] = foldl(fun(X, Acc) ->
+ true = lists:member(X, Acc),
+ lists:delete(X, Acc) end,
+ DnVsnL,
+ [{App, Vsn} || {load_object_code,{App,Vsn,_}} <- Dn]),
+ ok.
+
+check_restart_emulator() ->
+ {ok, [{_V1, [{_, _, Up}], [{_, _, Dn}]}]} = file:consult(relup),
+ restart_new_emulator = lists:last(Up),
+ restart_new_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."];
+no_appup_relup(Config) when is_list(Config) ->
+ ?line {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),
+
+ ?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])],
+
+ ?line ok = file:set_cwd(LatestDir),
+
+ %% Check that appup might be missing
+ ?line ok =
+ systools:make_relup(LatestName, [LatestName], [], [{path, P1}]),
+ ?line {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,_,_}}}}} =
+ systools:make_relup(LatestName, [], [LatestName0],
+ [silent, {path, P1}]),
+
+ %% 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, _, _, _}} =
+ systools:make_relup(LatestName0, [], [LatestName1],
+ [silent, {path, P2}]),
+
+ ?line ok = file:set_cwd(OldDir),
+ ok.
+
+%% make_relup
+%%
+bad_appup_relup(suite) -> [];
+bad_appup_relup(doc) ->
+ ["Check that badly written appup files are detected"];
+bad_appup_relup(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+
+ ?line {LatestDir,LatestName} = create_script(latest_small,Config),
+ ?line {_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])],
+
+ ?line ok = file:set_cwd(LatestDir),
+
+ %% Check that bad appup is trapped
+ ?line error =
+ systools:make_relup(LatestName, [LatestName0], [], [{path, N2}]),
+ ?line {error,_,{file_problem, {_, {error, {parse,_, _}}}}} =
+ systools:make_relup(LatestName, [], [LatestName0],
+ [silent, {path, N2}]),
+
+ ?line ok = file:set_cwd(OldDir),
+ ok.
+
+%% make_relup
+%%
+abnormal_relup(suite) -> [];
+abnormal_relup(doc) ->
+ ["Check some abnormal cases"];
+abnormal_relup(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+
+ ?line {LatestDir,LatestName} = create_script(latest0,Config),
+ ?line {_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),
+ 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"];
+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,
+ %% ?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),
+ ok.
+
+
+otp_6226(suite) ->
+ [];
+otp_6226(doc) ->
+ ["{outdir,Dir} option for systools:make_script()"];
+otp_6226(Config) when is_list(Config) ->
+ PrivDir = ?privdir,
+ ?line {ok, OldDir} = file:get_cwd(),
+
+ ?line {LatestDir, LatestName} = create_script(latest0,Config),
+ ?line {_LatestDir, LatestName1} = create_script(latest1,Config),
+
+ ?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])],
+
+ ?line ok = file:set_cwd(LatestDir),
+
+
+ %% Create an outdir1 directory
+ ?line ok = file:make_dir("outdir1"),
+
+ %% ==== Now test systools:make_script ====
+ %% a) badarg
+ ?line {'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),
+
+ %% 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),
+
+ %% d) absolute but incorrect path
+ ?line Outdir2 = filename:join(PrivDir, "outdir2"),
+ ?line Script2 = filename:join(Outdir2, LatestName ++ ".script"),
+ ?line {error,_,{open,Script2,_}} =
+ systools:make_script(LatestName, [{outdir,Outdir2},{path,P},silent]),
+
+ %% e) relative but incorrect path
+ ?line {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),
+
+ %% ==== Now test systools:make_tar =====
+ ?line {ok,_,[]} = systools:make_script(LatestName, [{path,P},silent]),
+ %% a) badarg
+ ?line {'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),
+
+ %% 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),
+
+ %% d) absolute but incorrect path
+ ?line Tar2 = filename:join(Outdir2,LatestName++".tar.gz"),
+ ?line {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]),
+
+ %% 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),
+
+ %% ===== Now test systools:make_relup =====
+ %% a) badarg
+ ?line {'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),
+
+ %% 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),
+
+ %% d) absolute but incorrect path
+ ?line {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}}} =
+ systools:make_relup(LatestName,[LatestName1],[LatestName1],
+ [{outdir,"./outdir2"},{path,P},silent]),
+
+ %% f) with .rel in another directory than cwd
+ %% -- not necessary to test since relup by default is placed in
+ %% cwd, not in the same directory as the .rel file --
+
+ %% Change back to previous working directory
+ ?line ok = file:set_cwd(OldDir),
+ ok.
+
+
+%%%%%%
+%%%%%% Utilities
+%%%%%%
+
+check_script_path(RelName) ->
+ {ok, [Conts]} = read_script_file(RelName),
+ {script, {_, _}, ListOfThings} = Conts,
+ case lists:keysearch(path, 1, ListOfThings) of
+ {value, {path, [$$,$R,$O,$O,$T | _]}} -> %"$ROOT..."
+ false;
+ _ -> ok
+ end.
+
+check_var_script_file(VarDirs, NoExistDirs, RelName) ->
+ {ok, [Conts]} = read_script_file(RelName),
+ {script, {_, _}, ListOfThings} = Conts,
+ AllPaths = lists:append(lists:map(fun({path, P}) -> P;
+ (_) -> []
+ end,
+ ListOfThings)),
+ case lists:filter(fun(VarDir) -> lists:member(VarDir, AllPaths) end,
+ VarDirs) of
+ VarDirs ->
+ ok;
+ _ ->
+ test_server:fail("All variable dirs not in generated script")
+ end,
+ case lists:filter(fun(NoExistDir) -> lists:member(NoExistDir, AllPaths) end,
+ NoExistDirs) of
+ [] ->
+ ok;
+ _ ->
+ test_server:fail("Unexpected dirs in generated script")
+ end.
+
+check_include_script(RelName, ExpectedLoad, ExpectedStart) ->
+ {ok, [Conts]} = read_script_file(RelName),
+ {script, {_, _}, ListOfThings} = Conts,
+
+ %% Check that the applications are loaded in given order !
+ ActualLoad =
+ [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,
+
+ %% Check that applications are started in given order !
+ ActualStart =
+ [App || {apply,{application,start_boot,[App|_]}} <- ListOfThings,
+ App =/= kernel,
+ App =/= stdlib],
+
+ if ActualStart =:= ExpectedStart -> ok;
+ true -> test_server:fail({bad_start_order, ActualStart,ExpectedStart})
+ end,
+
+ ok.
+
+read_script_file(RelName) ->
+ file:consult(RelName ++ ".script").
+
+check_var_tar(Variable, RelName) ->
+ Expected = tar_name(Variable),
+ case check_tar(Expected,RelName) of
+ ok ->
+ ok;
+ {error, {erroneous_tar_file, _, missing, _}} ->
+ {error, {not_generated, Expected}}
+ end.
+
+exists_tar_file(Name) ->
+ File = tar_name(Name),
+ case filelib:is_regular(File) of
+ true ->
+ ok = file:delete(File),
+ true;
+ _ ->
+ false
+ end.
+
+%% Take a snap of the generated tar file and check if a certain
+%% file is included.
+%% This ensures at least that the tar file is generated.
+check_tar(File, RelName) ->
+ TarContents = tar_contents(RelName),
+ case lists:member(File,TarContents) of
+ true -> ok;
+ _ -> {error, {erroneous_tar_file, tar_name(RelName), missing, File}}
+ end.
+
+%% Check that the given files exist in the tar file, and that they are
+%% not symlinks
+check_tar_regular(PrivDir, Files, RelName) ->
+ TmpDir = fname(PrivDir,tmp),
+ ok = file:make_dir(TmpDir),
+ ok = erl_tar:extract(tar_name(RelName),
+ [{files,Files},{cwd,TmpDir},compressed]),
+ R = lists:foldl(fun(File,Acc) ->
+ case file:read_link_info(fname(TmpDir,File)) of
+ {ok,#file_info{type=regular}} ->
+ Acc;
+ {ok,#file_info{type=Other}} ->
+ [{File,Other}|Acc];
+ _ ->
+ [{File,missing}|Acc]
+ end
+ end,
+ [],
+ Files),
+ delete_tree(TmpDir),
+ case R of
+ [] ->
+ ok;
+ NotThere ->
+ {error,{erroneous_tar_file,tar_name(RelName),NotThere}}
+ end.
+
+delete_tree(Dir) ->
+ case filelib:is_dir(Dir) of
+ true ->
+ {ok,Files} = file:list_dir(Dir),
+ lists:foreach(fun(File) -> delete_tree(filename:join(Dir,File)) end,
+ Files),
+ file:del_dir(Dir);
+ false ->
+ ok = file:delete(Dir)
+ end.
+
+tar_contents(Name) ->
+ {ok, Cont} = erl_tar:table(Name ++ ".tar.gz", [compressed]),
+ Cont.
+
+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)};
+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)};
+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)};
+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)};
+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)};
+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)};
+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)};
+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)};
+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)};
+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)};
+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),
+ {filename:dirname(Name), filename:basename(Name)}.
+
+create_include_files(inc1, Config) ->
+ ?line PrivDir = ?privdir,
+ ?line 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),
+
+ 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",
+ 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),
+ 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),
+
+ %% 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",
+ 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),
+ 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),
+
+ %% 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",
+ 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),
+ 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),
+
+ %% 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",
+ 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),
+ 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),
+
+ %% 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",
+ 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),
+ 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),
+
+ %% 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",
+ 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),
+ 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),
+
+ %% 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",
+ 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),
+ 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),
+
+ %% 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",
+ 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),
+ 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),
+
+ %% 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",
+ 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),
+ 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),
+
+ %% 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",
+ 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),
+ 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),
+
+ Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\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_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),
+
+ Rel = "{release, {\"test\",\"R1A\"}, {erts, \"45\"},\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_apps(Dir) ->
+ T1 = "{application, t1,\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",
+ 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",
+ 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",
+ 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",
+ 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",
+ 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",
+ 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",
+ 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",
+ 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",
+ 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",
+ 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",
+ 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",
+ 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",
+ 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",
+ 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",
+ file:write_file(fname(Dir, 'aa12.app'), list_to_binary(T13)).
+
+fname(N) ->
+ filename:join(N).
+
+fname(Dir, Basename) ->
+ filename:join(Dir, Basename).
diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/ebin/db.app b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/ebin/db.app
new file mode 100644
index 0000000000..d375768b99
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/ebin/db.app
@@ -0,0 +1,8 @@
+{application, db,
+ [{description, "ERICSSON NR FOR DB"},
+ {vsn, "2.0"},
+ {modules, [{db1, "1.0"}, {db2, "1.0"}]},
+ {registered, []},
+ {applications, []},
+ {env, []},
+ {start, {db1, start, []}}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/ebin/db.appup b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/ebin/db.appup
new file mode 100644
index 0000000000..621838f0b4
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/ebin/db.appup
@@ -0,0 +1,20 @@
+%%
+%% Release upgrade script for db (data base)
+%%
+
+{
+ "2.1",
+%%% Upgrade from:
+ [
+ {"1.0", [{update, db1, soft, soft_purge, soft_purge, []},
+ {update, db2, soft, soft_purge, soft_purge, [db1]}]},
+ {"1.1", [{update, db1, soft, soft_purge, soft_purge, []},
+ {update, db2, soft, soft_purge, soft_purge, [db1]}]}
+ ],
+
+%%% Downgrade to:
+ [
+ {"1.0", [{update, db1, soft, soft_purge, soft_purge, []},
+ {update, db2, soft, soft_purge, soft_purge, [db1]}]}
+ ]
+}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/src/db1.erl b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/src/db1.erl
new file mode 100644
index 0000000000..a17640316e
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/src/db1.erl
@@ -0,0 +1,2 @@
+-module(db2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/src/db2.erl b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/src/db2.erl
new file mode 100644
index 0000000000..a17640316e
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/db-2.1/src/db2.erl
@@ -0,0 +1,2 @@
+-module(db2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/ebin/fe.app
new file mode 100644
index 0000000000..d3bd85cda6
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/ebin/fe.app
@@ -0,0 +1,8 @@
+{application, fe,
+ [{description, "ERICSSON NR FOR FE"},
+ {vsn, "3.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_bad_app_vsn/lib/fe-3.1/ebin/fe.appup b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/ebin/fe.appup
new file mode 100644
index 0000000000..4ab13c1bae
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/ebin/fe.appup
@@ -0,0 +1,27 @@
+%%
+%% Release upgrade script for fe (front end)
+%%
+
+{
+ "3.1",
+%%% Upgrade from:
+ [
+ {"2.1.1", [{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.1", [{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]}
+ ]}
+ ],
+
+%%% Downgrade to:
+ [
+ {"2.1", [{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/d_bad_app_vsn/lib/fe-3.1/src/fe1.erl b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/src/fe1.erl
new file mode 100644
index 0000000000..aa5bfa8098
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/src/fe1.erl
@@ -0,0 +1,2 @@
+-module(fe1).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/src/fe2.erl b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/src/fe2.erl
new file mode 100644
index 0000000000..869f3b93c8
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/src/fe2.erl
@@ -0,0 +1,2 @@
+-module(fe2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/src/fe3.erl b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/src/fe3.erl
new file mode 100644
index 0000000000..6473342f52
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_app_vsn/lib/fe-3.1/src/fe3.erl
@@ -0,0 +1,2 @@
+-module(fe3).
+-vsn("2.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-3.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_bad_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_bad_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_bad_appup/lib/fe-3.1/ebin/fe.appup b/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-3.1/ebin/fe.appup
new file mode 100644
index 0000000000..dac4c00851
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-3.1/ebin/fe.appup
@@ -0,0 +1,27 @@
+%%
+%% Release upgrade script for fe (front end)
+%%
+
+{
+ "3.1",
+%%% Upgrade from:
+ [
+ {"2.1.1" [{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.1", [{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]}
+ ]}
+ ],
+
+%%% Downgrade to:
+ [
+ {"2.1", [{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/d_bad_mod+warn/lib/db-2.1/ebin/db.app b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/ebin/db.app
new file mode 100644
index 0000000000..191919f8d3
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/ebin/db.app
@@ -0,0 +1,8 @@
+{application, db,
+ [{description, "ERICSSON NR FOR DB"},
+ {vsn, "2.1"},
+ {modules, [{db1, "1.0"}, {db2, "1.0"}]},
+ {registered, []},
+ {applications, []},
+ {env, []},
+ {start, {db1, start, []}}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/ebin/db.appup b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/ebin/db.appup
new file mode 100644
index 0000000000..621838f0b4
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/ebin/db.appup
@@ -0,0 +1,20 @@
+%%
+%% Release upgrade script for db (data base)
+%%
+
+{
+ "2.1",
+%%% Upgrade from:
+ [
+ {"1.0", [{update, db1, soft, soft_purge, soft_purge, []},
+ {update, db2, soft, soft_purge, soft_purge, [db1]}]},
+ {"1.1", [{update, db1, soft, soft_purge, soft_purge, []},
+ {update, db2, soft, soft_purge, soft_purge, [db1]}]}
+ ],
+
+%%% Downgrade to:
+ [
+ {"1.0", [{update, db1, soft, soft_purge, soft_purge, []},
+ {update, db2, soft, soft_purge, soft_purge, [db1]}]}
+ ]
+}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/src/db1.erl b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/src/db1.erl
new file mode 100644
index 0000000000..a17640316e
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/src/db1.erl
@@ -0,0 +1,2 @@
+-module(db2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/src/db2.erl b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/src/db2.erl
new file mode 100644
index 0000000000..a17640316e
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/db-2.1/src/db2.erl
@@ -0,0 +1,2 @@
+-module(db2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/ebin/fe.app
new file mode 100644
index 0000000000..d3bd85cda6
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/ebin/fe.app
@@ -0,0 +1,8 @@
+{application, fe,
+ [{description, "ERICSSON NR FOR FE"},
+ {vsn, "3.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_bad_mod+warn/lib/fe-3.1/ebin/fe.appup b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/ebin/fe.appup
new file mode 100644
index 0000000000..2db69eba76
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/ebin/fe.appup
@@ -0,0 +1,27 @@
+%%
+%% Release upgrade script for fe (front end)
+%%
+
+{
+ "3.1",
+%%% Upgrade from:
+ [
+ {"2.1.1", [{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.1", [{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]}
+ ]}
+ ],
+
+%%% Downgrade to:
+ [
+ {"2.1", [{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/d_bad_mod+warn/lib/fe-3.1/src/fe1.erl b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/src/fe1.erl
new file mode 100644
index 0000000000..cdbb9ef532
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/src/fe1.erl
@@ -0,0 +1,2 @@
+-module(fe1).
+-vsn("1.1").
diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/src/fe2.erl b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/src/fe2.erl
new file mode 100644
index 0000000000..869f3b93c8
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/src/fe2.erl
@@ -0,0 +1,2 @@
+-module(fe2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/src/fe3.erl b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/src/fe3.erl
new file mode 100644
index 0000000000..6473342f52
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_mod+warn/lib/fe-3.1/src/fe3.erl
@@ -0,0 +1,2 @@
+-module(fe3).
+-vsn("2.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/ebin/db.app b/lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/ebin/db.app
new file mode 100644
index 0000000000..3e0ac3c3c9
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/ebin/db.app
@@ -0,0 +1,8 @@
+{application, db,
+ [{description, "ERICSSON NR FOR DB"},
+ {vsn, "2.1"},
+ {modules, [{db1, "1.0"}, {db2, "1.0"}, {db3, "2.0"}]},
+ {registered, []},
+ {applications, []},
+ {env, []},
+ {start, {db1, start, []}}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/ebin/db.appup b/lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/ebin/db.appup
new file mode 100644
index 0000000000..621838f0b4
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/ebin/db.appup
@@ -0,0 +1,20 @@
+%%
+%% Release upgrade script for db (data base)
+%%
+
+{
+ "2.1",
+%%% Upgrade from:
+ [
+ {"1.0", [{update, db1, soft, soft_purge, soft_purge, []},
+ {update, db2, soft, soft_purge, soft_purge, [db1]}]},
+ {"1.1", [{update, db1, soft, soft_purge, soft_purge, []},
+ {update, db2, soft, soft_purge, soft_purge, [db1]}]}
+ ],
+
+%%% Downgrade to:
+ [
+ {"1.0", [{update, db1, soft, soft_purge, soft_purge, []},
+ {update, db2, soft, soft_purge, soft_purge, [db1]}]}
+ ]
+}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/src/db2.erl b/lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/src/db2.erl
new file mode 100644
index 0000000000..a17640316e
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/src/db2.erl
@@ -0,0 +1,2 @@
+-module(db2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/src/db3.erl b/lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/src/db3.erl
new file mode 100644
index 0000000000..6473342f52
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_links/lib/db-2.1/src/db3.erl
@@ -0,0 +1,2 @@
+-module(fe3).
+-vsn("2.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_links/lib/fe-3.1/ebin/fe.appup b/lib/sasl/test/systools_SUITE_data/d_links/lib/fe-3.1/ebin/fe.appup
new file mode 100644
index 0000000000..4ab13c1bae
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_links/lib/fe-3.1/ebin/fe.appup
@@ -0,0 +1,27 @@
+%%
+%% Release upgrade script for fe (front end)
+%%
+
+{
+ "3.1",
+%%% Upgrade from:
+ [
+ {"2.1.1", [{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.1", [{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]}
+ ]}
+ ],
+
+%%% Downgrade to:
+ [
+ {"2.1", [{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/d_links/lib/fe-3.1/src/fe1.erl b/lib/sasl/test/systools_SUITE_data/d_links/lib/fe-3.1/src/fe1.erl
new file mode 100644
index 0000000000..aa5bfa8098
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_links/lib/fe-3.1/src/fe1.erl
@@ -0,0 +1,2 @@
+-module(fe1).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_links/lib/fe-3.1/src/fe2.erl b/lib/sasl/test/systools_SUITE_data/d_links/lib/fe-3.1/src/fe2.erl
new file mode 100644
index 0000000000..869f3b93c8
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_links/lib/fe-3.1/src/fe2.erl
@@ -0,0 +1,2 @@
+-module(fe2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_links/lib/fe-3.1/src/fe3.erl b/lib/sasl/test/systools_SUITE_data/d_links/lib/fe-3.1/src/fe3.erl
new file mode 100644
index 0000000000..6473342f52
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_links/lib/fe-3.1/src/fe3.erl
@@ -0,0 +1,2 @@
+-module(fe3).
+-vsn("2.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/ebin/db.app b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/ebin/db.app
new file mode 100644
index 0000000000..191919f8d3
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/ebin/db.app
@@ -0,0 +1,8 @@
+{application, db,
+ [{description, "ERICSSON NR FOR DB"},
+ {vsn, "2.1"},
+ {modules, [{db1, "1.0"}, {db2, "1.0"}]},
+ {registered, []},
+ {applications, []},
+ {env, []},
+ {start, {db1, start, []}}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/ebin/db.appup b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/ebin/db.appup
new file mode 100644
index 0000000000..621838f0b4
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/ebin/db.appup
@@ -0,0 +1,20 @@
+%%
+%% Release upgrade script for db (data base)
+%%
+
+{
+ "2.1",
+%%% Upgrade from:
+ [
+ {"1.0", [{update, db1, soft, soft_purge, soft_purge, []},
+ {update, db2, soft, soft_purge, soft_purge, [db1]}]},
+ {"1.1", [{update, db1, soft, soft_purge, soft_purge, []},
+ {update, db2, soft, soft_purge, soft_purge, [db1]}]}
+ ],
+
+%%% Downgrade to:
+ [
+ {"1.0", [{update, db1, soft, soft_purge, soft_purge, []},
+ {update, db2, soft, soft_purge, soft_purge, [db1]}]}
+ ]
+}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/src/db1.erl b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/src/db1.erl
new file mode 100644
index 0000000000..a17640316e
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/src/db1.erl
@@ -0,0 +1,2 @@
+-module(db2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/src/db2.erl b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/src/db2.erl
new file mode 100644
index 0000000000..a17640316e
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/db-2.1/src/db2.erl
@@ -0,0 +1,2 @@
+-module(db2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/ebin/fe.app
new file mode 100644
index 0000000000..d3bd85cda6
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/ebin/fe.app
@@ -0,0 +1,8 @@
+{application, fe,
+ [{description, "ERICSSON NR FOR FE"},
+ {vsn, "3.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_missing_src/lib/fe-3.1/ebin/fe.appup b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/ebin/fe.appup
new file mode 100644
index 0000000000..4ab13c1bae
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/ebin/fe.appup
@@ -0,0 +1,27 @@
+%%
+%% Release upgrade script for fe (front end)
+%%
+
+{
+ "3.1",
+%%% Upgrade from:
+ [
+ {"2.1.1", [{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.1", [{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]}
+ ]}
+ ],
+
+%%% Downgrade to:
+ [
+ {"2.1", [{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/d_missing_src/lib/fe-3.1/src/fe1.erl b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/src/fe1.erl
new file mode 100644
index 0000000000..cdbb9ef532
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/src/fe1.erl
@@ -0,0 +1,2 @@
+-module(fe1).
+-vsn("1.1").
diff --git a/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/src/fe2.erl b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/src/fe2.erl
new file mode 100644
index 0000000000..869f3b93c8
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/src/fe2.erl
@@ -0,0 +1,2 @@
+-module(fe2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/src/fe3.erl b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/src/fe3.erl
new file mode 100644
index 0000000000..6473342f52
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_missing_src/lib/fe-3.1/src/fe3.erl
@@ -0,0 +1,2 @@
+-module(fe3).
+-vsn("2.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-2.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_no_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_no_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_no_appup/lib/fe-2.1/ebin/fe.appup b/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-2.1/ebin/fe.appup
new file mode 100644
index 0000000000..2db69eba76
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-2.1/ebin/fe.appup
@@ -0,0 +1,27 @@
+%%
+%% Release upgrade script for fe (front end)
+%%
+
+{
+ "3.1",
+%%% Upgrade from:
+ [
+ {"2.1.1", [{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.1", [{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]}
+ ]}
+ ],
+
+%%% Downgrade to:
+ [
+ {"2.1", [{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/d_no_appup/lib/fe-3.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_no_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_no_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_normal/lib/db-1.0/ebin/db.app b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.0/ebin/db.app
new file mode 100644
index 0000000000..22530ee335
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.0/ebin/db.app
@@ -0,0 +1,8 @@
+{application, db,
+ [{description, "ERICSSON NR FOR DB"},
+ {vsn, "1.0"},
+ {modules, [{db1, "1.0"}, {db2, "1.0"}]},
+ {registered, []},
+ {applications, []},
+ {env, []},
+ {start, {db1, start, []}}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.0/src/db1.erl b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.0/src/db1.erl
new file mode 100644
index 0000000000..a17640316e
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.0/src/db1.erl
@@ -0,0 +1,2 @@
+-module(db2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.0/src/db2.erl b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.0/src/db2.erl
new file mode 100644
index 0000000000..a17640316e
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.0/src/db2.erl
@@ -0,0 +1,2 @@
+-module(db2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.1/ebin/db.app b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.1/ebin/db.app
new file mode 100644
index 0000000000..7243a0a96a
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.1/ebin/db.app
@@ -0,0 +1,8 @@
+{application, db,
+ [{description, "ERICSSON NR FOR DB"},
+ {vsn, "1.1"},
+ {modules, [{db1, "1.0"}, {db2, "1.0"}]},
+ {registered, []},
+ {applications, []},
+ {env, []},
+ {start, {db1, start, []}}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.1/src/db1.erl b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.1/src/db1.erl
new file mode 100644
index 0000000000..a17640316e
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.1/src/db1.erl
@@ -0,0 +1,2 @@
+-module(db2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.1/src/db2.erl b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.1/src/db2.erl
new file mode 100644
index 0000000000..a17640316e
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-1.1/src/db2.erl
@@ -0,0 +1,2 @@
+-module(db2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/ebin/db.app b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/ebin/db.app
new file mode 100644
index 0000000000..202d7f1234
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/ebin/db.app
@@ -0,0 +1,7 @@
+{application, db,
+ [{description, "ERICSSON NR FOR DB"},
+ {vsn, "2.1"},
+ {modules, [{db1, "1.0"}, {db2, "1.0"}]},
+ {registered, []},
+ {applications, []},
+ {mod, {db1, []}}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/ebin/db.appup b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/ebin/db.appup
new file mode 100644
index 0000000000..621838f0b4
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/ebin/db.appup
@@ -0,0 +1,20 @@
+%%
+%% Release upgrade script for db (data base)
+%%
+
+{
+ "2.1",
+%%% Upgrade from:
+ [
+ {"1.0", [{update, db1, soft, soft_purge, soft_purge, []},
+ {update, db2, soft, soft_purge, soft_purge, [db1]}]},
+ {"1.1", [{update, db1, soft, soft_purge, soft_purge, []},
+ {update, db2, soft, soft_purge, soft_purge, [db1]}]}
+ ],
+
+%%% Downgrade to:
+ [
+ {"1.0", [{update, db1, soft, soft_purge, soft_purge, []},
+ {update, db2, soft, soft_purge, soft_purge, [db1]}]}
+ ]
+}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/src/db1.erl b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/src/db1.erl
new file mode 100644
index 0000000000..7cddf6bb63
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/src/db1.erl
@@ -0,0 +1,13 @@
+-module(db1).
+-vsn("1.0").
+
+-export([a/0]).
+
+a() ->
+ lists:non_existing_func("dummy_list"),
+ b().
+
+b() ->
+ fe2:non_existing_func(),
+ db2:non_existing_func(),
+ fe1:a().
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/src/db2.erl b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/src/db2.erl
new file mode 100644
index 0000000000..a17640316e
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-2.1/src/db2.erl
@@ -0,0 +1,2 @@
+-module(db2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-3.1/ebin/db.app b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-3.1/ebin/db.app
new file mode 100644
index 0000000000..97643561eb
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-3.1/ebin/db.app
@@ -0,0 +1,7 @@
+{application, db,
+ [{description, "ERICSSON NR FOR DB"},
+ {vsn, "3.1"},
+ {modules, [db1, db2]},
+ {registered, []},
+ {applications, []},
+ {mod, {db1, []}}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-3.1/ebin/db.appup b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-3.1/ebin/db.appup
new file mode 100644
index 0000000000..e636eee158
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-3.1/ebin/db.appup
@@ -0,0 +1,20 @@
+%%
+%% Release upgrade script for db (data base)
+%%
+
+{
+ "3.1",
+%%% Upgrade from:
+ [
+ {"1.0", [{update, db1, soft, soft_purge, soft_purge, []},
+ {update, db2, soft, soft_purge, soft_purge, [db1]}]},
+ {"1.1", [{update, db1, soft, soft_purge, soft_purge, []},
+ {update, db2, soft, soft_purge, soft_purge, [db1]}]}
+ ],
+
+%%% Downgrade to:
+ [
+ {"1.0", [{update, db1, soft, soft_purge, soft_purge, []},
+ {update, db2, soft, soft_purge, soft_purge, [db1]}]}
+ ]
+}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-3.1/src/db1.erl b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-3.1/src/db1.erl
new file mode 100644
index 0000000000..a17640316e
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-3.1/src/db1.erl
@@ -0,0 +1,2 @@
+-module(db2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-3.1/src/db2.erl b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-3.1/src/db2.erl
new file mode 100644
index 0000000000..a17640316e
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/db-3.1/src/db2.erl
@@ -0,0 +1,2 @@
+-module(db2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_normal/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_normal/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_normal/lib/fe-2.1.1/src/fe1.erl b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1.1/src/fe1.erl
new file mode 100644
index 0000000000..aa5bfa8098
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1.1/src/fe1.erl
@@ -0,0 +1,2 @@
+-module(fe1).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1.1/src/fe2.erl b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1.1/src/fe2.erl
new file mode 100644
index 0000000000..869f3b93c8
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1.1/src/fe2.erl
@@ -0,0 +1,2 @@
+-module(fe2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1.1/src/fe3.erl b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1.1/src/fe3.erl
new file mode 100644
index 0000000000..6473342f52
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1.1/src/fe3.erl
@@ -0,0 +1,2 @@
+-module(fe3).
+-vsn("2.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1/ebin/fe.app
new file mode 100644
index 0000000000..47ea248720
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/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_normal/lib/fe-2.1/src/fe1.erl b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1/src/fe1.erl
new file mode 100644
index 0000000000..aa5bfa8098
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1/src/fe1.erl
@@ -0,0 +1,2 @@
+-module(fe1).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1/src/fe2.erl b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1/src/fe2.erl
new file mode 100644
index 0000000000..869f3b93c8
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1/src/fe2.erl
@@ -0,0 +1,2 @@
+-module(fe2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1/src/fe3.erl b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1/src/fe3.erl
new file mode 100644
index 0000000000..6473342f52
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-2.1/src/fe3.erl
@@ -0,0 +1,2 @@
+-module(fe3).
+-vsn("2.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/ebin/fe.app
new file mode 100644
index 0000000000..0696e2494c
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/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_normal/lib/fe-3.1/ebin/fe.appup b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/ebin/fe.appup
new file mode 100644
index 0000000000..2db69eba76
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/ebin/fe.appup
@@ -0,0 +1,27 @@
+%%
+%% Release upgrade script for fe (front end)
+%%
+
+{
+ "3.1",
+%%% Upgrade from:
+ [
+ {"2.1.1", [{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.1", [{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]}
+ ]}
+ ],
+
+%%% Downgrade to:
+ [
+ {"2.1", [{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/d_normal/lib/fe-3.1/src/fe1.erl b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/src/fe1.erl
new file mode 100644
index 0000000000..8aca89b2c7
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/src/fe1.erl
@@ -0,0 +1,7 @@
+-module(fe1).
+-vsn("1.0").
+
+-export([a/0]).
+
+a() ->
+ ok.
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/src/fe2.erl b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/src/fe2.erl
new file mode 100644
index 0000000000..869f3b93c8
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/src/fe2.erl
@@ -0,0 +1,2 @@
+-module(fe2).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/src/fe3.erl b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/src/fe3.erl
new file mode 100644
index 0000000000..6473342f52
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_normal/lib/fe-3.1/src/fe3.erl
@@ -0,0 +1,2 @@
+-module(fe3).
+-vsn("2.0").
diff --git a/lib/sasl/test/systools_SUITE_data/lib/kernel/ebin/kernel.app b/lib/sasl/test/systools_SUITE_data/lib/kernel/ebin/kernel.app
new file mode 100644
index 0000000000..e33314be7a
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/lib/kernel/ebin/kernel.app
@@ -0,0 +1,6 @@
+{application, kernel,
+ [{description, "FAKE KERNEL"},
+ {vsn, "1.0"},
+ {modules, []},
+ {registered, []},
+ {applications, []}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/lib/kernel/ebin/kernel.appup b/lib/sasl/test/systools_SUITE_data/lib/kernel/ebin/kernel.appup
new file mode 100644
index 0000000000..c53f07591f
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/lib/kernel/ebin/kernel.appup
@@ -0,0 +1,12 @@
+%%
+%% Fake release upgrade script for kernel
+%%
+
+{
+ "4.4.1",
+ [
+ ],
+
+ [
+ ]
+}.
diff --git a/lib/sasl/test/systools_SUITE_data/lib/stdlib/ebin/stdlib.app b/lib/sasl/test/systools_SUITE_data/lib/stdlib/ebin/stdlib.app
new file mode 100644
index 0000000000..288fcfe74e
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/lib/stdlib/ebin/stdlib.app
@@ -0,0 +1,6 @@
+{application, stdlib,
+ [{description, "FAKE STDLIB"},
+ {vsn, "1.0"},
+ {modules, []},
+ {registered, []},
+ {applications, []}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/lib/stdlib/ebin/stdlib.appup b/lib/sasl/test/systools_SUITE_data/lib/stdlib/ebin/stdlib.appup
new file mode 100644
index 0000000000..b521eb5d71
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/lib/stdlib/ebin/stdlib.appup
@@ -0,0 +1,12 @@
+%%
+%% Fake release upgrade script for stdlib
+%%
+
+{
+ "1.1",
+ [
+ ],
+
+ [
+ ]
+}.
diff --git a/lib/sasl/test/systools_rc_SUITE.erl b/lib/sasl/test/systools_rc_SUITE.erl
new file mode 100644
index 0000000000..bb93f38fa7
--- /dev/null
+++ b/lib/sasl/test/systools_rc_SUITE.erl
@@ -0,0 +1,488 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(systools_rc_SUITE).
+
+-include_lib("test_server/include/test_server.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]).
+
+%%-----------------------------------------------------------------
+%% 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].
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+
+syntax_check(suite) -> [];
+syntax_check(Config) when is_list(Config) ->
+ PreApps =
+ [#application{name = test,
+ description = "TEST",
+ vsn = "0.1",
+ modules = [{foo,1},{bar,1},{baz,1},{old_mod,1}],
+ regs = [],
+ mod = {sasl, []}},
+ #application{name = snmp,
+ description = "SNMP",
+ vsn = "1.0",
+ modules = [snmp],
+ regs = [],
+ mod = {snmp, []}}],
+ Apps =
+ [#application{name = test,
+ description = "TEST",
+ vsn = "1.0",
+ modules = [{foo,1},{bar,1},{baz,1},{new_mod,1}],
+ regs = [],
+ mod = {sasl, []}}],
+ S1 = [
+ {update, bar, {advanced, extra}, brutal_purge, brutal_purge, []},
+ {update, foo, soft, soft_purge, soft_purge, [bar]},
+ {update, baz, 5000, soft, brutal_purge, brutal_purge, []},
+ {add_module, new_mod},
+ {remove_application, snmp}
+ ],
+ ?line {ok, _} = systools_rc:translate_scripts([S1], Apps, PreApps),
+ S2 = [
+ {apply, {m, f, [a]}},
+ {load_object_code, {tst, "1.0", [new_mod]}},
+ point_of_no_return,
+ {update, bar, {advanced, extra}, brutal_purge, brutal_purge, []},
+ {update, foo, soft, soft_purge, soft_purge, [bar]},
+ {load, {new_mod, soft_purge, soft_purge}},
+ {remove, {old_mod, soft_purge, soft_purge}},
+ {purge, [m1, m2]},
+ {suspend, [m1]},
+ {code_change, [{m1, extra}]},
+ {resume, [m1]},
+ {stop, [m3,m4]},
+ {start, [m3,m4]},
+ {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, []),
+ S3 = [{apply, {m, f, a}}],
+ ?line {error, _, _} = systools_rc:translate_scripts([S3], Apps, []),
+ S3_1 = [{apply, {m, 3, a}}],
+ ?line {error, _, _} = systools_rc:translate_scripts([S3_1], Apps, []),
+ S4 = [{apply, {m, f}}],
+ ?line {error, _, _} = systools_rc:translate_scripts([S4], Apps, []),
+ S5 = [{load_object_code, hej}],
+ ?line {error, _, _} = systools_rc:translate_scripts([S5], Apps, []),
+ S6 = [{load_object_code, {342, "1.0", [foo]}}],
+ ?line {error, _, _} = systools_rc:translate_scripts([S6], Apps, []),
+ S7 = [{load_object_code, {tets, "1.0", foo}}],
+ ?line {error, _, _} = systools_rc:translate_scripts([S7], Apps, []),
+ S8 = [{suspend, [m1]}, point_of_no_return],
+ ?line {error, _, _} = systools_rc:translate_scripts([S8], Apps, []),
+ S9 = [{update, ba, {advanced, extra}, brutal_purge, brutal_purge, []}],
+ ?line {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, []),
+ S11 = [{update, bar, {advanced, extra}, brutal_purge, brutal_purge, [ba]}],
+ ?line {error, _, _} = systools_rc:translate_scripts([S11], Apps, []),
+ S12 = [{update, bar, advanced, brutal_purge, brutal_purge, []}],
+ ?line {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, []),
+ S14 = [{update, bar, {advanced, extra}, brutal_purge, rutal_purge, [ba]}],
+ ?line {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, []),
+ S16 = [{code_change, [module]}],
+ ?line {error, _, _} = systools_rc:translate_scripts([S16], Apps, []),
+ ?line ok.
+
+translate(suite) -> [];
+translate(Config) when is_list(Config) ->
+ Apps =
+ [#application{name = test,
+ description = "TEST",
+ vsn = "1.0",
+ modules = [{foo,1},{bar,1},{baz,1},
+ {x,1},{y,1},{z,1}],
+ regs = [],
+ 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,
+
+ %% 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,
+
+ 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,
+
+ %% 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,
+
+ 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,
+
+ %% 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,
+
+ 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,
+
+ 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,
+
+ %% 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,
+
+ Up5a = [{update, foo, dynamic, infinity, soft, soft_purge,
+ soft_purge, [bar, baz]},
+ {update, bar, static, 7000, {advanced, []}, soft_purge,
+ 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,
+
+ Up5b = [{update, foo, dynamic, infinity, soft, soft_purge,
+ soft_purge, [bar, baz]},
+ {update, bar, dynamic, 7000, {advanced, []}, soft_purge,
+ 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,
+
+ %% 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,
+
+ %% 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,
+
+ %% Complex circular dependencies, check only order
+ %%
+ Up8 = [{update, foo, soft, soft_purge, soft_purge, [baz]},
+ {update, y, soft, soft_purge, soft_purge, [bar]},
+ {update, x, soft, soft_purge, soft_purge, [y, z]},
+ {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,
+
+ %% Check that order among other instructions isn't changed
+ Up9 = [{update, foo, soft, soft_purge, soft_purge, [baz]},
+ {apply, {m, f, [1]}},
+ {update, y, soft, soft_purge, soft_purge, [bar]},
+ {apply, {m, f, [2]}},
+ {update, x, soft, soft_purge, soft_purge, [y, z]},
+ {apply, {m, f, [3]}},
+ {update, z, soft, soft_purge, soft_purge, [x]},
+ {apply, {m, f, [4]}},
+ {update, bar, soft, soft_purge, soft_purge, [baz]},
+ {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, []),
+ Other2 = [X || {apply, {m, f, [X]}} <- X9],
+ ?line [1,2,3,4,5,6] = lists:sort(Other2),
+ ?line ok.
+
+
+translate_app(suite) -> [];
+translate_app(Config) when is_list(Config) ->
+ PreApps =
+ [#application{name = test,
+ description = "TEST",
+ vsn = "1.0",
+ modules = [{foo,1},{bar,1},{baz,1}],
+ regs = [],
+ mod = {sasl, []}},
+ #application{name = pelle,
+ description = "PELLE",
+ vsn = "1.0",
+ modules = [pelle, kalle],
+ regs = [],
+ mod = {pelle, []}}],
+ Apps =
+ [#application{name = test,
+ description = "TEST",
+ vsn = "1.0",
+ modules = [{foo,1},{bar,1},{baz,1}],
+ regs = [],
+ mod = {sasl, []}}],
+ %% 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,
+
+ %% 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,
+
+ %% 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.