feature: Initial commit of simple test environment.

This initial commit was just to put the infrastructure
in to be able to connect to a test server from the simple
OTE-IDE.

Change-Id: I6837304875f6a35bca915245ee174d087749b228
diff --git a/org.eclipse.ote.simple.oteide.product.feature/feature.xml b/org.eclipse.ote.simple.oteide.product.feature/feature.xml
index afe0ceb..5f80928 100644
--- a/org.eclipse.ote.simple.oteide.product.feature/feature.xml
+++ b/org.eclipse.ote.simple.oteide.product.feature/feature.xml
@@ -76,4 +76,11 @@
          version="0.0.0"
          unpack="false"/>
 
+   <plugin
+         id="org.eclipse.ote.simple.test.environment"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
 </feature>
diff --git a/org.eclipse.ote.simple.oteide.product.load/data/precompiledServerBundleList.txt b/org.eclipse.ote.simple.oteide.product.load/data/precompiledServerBundleList.txt
index 178be8d..50c9524 100644
--- a/org.eclipse.ote.simple.oteide.product.load/data/precompiledServerBundleList.txt
+++ b/org.eclipse.ote.simple.oteide.product.load/data/precompiledServerBundleList.txt
@@ -3,5 +3,6 @@
 					org.eclipse.ote.io
 					org.eclipse.ote.message.lookup
 					org.eclipse.ote.services.core
+					org.eclipse.ote.simple.test.environment
 					org.eclipse.ote.statemachine
 			
\ No newline at end of file
diff --git a/org.eclipse.ote.simple.oteide.product.parent/pom.xml b/org.eclipse.ote.simple.oteide.product.parent/pom.xml
index d2d000a..3b44c18 100644
--- a/org.eclipse.ote.simple.oteide.product.parent/pom.xml
+++ b/org.eclipse.ote.simple.oteide.product.parent/pom.xml
@@ -20,6 +20,7 @@
 		<module>../org.eclipse.ote.simple.oteide.product.load</module>
 		<module>../org.eclipse.ote.simple.oteide.product.feature</module>
 		<module>../org.eclipse.ote.simple.oteide.product</module>
+		<module>../org.eclipse.ote.simple.test.environment</module>
 	</modules>
 
 	
