479329: Client and Server Test Environment cannot be replaced 

Change-Id: I5c297c5e51c5596097b89143a7261f15330fb027
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=479329
Reviewed-on: https://git.eclipse.org/r/57708
Reviewed-by: Andi Bur <andi.bur@gmail.com>
Tested-by: Andi Bur <andi.bur@gmail.com>
diff --git a/org.eclipse.scout.rt.testing.client/src/org/eclipse/scout/testing/client/runner/ScoutClientTestRunner.java b/org.eclipse.scout.rt.testing.client/src/org/eclipse/scout/testing/client/runner/ScoutClientTestRunner.java
index 9f35259..6a595e0 100644
--- a/org.eclipse.scout.rt.testing.client/src/org/eclipse/scout/testing/client/runner/ScoutClientTestRunner.java
+++ b/org.eclipse.scout.rt.testing.client/src/org/eclipse/scout/testing/client/runner/ScoutClientTestRunner.java
@@ -14,7 +14,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -23,6 +22,7 @@
 import org.eclipse.scout.commons.logger.ScoutLogManager;
 import org.eclipse.scout.commons.serialization.SerializationUtility;
 import org.eclipse.scout.rt.client.IClientSession;
+import org.eclipse.scout.rt.testing.shared.runner.TestEnvironmentUtility;
 import org.eclipse.scout.rt.testing.shared.services.common.exceptionhandler.ProcessingRuntimeExceptionUnwrappingStatement;
 import org.eclipse.scout.testing.client.DefaultTestClientSessionProvider;
 import org.eclipse.scout.testing.client.ITestClientSessionProvider;
@@ -49,14 +49,17 @@
   private static ITestClientSessionProvider s_defaultClientSessionProvider = new DefaultTestClientSessionProvider();
   private static Class<? extends IClientSession> s_defaultClientSessionClass;
   private static final IScoutLogger LOG;
