Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Walther2021-06-29 09:04:55 -0400
committerThomas Watson2021-08-13 09:20:45 -0400
commit9586a04ba4659bb940887f1f0b9beaa2434b0836 (patch)
tree61bc3783c626600083ad3b0ea267ae42717de8b7
parenta433328627eee648bf628dcc317c5d269f9a3bb8 (diff)
downloadrt.equinox.framework-9586a04ba4659bb940887f1f0b9beaa2434b0836.tar.gz
rt.equinox.framework-9586a04ba4659bb940887f1f0b9beaa2434b0836.tar.xz
rt.equinox.framework-9586a04ba4659bb940887f1f0b9beaa2434b0836.zip
This is hard to test cleanly because relaunching requires the first application to exit, but exiting the test runner application ends the test. Work around that by using the test runner as the second (relaunched) application. This means that if the test fails, it shows up not as failed but with an error "Test did not run". Change-Id: I12dc31f42e2d7b4f261610ab0190ed5940d62d55 Signed-off-by: Christian Walther <walther@indel.ch> Reviewed-on: https://git.eclipse.org/r/c/equinox/rt.equinox.framework/+/182604 Tested-by: Equinox Bot <equinox-bot@eclipse.org> Reviewed-by: Thomas Watson <tjwatson@us.ibm.com>
-rw-r--r--bundles/org.eclipse.osgi.tests/plugin.xml12
-rw-r--r--bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/appadmin/AllTests.java1
-rw-r--r--bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/appadmin/ApplicationRelaunchTest.java121
-rw-r--r--bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/appadmin/RelaunchApp.java136
4 files changed, 270 insertions, 0 deletions
diff --git a/bundles/org.eclipse.osgi.tests/plugin.xml b/bundles/org.eclipse.osgi.tests/plugin.xml
index b27d6ae5d..f8453e146 100644
--- a/bundles/org.eclipse.osgi.tests/plugin.xml
+++ b/bundles/org.eclipse.osgi.tests/plugin.xml
@@ -95,4 +95,16 @@
</run>
</application>
</extension>
+ <extension
+ id="relaunchApp"
+ point="org.eclipse.core.runtime.applications">
+ <application
+ cardinality="1"
+ thread="main"
+ visible="true">
+ <run
+ class="org.eclipse.osgi.tests.appadmin.RelaunchApp">
+ </run>
+ </application>
+ </extension>
</plugin>
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/appadmin/AllTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/appadmin/AllTests.java
index 37a0e7283..66f8ca602 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/appadmin/AllTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/appadmin/AllTests.java
@@ -20,6 +20,7 @@ public class AllTests {
public static Test suite() {
TestSuite suite = new TestSuite(AllTests.class.getName());
suite.addTest(ApplicationAdminTest.suite());
+ suite.addTest(ApplicationRelaunchTest.suite());
return suite;
}
}
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/appadmin/ApplicationRelaunchTest.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/appadmin/ApplicationRelaunchTest.java
new file mode 100644
index 000000000..d91ba9af9
--- /dev/null
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/appadmin/ApplicationRelaunchTest.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2021 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.osgi.tests.appadmin;
+
+import java.util.HashMap;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.eclipse.core.tests.session.ConfigurationSessionTestSuite;
+import org.eclipse.core.tests.session.SetupManager.SetupException;
+import org.eclipse.osgi.tests.OSGiTest;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.application.ApplicationDescriptor;
+import org.osgi.service.application.ApplicationHandle;
+
+// This is for the most part a stripped down copy of ApplicationAdminTest.
+public class ApplicationRelaunchTest extends OSGiTest {
+ public static final String testRunnerRelauncherApp = PI_OSGI_TESTS + ".relaunchApp"; //$NON-NLS-1$
+ public static final String testResults = "test.results"; //$NON-NLS-1$
+ public static final String SUCCESS = "success"; //$NON-NLS-1$
+ public static final String simpleResults = "test.simpleResults"; //$NON-NLS-1$
+ public static final String[] tests = new String[] { "testRelaunch" };
+ private static final String PI_OSGI_SERVICES = "org.eclipse.osgi.services"; //$NON-NLS-1$
+ private static final String PI_OSGI_UTIL = "org.eclipse.osgi.util";
+
+ public static Test suite() {
+ TestSuite suite = new TestSuite(ApplicationRelaunchTest.class.getName());
+
+ ConfigurationSessionTestSuite appAdminSessionTest = new ConfigurationSessionTestSuite(PI_OSGI_TESTS, ApplicationRelaunchTest.class.getName());
+ String[] ids = ConfigurationSessionTestSuite.MINIMAL_BUNDLE_SET;
+ for (String id : ids) {
+ appAdminSessionTest.addBundle(id);
+ }
+ appAdminSessionTest.addBundle(PI_OSGI_UTIL);
+ appAdminSessionTest.addBundle(PI_OSGI_SERVICES);
+ appAdminSessionTest.addBundle(PI_OSGI_TESTS);
+ appAdminSessionTest.setApplicationId(testRunnerRelauncherApp);
+ try {
+ appAdminSessionTest.getSetup().setSystemProperty("eclipse.application.registerDescriptors", "true"); //$NON-NLS-1$//$NON-NLS-2$
+ } catch (SetupException e) {
+ throw new RuntimeException(e);
+ }
+ // we add tests the hard way so we can control the order of the tests.
+ for (String test : tests) {
+ appAdminSessionTest.addTest(new ApplicationRelaunchTest(test));
+ }
+ suite.addTest(appAdminSessionTest);
+ return suite;
+ }
+
+ public ApplicationRelaunchTest(String name) {
+ super(name);
+ }
+
+ private ApplicationDescriptor getApplication(String appName) {
+ try {
+ BundleContext context = getContext();
+ assertNotNull("BundleContext is null!!", context); //$NON-NLS-1$
+ Class appDescClass = ApplicationDescriptor.class;
+ assertNotNull("ApplicationDescriptor.class is null!!", appDescClass); //$NON-NLS-1$
+ ServiceReference[] refs = context.getServiceReferences(appDescClass.getName(), "(" + ApplicationDescriptor.APPLICATION_PID + "=" + appName + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ if (refs == null || refs.length == 0) {
+ refs = getContext().getServiceReferences(ApplicationDescriptor.class.getName(), null);
+ String availableApps = ""; //$NON-NLS-1$
+ if (refs != null) {
+ for (int i = 0; i < refs.length; i++) {
+ availableApps += refs[i].getProperty(ApplicationDescriptor.APPLICATION_PID);
+ if (i < refs.length - 1)
+ availableApps += ","; //$NON-NLS-1$
+ }
+ }
+ fail("Could not find app pid: " + appName + " available apps are: " + availableApps); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ ApplicationDescriptor result = (ApplicationDescriptor) getContext().getService(refs[0]);
+ if (result != null)
+ getContext().ungetService(refs[0]);
+ else
+ fail("Could not get application descriptor service: " + appName); //$NON-NLS-1$
+ return result;
+ } catch (InvalidSyntaxException e) {
+ fail("Could not create app filter", e); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ private HashMap getArguments() {
+ HashMap args = new HashMap();
+ args.put(testResults, new HashMap());
+ return args;
+ }
+
+ public void testRelaunch() {
+ // this is the same as ApplicationAdminTest.testSimpleApp() (but launched
+ // through a different test runner app RelaunchApp which is the thing being
+ // tested)
+ ApplicationDescriptor app = getApplication(PI_OSGI_TESTS + ".simpleApp"); //$NON-NLS-1$
+ HashMap args = getArguments();
+ HashMap results = (HashMap) args.get(testResults);
+ try {
+ ApplicationHandle handle = app.launch(args);
+ handle.destroy();
+ } catch (Throwable e) {
+ fail("failed to launch simpleApp", e); //$NON-NLS-1$
+ }
+ String result = (String) results.get(simpleResults);
+ assertEquals("Check application result", SUCCESS, result); //$NON-NLS-1$
+ }
+
+}
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/appadmin/RelaunchApp.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/appadmin/RelaunchApp.java
new file mode 100644
index 000000000..f349f77d6
--- /dev/null
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/appadmin/RelaunchApp.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+* Copyright (c) 2021 Indel AG and others.
+*
+* This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License 2.0
+* which accompanies this distribution, and is available at
+* https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+*
+* Contributors:
+* Indel AG - initial API and implementation
+*******************************************************************************/
+package org.eclipse.osgi.tests.appadmin;
+
+import java.util.Collection;
+import java.util.Map;
+import org.eclipse.equinox.app.IApplication;
+import org.eclipse.equinox.app.IApplicationContext;
+import org.eclipse.osgi.service.environment.EnvironmentInfo;
+import org.eclipse.osgi.tests.OSGiTestsActivator;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.application.ApplicationDescriptor;
+import org.osgi.service.application.ApplicationException;
+import org.osgi.service.application.ApplicationHandle;
+
+public class RelaunchApp implements IApplication {
+
+ @Override
+ public Object start(IApplicationContext context) throws Exception {
+ final Map arguments = context.getArguments();
+
+ // Setting eclipse.allowAppRelaunch to true at runtime should allow us to launch
+ // multiple applications in sequence
+ ServiceReference<EnvironmentInfo> envref = OSGiTestsActivator.getContext()
+ .getServiceReference(EnvironmentInfo.class);
+ EnvironmentInfo env = OSGiTestsActivator.getContext().getService(envref);
+ if (Boolean.valueOf(env.getProperty("eclipse.allowAppRelaunch"))) { //$NON-NLS-1$
+ throw new AssertionError("eclipse.allowAppRelaunch should not be set initially"); //$NON-NLS-1$
+ }
+ env.setProperty("eclipse.allowAppRelaunch", "true"); //$NON-NLS-1$ //$NON-NLS-2$
+ OSGiTestsActivator.getContext().ungetService(envref);
+
+ // Get a handle for the running application so we can wait for it to exit
+ ServiceReference<ApplicationHandle> thisAppRef = OSGiTestsActivator.getContext()
+ .getServiceReference(ApplicationHandle.class);
+ ApplicationHandle thisAppHandle = OSGiTestsActivator.getContext().getService(thisAppRef);
+
+ new Thread("launcher") { //$NON-NLS-1$
+ public void run() {
+ // Wait for this application to exit
+ try {
+ thisAppHandle.getExitValue(0);
+ } catch (ApplicationException e) {
+ // does not occur for timeout 0
+ } catch (InterruptedException e) {
+ // I don't think this should occur
+ e.printStackTrace();
+ }
+
+ // Get the descriptor for the actual test runner application.
+ // Need a test runner that runs in the main thread to avoid race conditions.
+ Collection<ServiceReference<ApplicationDescriptor>> testAppRefs = null;
+ try {
+ testAppRefs = OSGiTestsActivator.getContext().getServiceReferences(
+ org.osgi.service.application.ApplicationDescriptor.class,
+ "(" + Constants.SERVICE_PID + "=org.eclipse.pde.junit.runtime.nonuithreadtestapplication)"); //$NON-NLS-1$ //$NON-NLS-2$
+ } catch (InvalidSyntaxException e) {
+ // shouldn't happen, the hardcoded filter expression
+ // should be syntactically correct
+ e.printStackTrace();
+ }
+ ServiceReference<ApplicationDescriptor> testAppRef = testAppRefs.iterator().next();
+ ApplicationDescriptor testAppDescriptor = OSGiTestsActivator.getContext().getService(testAppRef);
+
+ // Launch the new application
+ // If it does launch, it will run some unrelated succeeding test
+ // and thereby confirm that relaunching works.
+ try {
+ ApplicationHandle testAppHandle;
+ // There is a race condition in that the previous
+ // application may not have exited far enough yet for
+ // the EclipseAppLauncher to allow launching of a new
+ // application: Setting the exit value happens earlier
+ // in EclipseAppLauncher.runApplication() (inside
+ // EclipseAppHandle.run()) than releasing runningLock.
+ // Unfortunately there is no way to wait for the
+ // EclipseAppLauncher to be ready, so just try again
+ // after a delay when that happens.
+ while (true) {
+ try {
+ testAppHandle = testAppDescriptor.launch(arguments);
+ break;
+ } catch (IllegalStateException e) {
+ Thread.sleep(100);
+ }
+ }
+
+ // Wait for the test application to exit
+ testAppHandle.getExitValue(0);
+ } catch (ApplicationException | InterruptedException e) {
+ // ApplicationException "The main thread is not available to launch the
+ // application" can happen when the test fails
+ e.printStackTrace();
+ } finally {
+ OSGiTestsActivator.getContext().ungetService(thisAppRef);
+ OSGiTestsActivator.getContext().ungetService(testAppRef);
+
+ try {
+ // This will not return but cause the process to terminate
+ OSGiTestsActivator.getContext().getBundle(0).stop();
+ } catch (BundleException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }.start();
+
+ // If relaunching does not work, the process will end after this and the test
+ // will end with an error "Test did not run". The "launcher" thread will be
+ // killed wherever its execution happens to be, which is a race condition that
+ // means that there may be various exceptions printed or not. However even if it
+ // successfully got past testAppDescriptor.launch(), the test runner which wants
+ // to run in the main thread will never actually run, so the test cannot
+ // mistakenly succeed.
+ return null;
+ }
+
+ @Override
+ public void stop() {
+ }
+
+}

Back to the top