diff --git a/org.eclipse.ote.simple.test.environment/.classpath b/org.eclipse.ote.simple.test.environment/.classpath
new file mode 100644
index 0000000..eca7bdb
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.ote.simple.test.environment/.project b/org.eclipse.ote.simple.test.environment/.project
new file mode 100644
index 0000000..fd6c04c
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/.project
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.ote.simple.test.environment</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ds.core.builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/org.eclipse.ote.simple.test.environment/META-INF/MANIFEST.MF b/org.eclipse.ote.simple.test.environment/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..61be262
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/META-INF/MANIFEST.MF
@@ -0,0 +1,44 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: OTE Simple Test Environment
+Bundle-SymbolicName: org.eclipse.ote.simple.test.environment
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.eclipse.ote.simple.test.environment.internal.Activator
+Require-Bundle: org.eclipse.core.runtime
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Import-Package: com.fasterxml.jackson.annotation,
+ com.fasterxml.jackson.core,
+ com.fasterxml.jackson.databind,
+ com.fasterxml.jackson.databind.jsontype,
+ org.eclipse.osee.connection.service,
+ org.eclipse.osee.framework.core.data,
+ org.eclipse.osee.framework.core.enums,
+ org.eclipse.osee.framework.jdk.core.persistence,
+ org.eclipse.osee.framework.jdk.core.type,
+ org.eclipse.osee.framework.jdk.core.util,
+ org.eclipse.osee.framework.jdk.core.util.xml,
+ org.eclipse.osee.framework.logging,
+ org.eclipse.osee.ote.core,
+ org.eclipse.osee.ote.core.environment,
+ org.eclipse.osee.ote.core.environment.config,
+ org.eclipse.osee.ote.core.environment.interfaces,
+ org.eclipse.osee.ote.core.environment.jini,
+ org.eclipse.osee.ote.core.framework,
+ org.eclipse.osee.ote.core.framework.command,
+ org.eclipse.osee.ote.core.framework.event,
+ org.eclipse.osee.ote.core.framework.testrun,
+ org.eclipse.osee.ote.core.log,
+ org.eclipse.osee.ote.core.log.record,
+ org.eclipse.osee.ote.core.log.record.json,
+ org.eclipse.osee.ote.core.testPoint,
+ org.eclipse.osee.ote.message,
+ org.eclipse.osee.ote.message.enums,
+ org.eclipse.osee.ote.message.timer,
+ org.eclipse.osee.ote.server,
+ org.eclipse.ote.services.core
+Export-Package: org.eclipse.ote.simple.test.environment,
+ org.eclipse.ote.simple.test.environment.listener,
+ org.eclipse.ote.simple.test.environment.outfile,
+ org.eclipse.ote.simple.test.environment.outfile.xml
+Service-Component: OSGI-INF/*.xml
diff --git a/org.eclipse.ote.simple.test.environment/build.properties b/org.eclipse.ote.simple.test.environment/build.properties
new file mode 100644
index 0000000..5b359b5
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .
\ No newline at end of file
diff --git a/org.eclipse.ote.simple.test.environment/pom.xml b/org.eclipse.ote.simple.test.environment/pom.xml
new file mode 100644
index 0000000..25249cd
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/pom.xml
@@ -0,0 +1,17 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>org.eclipse.ote.build</groupId>
+		<artifactId>core</artifactId>
+		<version>1.0.0-SNAPSHOT</version>
+		<relativePath>../org.eclipse.ote.build/maven/core/</relativePath>
+	</parent>
+
+	<artifactId>org.eclipse.ote.simple.test.environment</artifactId>
+	<packaging>eclipse-plugin</packaging>
+	<name>Eclipse OTE Simple Test Environment (Incubation)</name>
+
+</project>
\ No newline at end of file
diff --git a/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestEnvironment.java b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestEnvironment.java
new file mode 100644
index 0000000..8458ec3
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestEnvironment.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Boeing.
+ * 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:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ote.simple.test.environment;
+
+import java.util.Set;
+
+import org.eclipse.osee.ote.core.IUserSession;
+import org.eclipse.osee.ote.core.TestScript;
+import org.eclipse.osee.ote.core.environment.ScriptControl;
+import org.eclipse.osee.ote.core.environment.interfaces.IRuntimeLibraryManager;
+import org.eclipse.osee.ote.message.MessageSystemTestEnvironment;
+import org.eclipse.osee.ote.message.enums.DataType;
+import org.eclipse.osee.ote.message.timer.RealTime;
+
+/**
+ * @author Andy Jury
+ */
+public class SimpleTestEnvironment extends MessageSystemTestEnvironment {
+
+   public SimpleTestEnvironment(IRuntimeLibraryManager runtimeLibManager) {
+      super(new SimpleTestEnvironmentFactory(new RealTime(), new ScriptControl(), new SimpleTestStation(), runtimeLibManager));
+   }
+
+   @Override
+   public boolean isPhysicalTypeAvailable(DataType physicalType) {
+      return false;
+   }
+
+   @Override
+   public Set<? extends DataType> getDataTypes() {
+      return null;
+   }
+
+   @Override
+   protected TestScript instantiateScriptClass(Class<?> scriptClass, IUserSession connection) {
+      return null;
+   }
+
+   @Override
+   public void singleStepEnv() {
+      // Intentionally empty block
+   }
+
+   @Override
+   public Object getModel(String modelClassName) {
+      return null;
+   }
+
+   @Override
+   protected void loadExternalDrivers() {
+      // Intentionally empty block
+   }
+}
diff --git a/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestEnvironmentFactory.java b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestEnvironmentFactory.java
new file mode 100644
index 0000000..7930e4f
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestEnvironmentFactory.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Boeing.
+ * 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:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ote.simple.test.environment;
+
+import org.eclipse.osee.ote.core.environment.ReportDataControl;
+import org.eclipse.osee.ote.core.environment.interfaces.IEnvironmentFactory;
+import org.eclipse.osee.ote.core.environment.interfaces.IReportData;
+import org.eclipse.osee.ote.core.environment.interfaces.IRuntimeLibraryManager;
+import org.eclipse.osee.ote.core.environment.interfaces.IScriptControl;
+import org.eclipse.osee.ote.core.environment.interfaces.ITestLogger;
+import org.eclipse.osee.ote.core.environment.interfaces.ITestStation;
+import org.eclipse.osee.ote.core.environment.interfaces.ITimerControl;
+import org.eclipse.osee.ote.core.framework.BaseCommandContextFactory;
+import org.eclipse.osee.ote.core.framework.BaseRunManager;
+import org.eclipse.osee.ote.core.framework.BaseTestLifecycleListenerProvider;
+import org.eclipse.osee.ote.core.framework.ICommandContextFactory;
+import org.eclipse.osee.ote.core.framework.IRunManager;
+import org.eclipse.osee.ote.core.framework.ITestLifecycleListenerProvider;
+import org.eclipse.osee.ote.core.framework.command.BaseCommandManager;
+import org.eclipse.osee.ote.core.framework.command.ICommandManager;
+import org.eclipse.osee.ote.core.framework.event.BaseEventDataProvider;
+import org.eclipse.osee.ote.core.framework.event.IEventDataProvider;
+import org.eclipse.osee.ote.core.framework.testrun.BaseTestRunListenerProviderFactory;
+import org.eclipse.osee.ote.core.framework.testrun.BaseTestRunManager;
+import org.eclipse.osee.ote.core.framework.testrun.ITestFactory;
+import org.eclipse.osee.ote.core.framework.testrun.ITestResultCollectorFactory;
+import org.eclipse.osee.ote.core.framework.testrun.ITestRunListenerProviderFactory;
+import org.eclipse.osee.ote.core.framework.testrun.ITestRunManager;
+import org.eclipse.osee.ote.core.log.TestLogger;
+import org.eclipse.ote.simple.test.environment.listener.SimpleGCListener;
+import org.eclipse.ote.simple.test.environment.listener.SimpleTestLifeCycleListener;
+
+/**
+ * @author Andy Jury
+ */
+public class SimpleTestEnvironmentFactory implements IEnvironmentFactory {
+
+   private final ITimerControl timerCtrl;
+   private final IScriptControl scriptCtrl;
+   private final IReportData reportData;
+   private final ITestLogger testLogger;
+
+   private final ICommandContextFactory cmdContextFactory;
+   private final ICommandManager cmdManager;
+   private final IRunManager runManager;
+   private final IRuntimeLibraryManager runtimeManager;
+   private final ITestStation station;
+
+   public SimpleTestEnvironmentFactory(ITimerControl timerCtrl, IScriptControl scriptControl, ITestStation station, IRuntimeLibraryManager runtimeManager) {
+
+      this.timerCtrl = timerCtrl;
+      this.scriptCtrl = scriptControl;
+      this.station = station;
+      this.runtimeManager = runtimeManager;
+      this.reportData = new ReportDataControl();
+      this.testLogger = new TestLogger();
+      this.cmdManager = new BaseCommandManager();
+      this.cmdContextFactory = new BaseCommandContextFactory();
+      this.runManager = createRunManager();
+
+      timerCtrl.setRunManager(runManager);
+      runManager.addListener(new SimpleTestLifeCycleListener());
+      runManager.addListener(new SimpleGCListener());
+   }
+
+   private BaseRunManager createRunManager() {
+      ITestRunManager testRunManager = createTestRunManager();
+      // Create test life-cycle manager
+      IEventDataProvider eventDataProvider = new BaseEventDataProvider();
+      ITestLifecycleListenerProvider lifeCycleListenerProvider = new BaseTestLifecycleListenerProvider(eventDataProvider);
+      ITestResultCollectorFactory resultCollectorFactory = new SimpleTestResultCollectorFactory();
+      return new BaseRunManager(testRunManager, lifeCycleListenerProvider, resultCollectorFactory);
+   }
+
+   private ITestRunManager createTestRunManager() {
+      ITestFactory testFactory = new SimpleTestFactory(runtimeManager);
+      ITestRunListenerProviderFactory baseTestRunListenerProviderFactory = new BaseTestRunListenerProviderFactory();
+      return new BaseTestRunManager(testFactory, baseTestRunListenerProviderFactory);
+   }
+
+   @Override
+   public ITimerControl getTimerControl() {
+      return timerCtrl;
+   }
+
+   @Override
+   public IScriptControl getScriptControl() {
+      return scriptCtrl;
+   }
+
+   @Override
+   public IReportData getReportDataControl() {
+      return reportData;
+   }
+
+   @Override
+   public ITestLogger getTestLogger() {
+      return testLogger;
+   }
+
+   @Override
+   public ICommandContextFactory getCommandContextFactory() {
+      return cmdContextFactory;
+   }
+
+   @Override
+   public ICommandManager getCommandManager() {
+      return cmdManager;
+   }
+
+   @Override
+   public IRunManager getRunManager() {
+      return runManager;
+   }
+
+   @Override
+   public ITestStation getTestStation() {
+      return station;
+   }
+
+   @Override
+   public IRuntimeLibraryManager getRuntimeManager() {
+      return runtimeManager;
+   }
+
+}
diff --git a/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestEnvironmentStartupFactory.java b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestEnvironmentStartupFactory.java
new file mode 100644
index 0000000..c5199f5
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestEnvironmentStartupFactory.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Boeing.
+ * 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:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ote.simple.test.environment;
+
+import java.io.IOException;
+import java.util.Hashtable;
+
+import org.eclipse.osee.ote.core.environment.interfaces.IRuntimeLibraryManager;
+import org.eclipse.osee.ote.message.MessageSystemTestEnvironment;
+import org.eclipse.osee.ote.server.TestEnvironmentFactory;
+import org.eclipse.ote.simple.test.environment.internal.Activator;
+
+/**
+ * @author Andy Jury
+ */
+public class SimpleTestEnvironmentStartupFactory implements TestEnvironmentFactory {
+
+   @Override
+   public MessageSystemTestEnvironment createEnvironment(IRuntimeLibraryManager runtimeLibraryManager) throws IOException {
+
+      SimpleTestEnvironment env = new SimpleTestEnvironment(runtimeLibraryManager);
+
+      Activator.getDefault().getBundle().getBundleContext().registerService(new String[] { SimpleTestEnvironment.class.getName() },
+            env,
+            new Hashtable<String, Object>());
+      return env;
+   }
+
+}
diff --git a/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestFactory.java b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestFactory.java
new file mode 100644
index 0000000..815e77a
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestFactory.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Boeing.
+ * 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:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ote.simple.test.environment;
+
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import org.eclipse.osee.framework.jdk.core.type.IPropertyStore;
+import org.eclipse.osee.framework.logging.OseeLog;
+import org.eclipse.osee.ote.core.TestScript;
+import org.eclipse.osee.ote.core.environment.TestEnvironment;
+import org.eclipse.osee.ote.core.environment.interfaces.IRuntimeLibraryManager;
+import org.eclipse.osee.ote.core.environment.jini.ITestEnvironmentCommandCallback;
+import org.eclipse.osee.ote.core.framework.command.RunTestsKeys;
+import org.eclipse.osee.ote.core.framework.testrun.ITestFactory;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.wiring.BundleWiring;
+
+/**
+ * @author Andy Jury
+ */
+public class SimpleTestFactory implements ITestFactory {
+
+   private final IRuntimeLibraryManager rtLibManager;
+
+   public SimpleTestFactory(IRuntimeLibraryManager rtLibManager) {
+      this.rtLibManager = rtLibManager;
+   }
+
+   @Override
+   public TestScript createInstance(TestEnvironment env, IPropertyStore properties) throws Exception {
+      String scriptClassStr = properties.get(RunTestsKeys.testClass.name());
+      Class<?> scriptClass = null;
+      Throwable scriptClassLoaderTh = null;
+      Throwable bundleClassLoaderTh = null;
+      try {
+         scriptClass = rtLibManager.loadFromScriptClassLoader(scriptClassStr);
+      } catch (Throwable th) {
+         scriptClassLoaderTh = th;
+      }
+      if (scriptClass == null) {
+         try {
+            scriptClass = loadClass(scriptClassStr);
+         } catch (Throwable th) {
+            bundleClassLoaderTh = th;
+         }
+      }
+      if (scriptClass == null) {
+         if (scriptClassLoaderTh != null) {
+            OseeLog.log(getClass(), Level.SEVERE, scriptClassLoaderTh);
+         }
+         if (bundleClassLoaderTh != null) {
+            OseeLog.log(getClass(), Level.SEVERE, bundleClassLoaderTh);
+         }
+      }
+
+      if (scriptClass == null) {
+         if (bundleClassLoaderTh != null) {
+            throw new Exception(bundleClassLoaderTh);
+         }
+         if (scriptClassLoaderTh != null) {
+            throw new Exception(scriptClassLoaderTh);
+         }
+      }
+      Constructor<?> constructor = scriptClass.getConstructor(new Class[] { SimpleTestEnvironment.class, ITestEnvironmentCommandCallback.class });
+      return (TestScript) constructor.newInstance(env, null);
+   }
+
+   List<BundleWiring> fastCache = new ArrayList<BundleWiring>();
+
+   @SuppressWarnings("rawtypes")
+   public Class loadClass(String classToLoad) throws ClassNotFoundException {
+      Bundle[] allBundles = FrameworkUtil.getBundle(getClass()).getBundleContext().getBundles();
+
+      for (BundleWiring wiring : fastCache) {
+         try {
+            Class clazz = wiring.getClassLoader().loadClass(classToLoad);
+            // System.out.println("loaded " + classToLoad + " from " +
+            // wiring.getBundle().getSymbolicName());
+            return clazz;
+         } catch (Throwable ex) {
+         }
+      }
+
+      for (Bundle bundle : allBundles) {
+         BundleWiring wiring = bundle.adapt(BundleWiring.class);
+         if (wiring != null) {
+            try {
+               Class clazz = wiring.getClassLoader().loadClass(classToLoad);
+               // System.out.println("loaded " + classToLoad + " from " +
+               // wiring.getBundle().getSymbolicName());
+               fastCache.add(wiring);
+               return clazz;
+            } catch (Throwable ex) {
+            }
+         }
+      }
+      throw new ClassNotFoundException(classToLoad);
+   }
+}
diff --git a/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestResultCollector.java b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestResultCollector.java
new file mode 100644
index 0000000..c3bf765
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestResultCollector.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Boeing.
+ * 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:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ote.simple.test.environment;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.osee.framework.core.enums.OteRunTestsKeys;
+import org.eclipse.osee.framework.jdk.core.type.IPropertyStore;
+import org.eclipse.osee.framework.jdk.core.util.Strings;
+import org.eclipse.osee.framework.logging.ILoggerListener;
+import org.eclipse.osee.framework.logging.OseeLog;
+import org.eclipse.osee.ote.core.environment.TestEnvironment;
+import org.eclipse.osee.ote.core.environment.interfaces.ITestLogger;
+import org.eclipse.osee.ote.core.framework.IRunManager;
+import org.eclipse.osee.ote.core.framework.testrun.ITestResultCollector;
+import org.eclipse.osee.ote.core.log.record.PropertyStoreRecord;
+import org.eclipse.osee.ote.core.log.record.TestRecord;
+import org.eclipse.ote.simple.test.environment.outfile.ScriptJsonOutLogHandler;
+import org.eclipse.ote.simple.test.environment.outfile.ScriptStreamOutLogHandler;
+
+/**
+ * @author Andy Jury
+ */
+public class SimpleTestResultCollector implements ITestResultCollector {
+   private ILoggerListener loggerListener;
+   private ScriptStreamOutLogHandler handlerStream;
+   private ScriptJsonOutLogHandler jsonHandler;
+   private final Matcher fileNumberMatcher = Pattern.compile("(.*)\\.(\\d+)\\.tmo").matcher("");
+
+   @Deprecated
+   @Override
+   public void initialize(IPropertyStore propertyStore, TestEnvironment testEnvironment) throws Exception {
+      initialize(propertyStore, testEnvironment.getOutDir(), testEnvironment.getLogger(), testEnvironment.getRunManager());
+   }
+
+   public void initialize(IPropertyStore propertyStore, File outfileDirectory, ITestLogger testLogger, IRunManager runManager) throws IOException {
+      String serverOutfilePath;
+      String value = propertyStore.get(OteRunTestsKeys.serverOutfileFolderOverride.name());
+      final String testClass = propertyStore.get(OteRunTestsKeys.testClass.name());
+      File folderPath = new File(value);
+      if (folderPath.exists() && folderPath.isDirectory()) {
+         int number = getHighestExistingFileNumber(folderPath, testClass);
+         number++;
+         if (number > 0) {
+            serverOutfilePath = new File(folderPath, testClass + "." + number + ".tmo").getAbsolutePath();
+         } else {
+            serverOutfilePath = new File(folderPath, testClass + ".tmo").getAbsolutePath();
+         }
+      } else {
+         serverOutfilePath = File.createTempFile(propertyStore.get(OteRunTestsKeys.testClass.name()), ".tmo", outfileDirectory).getPath();
+      }
+      propertyStore.put(OteRunTestsKeys.serverOutfilePath.name(), serverOutfilePath);
+      String distributionStatement = propertyStore.get("distributionStatement");
+      if (Strings.isValid(distributionStatement)) {
+         handlerStream = new ScriptStreamOutLogHandler(new File(propertyStore.get(OteRunTestsKeys.serverOutfilePath.name())), distributionStatement);
+         jsonHandler = new ScriptJsonOutLogHandler(new File(propertyStore.get(OteRunTestsKeys.serverOutfilePath.name())), distributionStatement);
+      } else {
+         handlerStream = new ScriptStreamOutLogHandler(new File(propertyStore.get(OteRunTestsKeys.serverOutfilePath.name())));
+         jsonHandler = new ScriptJsonOutLogHandler(new File(propertyStore.get(OteRunTestsKeys.serverOutfilePath.name())));
+      }
+      testLogger.addHandler(handlerStream);
+      testLogger.addHandler(jsonHandler);
+      loggerListener = new DefaultLoggingListener(testLogger, runManager);
+      try {
+         TestRecord.setLocationLoggingOn(true);
+         String loggingLevel = propertyStore.get("logging.level");
+         if (loggingLevel.length() > 0) {
+            Level levelToSet = Level.parse(loggingLevel);
+            handlerStream.setLevel(levelToSet);
+            jsonHandler.setLevel(levelToSet);
+            if (levelToSet.intValue() >= Level.WARNING.intValue()) {
+               TestRecord.setLocationLoggingOn(false);
+            }
+         }
+      } catch (IllegalArgumentException ex) {
+         OseeLog.log(SimpleTestResultCollector.class, Level.SEVERE, "Unable to set outfile log level.", ex);
+      }
+      testLogger.log(new PropertyStoreRecord(propertyStore));
+      OseeLog.registerLoggerListener(loggerListener);
+   }
+
+   private int getHighestExistingFileNumber(final File folder, final String fileName) {
+      String[] files = folder.list(new FilenameFilter() {
+         @Override
+         public boolean accept(File dir, String name) {
+            return name.contains(fileName);
+         }
+      });
+      if (files.length == 0) {
+         return 0;
+      }
+      int highestNumber = 1;
+      for (String file : files) {
+         fileNumberMatcher.reset(file);
+         if (fileNumberMatcher.find()) {
+            String num = fileNumberMatcher.group(2);
+            try {
+               int newNum = Integer.parseInt(num);
+               if (newNum > highestNumber) {
+                  highestNumber = newNum;
+               }
+            } catch (NumberFormatException ex) {
+               // we'll just use the highest detected number or 1 in this case
+            }
+         }
+      }
+      return highestNumber;
+   }
+
+   @Deprecated
+   @Override
+   public void dispose(TestEnvironment testEnvironment) throws Exception {
+      dispose(testEnvironment.getLogger());
+   }
+
+   public void dispose(ITestLogger logger) {
+      try {
+         handlerStream.flushRecords();
+         handlerStream.close();
+         jsonHandler.flushRecords();
+         jsonHandler.close();
+      } catch (Throwable ex) {
+         ex.printStackTrace();
+      } finally {
+         logger.removeHandler(handlerStream);
+         logger.removeHandler(jsonHandler);
+         handlerStream = null;
+         jsonHandler = null;
+         OseeLog.unregisterLoggerListener(loggerListener);
+         loggerListener = null;
+      }
+   }
+
+   private static final class DefaultLoggingListener implements ILoggerListener {
+      private ITestLogger testLogger;
+      private IRunManager runManager;
+
+      public DefaultLoggingListener(ITestLogger testLogger, IRunManager runManager) {
+         this.testLogger = testLogger;
+         this.runManager = runManager;
+      }
+
+      @Override
+      public void log(String loggerName, Level level, String message, Throwable th) {
+         if (testLogger != null && !runManager.isAborted()) {
+            testLogger.log(level, message, th);
+         }
+      }
+   }
+}
diff --git a/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestResultCollectorFactory.java b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestResultCollectorFactory.java
new file mode 100644
index 0000000..57ee073
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestResultCollectorFactory.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Boeing.
+ * 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:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ote.simple.test.environment;
+
+import org.eclipse.osee.ote.core.framework.testrun.ITestResultCollector;
+import org.eclipse.osee.ote.core.framework.testrun.ITestResultCollectorFactory;
+
+/**
+ * @author Roberto E. Escobar
+ * @author Andy Jury
+ */
+public class SimpleTestResultCollectorFactory implements ITestResultCollectorFactory {
+
+   @Override
+   public ITestResultCollector createCollector() {
+      return new SimpleTestResultCollector();
+   }
+}
diff --git a/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestStation.java b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestStation.java
new file mode 100644
index 0000000..51f07ab
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/SimpleTestStation.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Boeing.
+ * 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:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ote.simple.test.environment;
+
+import java.util.List;
+
+import org.eclipse.osee.ote.core.environment.interfaces.IOTypeDefinition;
+import org.eclipse.osee.ote.core.environment.interfaces.IOTypeHandlerDefinition;
+import org.eclipse.osee.ote.core.environment.interfaces.ITestStation;
+
+/**
+ * @author Andy Jury
+ */
+public class SimpleTestStation implements ITestStation {
+
+   private String outletIp;
+   private int outletPort;
+   protected String vmeConnectionName;
+
+   public SimpleTestStation() {
+      this.vmeConnectionName = "NA";
+   }
+
+   @Override
+   public List<IOTypeHandlerDefinition> getSupportedDriverTypes() {
+      return null;
+   }
+
+   @Override
+   public boolean isPhysicalTypeAvailable(IOTypeDefinition type) {
+      return false;
+   }
+
+   @Override
+   public String getOutletIp() {
+      return outletIp;
+   }
+
+   @Override
+   public void setOutletIp(String outletIp) {
+      this.outletIp = outletIp;
+   }
+
+   @Override
+   public int getOutletPort() {
+      return outletPort;
+   }
+
+   @Override
+   public void setOutletPort(int outletPort) {
+      this.outletPort = outletPort;
+   }
+
+   @Override
+   public String getVmeConnectionName() {
+      return vmeConnectionName;
+   }
+
+   @Override
+   public void turnPowerSupplyOnOff(boolean turnOn) {
+      // Intentionally empty block
+   }
+}
diff --git a/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/internal/Activator.java b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/internal/Activator.java
new file mode 100644
index 0000000..55e2a62
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/internal/Activator.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Boeing.
+ * 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:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ote.simple.test.environment.internal;
+
+import org.eclipse.core.runtime.Plugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * @author Andy Jury
+ * 
+ *         The activator class controls the plug-in life cycle
+ */
+public class Activator extends Plugin {
+
+   public static final String PLUGIN_ID = "org.eclipse.ote.simple.test.environment";
+
+   private static Activator plugin;
+
+   public Activator() {
+   }
+
+   @Override
+   public void start(BundleContext context) throws Exception {
+      super.start(context);
+      plugin = this;
+   }
+
+   @Override
+   public void stop(BundleContext context) throws Exception {
+      plugin = null;
+   }
+
+   /**
+    * Returns the shared instance
+    *
+    * @return the shared instance
+    */
+   public static Activator getDefault() {
+      return plugin;
+   }
+
+}
diff --git a/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/listener/SimpleGCListener.java b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/listener/SimpleGCListener.java
new file mode 100644
index 0000000..1d31526
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/listener/SimpleGCListener.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Boeing.
+ * 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:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ote.simple.test.environment.listener;
+
+import java.util.List;
+import java.util.logging.Level;
+
+import org.eclipse.osee.framework.logging.OseeLog;
+import org.eclipse.osee.ote.core.GCHelper;
+import org.eclipse.osee.ote.core.OteLevel;
+import org.eclipse.osee.ote.core.TestScript;
+import org.eclipse.osee.ote.core.environment.TestEnvironment;
+import org.eclipse.osee.ote.core.framework.IMethodResult;
+import org.eclipse.osee.ote.core.framework.ITestLifecycleListener;
+import org.eclipse.osee.ote.core.framework.MethodResultImpl;
+import org.eclipse.osee.ote.core.framework.ReturnCode;
+import org.eclipse.osee.ote.core.framework.event.IEventData;
+
+/**
+ * @author Andy Jury
+ */
+public class SimpleGCListener implements ITestLifecycleListener {
+   /**
+    * @return MB of used memory
+    */
+   private static long getUsedMemory() {
+      return (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1000000;
+   }
+
+   private long preinstantiationMem;
+
+   @Override
+   public IMethodResult preInstantiation(IEventData eventData, TestEnvironment env) {
+      preinstantiationMem = getUsedMemory();
+      return new MethodResultImpl(ReturnCode.OK);
+   }
+
+   @Override
+   public IMethodResult postInstantiation(IEventData eventData, TestEnvironment env) {
+      OseeLog.log(getClass(), OteLevel.TEST_EVENT, "Test server memory at script start: " + preinstantiationMem + "MB");
+      return new MethodResultImpl(ReturnCode.OK);
+   }
+
+   @Override
+   public IMethodResult preDispose(IEventData eventData, TestEnvironment env) {
+      sendMemoryLeakInformationToClient(eventData.getTest());
+      return new MethodResultImpl(ReturnCode.OK);
+   }
+
+   @Override
+   public IMethodResult postDispose(IEventData eventData, TestEnvironment env) {
+      Runtime.getRuntime().gc();
+      return new MethodResultImpl(ReturnCode.OK);
+   }
+
+   private void sendMemoryLeakInformationToClient(TestScript test) {
+      @SuppressWarnings("unchecked")
+      List<Object> tests = GCHelper.getGCHelper().getInstancesOfType(TestScript.class);
+      if (tests.size() > 2) {
+         String message = buildMemoryLeakString(tests, test);
+         try {
+            test.prompt(message);
+         } catch (InterruptedException ex) {
+            OseeLog.log(SimpleGCListener.class, Level.SEVERE, "Failed to send prompt data back to client.\n" + message);
+         }
+      }
+   }
+
+   private String buildMemoryLeakString(List<Object> tests, TestScript test) {
+      StringBuilder sb = new StringBuilder();
+      sb.append("Tests that are likely memory leaks:\n");
+      for (Object obj : tests) {
+         if (obj != test) {
+            sb.append("\t");
+            sb.append(obj.toString());
+            sb.append("\n");
+         }
+      }
+      sb.append("For more information type: 'objinst -gc'\n");
+      return sb.toString();
+   }
+
+}
diff --git a/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/listener/SimpleTestLifeCycleListener.java b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/listener/SimpleTestLifeCycleListener.java
new file mode 100644
index 0000000..1507f5e
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/listener/SimpleTestLifeCycleListener.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Boeing.
+ * 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:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ote.simple.test.environment.listener;
+
+import java.util.Date;
+import java.util.logging.Level;
+
+import org.eclipse.osee.framework.logging.BaseStatus;
+import org.eclipse.osee.framework.logging.OseeLog;
+import org.eclipse.osee.ote.core.OteLevel;
+import org.eclipse.osee.ote.core.TestScript;
+import org.eclipse.osee.ote.core.environment.TestEnvironment;
+import org.eclipse.osee.ote.core.framework.IMethodResult;
+import org.eclipse.osee.ote.core.framework.ITestLifecycleListener;
+import org.eclipse.osee.ote.core.framework.MethodResultImpl;
+import org.eclipse.osee.ote.core.framework.ReturnCode;
+import org.eclipse.osee.ote.core.framework.event.IEventData;
+import org.eclipse.ote.simple.test.environment.SimpleTestEnvironment;
+import org.eclipse.ote.simple.test.environment.outfile.xml.SystemInfo;
+import org.eclipse.ote.simple.test.environment.outfile.xml.TestPointResults;
+import org.eclipse.ote.simple.test.environment.outfile.xml.TimeSummary;
+
+/**
+ * @author Andrew M. Finkbeiner
+ * @author Andy Jury
+ */
+public final class SimpleTestLifeCycleListener implements ITestLifecycleListener {
+
+   private Date startTime;
+
+   public SimpleTestLifeCycleListener() {
+   }
+
+   @Override
+   public IMethodResult postDispose(IEventData eventData, TestEnvironment env) {
+      return new MethodResultImpl(ReturnCode.OK);
+   }
+
+   @Override
+   public IMethodResult postInstantiation(IEventData eventData, TestEnvironment env) {
+      eventData.getTest().addTestRunListener(new SimpleTestRunListener(env));
+      eventData.getTest().addScriptSummary(env.getRuntimeManager());
+      startTime = new Date();
+      return new MethodResultImpl(ReturnCode.OK);
+   }
+
+   /**
+    * The contract we're assuming is that preDispose is too late for messaging
+    * to still be done after the conclusion of
+    * the script running. To do that use postRun from ITestRunListener.
+    */
+
+   @SuppressWarnings("deprecation")
+   @Override
+   public IMethodResult preDispose(IEventData eventData, TestEnvironment env) {
+      MethodResultImpl result = new MethodResultImpl(ReturnCode.OK);
+
+      try {
+         addTimeSummaryToScript(eventData.getTest());
+
+         addTestPointSummaryToScriptLog(eventData.getTest());
+
+         addSystemInfoToScriptLog(eventData.getTest());
+
+         eventData.getTest().getLogger().log(eventData.getTest().getScriptResultRecord());
+
+         OseeLog.log(SimpleTestEnvironment.class, OteLevel.TEST_EVENT, String.format("%s Pass[%d] Fail[%d] Aborted[%b]",
+               eventData.getTest().getClass().getSimpleName(), eventData.getTest().getPasses(),
+               eventData.getTest().getFails(), eventData.getTest().isAborted()));
+
+         env.onScriptComplete();
+      } catch (InterruptedException ex) {
+         result = new MethodResultImpl(ReturnCode.ERROR);
+         result.addStatus(new BaseStatus(SimpleTestEnvironment.class.getName(), Level.SEVERE, ex));
+      }
+
+      return result;
+   }
+
+   private void addTimeSummaryToScript(TestScript test) {
+      final Date endTime = new Date();
+      final long elapsedTime = endTime.getTime() - startTime.getTime();
+      long seconds = elapsedTime / 1000;
+      long minutes = seconds / 60;
+      seconds = seconds % 60;
+      long hours = minutes / 60;
+      minutes = minutes % 60;
+      final String elapsed = String.format("%d:%02d:%02d", hours, minutes, seconds);
+
+      TimeSummary timeSummary = new TimeSummary(elapsedTime, startTime, endTime, elapsed);
+      test.addScriptSummary(timeSummary);
+
+   }
+
+   private void addTestPointSummaryToScriptLog(final TestScript test) {
+
+      TestPointResults testPointResults = new TestPointResults(test.getPasses(), test.getFails(), test.isAborted());
+      test.addScriptSummary(testPointResults);
+
+   }
+
+   private void addSystemInfoToScriptLog(TestScript test) {
+
+      SystemInfo systemInfo = new SystemInfo();
+      test.addScriptSummary(systemInfo);
+
+   }
+
+   @SuppressWarnings("deprecation")
+   @Override
+   public IMethodResult preInstantiation(IEventData eventData, TestEnvironment env) {
+      env.onScriptSetup();
+      ((SimpleTestEnvironment) env).notifyPreInstantiationListeners();
+      return new MethodResultImpl(ReturnCode.OK);
+   }
+
+}
diff --git a/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/listener/SimpleTestRunListener.java b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/listener/SimpleTestRunListener.java
new file mode 100644
index 0000000..9d7f790
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/listener/SimpleTestRunListener.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Boeing.
+ * 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:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ote.simple.test.environment.listener;
+
+import java.util.logging.Level;
+
+import org.eclipse.osee.framework.logging.BaseStatus;
+import org.eclipse.osee.framework.logging.OseeLog;
+import org.eclipse.osee.ote.core.IUserSession;
+import org.eclipse.osee.ote.core.OSEEPerson1_4;
+import org.eclipse.osee.ote.core.OTESessionManager;
+import org.eclipse.osee.ote.core.environment.TestEnvironment;
+import org.eclipse.osee.ote.core.environment.config.ScriptVersionConfig;
+import org.eclipse.osee.ote.core.environment.interfaces.IScriptInitializer;
+import org.eclipse.osee.ote.core.framework.IMethodResult;
+import org.eclipse.osee.ote.core.framework.MethodResultImpl;
+import org.eclipse.osee.ote.core.framework.ReturnCode;
+import org.eclipse.osee.ote.core.framework.command.RunTestsKeys;
+import org.eclipse.osee.ote.core.framework.event.IEventData;
+import org.eclipse.osee.ote.core.framework.testrun.ITestRunListener;
+import org.eclipse.osee.ote.core.log.record.ScriptConfigRecord;
+import org.eclipse.osee.ote.core.log.record.ScriptInitRecord;
+import org.eclipse.ote.services.core.ServiceUtility;
+import org.eclipse.ote.simple.test.environment.SimpleTestEnvironment;
+
+/**
+ * @author Andrew M. Finkbeiner
+ * @author Andy Jury
+ */
+public class SimpleTestRunListener implements ITestRunListener {
+
+   private final TestEnvironment env;
+
+   private OSEEPerson1_4 validUser = new OSEEPerson1_4("ERROR", "ERROR", "ERROR");
+
+   public SimpleTestRunListener(TestEnvironment env) {
+      this.env = env;
+   }
+
+   /**
+    * The contract we're assuming is that postRun will allow for messaging to
+    * still be done after the conclusion of the
+    * script running.
+    */
+   @SuppressWarnings("deprecation")
+   @Override
+   public IMethodResult postRun(IEventData eventData) {
+
+      eventData.getTest().endTest();
+      eventData.getTest().processScriptcompleteListeners();
+
+      if (env.getScriptCtrl().isLocked()) {
+         env.getScriptCtrl().unlock();
+      }
+
+      return new MethodResultImpl(ReturnCode.OK);
+   }
+
+   @Override
+   public IMethodResult postTestCase(IEventData eventData) {
+      return new MethodResultImpl(ReturnCode.OK);
+   }
+
+   @Override
+   public IMethodResult preRun(IEventData eventData) {
+      // from TestScript
+      MethodResultImpl result = new MethodResultImpl(ReturnCode.OK);
+      env.getScriptCtrl().setScriptReady(true);
+
+      ScriptConfigRecord scriptConfig = new ScriptConfigRecord(eventData.getTest());
+      try {
+         OTESessionManager sessionManager = ServiceUtility.getService(OTESessionManager.class);
+         IUserSession session = sessionManager.getActiveUser();
+         validUser = session.getUser();
+      } catch (Exception ex) {
+         OseeLog.log(getClass(), Level.WARNING, "Failed to get the user from the client OSEE", ex);
+      }
+      scriptConfig.setExecutedBy(validUser.getName(), validUser.getEmail(), validUser.getId());
+      ScriptVersionConfig version = new ScriptVersionConfig(eventData.getProperties().get(RunTestsKeys.version_repositoryType.name()),
+            eventData.getProperties().get(RunTestsKeys.version_location.name()),
+            eventData.getProperties().get(RunTestsKeys.version_revision.name()),
+            eventData.getProperties().get(RunTestsKeys.version_lastAuthor.name()),
+            eventData.getProperties().get(RunTestsKeys.version_lastModificationDate.name()),
+            eventData.getProperties().get(RunTestsKeys.version_modifiedFlag.name()));
+      scriptConfig.setScriptVersion(version);
+      eventData.getTest().getLogger().log(scriptConfig);
+
+      env.getScriptCtrl().lock();
+
+      try {
+         eventData.getTest().getLogger().log(new ScriptInitRecord(eventData.getTest(), true)); // Outfile
+                                                                                               // logging
+         IScriptInitializer initializer = eventData.getTest().getScriptInitializer();
+         if (initializer != null) {
+            initializer.doScriptInitialProcessing();
+         }
+         eventData.getTest().getLogger().log(new ScriptInitRecord(eventData.getTest(), false));
+
+      } catch (Exception ex) {
+         if (result.getReturnCode() == ReturnCode.OK) {
+            result.setReturnCode(ReturnCode.ERROR);
+            result.addStatus(new BaseStatus(SimpleTestEnvironment.class.getName(), Level.SEVERE, ex));
+         } else {
+            result.addStatus(new BaseStatus(SimpleTestEnvironment.class.getName(), Level.SEVERE, ex));
+         }
+      }
+
+      return result;
+   }
+
+   @Override
+   public IMethodResult preTestCase(IEventData eventData) {
+      return new MethodResultImpl(ReturnCode.OK);
+   }
+
+}
diff --git a/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/outfile/ScriptJsonOutLogHandler.java b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/outfile/ScriptJsonOutLogHandler.java
new file mode 100644
index 0000000..4263990
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/outfile/ScriptJsonOutLogHandler.java
@@ -0,0 +1,253 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Boeing.
+ * 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:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ote.simple.test.environment.outfile;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Handler;
+import java.util.logging.LogRecord;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import org.eclipse.osee.framework.jdk.core.persistence.XmlizableStream;
+import org.eclipse.osee.ote.core.environment.interfaces.ITestPoint;
+import org.eclipse.osee.ote.core.log.record.ScriptResultRecord;
+import org.eclipse.osee.ote.core.log.record.TestPointRecord;
+import org.eclipse.osee.ote.core.log.record.json.LogRecordModule;
+import org.eclipse.osee.ote.core.testPoint.CheckGroup;
+import org.eclipse.osee.ote.core.testPoint.CheckPoint;
+import org.eclipse.osee.ote.core.testPoint.Operation;
+import org.eclipse.ote.simple.test.environment.outfile.xml.TestPointResults;
+import org.eclipse.ote.simple.test.environment.outfile.xml.TimeSummary;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder;
+
+/**
+ * @author Andy Jury
+ */
+public class ScriptJsonOutLogHandler extends Handler {
+   private Map<String, Object> minimum = new HashMap<String, Object>();
+   private final ObjectMapper mapper = new ObjectMapper();
+   private File outfile;
+   private ZipOutputStream zip;
+   private String distrStatement;
+
+   public ScriptJsonOutLogHandler(final File outFile, final String distributionStatement) {
+      super();
+      outfile = outFile;
+      distrStatement = distributionStatement;
+   }
+
+   public ScriptJsonOutLogHandler(File outFile) {
+      this(outFile, "DISTRO_STATEMENT_HERE");
+   }
+
+   @Override
+   public synchronized void publish(final LogRecord logRecord) {
+      if (isLoggable(logRecord)) {
+         try {
+            publisihMinimum(logRecord);
+         } catch (Exception ex) {
+            logError(ex);
+         }
+      }
+   }
+
+   private void publisihMinimum(LogRecord logRecord) {
+      try {
+         minimum.put("machineName", InetAddress.getLocalHost().getHostName());
+      } catch (UnknownHostException ex) {
+         logError(ex, "Unable to determine machine name");
+      }
+      if (logRecord instanceof ScriptResultRecord) {
+         ScriptResultRecord srr = (ScriptResultRecord) logRecord;
+         minimum.put("ScriptName", logRecord.getMessage());
+         for (XmlizableStream rec : srr.getResults()) {
+            if (rec instanceof TimeSummary) {
+               TimeSummary ts = (TimeSummary) rec;
+               minimum.put("elapsedTime", ts.getElapsedTime());
+               minimum.put("startTime", ts.getStartTime());
+               minimum.put("endTime", ts.getEndTime());
+            } else if (rec instanceof TestPointResults) {
+               Map<String, Object> results = new HashMap<String, Object>();
+               results.put("passes", ((TestPointResults) rec).getPasses());
+               results.put("fails", ((TestPointResults) rec).getFails());
+               results.put("aborted", ((TestPointResults) rec).isAborted());
+               results.put("total", ((TestPointResults) rec).getTotal());
+               minimum.put("results", results);
+            }
+         }
+      } else if (logRecord instanceof TestPointRecord) {
+         @SuppressWarnings("unchecked")
+         List<Object> testPoints = (List<Object>) minimum.get("testPoints");
+         if (testPoints == null) {
+            testPoints = new ArrayList<Object>();
+            minimum.put("testPoints", testPoints);
+         }
+         ITestPoint testPoint = ((TestPointRecord) logRecord).getTestPoint();
+         int number = ((TestPointRecord) logRecord).getNumber();
+         boolean overall = testPoint.isPass();
+         handleTestPoint(testPoint, testPoints, number, "", overall, String.valueOf(number));
+      }
+   }
+
+   private void handleTestPoint(ITestPoint testPoint, List<Object> testPoints, int number, String groupName, boolean overallPass, String levelNum) {
+      if (testPoint instanceof CheckPoint) {
+         Map<String, Object> point = convertCheckPoint((CheckPoint) testPoint, number, groupName, overallPass, levelNum);
+         testPoints.add(point);
+      } else if (testPoint instanceof CheckGroup) {
+         CheckGroup group = (CheckGroup) testPoint;
+         ArrayList<ITestPoint> groupPoints = group.getTestPoints();
+         Operation op = group.getOperation();
+         String curGroupName = group.getGroupName() + " [" + op.getName() + "]";
+         for (int i = 0; i < groupPoints.size(); i++) {
+            ITestPoint tp = groupPoints.get(i);
+            handleTestPoint(tp, testPoints, number, curGroupName, overallPass, levelNum + "." + (i + 1));
+         }
+      }
+   }
+
+   private Map<String, Object> convertCheckPoint(CheckPoint checkPoint, int number, String groupName, boolean overallPass, String levelNum) {
+      Map<String, Object> tpMap = new HashMap<String, Object>();
+      tpMap.put("name", checkPoint.getTestPointName());
+      tpMap.put("expected", checkPoint.getExpected());
+      tpMap.put("actual", checkPoint.getActual());
+      tpMap.put("pass", checkPoint.isPass());
+      tpMap.put("number", number);
+      tpMap.put("overall", overallPass);
+      if (!groupName.isEmpty()) {
+         tpMap.put("groupName", groupName);
+      }
+      tpMap.put("tpLevel", levelNum);
+      return tpMap;
+   }
+
+   private boolean prepareToFlush() {
+      setupJson();
+      return setupOutputFile();
+   }
+
+   private void setupJson() {
+      mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
+      mapper.configure(MapperFeature.AUTO_DETECT_FIELDS, false);
+      mapper.configure(MapperFeature.AUTO_DETECT_GETTERS, false);
+      mapper.configure(MapperFeature.AUTO_DETECT_IS_GETTERS, false);
+      mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
+      mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+      mapper.registerModule(new LogRecordModule());
+      TypeResolverBuilder<?> typeResolver = new TmoTypeResolverBuilder();
+      typeResolver.init(JsonTypeInfo.Id.CLASS, null);
+      typeResolver.inclusion(JsonTypeInfo.As.PROPERTY);
+      typeResolver.typeProperty("@CLASS");
+      mapper.setDefaultTyping(typeResolver);
+   }
+
+   private boolean setupOutputFile() {
+      boolean result = true;
+      String path;
+      try {
+         path = outfile.getCanonicalPath();
+         path = path.substring(0, path.length() - 1) + 'z';
+         File file = new File(path);
+         FileOutputStream fos;
+         try {
+            fos = new FileOutputStream(file);
+            BufferedOutputStream bos = new BufferedOutputStream(fos);
+            zip = new ZipOutputStream(bos);
+         } catch (FileNotFoundException ex) {
+            logError(ex, "Zip file creation failed");
+            result = false;
+         }
+      } catch (IOException ex) {
+         logError(ex, "Failed to get canaonical path from outFile");
+         result = false;
+      }
+      return result;
+   }
+
+   public synchronized void flushRecords() {
+      if (prepareToFlush()) {
+         writeZipEntry("Minimum", minimum);
+         writeZipEntry("DistributionStatement", distrStatement);
+      }
+   }
+
+   private void writeZipEntry(final String basename, final Object object) {
+      try {
+         byte[] buffer = new byte[1024];
+         File temp = File.createTempFile(basename, "json");
+         mapper.writeValue(temp, object);
+         FileInputStream input = new FileInputStream(temp);
+         ZipEntry entry = new ZipEntry(basename + ".json");
+         zip.putNextEntry(entry);
+         int len;
+         while ((len = input.read(buffer)) > 0) {
+            zip.write(buffer, 0, len);
+         }
+         input.close();
+         temp.delete();
+      } catch (JsonGenerationException ex) {
+         logError(ex);
+      } catch (JsonMappingException ex) {
+         logError(ex);
+      } catch (IOException ex) {
+         logError(ex);
+      }
+   }
+
+   @Override
+   public void close() throws SecurityException {
+      try {
+         zip.close();
+      } catch (Exception ex) {
+         logError(ex);
+      }
+   }
+
+   @Override
+   public void flush() {
+      // don't call this method
+   }
+
+   private void logError(final Exception ex) {
+      logError(ex);
+   }
+
+   private void logError(final Exception ex, final String message) {
+      if (message != null && message.trim().length() > 0) {
+         System.err.println(message);
+      }
+      if (ex != null) {
+         ex.printStackTrace();
+      } else {
+         Throwable throwable = new Throwable();
+         throwable.printStackTrace();
+      }
+   }
+}
\ No newline at end of file
diff --git a/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/outfile/ScriptStreamOutLogHandler.java b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/outfile/ScriptStreamOutLogHandler.java
new file mode 100644
index 0000000..656e0e8
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/outfile/ScriptStreamOutLogHandler.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Boeing.
+ * 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:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ote.simple.test.environment.outfile;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.eclipse.osee.framework.jdk.core.util.xml.XMLStreamWriterPrettyPrint;
+import org.eclipse.osee.framework.logging.OseeLog;
+import org.eclipse.osee.ote.core.environment.TestEnvironment;
+import org.eclipse.osee.ote.core.log.record.ScriptInitRecord;
+import org.eclipse.osee.ote.core.log.record.ScriptResultRecord;
+import org.eclipse.osee.ote.core.log.record.TestCaseRecord;
+import org.eclipse.osee.ote.core.log.record.TestRecord;
+import org.eclipse.osee.ote.core.log.record.TraceRecordEnd;
+
+/**
+ * @author Andrew M. Finkbeiner
+ * @author Andy Jury
+ */
+public class ScriptStreamOutLogHandler extends Handler {
+   private final List<LogRecord> records;
+   private OutputStream outputStream;
+   private XMLStreamWriter writer;
+
+   public ScriptStreamOutLogHandler(File outFile, String distributionStatement) {
+      super();
+      records = new ArrayList<LogRecord>();
+      try {
+         outputStream = new BufferedOutputStream(new FileOutputStream(outFile), 8192 * 16);
+         XMLOutputFactory factory = XMLOutputFactory.newInstance();
+         writer = new XMLStreamWriterPrettyPrint(factory.createXMLStreamWriter(outputStream));
+         writer.writeStartDocument("1.0");
+         writer.writeComment(distributionStatement);
+         writer.writeStartElement("TestScript");
+         OseeLog.log(TestEnvironment.class, Level.FINE, outFile.getAbsolutePath());
+      } catch (FileNotFoundException ex) {
+         OseeLog.log(TestEnvironment.class, Level.SEVERE, ex);
+      } catch (XMLStreamException ex) {
+         OseeLog.log(TestEnvironment.class, Level.SEVERE, ex);
+      }
+   }
+
+   public ScriptStreamOutLogHandler(File outFile) {
+      this(outFile, "DISTRO_STATEMENT_HERE");
+   }
+
+   public String getXSLTransformName() {
+      return "outputNormal.xsl";
+   }
+
+   @Override
+   public synchronized void publish(LogRecord logRecord) {
+      if (isLoggable(logRecord)) {
+         records.add(logRecord);
+      }
+   }
+
+   public synchronized void flushRecords() {
+      boolean started = false;
+      try {
+         for (int i = 0; i < records.size(); i++) {
+            LogRecord logRecord = records.get(i);
+
+            if (logRecord instanceof TestRecord) {
+               TestRecord record = (TestRecord) logRecord;
+
+               if (record instanceof ScriptInitRecord) {
+                  if (!((ScriptInitRecord) record).getStartFlag()) {
+                     continue;
+                  }
+               }
+
+               if (!started && isTopLevelElement(record)) {
+                  started = true;
+                  record.toXml(writer);
+               } else if (isTopLevelElement(record)) {
+                  writer.writeEndElement();
+                  record.toXml(writer);
+               } else if (record instanceof TraceRecordEnd) {
+                  record.toXml(writer);
+                  writer.writeEndElement();
+               } else {
+                  record.toXml(writer);
+               }
+            } else {
+               writer.writeStartElement("OteLog");
+               writer.writeAttribute("Level", logRecord.getLevel().getLocalizedName());
+               writer.writeAttribute("Logger", logRecord.getLoggerName());
+               writer.writeStartElement("Message");
+               writer.writeCharacters(logRecord.getMessage());
+               writer.writeEndElement();
+               if (logRecord.getThrown() != null) {
+                  StringWriter sw = new StringWriter();
+                  PrintWriter pw = new PrintWriter(sw);
+                  logRecord.getThrown().printStackTrace(pw);
+                  pw.close();
+                  writer.writeStartElement("Throwable");
+                  writer.writeCharacters(sw.toString());
+                  writer.writeEndElement();
+               }
+               writer.writeEndElement();
+            }
+         }
+      } catch (XMLStreamException ex) {
+         OseeLog.log(ScriptStreamOutLogHandler.class, Level.SEVERE, ex);
+      } finally {
+         try {
+            writer.writeEndDocument();
+         } catch (XMLStreamException ex) {
+            OseeLog.log(ScriptStreamOutLogHandler.class, Level.SEVERE, ex);
+         }
+         records.clear();
+      }
+   }
+
+   private boolean isTopLevelElement(TestRecord record) {
+      return record instanceof TestCaseRecord || record instanceof ScriptResultRecord || record instanceof ScriptInitRecord;
+   }
+
+   @Override
+   public void close() throws SecurityException {
+      try {
+         writer.flush();
+         writer.close();
+         outputStream.close();
+      } catch (IOException ex) {
+         OseeLog.log(TestEnvironment.class, Level.SEVERE, ex);
+      } catch (XMLStreamException ex) {
+         OseeLog.log(TestEnvironment.class, Level.SEVERE, ex);
+      }
+   }
+
+   @Override
+   public void flush() {
+      // don't call this method
+   }
+}
\ No newline at end of file
diff --git a/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/outfile/TmoTypeResolverBuilder.java b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/outfile/TmoTypeResolverBuilder.java
new file mode 100644
index 0000000..c363046
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/outfile/TmoTypeResolverBuilder.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Boeing.
+ * 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:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ote.simple.test.environment.outfile;
+
+import com.fasterxml.jackson.databind.ObjectMapper.DefaultTypeResolverBuilder;
+import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;
+import com.fasterxml.jackson.databind.JavaType;
+
+/**
+ * @author Andy Jury
+ */
+public class TmoTypeResolverBuilder extends DefaultTypeResolverBuilder {
+
+   private static final long serialVersionUID = 7969848188152891576L;
+
+   public TmoTypeResolverBuilder() {
+      super(DefaultTyping.NON_FINAL);
+   }
+
+   @SuppressWarnings("rawtypes")
+   @Override
+   public boolean useForType(JavaType t) {
+      final Class clazz = t.getRawClass();
+      final String name = clazz.getName();
+      if (name.startsWith("java.") || !name.contains(".")) {
+         return false;
+      }
+      return true;
+   }
+}
diff --git a/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/outfile/xml/SystemInfo.java b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/outfile/xml/SystemInfo.java
new file mode 100644
index 0000000..4dd5bd3
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/outfile/xml/SystemInfo.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Boeing.
+ * 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:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ote.simple.test.environment.outfile.xml;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.eclipse.osee.framework.core.data.OseeCodeVersion;
+import org.eclipse.osee.framework.jdk.core.persistence.Xmlizable;
+import org.eclipse.osee.framework.jdk.core.persistence.XmlizableStream;
+import org.eclipse.osee.ote.core.OteProperties;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * @author Andy Jury
+ */
+public class SystemInfo implements Xmlizable, XmlizableStream {
+   @Override
+   public Element toXml(Document doc) {
+      Element recordElement = doc.createElement("SystemInfo");
+      recordElement.setAttribute("osName", System.getProperty("os.name"));
+      recordElement.setAttribute("osVersion", System.getProperty("os.version"));
+      recordElement.setAttribute("osArch", System.getProperty("os.arch"));
+      recordElement.setAttribute("oseeVersion", OseeCodeVersion.getVersion());
+      recordElement.setAttribute("javaVersion", System.getProperty("java.version"));
+      String title = OteProperties.getOseeOteServerTitle();
+      if (title != null) {
+         recordElement.setAttribute("oseeServerTitle", title);
+      }
+      return recordElement;
+   }
+
+   @Override
+   public void toXml(XMLStreamWriter writer) throws XMLStreamException {
+      writer.writeStartElement("SystemInfo");
+      writer.writeAttribute("osName", System.getProperty("os.name"));
+      writer.writeAttribute("osVersion", System.getProperty("os.version"));
+      writer.writeAttribute("osArch", System.getProperty("os.arch"));
+      writer.writeAttribute("oseeVersion", OseeCodeVersion.getVersion());
+      writer.writeAttribute("javaVersion", System.getProperty("java.version"));
+      String title = OteProperties.getOseeOteServerTitle();
+      if (title != null) {
+         writer.writeAttribute("oseeServerTitle", title);
+      }
+      writer.writeEndElement();
+   }
+
+   @JsonProperty
+   public String getOperatingSystem() {
+      return System.getProperty("os.name");
+   }
+
+   @JsonProperty
+   public String getOperatingSystemVersion() {
+      return System.getProperty("os.version");
+   }
+
+   @JsonProperty
+   public String getArchitecture() {
+      return System.getProperty("os.arch");
+   }
+
+   @JsonProperty
+   public String getOseeCodeVersion() {
+      return OseeCodeVersion.getVersion();
+   }
+
+   @JsonProperty
+   public String getJavaVersion() {
+      return System.getProperty("java.version");
+   }
+
+   @JsonProperty
+   public String getOteServerTitle() {
+      return OteProperties.getOseeOteServerTitle();
+   }
+}
diff --git a/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/outfile/xml/TestPointResults.java b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/outfile/xml/TestPointResults.java
new file mode 100644
index 0000000..e3d8433
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/outfile/xml/TestPointResults.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Boeing.
+ * 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:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ote.simple.test.environment.outfile.xml;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.eclipse.osee.framework.jdk.core.persistence.Xmlizable;
+import org.eclipse.osee.framework.jdk.core.persistence.XmlizableStream;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * @author Andy Jury
+ */
+public class TestPointResults implements Xmlizable, XmlizableStream {
+
+   @JsonProperty
+   private final int passes;
+   @JsonProperty
+   private final int fails;
+   @JsonProperty
+   private final boolean aborted;
+   @JsonProperty
+   private final int total;
+
+   public TestPointResults(int passes, int fails, boolean isAborted) {
+      super();
+      this.passes = passes;
+      this.fails = fails;
+      this.aborted = isAborted;
+      this.total = passes + fails;
+   }
+
+   @Override
+   public Element toXml(Document doc) {
+      Element recordElement = doc.createElement("TestPointResults");
+      recordElement.setAttribute("pass", Integer.toString(passes));
+      recordElement.setAttribute("fail", Integer.toString(fails));
+      recordElement.setAttribute("aborted", Boolean.toString(aborted));
+      recordElement.setAttribute("total", Integer.toString(total));
+      return recordElement;
+   }
+
+   @Override
+   public void toXml(XMLStreamWriter writer) throws XMLStreamException {
+      writer.writeStartElement("TestPointResults");
+      writer.writeAttribute("pass", Integer.toString(passes));
+      writer.writeAttribute("fail", Integer.toString(fails));
+      writer.writeAttribute("aborted", Boolean.toString(aborted));
+      writer.writeAttribute("total", Integer.toString(total));
+      writer.writeEndElement();
+   }
+
+   public int getPasses() {
+      return passes;
+   }
+
+   public int getFails() {
+      return fails;
+   }
+
+   public boolean isAborted() {
+      return aborted;
+   }
+
+   public int getTotal() {
+      return total;
+   }
+
+}
diff --git a/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/outfile/xml/TimeSummary.java b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/outfile/xml/TimeSummary.java
new file mode 100644
index 0000000..8edc06e
--- /dev/null
+++ b/org.eclipse.ote.simple.test.environment/src/org/eclipse/ote/simple/test/environment/outfile/xml/TimeSummary.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Boeing.
+ * 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:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ote.simple.test.environment.outfile.xml;
+
+import java.util.Date;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.eclipse.osee.framework.jdk.core.persistence.Xmlizable;
+import org.eclipse.osee.framework.jdk.core.persistence.XmlizableStream;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * @author Andy Jury
+ */
+public class TimeSummary implements Xmlizable, XmlizableStream {
+
+   @JsonProperty
+   private final long elapsedTime;
+   @JsonProperty
+   private final Date startTime;
+   @JsonProperty
+   private final Date endTime;
+   @JsonProperty
+   private final String elapsed;
+
+   public TimeSummary(long elapsedTime, Date startTime, Date endTime, String elapsed) {
+      super();
+      this.elapsedTime = elapsedTime;
+      this.startTime = startTime;
+      this.endTime = endTime;
+      this.elapsed = elapsed;
+   }
+
+   @Override
+   public Element toXml(Document doc) {
+      Element recordElement = doc.createElement("TimeSummary");
+      recordElement.setAttribute("milliseconds", Long.toString(elapsedTime));
+      recordElement.setAttribute("startDate", startTime.toString());
+      recordElement.setAttribute("endDate", endTime.toString());
+      recordElement.setAttribute("elapsed", elapsed);
+      return recordElement;
+   }
+
+   @Override
+   public void toXml(XMLStreamWriter writer) throws XMLStreamException {
+      writer.writeStartElement("TimeSummary");
+      writer.writeAttribute("milliseconds", Long.toString(elapsedTime));
+      writer.writeAttribute("startDate", startTime.toString());
+      writer.writeAttribute("endDate", endTime.toString());
+      writer.writeAttribute("elapsed", elapsed);
+      writer.writeEndElement();
+   }
+
+   public long getElapsedTime() {
+      return elapsedTime;
+   }
+
+   public Date getStartTime() {
+      return startTime;
+   }
+
+   public Date getEndTime() {
+      return endTime;
+   }
+
+   public String getElapsed() {
+      return elapsed;
+   }
+
+}