-  private static final IClientTestEnvironment FACTORY;
+  private static final IClientTestEnvironment CLIENT_TEST_ENVIRONMENT;
 
   static {
     LOG = ScoutLogManager.getLogger(ScoutClientTestRunner.class);
-    FACTORY = createClientTestEnvironmentFactory();
+    CLIENT_TEST_ENVIRONMENT = TestEnvironmentUtility.createTestEnvironment(
+        IClientTestEnvironment.class,
+        "org.eclipse.scout.testing.client.runner.customClientTestEnvironmentClassName",
+        "org.eclipse.scout.testing.client.runner.CustomClientTestEnvironment");
 
-    if (FACTORY != null) {
-      FACTORY.setupGlobalEnvironment();
+    if (CLIENT_TEST_ENVIRONMENT != null) {
+      CLIENT_TEST_ENVIRONMENT.setupGlobalEnvironment();
     }
   }
 
@@ -89,8 +92,8 @@
   public ScoutClientTestRunner(Class<?> klass) throws InitializationError {
     super(klass);
 
-    if (FACTORY != null) {
-      FACTORY.setupInstanceEnvironment();
+    if (CLIENT_TEST_ENVIRONMENT != null) {
+      CLIENT_TEST_ENVIRONMENT.setupInstanceEnvironment();
     }
 
     try {
@@ -280,32 +283,4 @@
     }
     return forceCreateNewSession;
   }
-
-  private static IClientTestEnvironment createClientTestEnvironmentFactory() {
-    IClientTestEnvironment environment = null;
-    if (SerializationUtility.getClassLoader() != null) {
-      // check whether there is a custom test environment available
-      try {
-        Class<?> customTestEnvironment = SerializationUtility.getClassLoader().loadClass("org.eclipse.scout.testing.client.runner.CustomClientTestEnvironment");
-        LOG.info("loaded custom test environment: [" + customTestEnvironment + "]");
-        if (!IClientTestEnvironment.class.isAssignableFrom(customTestEnvironment)) {
-          LOG.warn("custom test environment is not implementing [" + IClientTestEnvironment.class + "]");
-        }
-        else if (Modifier.isAbstract(customTestEnvironment.getModifiers())) {
-          LOG.warn("custom test environment is an abstract class [" + customTestEnvironment + "]");
-        }
-        else {
-          environment = (IClientTestEnvironment) customTestEnvironment.newInstance();
-        }
-      }
-      catch (ClassNotFoundException e) {
-        // no custom test environment installed
-      }
-      catch (Exception e) {
-        LOG.warn("Unexpected problem while creating a new instance of custom test environment", e);
-      }
-    }
-    return environment;
-  }
-
 }
diff --git a/org.eclipse.scout.rt.testing.server/src/org/eclipse/scout/rt/testing/server/runner/ScoutServerTestRunner.java b/org.eclipse.scout.rt.testing.server/src/org/eclipse/scout/rt/testing/server/runner/ScoutServerTestRunner.java
index 59d29a8..41e5044 100644
--- a/org.eclipse.scout.rt.testing.server/src/org/eclipse/scout/rt/testing/server/runner/ScoutServerTestRunner.java
+++ b/org.eclipse.scout.rt.testing.server/src/org/eclipse/scout/rt/testing/server/runner/ScoutServerTestRunner.java
@@ -14,7 +14,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -29,6 +28,7 @@
 import org.eclipse.scout.rt.server.IServerSession;
 import org.eclipse.scout.rt.testing.server.DefaultTestServerSessionProvider;
 import org.eclipse.scout.rt.testing.server.ITestServerSessionProvider;
+import org.eclipse.scout.rt.testing.shared.runner.TestEnvironmentUtility;
 import org.eclipse.scout.rt.testing.shared.services.common.exceptionhandler.ProcessingRuntimeExceptionUnwrappingStatement;
 import org.eclipse.scout.service.SERVICES;
 import org.junit.AfterClass;
@@ -87,15 +87,19 @@
   private static ITestServerSessionProvider s_defaultServerSessionProvider = new DefaultTestServerSessionProvider();
   private static final IServerJobService BACKEND_JOB_SERVICE;
   private static final IScoutLogger LOG;
-  private static final IServerTestEnvironment FACTORY;
+  private static final IServerTestEnvironment SERVER_TEST_ENVIRONMENT;
 
   static {
     LOG = ScoutLogManager.getLogger(ScoutServerTestRunner.class);
-    FACTORY = createServerTestEnvironmentFactory();
+    SERVER_TEST_ENVIRONMENT = TestEnvironmentUtility.createTestEnvironment(
+        IServerTestEnvironment.class,
+        "org.eclipse.scout.testing.server.runner.customServerTestEnvironmentClassName",
+        "org.eclipse.scout.testing.server.runner.CustomServerTestEnvironment");
+
     BACKEND_JOB_SERVICE = SERVICES.getService(IServerJobService.class);
 
-    if (FACTORY != null) {
-      FACTORY.setupGlobalEnvironment();
+    if (SERVER_TEST_ENVIRONMENT != null) {
+      SERVER_TEST_ENVIRONMENT.setupGlobalEnvironment();
     }
   }
 
@@ -126,8 +130,8 @@
   public ScoutServerTestRunner(Class<?> klass) throws InitializationError {
     super(klass);
 
-    if (FACTORY != null) {
-      FACTORY.setupInstanceEnvironment();
+    if (SERVER_TEST_ENVIRONMENT != null) {
+      SERVER_TEST_ENVIRONMENT.setupInstanceEnvironment();
     }
 
     try {
@@ -344,32 +348,4 @@
       return m_serverSession;
     }
   }
-
-  private static IServerTestEnvironment createServerTestEnvironmentFactory() {
-    IServerTestEnvironment environment = null;
-    if (SerializationUtility.getClassLoader() != null) {
-      // check whether there is a custom test environment available
-      try {
-        Class<?> customTestEnvironment = SerializationUtility.getClassLoader().loadClass("org.eclipse.scout.testing.server.runner.CustomServerTestEnvironment");
-        LOG.info("loaded custom test environment: [" + customTestEnvironment + "]");
-        if (!IServerTestEnvironment.class.isAssignableFrom(customTestEnvironment)) {
-          LOG.warn("custom test environment is not implementing [" + IServerTestEnvironment.class + "]");
-        }
-        else if (Modifier.isAbstract(customTestEnvironment.getModifiers())) {
-          LOG.warn("custom test environment is an abstract class [" + customTestEnvironment + "]");
-        }
-        else {
-          environment = (IServerTestEnvironment) customTestEnvironment.newInstance();
-        }
-      }
-      catch (ClassNotFoundException e) {
-        LOG.debug("no custom custom test environment installed", e);
-      }
-      catch (Exception e) {
-        LOG.warn("Unexpected problem while creating a new instance of custom test environment", e);
-      }
-    }
-    return environment;
-  }
-
 }
diff --git a/org.eclipse.scout.rt.testing.shared.test/src/org/eclipse/scout/rt/testing/shared/runner/TestEnvironmentUtilityTest.java b/org.eclipse.scout.rt.testing.shared.test/src/org/eclipse/scout/rt/testing/shared/runner/TestEnvironmentUtilityTest.java
new file mode 100644
index 0000000..c141262
--- /dev/null
+++ b/org.eclipse.scout.rt.testing.shared.test/src/org/eclipse/scout/rt/testing/shared/runner/TestEnvironmentUtilityTest.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2015 BSI Business Systems Integration AG.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     BSI Business Systems Integration AG - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.scout.rt.testing.shared.runner;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+import org.eclipse.scout.rt.testing.shared.runner.fixture.CustomTestingTestEnvironment;
+import org.eclipse.scout.rt.testing.shared.runner.fixture.DefaultTestingTestEnvironment;
+import org.eclipse.scout.rt.testing.shared.runner.fixture.ITestingTestEnvironment;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @since 4.2.x
+ */
+public class TestEnvironmentUtilityTest {
+
+  private static final String CUSTOM_TESTING_ENV_PROPERTY_NAME = "customTestingTestEnvironmentPropertyName";
+  private static final String DEFAULT_TESTING_ENV_CLASS_NAME = DefaultTestingTestEnvironment.class.getName();
+
+  @Before
+  @After
+  public void cleanup() throws Exception {
+    System.clearProperty(CUSTOM_TESTING_ENV_PROPERTY_NAME);
+  }
+
+  @Test
+  public void noTestEnvironment() throws Exception {
+    ITestingTestEnvironment env = TestEnvironmentUtility.createTestEnvironment(
+        ITestingTestEnvironment.class,
+        "notImportant",
+        "NonExistingDefaultTestingTestEnvironment");
+    assertNull(env);
+  }
+
+  @Test
+  public void defaultTestEnvironment() throws Exception {
+    ITestingTestEnvironment env = TestEnvironmentUtility.createTestEnvironment(
+        ITestingTestEnvironment.class,
+        "notImportant",
+        DEFAULT_TESTING_ENV_CLASS_NAME);
+    assertNotNull(env);
+    assertSame(DefaultTestingTestEnvironment.class, env.getClass());
+  }
+
+  @Test
+  public void defaultTestEnvironmentNotImplementingExpectedInterface() throws Exception {
+    ITestingTestEnvironment env = TestEnvironmentUtility.createTestEnvironment(
+        ITestingTestEnvironment.class,
+        "notImportant",
+        Object.class.getName()); // Object is not an ITestingTestEnvironment
+    assertNull(env);
+  }
+
+  @Test
+  public void customTestEnvironment() throws Exception {
+    System.setProperty(CUSTOM_TESTING_ENV_PROPERTY_NAME, CustomTestingTestEnvironment.class.getName());
+    ITestingTestEnvironment env = TestEnvironmentUtility.createTestEnvironment(
+        ITestingTestEnvironment.class,
+        CUSTOM_TESTING_ENV_PROPERTY_NAME,
+        DEFAULT_TESTING_ENV_CLASS_NAME);
+    assertNotNull(env);
+    assertSame(CustomTestingTestEnvironment.class, env.getClass());
+  }
+
+  @Test(expected = IllegalStateException.class)
+  public void customTestEnvironmentReferencingNonExistingClass() throws Exception {
+    System.setProperty(CUSTOM_TESTING_ENV_PROPERTY_NAME, "NonExistingCustomTestEnvironment");
+    TestEnvironmentUtility.createTestEnvironment(
+        ITestingTestEnvironment.class,
+        CUSTOM_TESTING_ENV_PROPERTY_NAME,
+        DEFAULT_TESTING_ENV_CLASS_NAME);
+  }
+
+  @Test(expected = IllegalStateException.class)
+  public void customTestEnvironmentNotImplementingExpectedInterface() throws Exception {
+    System.setProperty(CUSTOM_TESTING_ENV_PROPERTY_NAME, Object.class.getName()); // Object is not an ITestingTestEnvironment
+    TestEnvironmentUtility.createTestEnvironment(
+        ITestingTestEnvironment.class,
+        CUSTOM_TESTING_ENV_PROPERTY_NAME,
+        DEFAULT_TESTING_ENV_CLASS_NAME);
+  }
+}
diff --git a/org.eclipse.scout.rt.testing.shared.test/src/org/eclipse/scout/rt/testing/shared/runner/fixture/CustomTestingTestEnvironment.java b/org.eclipse.scout.rt.testing.shared.test/src/org/eclipse/scout/rt/testing/shared/runner/fixture/CustomTestingTestEnvironment.java
new file mode 100644
index 0000000..aa6fa8f
--- /dev/null
+++ b/org.eclipse.scout.rt.testing.shared.test/src/org/eclipse/scout/rt/testing/shared/runner/fixture/CustomTestingTestEnvironment.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2015 BSI Business Systems Integration AG.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     BSI Business Systems Integration AG - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.scout.rt.testing.shared.runner.fixture;
+
+/**
+ * @since 4.2.x
+ */
+public class CustomTestingTestEnvironment implements ITestingTestEnvironment {
+}
diff --git a/org.eclipse.scout.rt.testing.shared.test/src/org/eclipse/scout/rt/testing/shared/runner/fixture/DefaultTestingTestEnvironment.java b/org.eclipse.scout.rt.testing.shared.test/src/org/eclipse/scout/rt/testing/shared/runner/fixture/DefaultTestingTestEnvironment.java
new file mode 100644
index 0000000..6a6ac21
--- /dev/null
+++ b/org.eclipse.scout.rt.testing.shared.test/src/org/eclipse/scout/rt/testing/shared/runner/fixture/DefaultTestingTestEnvironment.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2015 BSI Business Systems Integration AG.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     BSI Business Systems Integration AG - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.scout.rt.testing.shared.runner.fixture;
+
+/**
+ * @since 4.2.x
+ */
+public class DefaultTestingTestEnvironment implements ITestingTestEnvironment {
+}
diff --git a/org.eclipse.scout.rt.testing.shared.test/src/org/eclipse/scout/rt/testing/shared/runner/fixture/ITestingTestEnvironment.java b/org.eclipse.scout.rt.testing.shared.test/src/org/eclipse/scout/rt/testing/shared/runner/fixture/ITestingTestEnvironment.java
new file mode 100644
index 0000000..e0f096a
--- /dev/null
+++ b/org.eclipse.scout.rt.testing.shared.test/src/org/eclipse/scout/rt/testing/shared/runner/fixture/ITestingTestEnvironment.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2015 BSI Business Systems Integration AG.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     BSI Business Systems Integration AG - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.scout.rt.testing.shared.runner.fixture;
+
+/**
+ * @since 4.2.x
+ */
+public interface ITestingTestEnvironment {
+}
diff --git a/org.eclipse.scout.rt.testing.shared/src/org/eclipse/scout/rt/testing/shared/runner/TestEnvironmentUtility.java b/org.eclipse.scout.rt.testing.shared/src/org/eclipse/scout/rt/testing/shared/runner/TestEnvironmentUtility.java
new file mode 100644
index 0000000..b035272
--- /dev/null
+++ b/org.eclipse.scout.rt.testing.shared/src/org/eclipse/scout/rt/testing/shared/runner/TestEnvironmentUtility.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2015 BSI Business Systems Integration AG.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     BSI Business Systems Integration AG - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.scout.rt.testing.shared.runner;
+
+import java.lang.reflect.Modifier;
+
+import org.eclipse.scout.commons.StringUtility;
+import org.eclipse.scout.commons.logger.IScoutLogger;
+import org.eclipse.scout.commons.logger.ScoutLogManager;
+import org.eclipse.scout.commons.serialization.SerializationUtility;
+import org.eclipse.scout.rt.testing.shared.Activator;
+
+/**
+ * Utility for creating a custom test environment instance.
+ * 
+ * @since 4.2.x
+ */
+public final class TestEnvironmentUtility {
+
+  private static final IScoutLogger LOG = ScoutLogManager.getLogger(TestEnvironmentUtility.class);
+
+  private TestEnvironmentUtility() {
+  }
+
+  /**
+   * Creates a new test environment instance. If a configuration value with the given property name is set, it is
+   * resolved and an exception is thrown in case of an error. If the config value is not set, the default environment
+   * class is loaded. If it does not exist or in case of an error, <code>null</code> is returned.
+   */
+  public static <T> T createTestEnvironment(Class<T> testEnvironmentClass, String customTestEnvironmentConfigPropertyName, String defaultCustomTestEnvironmentClassName) {
+    if (SerializationUtility.getClassLoader() == null) {
+      return null;
+    }
+
+    // check whether there is a custom test environment available
+    Activator activator = Activator.getDefault();
+    if (activator != null) {
+      String className = StringUtility.trim(activator.getBundle().getBundleContext().getProperty(customTestEnvironmentConfigPropertyName));
+      if (StringUtility.hasText(className)) {
+        T environment = loadCustomTestEnvironmentClass(testEnvironmentClass, className);
+        if (environment == null) {
+          LOG.error("custom test environment specified by config property cannot be loaded '{}'", className);
+          throw new IllegalStateException("Custom test environment cannot be loaded. Check configuration.");
+        }
+        return environment;
+      }
+    }
+    return loadCustomTestEnvironmentClass(testEnvironmentClass, defaultCustomTestEnvironmentClassName);
+  }
+
+  private static <T> T loadCustomTestEnvironmentClass(Class<T> testEnvironmentClass, String customTestEnvironmentClassName) {
+    T environment = null;
+    try {
+      Class<?> customTestEnvironment = SerializationUtility.getClassLoader().loadClass(customTestEnvironmentClassName);
+      LOG.info("loaded custom test environment: [" + customTestEnvironment + "]");
+      if (!testEnvironmentClass.isAssignableFrom(customTestEnvironment)) {
+        LOG.warn("custom test environment is not implementing [" + testEnvironmentClass + "]");
+      }
+      else if (Modifier.isAbstract(customTestEnvironment.getModifiers())) {
+        LOG.warn("custom test environment is an abstract class [" + customTestEnvironment + "]");
+      }
+      else {
+        environment = testEnvironmentClass.cast(customTestEnvironment.newInstance());
+      }
+    }
+    catch (ClassNotFoundException e) {
+      LOG.debug("no custom custom test environment installed", e);
+    }
+    catch (Exception e) {
+      LOG.warn("Unexpected problem while creating a new instance of custom test environment", e);
+    }
+    return environment;
+  }
+}