diff --git a/agent-job.yaml b/agent-job.yaml
new file mode 100644
index 0000000..78ac618
--- /dev/null
+++ b/agent-job.yaml
@@ -0,0 +1,22 @@
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: agent
+spec:
+ parallelism: 2
+ ttlSecondsAfterFinished: 0
+ template:
+ metadata:
+ labels:
+ app: agent
+ spec:
+ containers:
+ - name: agent-container
+ image:
+ livenessProbe:
+ httpGet:
+ path: /health
+ port: 4567
+ initialDelaySeconds: 20
+ periodSeconds: 3
+ restartPolicy: Never
diff --git a/driver_statefulset.yaml b/driver_statefulset.yaml
new file mode 100644
index 0000000..4fc897e
--- /dev/null
+++ b/driver_statefulset.yaml
@@ -0,0 +1,66 @@
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: driver
+spec:
+ selector:
+ matchLabels:
+ app: driver
+ serviceName: driver
+ replicas: 2
+ template:
+ metadata:
+ labels:
+ app: driver
+ spec:
+ containers:
+ - image:
+ env:
+ - name: NR_DRIVERS
+ value: "2" # set this value to the value of spec.replicas field
+ name: driver-container
+ ports:
+ - containerPort: 4567
+ - containerPort: 80
+ livenessProbe:
+ httpGet:
+ path: /health
+ port: 4567
+ initialDelaySeconds: 20
+ periodSeconds: 3
+
+---
+
+# headless service required by StatefulSet resource
+apiVersion: v1
+kind: Service
+metadata:
+ name: driver
+ labels:
+ app: driver
+spec:
+ ports:
+ - port: 80
+ protocol: TCP
+ targetPort: 4567
+ name: http
+ selector:
+ app: driver
+
+---
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+ name: driver
+ annotations:
+ kubernetes.io/ingress.class: nginx
+ nginx.ingress.kubernetes.io/ssl-redirect: "false"
+ nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
+spec:
+ rules:
+ - http:
+ paths:
+ - backend:
+ serviceName: driver
+ servicePort: 80
+ path: /config
diff --git a/toughday/pom.xml b/toughday/pom.xml
index 4137f5e..f9182fb 100644
--- a/toughday/pom.xml
+++ b/toughday/pom.xml
@@ -271,5 +271,11 @@
test
+
+ com.sparkjava
+ spark-core
+ 2.7.2
+
+
diff --git a/toughday/src/main/java/com/adobe/qe/toughday/Main.java b/toughday/src/main/java/com/adobe/qe/toughday/Main.java
index 7b57ebb..e2243b4 100644
--- a/toughday/src/main/java/com/adobe/qe/toughday/Main.java
+++ b/toughday/src/main/java/com/adobe/qe/toughday/Main.java
@@ -11,14 +11,15 @@
*/
package com.adobe.qe.toughday;
-
import com.adobe.qe.toughday.internal.core.engine.Engine;
import com.adobe.qe.toughday.internal.core.config.parsers.cli.CliParser;
import com.adobe.qe.toughday.internal.core.config.Configuration;
+import com.adobe.qe.toughday.internal.core.distributedtd.ExecutionTrigger;
+import com.adobe.qe.toughday.internal.core.distributedtd.cluster.Agent;
+import com.adobe.qe.toughday.internal.core.distributedtd.cluster.driver.Driver;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-
/**
* Main class. Creates a Configuration and an engine and runs the tests.
*/
@@ -31,8 +32,6 @@ public class Main {
}
public static void main(String[] args) {
-
-
CliParser cliParser = new CliParser();
System.out.println();
@@ -51,15 +50,27 @@ public static void main(String[] args) {
System.exit(1);
}
- Engine engine = new Engine(configuration);
- engine.runTests();
+ /* check if we should trigger an execution query in the cluster. */
+ if (configuration.executeInDitributedMode()) {
+ new ExecutionTrigger(configuration).triggerDistributedExecution();
+ System.exit(0);
+ } else if (configuration.getDistributedConfig().getAgent()) {
+ Agent agent = new Agent();
+ agent.start();
+ } else if (configuration.getDistributedConfig().getDriver()) {
+ Driver driver = new Driver(configuration);
+ driver.run();
+ } else {
+ Engine engine = new Engine(configuration);
+ engine.runTests();
- System.exit(0);
+ System.exit(0);
+ }
} catch (Throwable t) {
LOG.error("Error encountered: "
+ (t.getMessage() != null ? t.getMessage() : "Please check toughday.log for more information."));
LogManager.getLogger(Engine.class).error("Error encountered", t);
+ System.exit(-1);
}
- System.exit(0);
}
}
diff --git a/toughday/src/main/java/com/adobe/qe/toughday/internal/core/TestSuite.java b/toughday/src/main/java/com/adobe/qe/toughday/internal/core/TestSuite.java
index 80ab294..88b7063 100644
--- a/toughday/src/main/java/com/adobe/qe/toughday/internal/core/TestSuite.java
+++ b/toughday/src/main/java/com/adobe/qe/toughday/internal/core/TestSuite.java
@@ -21,7 +21,7 @@
/**
* Test suite class.
*/
-public class TestSuite {
+public class TestSuite implements Cloneable {
private List setupStep;
private String description = "";
private List tags = new ArrayList<>();
@@ -39,6 +39,24 @@ public TestSuite() {
totalWeight = 0;
}
+ /**
+ * Creates a copy of the current test suite. All tests contained by the test suite are cloned.
+ * @throws CloneNotSupportedException if the object to be cloned does not implement the Cloneable interface.
+ */
+ public TestSuite clone() throws CloneNotSupportedException {
+ TestSuite newInstance = (TestSuite) super.clone();
+
+ /* clone all the tests in the TestSuite */
+ newInstance.orderedTests = new ArrayList<>();
+ newInstance.nameMap = new HashMap<>();
+
+ for (AbstractTest test : this.getTests()) {
+ newInstance.add(test.clone());
+ }
+
+ return newInstance;
+ }
+
/**
* Method for adding a test.
* @param test
diff --git a/toughday/src/main/java/com/adobe/qe/toughday/internal/core/config/ConfigParams.java b/toughday/src/main/java/com/adobe/qe/toughday/internal/core/config/ConfigParams.java
index e47fd3f..b59b1af 100644
--- a/toughday/src/main/java/com/adobe/qe/toughday/internal/core/config/ConfigParams.java
+++ b/toughday/src/main/java/com/adobe/qe/toughday/internal/core/config/ConfigParams.java
@@ -26,6 +26,7 @@ public class ConfigParams implements Serializable {
private List phasesParams = new ArrayList<>();
private Map globalParams = new HashMap<>();
+ private Map distributedConfigParams = new HashMap<>();
private Map publishModeParams = new HashMap<>();
private Map runModeParams = new HashMap<>();
private List> items = new ArrayList<>();
@@ -94,6 +95,10 @@ public void setGlobalParams(Map globalParams) {
this.globalParams = globalParams;
}
+ public void setDistributedConfigParams(Map distributedConfigParams) {
+ this.distributedConfigParams = distributedConfigParams;
+ }
+
public void setPhasesParams(List phasesParams) {
this.phasesParams = phasesParams;
}
@@ -163,12 +168,15 @@ public Map getGlobalParams(){
return globalParams;
}
+ public Map getDistributedConfigParams() { return distributedConfigParams; }
+
public Map getPublishModeParams() { return publishModeParams; }
public Map getRunModeParams() { return runModeParams; }
public void merge(ConfigParams other) {
globalParams.putAll(other.getGlobalParams());
+ distributedConfigParams.putAll(other.distributedConfigParams);
items.addAll(other.items);
phasesParams.addAll(other.phasesParams);
diff --git a/toughday/src/main/java/com/adobe/qe/toughday/internal/core/config/Configuration.java b/toughday/src/main/java/com/adobe/qe/toughday/internal/core/config/Configuration.java
index 4523850..285a6a9 100644
--- a/toughday/src/main/java/com/adobe/qe/toughday/internal/core/config/Configuration.java
+++ b/toughday/src/main/java/com/adobe/qe/toughday/internal/core/config/Configuration.java
@@ -24,6 +24,7 @@
import com.adobe.qe.toughday.internal.core.engine.Phase;
import com.adobe.qe.toughday.internal.core.engine.PublishMode;
import com.adobe.qe.toughday.internal.core.engine.RunMode;
+import com.adobe.qe.toughday.internal.core.distributedtd.cluster.DistributedConfig;
import com.adobe.qe.toughday.metrics.Metric;
import com.adobe.qe.toughday.publishers.CSVPublisher;
import com.adobe.qe.toughday.publishers.ConsolePublisher;
@@ -36,9 +37,7 @@
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.reflections.Reflections;
-import java.io.File;
-import java.io.IOException;
-import java.lang.ref.WeakReference;
+import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -63,6 +62,7 @@ public class Configuration {
private PredefinedSuites predefinedSuites = new PredefinedSuites();
private GlobalArgs globalArgs;
+ private DistributedConfig distributedConfig;
private RunMode runMode;
private PublishMode publishMode;
private TestSuite globalSuite;
@@ -70,6 +70,7 @@ public class Configuration {
private Map globalMetrics = new LinkedHashMap<>();
private List phases = new ArrayList<>();
private Set phasesWithoutDuration = new HashSet<>();
+ private ConfigParams configParams;
private boolean defaultSuiteAddedFromConfigExclude = false;
private boolean anyMetricAdded = false;
private boolean anyPublisherAdded = false;
@@ -77,6 +78,37 @@ public class Configuration {
private Map feeders = new LinkedHashMap<>();
private Map objects = new HashMap<>();
+ public Configuration(String yamlConfig)
+ throws InvocationTargetException, NoSuchMethodException, InstantiationException, IOException, IllegalAccessException {
+ ConfigParams configParams = new YamlParser().parse(yamlConfig);
+ buildConfiguration(configParams);
+ }
+
+ public Configuration(String[] cmdLineArgs)
+ throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, IOException {
+ ConfigParams configParams = collectConfigurations(cmdLineArgs);
+ buildConfiguration(configParams);
+
+ }
+
+ /**
+ * Method for getting the property from a setter method
+ *
+ * @param methodName
+ * @return
+ */
+ public static String propertyFromMethod(String methodName) {
+ return methodName.startsWith("set") || methodName.startsWith("get") ? StringUtils.lowerCase(methodName.substring(3)) : StringUtils.lowerCase(methodName);
+ }
+
+ public static Map |