From 70da23db72838f5a78ab155aea02ee7080f23aaa Mon Sep 17 00:00:00 2001 From: Eamonn Mansour <47121388+eamansour@users.noreply.github.com> Date: Mon, 7 Oct 2024 14:08:57 +0100 Subject: [PATCH] Set overrides in DSS as a single property, refactor code for submitting runs (#654) * Change DSS overrides into single property, refactor submitRuns Signed-off-by: Eamonn Mansour <47121388+eamansour@users.noreply.github.com> * Update overrides comment Signed-off-by: Eamonn Mansour <47121388+eamansour@users.noreply.github.com> * Split overrides on newlines Signed-off-by: Eamonn Mansour <47121388+eamansour@users.noreply.github.com> * Load overrides from DSS in separate method Signed-off-by: Eamonn Mansour <47121388+eamansour@users.noreply.github.com> * Minor refactor to reduce duplicate prefix concatenation Signed-off-by: Eamonn Mansour <47121388+eamansour@users.noreply.github.com> * Change DSS overrides into a JSON array instead of a string separated by newlines Signed-off-by: Eamonn Mansour <47121388+eamansour@users.noreply.github.com> --------- Signed-off-by: Eamonn Mansour <47121388+eamansour@users.noreply.github.com> --- .../dev/galasa/framework/BaseTestRunner.java | 21 +- .../framework/FrameworkInitialisation.java | 25 +- .../dev/galasa/framework/FrameworkRuns.java | 487 +++++------ .../dev/galasa/framework/beans/Property.java | 37 + .../framework/beans/SubmitRunRequest.java | 198 +++++ .../galasa/framework/FrameworkRunsTest.java | 756 ++++++++++++++++++ .../galasa/framework/mocks/MockCPSStore.java | 2 +- .../galasa/framework/mocks/MockDSSStore.java | 34 +- .../galasa/framework/mocks/MockFramework.java | 37 +- 9 files changed, 1349 insertions(+), 248 deletions(-) create mode 100644 galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/beans/Property.java create mode 100644 galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/beans/SubmitRunRequest.java create mode 100644 galasa-parent/dev.galasa.framework/src/test/java/dev/galasa/framework/FrameworkRunsTest.java diff --git a/galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/BaseTestRunner.java b/galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/BaseTestRunner.java index 2886d7b54..d4faa95d3 100644 --- a/galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/BaseTestRunner.java +++ b/galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/BaseTestRunner.java @@ -14,14 +14,13 @@ import java.time.temporal.ChronoUnit; import java.nio.charset.StandardCharsets; import java.util.*; -import java.util.Map.Entry; import javax.validation.constraints.NotNull; import dev.galasa.ResultArchiveStoreContentType; +import dev.galasa.framework.beans.Property; import dev.galasa.framework.internal.runner.ITestRunnerEventsProducer; import dev.galasa.framework.spi.AbstractManager; -import dev.galasa.framework.spi.ConfigurationPropertyStoreException; import dev.galasa.framework.spi.DynamicStatusStoreException; import dev.galasa.framework.spi.FrameworkException; import dev.galasa.framework.spi.IConfigurationPropertyStoreService; @@ -33,6 +32,7 @@ import dev.galasa.framework.spi.ResultArchiveStoreException; import dev.galasa.framework.spi.teststructure.TestStructure; import dev.galasa.framework.spi.utils.DssUtils; +import dev.galasa.framework.spi.utils.GalasaGson; public class BaseTestRunner { @@ -61,6 +61,8 @@ public class BaseTestRunner { protected Properties overrideProperties; + private static final GalasaGson gson = new GalasaGson(); + protected void init(ITestRunnerDataProvider dataProvider) throws TestRunException { this.run = dataProvider.getRun() ; this.framework = dataProvider.getFramework(); @@ -166,12 +168,15 @@ private void loadOverrideProperties(Properties overrideProperties, IDynamicStatusStoreService dss) throws TestRunException { //*** Load the overrides if present try { - String prefix = "run." + run.getName() + ".override."; - Map runOverrides = dss.getPrefix(prefix); - for(Entry entry : runOverrides.entrySet()) { - String key = entry.getKey().substring(prefix.length()); - String value = entry.getValue(); - overrideProperties.put(key, value); + // The overrides DSS property contains a JSON array of overrides in the form: + // dss.framework.run.X.overrides=[{ "key1": "value1" }, { "key2", "value2" }] + String runOverridesProp = "run." + run.getName() + ".overrides"; + String runOverrides = dss.get(runOverridesProp); + if (runOverrides != null && !runOverrides.isBlank()) { + Property[] properties = gson.fromJson(runOverrides, Property[].class); + for (Property override : properties) { + overrideProperties.put(override.getKey(), override.getValue()); + } } } catch(Exception e) { throw new TestRunException("Problem loading overrides from the run properties", e); diff --git a/galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/FrameworkInitialisation.java b/galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/FrameworkInitialisation.java index bb35ae102..bfe919f8a 100644 --- a/galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/FrameworkInitialisation.java +++ b/galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/FrameworkInitialisation.java @@ -8,13 +8,15 @@ import java.io.IOException; import java.net.*; import java.util.*; -import java.util.Map.Entry; import java.nio.file.*; import javax.validation.constraints.NotNull; import org.apache.commons.logging.*; import org.osgi.framework.*; + +import dev.galasa.framework.beans.Property; import dev.galasa.framework.spi.*; import dev.galasa.framework.spi.creds.*; +import dev.galasa.framework.spi.utils.GalasaGson; public class FrameworkInitialisation implements IFrameworkInitialisation { @@ -35,6 +37,7 @@ public class FrameworkInitialisation implements IFrameworkInitialisation { private String galasaHome; + private static final GalasaGson gson = new GalasaGson(); public FrameworkInitialisation( Properties bootstrapProperties, @@ -144,18 +147,24 @@ public FrameworkInitialisation( // *** If this is a test run, add the overrides from the run dss properties to // these overrides if (testrun) { - String prefix = "run." + framework.getTestRunName() + ".override."; - int len = prefix.length(); + loadOverridePropertiesFromDss(overrideProperties); + } + } - Map runOverrides = this.dssFramework.getPrefix(prefix); - for (Entry override : runOverrides.entrySet()) { - String key = override.getKey().substring(len); + private void loadOverridePropertiesFromDss(Properties overrideProperties) throws DynamicStatusStoreException { + // The overrides DSS property contains a JSON array of overrides in the form: + // dss.framework.run.X.overrides=[{ "key1": "value1" }, { "key2", "value2" }] + String runOverridesProp = "run." + framework.getTestRunName() + ".overrides"; + String runOverrides = this.dssFramework.get(runOverridesProp); + if (runOverrides != null && !runOverrides.isBlank()) { + Property[] properties = gson.fromJson(runOverrides, Property[].class); + for (Property override : properties) { + String key = override.getKey(); String value = override.getValue(); - if (logger.isTraceEnabled()) { logger.trace("Setting run override " + key + "=" + value); } - overrideProperties.put(override.getKey(), override.getValue()); + overrideProperties.put(key, value); } } } diff --git a/galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/FrameworkRuns.java b/galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/FrameworkRuns.java index aa5a598c2..0fbe4ce69 100644 --- a/galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/FrameworkRuns.java +++ b/galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/FrameworkRuns.java @@ -23,7 +23,12 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import com.google.gson.JsonArray; + +import dev.galasa.framework.beans.Property; +import dev.galasa.framework.beans.SubmitRunRequest; import dev.galasa.framework.spi.AbstractManager; +import dev.galasa.framework.spi.ConfigurationPropertyStoreException; import dev.galasa.framework.spi.DynamicStatusStoreException; import dev.galasa.framework.spi.FrameworkException; import dev.galasa.framework.spi.IConfigurationPropertyStoreService; @@ -31,6 +36,7 @@ import dev.galasa.framework.spi.IFramework; import dev.galasa.framework.spi.IFrameworkRuns; import dev.galasa.framework.spi.IRun; +import dev.galasa.framework.spi.utils.GalasaGson; public class FrameworkRuns implements IFrameworkRuns { @@ -49,6 +55,8 @@ public class FrameworkRuns implements IFrameworkRuns { private final String RUN_PREFIX = "run."; + private static final GalasaGson gson = new GalasaGson(); + public FrameworkRuns(IFramework framework) throws FrameworkException { this.framework = framework; this.dss = framework.getDynamicStatusStoreService("framework"); @@ -144,263 +152,119 @@ public List getAllGroupedRuns(@NotNull String groupName) throws FrameworkE return runNames; } + private @NotNull IRun submitRun(SubmitRunRequest runRequest) throws FrameworkException { + IRun run = null; + setRunRequestDefaultsIfNotSet(runRequest); + + if (runRequest.getSharedEnvironmentPhase() != null) { + run = submitSharedEnvironmentRun(runRequest); + } else { + try { + String runName = assignNewRunName(runRequest); + run = new RunImpl(runName, this.dss); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new FrameworkException("Interrupted", e); + } catch (Exception e) { + throw new FrameworkException("Problem submitting job", e); + } + } + return run; + } + @Override @NotNull public @NotNull IRun submitRun(String runType, String requestor, String bundleName, @NotNull String testName, String groupName, String mavenRepository, String obr, String stream, boolean local, boolean trace, Properties overrides, SharedEnvironmentPhase sharedEnvironmentPhase, String sharedEnvironmentRunName, String language) throws FrameworkException { - if (testName == null) { - throw new FrameworkException("Missing test name"); - } - String bundleTest = null; - if (language == null) { - language = "java"; - } - if(language.equals("java")) { - if(bundleName == null) { - throw new FrameworkException("Missing bundle name"); - } else { - bundleTest = bundleName + "/" + testName; - } - } - - groupName = AbstractManager.nulled(groupName); - if (groupName == null) { - groupName = NO_GROUP; - } - runType = AbstractManager.nulled(runType); - if (runType == null) { - runType = NO_RUNTYPE; - } - runType = runType.toUpperCase(); - requestor = AbstractManager.nulled(requestor); - if (requestor == null) { - requestor = AbstractManager.nulled(cps.getProperty("run", "requestor")); - if (requestor == null) { - requestor = "unknown"; - } - } - stream = AbstractManager.nulled(stream); - - String runName = null; - - // *** Allocate the next number for the run type - - if (sharedEnvironmentPhase != null && sharedEnvironmentPhase == SharedEnvironmentPhase.BUILD) { - if (sharedEnvironmentRunName == null || sharedEnvironmentRunName.trim().isEmpty()) { - throw new FrameworkException("Missing run name for shared environment"); - } - - sharedEnvironmentRunName = sharedEnvironmentRunName.trim().toUpperCase(); - - if (!storeRun(sharedEnvironmentRunName, - bundleTest, - bundleName, - testName, - runType, - trace, - local, - mavenRepository, - obr, - stream, - groupName, - requestor, - overrides, - sharedEnvironmentPhase, - language)) { - throw new FrameworkException("Unable to submit shared environment run " + sharedEnvironmentRunName + ", is there a duplicate runname?"); - } - - return new RunImpl(sharedEnvironmentRunName, this.dss); - } - - //*** If this is discard, tweak the current run parameters - - if (sharedEnvironmentPhase != null && sharedEnvironmentPhase == SharedEnvironmentPhase.DISCARD) { - if (sharedEnvironmentRunName == null || sharedEnvironmentRunName.trim().isEmpty()) { - throw new FrameworkException("Missing run name for shared environment"); - } - - sharedEnvironmentRunName = sharedEnvironmentRunName.trim().toUpperCase(); - - RunImpl run = new RunImpl(sharedEnvironmentRunName, this.dss); - if (!run.isSharedEnvironment()) { - throw new FrameworkException("Run " + sharedEnvironmentRunName + " is not a shared environment"); - } - - if (!"UP".equalsIgnoreCase(run.getStatus())) { - throw new FrameworkException("Shared Environment " + sharedEnvironmentRunName + " is not up and running"); - } - - HashMap otherProperties = new HashMap<>(); - otherProperties.put(RUN_PREFIX + sharedEnvironmentRunName + ".override.framework.run.shared.environment.phase", sharedEnvironmentPhase.toString()); - if (groupName != null) { - otherProperties.put(RUN_PREFIX + sharedEnvironmentRunName + ".group", groupName); - } - if (!this.dss.putSwap(RUN_PREFIX + sharedEnvironmentRunName + ".status", "up", "queued", otherProperties)) { - throw new FrameworkException("Failed to switch Shared Environment " + sharedEnvironmentRunName + " to discard"); - } - - return new RunImpl(sharedEnvironmentRunName, this.dss); - } - - // *** Get the prefix of this run type - String typePrefix = AbstractManager.nulled(this.cps.getProperty("request.type." + runType, "prefix")); - if (typePrefix == null) { - if ("local".equals(runType)) { - typePrefix = "L"; - } else { - typePrefix = "U"; // *** For unknown prefix - } - } - - // *** Get the maximum number for this prefix - int maxNumber = Integer.MAX_VALUE; - String sMaxNumber = AbstractManager.nulled(this.cps.getProperty("request.prefix", "maximum", typePrefix)); - if (sMaxNumber != null) { - maxNumber = Integer.parseInt(sMaxNumber); - } - - try { - // *** Now loop until we find the next free number for this run type - boolean maxlooped = false; - while (runName == null) { - String pLastused = "request.prefix." + typePrefix + ".lastused"; - String sLatestNumber = this.dss.get(pLastused); - int latestNumber = 0; - if (sLatestNumber != null && !sLatestNumber.trim().isEmpty()) { - latestNumber = Integer.parseInt(sLatestNumber); - } - - // *** Add 1 to the run number and see if we get it - latestNumber++; - if (latestNumber > maxNumber) { // *** have we gone past the maximum number - if (maxlooped) { - throw new FrameworkException("Not enough request type numbers available, looped twice"); - } - latestNumber = 1; - maxlooped = true; // *** Safety check to make sure we havent gone through all the numbers again - } - - String sNewNumber = Integer.toString(latestNumber); - if (!this.dss.putSwap(pLastused, sLatestNumber, sNewNumber)) { - Thread.sleep(this.framework.getRandom().nextInt(200)); // *** Wait for a bit, to avoid race - // conditions - continue; // Try again with the new latest number - } - - String tempRunName = typePrefix + sNewNumber; - - if (!storeRun(tempRunName, - bundleTest, - bundleName, - testName, - runType, - trace, - local, - mavenRepository, - obr, - stream, - groupName, - requestor, - overrides, - null, - language)) { - Thread.sleep(this.framework.getRandom().nextInt(200)); // *** Wait for a bit, to avoid race - // conditions - continue; // *** Try again - } - - runName = tempRunName; // *** Got it - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new FrameworkException("Interrupted", e); - } catch (Exception e) { - throw new FrameworkException("Problem submitting job", e); - } - - return new RunImpl(runName, this.dss); + SubmitRunRequest runRequest = new SubmitRunRequest( + runType, + requestor, + bundleName, + testName, + groupName, + mavenRepository, + obr, + stream, + local, + trace, + overrides, + sharedEnvironmentPhase, + sharedEnvironmentRunName, + language + ); + return submitRun(runRequest); } - private boolean storeRun(String runName, - String bundleTest, - String bundleName, - String testName, - String runType, - boolean trace, - boolean local, - String mavenRepository, - String obr, - String stream, - String groupName, - String requestor, - Properties overrides, - SharedEnvironmentPhase sharedEnvironmentPhase, - String language) throws DynamicStatusStoreException { - - if (overrides == null) { - overrides = new Properties(); - } - String gherkinTest = null; - if(language.equals("gherkin")) { - bundleTest = NO_BUNDLE; - gherkinTest = testName; - bundleName = NO_BUNDLE; - } + private boolean storeRun(String runName, SubmitRunRequest runRequest) throws DynamicStatusStoreException { + String bundleName = runRequest.getBundleName(); + String testName = runRequest.getTestName(); + String bundleTest = runRequest.getBundleTest(); + String gherkinTest = runRequest.getGherkinTest(); + String runType = runRequest.getRunType(); + String mavenRepository = runRequest.getMavenRepository(); + String obr = runRequest.getObr(); + String stream = runRequest.getStream(); + String groupName = runRequest.getGroupName(); + String requestor = runRequest.getRequestor(); + SharedEnvironmentPhase sharedEnvironmentPhase = runRequest.getSharedEnvironmentPhase(); + Properties overrides = runRequest.getOverrides(); + boolean local = runRequest.isLocalRun(); + boolean trace = runRequest.isTraceEnabled(); + + String runPropertyPrefix = RUN_PREFIX + runName; + // *** Set up the otherRunProperties that will go with the Run number HashMap otherRunProperties = new HashMap<>(); - otherRunProperties.put(RUN_PREFIX + runName + ".status", "queued"); - otherRunProperties.put(RUN_PREFIX + runName + ".queued", Instant.now().toString()); - otherRunProperties.put(RUN_PREFIX + runName + ".testbundle", bundleName); - otherRunProperties.put(RUN_PREFIX + runName + ".testclass", testName); - otherRunProperties.put(RUN_PREFIX + runName + ".request.type", runType); - otherRunProperties.put(RUN_PREFIX + runName + ".local", Boolean.toString(local)); + otherRunProperties.put(runPropertyPrefix + ".status", "queued"); + otherRunProperties.put(runPropertyPrefix + ".queued", Instant.now().toString()); + otherRunProperties.put(runPropertyPrefix + ".testbundle", bundleName); + otherRunProperties.put(runPropertyPrefix + ".testclass", testName); + otherRunProperties.put(runPropertyPrefix + ".request.type", runType); + otherRunProperties.put(runPropertyPrefix + ".local", Boolean.toString(local)); if (trace) { - otherRunProperties.put(RUN_PREFIX + runName + ".trace", "true"); + otherRunProperties.put(runPropertyPrefix + ".trace", "true"); } if (mavenRepository != null) { - otherRunProperties.put(RUN_PREFIX + runName + ".repository", mavenRepository); + otherRunProperties.put(runPropertyPrefix + ".repository", mavenRepository); } if (obr != null) { - otherRunProperties.put(RUN_PREFIX + runName + ".obr", obr); + otherRunProperties.put(runPropertyPrefix + ".obr", obr); } if (stream != null) { - otherRunProperties.put(RUN_PREFIX + runName + ".stream", stream); + otherRunProperties.put(runPropertyPrefix + ".stream", stream); } if (groupName != null) { - otherRunProperties.put(RUN_PREFIX + runName + ".group", groupName); + otherRunProperties.put(runPropertyPrefix + ".group", groupName); } else { - otherRunProperties.put(RUN_PREFIX + runName + ".group", UUID.randomUUID().toString()); + otherRunProperties.put(runPropertyPrefix + ".group", UUID.randomUUID().toString()); } - otherRunProperties.put(RUN_PREFIX + runName + ".requestor", requestor.toLowerCase()); + otherRunProperties.put(runPropertyPrefix + ".requestor", requestor.toLowerCase()); if (sharedEnvironmentPhase != null) { - otherRunProperties.put(RUN_PREFIX + runName + ".shared.environment", "true"); + otherRunProperties.put(runPropertyPrefix + ".shared.environment", "true"); overrides.put("framework.run.shared.environment.phase", sharedEnvironmentPhase.toString()); } - if(gherkinTest != null) { - otherRunProperties.put(RUN_PREFIX + runName + ".gherkin", gherkinTest); + if (gherkinTest != null) { + otherRunProperties.put(runPropertyPrefix + ".gherkin", gherkinTest); } - // *** Add in the overrides - if (overrides != null) { - for (java.util.Map.Entry entry : overrides.entrySet()) { + // *** Add in the overrides as a single property + if (!overrides.isEmpty()) { + JsonArray overridesArray = new JsonArray(); + for (Map.Entry entry : overrides.entrySet()) { String key = (String) entry.getKey(); String value = (String) entry.getValue(); - - otherRunProperties.put(RUN_PREFIX + runName + ".override." + key, value); + overridesArray.add(gson.toJsonTree(new Property(key, value))); } + + otherRunProperties.put(runPropertyPrefix + ".overrides", gson.toJson(overridesArray)); } // *** See if we can setup the runnumber properties (clashes possible if low max // number or sharing prefix - if (!this.dss.putSwap(RUN_PREFIX + runName + ".test", null, bundleTest, otherRunProperties)) { - return false; // *** Try again - } - - return true; + return this.dss.putSwap(runPropertyPrefix + ".test", null, bundleTest, otherRunProperties); } @Override @@ -446,4 +310,181 @@ public IRun getRun(String runname) throws DynamicStatusStoreException { return new RunImpl(runname, this.dss); } + /** + * Get the prefix of a given run type + */ + private String getRunTypePrefix(String runType) throws ConfigurationPropertyStoreException { + String typePrefix = AbstractManager.nulled(this.cps.getProperty("request.type." + runType, "prefix")); + if (typePrefix == null) { + if ("local".equalsIgnoreCase(runType)) { + typePrefix = "L"; + } else { + typePrefix = "U"; // *** For unknown prefix + } + } + return typePrefix; + } + + /** + * Get the maximum number for the given type prefix + */ + private int getPrefixMaxNumber(String typePrefix) throws ConfigurationPropertyStoreException { + int maxNumber = Integer.MAX_VALUE; + String sMaxNumber = AbstractManager.nulled(this.cps.getProperty("request.prefix", "maximum", typePrefix)); + if (sMaxNumber != null) { + maxNumber = Integer.parseInt(sMaxNumber); + } + return maxNumber; + } + + /** + * Sets the relevant DSS properties when a shared environment run is being discarded + */ + private void setDiscardSharedEnvironmentPhaseProperties(IRun run, String sharedEnvironmentRunName, String groupName) throws FrameworkException { + if (!run.isSharedEnvironment()) { + throw new FrameworkException("Run " + sharedEnvironmentRunName + " is not a shared environment"); + } + + if (!"UP".equalsIgnoreCase(run.getStatus())) { + throw new FrameworkException("Shared Environment " + sharedEnvironmentRunName + " is not up and running"); + } + + HashMap otherProperties = new HashMap<>(); + String runPropertyPrefix = RUN_PREFIX + sharedEnvironmentRunName; + otherProperties.put(runPropertyPrefix + ".overrides", "framework.run.shared.environment.phase=" + SharedEnvironmentPhase.DISCARD.toString()); + if (groupName != null) { + otherProperties.put(runPropertyPrefix + ".group", groupName); + } + if (!this.dss.putSwap(runPropertyPrefix + ".status", "up", "queued", otherProperties)) { + throw new FrameworkException("Failed to switch Shared Environment " + sharedEnvironmentRunName + " to discard"); + } + } + + private String assignNewRunName(SubmitRunRequest runRequest) throws FrameworkException, InterruptedException { + String typePrefix = getRunTypePrefix(runRequest.getRunType()); + int maxNumber = getPrefixMaxNumber(typePrefix); + runRequest.setSharedEnvironmentPhase(null); + + // *** Now loop until we find the next free number for this run type + String runName = null; + boolean maxlooped = false; + while (runName == null) { + String pLastused = "request.prefix." + typePrefix + ".lastused"; + String sLatestNumber = this.dss.get(pLastused); + int latestNumber = 0; + if (sLatestNumber != null && !sLatestNumber.trim().isEmpty()) { + latestNumber = Integer.parseInt(sLatestNumber); + } + + // *** Add 1 to the run number and see if we get it + latestNumber++; + if (latestNumber > maxNumber) { // *** have we gone past the maximum number + if (maxlooped) { + throw new FrameworkException("Not enough request type numbers available, looped twice"); + } + latestNumber = 1; + maxlooped = true; // *** Safety check to make sure we havent gone through all the numbers again + } + + String sNewNumber = Integer.toString(latestNumber); + if (!this.dss.putSwap(pLastused, sLatestNumber, sNewNumber)) { + Thread.sleep(this.framework.getRandom().nextInt(200)); // *** Wait for a bit, to avoid race + // conditions + continue; // Try again with the new latest number + } + + String tempRunName = typePrefix + sNewNumber; + + if (!storeRun(tempRunName, runRequest)) { + Thread.sleep(this.framework.getRandom().nextInt(200)); // *** Wait for a bit, to avoid race + // conditions + continue; // *** Try again + } + + runName = tempRunName; // *** Got it + } + return runName; + } + + private IRun submitSharedEnvironmentRun(SubmitRunRequest runRequest) throws FrameworkException { + String sharedEnvironmentRunName = runRequest.getSharedEnvironmentRunName(); + SharedEnvironmentPhase sharedEnvironmentPhase = runRequest.getSharedEnvironmentPhase(); + IRun run = new RunImpl(sharedEnvironmentRunName, this.dss); + + if (sharedEnvironmentPhase == SharedEnvironmentPhase.BUILD + && !storeRun(sharedEnvironmentRunName, runRequest)) { + throw new FrameworkException("Unable to submit shared environment run " + sharedEnvironmentRunName + ", is there a duplicate runname?"); + } else if (sharedEnvironmentPhase == SharedEnvironmentPhase.DISCARD) { + //*** If this is discard, tweak the current run parameters + setDiscardSharedEnvironmentPhaseProperties(run, sharedEnvironmentRunName, runRequest.getGroupName()); + } + return run; + } + + private void setRunRequestDefaultsIfNotSet(SubmitRunRequest runRequest) throws FrameworkException { + setRunRequestTestDetails(runRequest); + + if (AbstractManager.nulled(runRequest.getGroupName()) == null) { + runRequest.setGroupName(NO_GROUP); + } + + String runType = AbstractManager.nulled(runRequest.getRunType()); + if (runType == null) { + runType = NO_RUNTYPE; + } + runRequest.setRunType(runType.toUpperCase()); + + setRunRequestRequestorDefault(runRequest); + + runRequest.setStream(AbstractManager.nulled(runRequest.getStream())); + + if (runRequest.getOverrides() == null) { + runRequest.setOverrides(new Properties()); + } + + formatSharedEnvironmentRunName(runRequest); + } + + private void setRunRequestTestDetails(SubmitRunRequest runRequest) throws FrameworkException { + String language = runRequest.getLanguage(); + if (language == null) { + language = "java"; + runRequest.setLanguage(language); + } + + if (language.equals("java")) { + if (runRequest.getBundleName() == null) { + throw new FrameworkException("Missing bundle name"); + } + runRequest.setBundleTest(runRequest.getBundleName() + "/" + runRequest.getTestName()); + } else if (language.equals("gherkin")) { + runRequest.setBundleTest(NO_BUNDLE); + runRequest.setGherkinTest(runRequest.getTestName()); + runRequest.setBundleName(NO_BUNDLE); + } + } + + private void setRunRequestRequestorDefault(SubmitRunRequest runRequest) throws FrameworkException { + String requestor = AbstractManager.nulled(runRequest.getRequestor()); + if (requestor == null) { + requestor = AbstractManager.nulled(cps.getProperty("run", "requestor")); + if (requestor == null) { + requestor = "unknown"; + } + runRequest.setRequestor(requestor); + } + } + + private void formatSharedEnvironmentRunName(SubmitRunRequest runRequest) throws FrameworkException { + SharedEnvironmentPhase sharedEnvironmentPhase = runRequest.getSharedEnvironmentPhase(); + if (sharedEnvironmentPhase != null) { + String sharedEnvironmentRunName = runRequest.getSharedEnvironmentRunName(); + + if (sharedEnvironmentRunName == null || sharedEnvironmentRunName.trim().isEmpty()) { + throw new FrameworkException("Missing run name for shared environment"); + } + + runRequest.setSharedEnvironmentRunName(sharedEnvironmentRunName.trim().toUpperCase()); + } + } } \ No newline at end of file diff --git a/galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/beans/Property.java b/galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/beans/Property.java new file mode 100644 index 000000000..083ff3763 --- /dev/null +++ b/galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/beans/Property.java @@ -0,0 +1,37 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package dev.galasa.framework.beans; + +import com.google.gson.annotations.SerializedName; + +public class Property { + @SerializedName("key") + private String key; + + @SerializedName("value") + private String value; + + public Property(String key, String value) { + this.key = key; + this.value = value; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/beans/SubmitRunRequest.java b/galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/beans/SubmitRunRequest.java new file mode 100644 index 000000000..3f64268a7 --- /dev/null +++ b/galasa-parent/dev.galasa.framework/src/main/java/dev/galasa/framework/beans/SubmitRunRequest.java @@ -0,0 +1,198 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package dev.galasa.framework.beans; + +import java.util.Properties; + +import dev.galasa.framework.spi.FrameworkException; +import dev.galasa.framework.spi.IFrameworkRuns.SharedEnvironmentPhase; + +/** + * An internal bean class containing the details required to submit a test run to the Galasa framework. + */ +public class SubmitRunRequest { + + private String runType; + private String requestor; + private String bundleName; + private String testName; + private String groupName; + private String mavenRepository; + private String obr; + private String stream; + private boolean isLocalRun; + private boolean isTraceEnabled = false; + private Properties overrides = new Properties(); + private SharedEnvironmentPhase sharedEnvironmentPhase; + private String sharedEnvironmentRunName; + private String language = "java"; + private String bundleTest; + private String gherkinTest; + + public SubmitRunRequest( + String runType, + String requestor, + String bundleName, + String testName, + String groupName, + String mavenRepository, + String obr, + String stream, + boolean isLocalRun, + boolean isTraceEnabled, + Properties overrides, + SharedEnvironmentPhase sharedEnvironmentPhase, + String sharedEnvironmentRunName, + String language + ) throws FrameworkException { + setTestName(testName); + + this.runType = runType; + this.requestor = requestor; + this.bundleName = bundleName; + this.groupName = groupName; + this.mavenRepository = mavenRepository; + this.obr = obr; + this.stream = stream; + this.isLocalRun = isLocalRun; + this.isTraceEnabled = isTraceEnabled; + this.overrides = overrides; + this.sharedEnvironmentPhase = sharedEnvironmentPhase; + this.sharedEnvironmentRunName = sharedEnvironmentRunName; + this.language = language; + } + + public String getRunType() { + return runType; + } + + public void setRunType(String runType) { + this.runType = runType; + } + + public String getRequestor() { + return requestor; + } + + public void setRequestor(String requestor) { + this.requestor = requestor; + } + + public String getBundleName() { + return bundleName; + } + + public void setBundleName(String bundleName) { + this.bundleName = bundleName; + } + + public String getTestName() { + return testName; + } + + public void setTestName(String testName) throws FrameworkException { + if (testName == null) { + throw new FrameworkException("Missing test name"); + } + this.testName = testName; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public String getMavenRepository() { + return mavenRepository; + } + + public void setMavenRepository(String mavenRepository) { + this.mavenRepository = mavenRepository; + } + + public String getObr() { + return obr; + } + + public void setObr(String obr) { + this.obr = obr; + } + + public String getStream() { + return stream; + } + + public void setStream(String stream) { + this.stream = stream; + } + + public boolean isLocalRun() { + return isLocalRun; + } + + public void setLocalRun(boolean isLocalRun) { + this.isLocalRun = isLocalRun; + } + + public boolean isTraceEnabled() { + return isTraceEnabled; + } + + public void setTraceEnabled(boolean isTraceEnabled) { + this.isTraceEnabled = isTraceEnabled; + } + + public Properties getOverrides() { + return overrides; + } + + public void setOverrides(Properties overrides) { + this.overrides = overrides; + } + + public SharedEnvironmentPhase getSharedEnvironmentPhase() { + return sharedEnvironmentPhase; + } + + public void setSharedEnvironmentPhase(SharedEnvironmentPhase sharedEnvironmentPhase) { + this.sharedEnvironmentPhase = sharedEnvironmentPhase; + } + + public String getSharedEnvironmentRunName() { + return sharedEnvironmentRunName; + } + + public void setSharedEnvironmentRunName(String sharedEnvironmentRunName) { + this.sharedEnvironmentRunName = sharedEnvironmentRunName; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public String getBundleTest() { + return bundleTest; + } + + public void setBundleTest(String bundleTest) { + this.bundleTest = bundleTest; + } + + public String getGherkinTest() { + return gherkinTest; + } + + public void setGherkinTest(String gherkinTest) { + this.gherkinTest = gherkinTest; + } +} diff --git a/galasa-parent/dev.galasa.framework/src/test/java/dev/galasa/framework/FrameworkRunsTest.java b/galasa-parent/dev.galasa.framework/src/test/java/dev/galasa/framework/FrameworkRunsTest.java new file mode 100644 index 000000000..b29e49797 --- /dev/null +++ b/galasa-parent/dev.galasa.framework/src/test/java/dev/galasa/framework/FrameworkRunsTest.java @@ -0,0 +1,756 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package dev.galasa.framework; + +import static org.assertj.core.api.Assertions.*; + +import java.util.HashMap; +import java.util.Properties; +import java.util.Map.Entry; + +import org.junit.Test; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +import dev.galasa.framework.mocks.MockCPSStore; +import dev.galasa.framework.mocks.MockDSSStore; +import dev.galasa.framework.mocks.MockFramework; +import dev.galasa.framework.spi.FrameworkException; +import dev.galasa.framework.spi.IRun; +import dev.galasa.framework.spi.IFrameworkRuns.SharedEnvironmentPhase; +import dev.galasa.framework.spi.utils.GalasaGson; + +public class FrameworkRunsTest { + + private static final GalasaGson gson = new GalasaGson(); + + private String getExpectedOverridesJson(Properties properties) { + JsonArray overridesArray = new JsonArray(); + + for (Entry entry : properties.entrySet()) { + JsonObject propertyJson = new JsonObject(); + propertyJson.addProperty("key", (String) entry.getKey()); + propertyJson.addProperty("value", (String) entry.getValue()); + overridesArray.add(propertyJson); + } + return gson.toJson(overridesArray); + } + + @Test + public void testSubmitRunReturnsSubmittedRun() throws Exception { + // Given... + MockDSSStore mockDss = new MockDSSStore(new HashMap<>()); + MockCPSStore mockCps = new MockCPSStore(new HashMap<>()); + MockFramework mockFramework = new MockFramework(mockCps, mockDss); + + FrameworkRuns frameworkRuns = new FrameworkRuns(mockFramework); + + String runType = "unknown"; + String requestor = "me"; + String bundleName = "mybundle"; + String testName = "mytest"; + String groupName = "my.group"; + String mavenRepo = "https://my.maven.repo"; + String obr = "mvn:my.group/my.group.obr/0.38.0/obr"; + String stream = "a-test-stream"; + boolean local = true; + boolean trace = true; + + Properties overrides = new Properties(); + String override1Key = "override1"; + String override1Value = "this-is-an-override"; + String override2Key = "override2"; + String override2Value = "this-is-another-override"; + overrides.setProperty(override1Key, override1Value); + overrides.setProperty(override2Key, override2Value); + + SharedEnvironmentPhase sharedEnvironmentPhase = null; + String sharedEnvironmentRunName = null; + String language = "java"; + + // When... + IRun run = frameworkRuns.submitRun( + runType, + requestor, + bundleName, + testName, + groupName, + mavenRepo, + obr, + stream, + local, + trace, + overrides, + sharedEnvironmentPhase, + sharedEnvironmentRunName, + language + ); + + // Then... + assertThat(run).isNotNull(); + assertThat(run.getName()).isEqualTo("U1"); + assertThat(run.getTest()).isEqualTo(bundleName + "/" + testName); + + // Check that the DSS has been populated with the correct run-related properties + assertThat(mockDss.get("request.prefix.U.lastused")).isEqualTo("1"); + assertThat(mockDss.get("run.U1.obr")).isEqualTo(obr); + assertThat(mockDss.get("run.U1.group")).isEqualTo(groupName); + assertThat(mockDss.get("run.U1.requestor")).isEqualTo(requestor); + assertThat(mockDss.get("run.U1.testbundle")).isEqualTo(bundleName); + assertThat(mockDss.get("run.U1.repository")).isEqualTo(mavenRepo); + assertThat(mockDss.get("run.U1.stream")).isEqualTo(stream); + assertThat(mockDss.get("run.U1.local")).isEqualTo(Boolean.toString(local)); + assertThat(mockDss.get("run.U1.testclass")).isEqualTo(testName); + assertThat(mockDss.get("run.U1.trace")).isEqualTo(Boolean.toString(trace)); + assertThat(mockDss.get("run.U1.request.type")).isEqualTo(runType.toUpperCase()); + assertThat(mockDss.get("run.U1.status")).isEqualTo("queued"); + assertThat(mockDss.get("run.U1.overrides")).isEqualTo(getExpectedOverridesJson(overrides)); + } + + @Test + public void testSubmitRunWithMaxRunNumberReachedReturnsSubmittedRunOk() throws Exception { + // Given... + MockDSSStore mockDss = new MockDSSStore(new HashMap<>()); + mockDss.put("request.prefix.U.lastused", "10"); + + MockCPSStore mockCps = new MockCPSStore(new HashMap<>()); + mockCps.setProperty("request.prefix.U.maximum", "10"); + + MockFramework mockFramework = new MockFramework(mockCps, mockDss); + + FrameworkRuns frameworkRuns = new FrameworkRuns(mockFramework); + + String runType = "unknown"; + String requestor = "me"; + String bundleName = "mybundle"; + String testName = "mytest"; + String groupName = "my.group"; + String mavenRepo = "https://my.maven.repo"; + String obr = "mvn:my.group/my.group.obr/0.38.0/obr"; + String stream = "a-test-stream"; + boolean local = true; + boolean trace = true; + + Properties overrides = new Properties(); + String override1Key = "override1"; + String override1Value = "this-is-an-override"; + String override2Key = "override2"; + String override2Value = "this-is-another-override"; + overrides.setProperty(override1Key, override1Value); + overrides.setProperty(override2Key, override2Value); + + SharedEnvironmentPhase sharedEnvironmentPhase = null; + String sharedEnvironmentRunName = null; + String language = "java"; + + // When... + IRun run = frameworkRuns.submitRun( + runType, + requestor, + bundleName, + testName, + groupName, + mavenRepo, + obr, + stream, + local, + trace, + overrides, + sharedEnvironmentPhase, + sharedEnvironmentRunName, + language + ); + + // Then... + assertThat(run).isNotNull(); + assertThat(run.getName()).isEqualTo("U1"); + assertThat(run.getTest()).isEqualTo(bundleName + "/" + testName); + + // Check that the DSS has been populated with the correct run-related properties + assertThat(mockDss.get("request.prefix.U.lastused")).isEqualTo("1"); + assertThat(mockDss.get("run.U1.obr")).isEqualTo(obr); + assertThat(mockDss.get("run.U1.group")).isEqualTo(groupName); + assertThat(mockDss.get("run.U1.requestor")).isEqualTo(requestor); + assertThat(mockDss.get("run.U1.testbundle")).isEqualTo(bundleName); + assertThat(mockDss.get("run.U1.repository")).isEqualTo(mavenRepo); + assertThat(mockDss.get("run.U1.stream")).isEqualTo(stream); + assertThat(mockDss.get("run.U1.local")).isEqualTo(Boolean.toString(local)); + assertThat(mockDss.get("run.U1.testclass")).isEqualTo(testName); + assertThat(mockDss.get("run.U1.trace")).isEqualTo(Boolean.toString(trace)); + assertThat(mockDss.get("run.U1.request.type")).isEqualTo(runType.toUpperCase()); + assertThat(mockDss.get("run.U1.status")).isEqualTo("queued"); + assertThat(mockDss.get("run.U1.overrides")).isEqualTo(getExpectedOverridesJson(overrides)); + } + + @Test + public void testSubmitRunWithMaxRunNumberReachedTwiceThrowsError() throws Exception { + // Given... + MockDSSStore mockDss = new MockDSSStore(new HashMap<>()); + mockDss.put("request.prefix.U.lastused", "10"); + + mockDss.setSwapSetToFail(true); + + MockCPSStore mockCps = new MockCPSStore(new HashMap<>()); + mockCps.setProperty("request.prefix.U.maximum", "0"); + + MockFramework mockFramework = new MockFramework(mockCps, mockDss); + + FrameworkRuns frameworkRuns = new FrameworkRuns(mockFramework); + + String runType = "unknown"; + String requestor = "me"; + String bundleName = "mybundle"; + String testName = "mytest"; + String groupName = "my.group"; + String mavenRepo = "https://my.maven.repo"; + String obr = "mvn:my.group/my.group.obr/0.38.0/obr"; + String stream = "a-test-stream"; + boolean local = true; + boolean trace = true; + + Properties overrides = new Properties(); + String override1Key = "override1"; + String override1Value = "this-is-an-override"; + String override2Key = "override2"; + String override2Value = "this-is-another-override"; + overrides.setProperty(override1Key, override1Value); + overrides.setProperty(override2Key, override2Value); + + SharedEnvironmentPhase sharedEnvironmentPhase = null; + String sharedEnvironmentRunName = null; + String language = "java"; + + // When... + FrameworkException thrown = catchThrowableOfType(() -> { + frameworkRuns.submitRun( + runType, + requestor, + bundleName, + testName, + groupName, + mavenRepo, + obr, + stream, + local, + trace, + overrides, + sharedEnvironmentPhase, + sharedEnvironmentRunName, + language + ); + }, FrameworkException.class); + + // Then... + assertThat(thrown).isNotNull(); + assertThat(thrown.getMessage()).isEqualTo("Not enough request type numbers available, looped twice"); + } + + @Test + public void testSubmitRunWithNoTestNameThrowsCorrectError() throws Exception { + // Given... + MockDSSStore mockDss = new MockDSSStore(new HashMap<>()); + MockCPSStore mockCps = new MockCPSStore(new HashMap<>()); + MockFramework mockFramework = new MockFramework(mockCps, mockDss); + + FrameworkRuns frameworkRuns = new FrameworkRuns(mockFramework); + + String testName = null; + + String runType = "unknown"; + String requestor = "me"; + String bundleName = "mybundle"; + String groupName = "my.group"; + String mavenRepo = "https://my.maven.repo"; + String obr = "mvn:my.group/my.group.obr/0.38.0/obr"; + String stream = "a-test-stream"; + boolean local = true; + boolean trace = true; + + Properties overrides = new Properties(); + + SharedEnvironmentPhase sharedEnvironmentPhase = null; + String sharedEnvironmentRunName = null; + String language = "java"; + + // When... + FrameworkException thrown = catchThrowableOfType(() -> { + frameworkRuns.submitRun( + runType, + requestor, + bundleName, + testName, + groupName, + mavenRepo, + obr, + stream, + local, + trace, + overrides, + sharedEnvironmentPhase, + sharedEnvironmentRunName, + language + ); + }, FrameworkException.class); + + // Then... + assertThat(thrown).isNotNull(); + assertThat(thrown.getMessage()).contains("Missing test name"); + } + + @Test + public void testSubmitRunWithNoBundleNameThrowsCorrectError() throws Exception { + // Given... + MockDSSStore mockDss = new MockDSSStore(new HashMap<>()); + MockCPSStore mockCps = new MockCPSStore(new HashMap<>()); + MockFramework mockFramework = new MockFramework(mockCps, mockDss); + + FrameworkRuns frameworkRuns = new FrameworkRuns(mockFramework); + + String bundleName = null; + + String testName = "mytest"; + String runType = "unknown"; + String requestor = "me"; + String groupName = "my.group"; + String mavenRepo = "https://my.maven.repo"; + String obr = "mvn:my.group/my.group.obr/0.38.0/obr"; + String stream = "a-test-stream"; + boolean local = true; + boolean trace = true; + + Properties overrides = new Properties(); + + SharedEnvironmentPhase sharedEnvironmentPhase = null; + String sharedEnvironmentRunName = null; + String language = "java"; + + // When... + FrameworkException thrown = catchThrowableOfType(() -> { + frameworkRuns.submitRun( + runType, + requestor, + bundleName, + testName, + groupName, + mavenRepo, + obr, + stream, + local, + trace, + overrides, + sharedEnvironmentPhase, + sharedEnvironmentRunName, + language + ); + }, FrameworkException.class); + + // Then... + assertThat(thrown).isNotNull(); + assertThat(thrown.getMessage()).contains("Missing bundle name"); + } + + @Test + public void testSubmitRunWithNoLanguageDefaultsToJavaBundleFormat() throws Exception { + // Given... + MockDSSStore mockDss = new MockDSSStore(new HashMap<>()); + MockCPSStore mockCps = new MockCPSStore(new HashMap<>()); + MockFramework mockFramework = new MockFramework(mockCps, mockDss); + + FrameworkRuns frameworkRuns = new FrameworkRuns(mockFramework); + + String language = null; + + String bundleName = "mybundle"; + String testName = "mytest"; + String runType = "unknown"; + String requestor = "me"; + String groupName = "my.group"; + String mavenRepo = "https://my.maven.repo"; + String obr = "mvn:my.group/my.group.obr/0.38.0/obr"; + String stream = "a-test-stream"; + boolean local = true; + boolean trace = true; + + Properties overrides = new Properties(); + + SharedEnvironmentPhase sharedEnvironmentPhase = null; + String sharedEnvironmentRunName = null; + + // When... + IRun run = frameworkRuns.submitRun( + runType, + requestor, + bundleName, + testName, + groupName, + mavenRepo, + obr, + stream, + local, + trace, + overrides, + sharedEnvironmentPhase, + sharedEnvironmentRunName, + language + ); + + // Then... + assertThat(run).isNotNull(); + assertThat(run.getName()).isEqualTo("U1"); + assertThat(run.getTest()).isEqualTo(bundleName + "/" + testName); + } + + @Test + public void testSubmitRunWithLocalRunTypeSetsRunPrefixCorrectly() throws Exception { + // Given... + MockDSSStore mockDss = new MockDSSStore(new HashMap<>()); + MockCPSStore mockCps = new MockCPSStore(new HashMap<>()); + MockFramework mockFramework = new MockFramework(mockCps, mockDss); + + FrameworkRuns frameworkRuns = new FrameworkRuns(mockFramework); + + String runType = "local"; + + String language = "java"; + String bundleName = "mybundle"; + String testName = "mytest"; + String requestor = "me"; + String groupName = "my.group"; + String mavenRepo = "https://my.maven.repo"; + String obr = "mvn:my.group/my.group.obr/0.38.0/obr"; + String stream = "a-test-stream"; + boolean local = true; + boolean trace = true; + + Properties overrides = new Properties(); + + SharedEnvironmentPhase sharedEnvironmentPhase = null; + String sharedEnvironmentRunName = null; + + // When... + IRun run = frameworkRuns.submitRun( + runType, + requestor, + bundleName, + testName, + groupName, + mavenRepo, + obr, + stream, + local, + trace, + overrides, + sharedEnvironmentPhase, + sharedEnvironmentRunName, + language + ); + + // Then... + assertThat(run).isNotNull(); + assertThat(run.getType()).isEqualTo(runType.toUpperCase()); + assertThat(run.getName()).isEqualTo("L1"); + } + + @Test + public void testSubmitRunWithGherkinReturnsRunCorrectly() throws Exception { + // Given... + MockDSSStore mockDss = new MockDSSStore(new HashMap<>()); + MockCPSStore mockCps = new MockCPSStore(new HashMap<>()); + MockFramework mockFramework = new MockFramework(mockCps, mockDss); + + FrameworkRuns frameworkRuns = new FrameworkRuns(mockFramework); + + String language = "gherkin"; + + String runType = "local"; + String bundleName = "mybundle"; + String testName = "mygherkintest"; + String requestor = "me"; + String groupName = "my.group"; + String mavenRepo = "https://my.maven.repo"; + String obr = "mvn:my.group/my.group.obr/0.38.0/obr"; + String stream = "a-test-stream"; + boolean local = true; + boolean trace = true; + + Properties overrides = new Properties(); + + SharedEnvironmentPhase sharedEnvironmentPhase = null; + String sharedEnvironmentRunName = null; + + // When... + IRun run = frameworkRuns.submitRun( + runType, + requestor, + bundleName, + testName, + groupName, + mavenRepo, + obr, + stream, + local, + trace, + overrides, + sharedEnvironmentPhase, + sharedEnvironmentRunName, + language + ); + + // Then... + assertThat(run).isNotNull(); + assertThat(run.getName()).isEqualTo("L1"); + assertThat(run.getGherkin()).isEqualTo(testName); + assertThat(run.getTestBundleName()).isEqualTo(null); + + // Check that the DSS has been populated with the correct run-related properties + assertThat(mockDss.get("run.L1.gherkin")).isEqualTo(testName); + assertThat(mockDss.get("run.L1.testclass")).isEqualTo(testName); + assertThat(mockDss.get("run.L1.testbundle")).isEqualTo("none"); + assertThat(mockDss.get("request.prefix.L.lastused")).isEqualTo("1"); + assertThat(mockDss.get("run.L1.obr")).isEqualTo(obr); + assertThat(mockDss.get("run.L1.group")).isEqualTo(groupName); + assertThat(mockDss.get("run.L1.requestor")).isEqualTo(requestor); + assertThat(mockDss.get("run.L1.repository")).isEqualTo(mavenRepo); + assertThat(mockDss.get("run.L1.stream")).isEqualTo(stream); + assertThat(mockDss.get("run.L1.local")).isEqualTo(Boolean.toString(local)); + assertThat(mockDss.get("run.L1.trace")).isEqualTo(Boolean.toString(trace)); + assertThat(mockDss.get("run.L1.request.type")).isEqualTo(runType.toUpperCase()); + assertThat(mockDss.get("run.L1.status")).isEqualTo("queued"); + } + + @Test + public void testSubmitRunWithSharedEnvironmentBuildPhaseReturnsRunCorrectly() throws Exception { + // Given... + MockDSSStore mockDss = new MockDSSStore(new HashMap<>()); + MockCPSStore mockCps = new MockCPSStore(new HashMap<>()); + MockFramework mockFramework = new MockFramework(mockCps, mockDss); + + FrameworkRuns frameworkRuns = new FrameworkRuns(mockFramework); + + SharedEnvironmentPhase sharedEnvironmentPhase = SharedEnvironmentPhase.BUILD; + String sharedEnvironmentRunName = "SHARED-RUN1"; + + String language = "java"; + String runType = "local"; + String bundleName = "mybundle"; + String testName = "mysharedenvtest"; + String requestor = "me"; + String groupName = "my.group"; + String mavenRepo = "https://my.maven.repo"; + String obr = "mvn:my.group/my.group.obr/0.38.0/obr"; + String stream = "a-test-stream"; + boolean local = true; + boolean trace = true; + + Properties overrides = new Properties(); + + // When... + IRun run = frameworkRuns.submitRun( + runType, + requestor, + bundleName, + testName, + groupName, + mavenRepo, + obr, + stream, + local, + trace, + overrides, + sharedEnvironmentPhase, + sharedEnvironmentRunName, + language + ); + + // Then... + assertThat(run).isNotNull(); + assertThat(run.getName()).isEqualTo(sharedEnvironmentRunName); + + Properties expectedOverrides = new Properties(); + expectedOverrides.put("framework.run.shared.environment.phase", "BUILD"); + + // Check that the DSS has been populated with the correct run-related properties + assertThat(mockDss.get("run.SHARED-RUN1.overrides")).isEqualTo(getExpectedOverridesJson(expectedOverrides)); + assertThat(mockDss.get("run.SHARED-RUN1.shared.environment")).isEqualTo("true"); + assertThat(mockDss.get("run.SHARED-RUN1.obr")).isEqualTo(obr); + assertThat(mockDss.get("run.SHARED-RUN1.group")).isEqualTo(groupName); + assertThat(mockDss.get("run.SHARED-RUN1.requestor")).isEqualTo(requestor); + assertThat(mockDss.get("run.SHARED-RUN1.testbundle")).isEqualTo(bundleName); + assertThat(mockDss.get("run.SHARED-RUN1.repository")).isEqualTo(mavenRepo); + assertThat(mockDss.get("run.SHARED-RUN1.stream")).isEqualTo(stream); + assertThat(mockDss.get("run.SHARED-RUN1.local")).isEqualTo(Boolean.toString(local)); + assertThat(mockDss.get("run.SHARED-RUN1.testclass")).isEqualTo(testName); + assertThat(mockDss.get("run.SHARED-RUN1.trace")).isEqualTo(Boolean.toString(trace)); + assertThat(mockDss.get("run.SHARED-RUN1.request.type")).isEqualTo(runType.toUpperCase()); + assertThat(mockDss.get("run.SHARED-RUN1.status")).isEqualTo("queued"); + } + + @Test + public void testSubmitRunWithSharedEnvironmentBuildPhaseAndNoRunNameThrowsError() throws Exception { + // Given... + MockDSSStore mockDss = new MockDSSStore(new HashMap<>()); + MockCPSStore mockCps = new MockCPSStore(new HashMap<>()); + MockFramework mockFramework = new MockFramework(mockCps, mockDss); + + FrameworkRuns frameworkRuns = new FrameworkRuns(mockFramework); + + SharedEnvironmentPhase sharedEnvironmentPhase = SharedEnvironmentPhase.BUILD; + String sharedEnvironmentRunName = null; + + String language = "java"; + String runType = "local"; + String bundleName = "mybundle"; + String testName = "mysharedenvtest"; + String requestor = "me"; + String groupName = "my.group"; + String mavenRepo = "https://my.maven.repo"; + String obr = "mvn:my.group/my.group.obr/0.38.0/obr"; + String stream = "a-test-stream"; + boolean local = true; + boolean trace = true; + + Properties overrides = new Properties(); + + // When... + FrameworkException thrown = catchThrowableOfType(() -> { + frameworkRuns.submitRun( + runType, + requestor, + bundleName, + testName, + groupName, + mavenRepo, + obr, + stream, + local, + trace, + overrides, + sharedEnvironmentPhase, + sharedEnvironmentRunName, + language + ); + }, FrameworkException.class); + + // Then... + assertThat(thrown).isNotNull(); + assertThat(thrown.getMessage()).isEqualTo("Missing run name for shared environment"); + } + + @Test + public void testSubmitRunWithSharedEnvironmentDiscardPhaseReturnsRunCorrectly() throws Exception { + // Given... + MockDSSStore mockDss = new MockDSSStore(new HashMap<>()); + String sharedEnvironmentRunName = "SHARED-RUN1"; + + mockDss.put("run." + sharedEnvironmentRunName + ".shared.environment", "true"); + mockDss.put("run." + sharedEnvironmentRunName + ".status", "up"); + + MockCPSStore mockCps = new MockCPSStore(new HashMap<>()); + MockFramework mockFramework = new MockFramework(mockCps, mockDss); + + FrameworkRuns frameworkRuns = new FrameworkRuns(mockFramework); + + SharedEnvironmentPhase sharedEnvironmentPhase = SharedEnvironmentPhase.DISCARD; + + String language = "java"; + String runType = "local"; + String bundleName = "mybundle"; + String testName = "mysharedenvtest"; + String requestor = "me"; + String groupName = "my.group"; + String mavenRepo = "https://my.maven.repo"; + String obr = "mvn:my.group/my.group.obr/0.38.0/obr"; + String stream = "a-test-stream"; + boolean local = true; + boolean trace = true; + + Properties overrides = new Properties(); + + // When... + IRun run = frameworkRuns.submitRun( + runType, + requestor, + bundleName, + testName, + groupName, + mavenRepo, + obr, + stream, + local, + trace, + overrides, + sharedEnvironmentPhase, + sharedEnvironmentRunName, + language + ); + + // Then... + assertThat(run).isNotNull(); + assertThat(run.getName()).isEqualTo(sharedEnvironmentRunName); + + // Check that the DSS has been populated with the correct run-related properties + assertThat(mockDss.get("run.SHARED-RUN1.overrides")).isEqualTo("framework.run.shared.environment.phase=DISCARD"); + assertThat(mockDss.get("run.SHARED-RUN1.shared.environment")).isEqualTo("true"); + assertThat(mockDss.get("run.SHARED-RUN1.group")).isEqualTo(groupName); + assertThat(mockDss.get("run.SHARED-RUN1.status")).isEqualTo("queued"); + } + + @Test + public void testSubmitRunWithDuplicateSharedEnvironmentBuildPhaseRunThrowsError() throws Exception { + // Given... + MockDSSStore mockDss = new MockDSSStore(new HashMap<>()); + mockDss.setSwapSetToFail(true); + + MockCPSStore mockCps = new MockCPSStore(new HashMap<>()); + String sharedEnvironmentRunName = "SHARED-RUN1"; + + mockDss.put("run." + sharedEnvironmentRunName + ".test", "existing/test"); + MockFramework mockFramework = new MockFramework(mockCps, mockDss); + + FrameworkRuns frameworkRuns = new FrameworkRuns(mockFramework); + + SharedEnvironmentPhase sharedEnvironmentPhase = SharedEnvironmentPhase.BUILD; + + String language = "java"; + String runType = "local"; + String bundleName = "mybundle"; + String testName = "mysharedenvtest"; + String requestor = "me"; + String groupName = "my.group"; + String mavenRepo = "https://my.maven.repo"; + String obr = "mvn:my.group/my.group.obr/0.38.0/obr"; + String stream = "a-test-stream"; + boolean local = true; + boolean trace = true; + + Properties overrides = new Properties(); + + // When... + FrameworkException thrown = catchThrowableOfType(() -> { + frameworkRuns.submitRun( + runType, + requestor, + bundleName, + testName, + groupName, + mavenRepo, + obr, + stream, + local, + trace, + overrides, + sharedEnvironmentPhase, + sharedEnvironmentRunName, + language + ); + }, FrameworkException.class); + + // Then... + assertThat(thrown).isNotNull(); + assertThat(thrown.getMessage()).contains("Unable to submit shared environment run", sharedEnvironmentRunName, "is there a duplicate runname?"); + } +} diff --git a/galasa-parent/dev.galasa.framework/src/test/java/dev/galasa/framework/mocks/MockCPSStore.java b/galasa-parent/dev.galasa.framework/src/test/java/dev/galasa/framework/mocks/MockCPSStore.java index 599b0c44a..c4f0a0bab 100644 --- a/galasa-parent/dev.galasa.framework/src/test/java/dev/galasa/framework/mocks/MockCPSStore.java +++ b/galasa-parent/dev.galasa.framework/src/test/java/dev/galasa/framework/mocks/MockCPSStore.java @@ -37,7 +37,7 @@ public MockCPSStore(@NotNull Map properties ) { @Override public void setProperty(@NotNull String key, @NotNull String value) throws ConfigurationPropertyStoreException { - throw new UnsupportedOperationException("Unimplemented method 'setProperty'"); + this.properties.put(key, value); } @Override diff --git a/galasa-parent/dev.galasa.framework/src/test/java/dev/galasa/framework/mocks/MockDSSStore.java b/galasa-parent/dev.galasa.framework/src/test/java/dev/galasa/framework/mocks/MockDSSStore.java index bfc1d1671..9da54bb77 100644 --- a/galasa-parent/dev.galasa.framework/src/test/java/dev/galasa/framework/mocks/MockDSSStore.java +++ b/galasa-parent/dev.galasa.framework/src/test/java/dev/galasa/framework/mocks/MockDSSStore.java @@ -7,6 +7,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.UUID; @@ -19,20 +20,25 @@ import dev.galasa.framework.spi.DynamicStatusStoreException; import dev.galasa.framework.spi.DynamicStatusStoreMatchException; import dev.galasa.framework.spi.IDssAction; +import dev.galasa.framework.spi.IDynamicResource; +import dev.galasa.framework.spi.IDynamicRun; import dev.galasa.framework.spi.IDynamicStatusStore; +import dev.galasa.framework.spi.IDynamicStatusStoreService; import dev.galasa.framework.spi.IDynamicStatusStoreWatcher; -public class MockDSSStore implements IDynamicStatusStore { +public class MockDSSStore implements IDynamicStatusStore, IDynamicStatusStoreService { private Map valueMap ; private Log logger = LogFactory.getLog(MockDSSStore.class.getName()); + private boolean isSwapSetToFail = false; + public MockDSSStore(Map valueMap) { this.valueMap = valueMap; } @Override public void put(@NotNull String key, @NotNull String value) throws DynamicStatusStoreException { - throw new UnsupportedOperationException("Unimplemented method 'put'"); + valueMap.put(key, value); } @Override @@ -52,8 +58,14 @@ public boolean putSwap(@NotNull String key, String oldValue, @NotNull String new public boolean putSwap(@NotNull String key, String oldValue, @NotNull String newValue, @NotNull Map others) throws DynamicStatusStoreException { logger.debug("DSS putswap of property "+key+" oldValue:"+oldValue+" newValue:"+newValue); - valueMap.put(key,newValue); - return true; + boolean isSuccessful = !isSwapSetToFail; + if (isSuccessful) { + valueMap.put(key,newValue); + for (Entry entry : others.entrySet()) { + valueMap.put(entry.getKey(), entry.getValue()); + } + } + return isSuccessful; } @Override @@ -75,6 +87,10 @@ public boolean putSwap(@NotNull String key, String oldValue, @NotNull String new return results; } + public void setSwapSetToFail(boolean isSwapSetToFail) { + this.isSwapSetToFail = isSwapSetToFail; + } + @Override public void delete(@NotNull String key) throws DynamicStatusStoreException { throw new UnsupportedOperationException("Unimplemented method 'delete'"); @@ -115,5 +131,15 @@ public void unwatch(UUID watchId) throws DynamicStatusStoreException { public void shutdown() throws DynamicStatusStoreException { throw new UnsupportedOperationException("Unimplemented method 'shutdown'"); } + + @Override + public IDynamicResource getDynamicResource(String resourceKey) { + throw new UnsupportedOperationException("Unimplemented method 'getDynamicResource'"); + } + + @Override + public IDynamicRun getDynamicRun() throws DynamicStatusStoreException { + throw new UnsupportedOperationException("Unimplemented method 'getDynamicRun'"); + } } diff --git a/galasa-parent/dev.galasa.framework/src/test/java/dev/galasa/framework/mocks/MockFramework.java b/galasa-parent/dev.galasa.framework/src/test/java/dev/galasa/framework/mocks/MockFramework.java index 195959875..ac402f6ba 100644 --- a/galasa-parent/dev.galasa.framework/src/test/java/dev/galasa/framework/mocks/MockFramework.java +++ b/galasa-parent/dev.galasa.framework/src/test/java/dev/galasa/framework/mocks/MockFramework.java @@ -9,7 +9,9 @@ import dev.galasa.framework.internal.cps.FpfConfigurationPropertyStore; import dev.galasa.framework.internal.cps.FrameworkConfigurationPropertyService; import dev.galasa.framework.spi.ConfigurationPropertyStoreException; +import dev.galasa.framework.spi.DynamicStatusStoreException; import dev.galasa.framework.spi.IConfigurationPropertyStoreService; +import dev.galasa.framework.spi.IDynamicStatusStoreService; import java.io.File; import java.util.Properties; @@ -19,23 +21,33 @@ public class MockFramework extends Framework { private Properties overrides = new Properties(); private Properties records = new Properties(); - private File cps; + private File cpsFile; + + private MockDSSStore mockDss; + private MockCPSStore mockCps; public MockFramework() { super(); } + public MockFramework(MockCPSStore mockCps, MockDSSStore mockDss) { + this.mockCps = mockCps; + this.mockDss = mockDss; + } + public MockFramework(File cpsFile) { - this.cps = cpsFile; + this.cpsFile = cpsFile; } @Override public @NotNull IConfigurationPropertyStoreService getConfigurationPropertyService(@NotNull String namespace) throws ConfigurationPropertyStoreException { IConfigurationPropertyStoreService cpsService = null; - if (this.cps != null) { + if (this.mockCps != null) { + cpsService = mockCps; + } else if (this.cpsFile != null) { try { cpsService = new FrameworkConfigurationPropertyService(this, - new FpfConfigurationPropertyStore(cps.toURI()), overrides, records, namespace); + new FpfConfigurationPropertyStore(cpsFile.toURI()), overrides, records, namespace); } catch (Exception e) { throw new ConfigurationPropertyStoreException("error initialising", e); } @@ -44,4 +56,21 @@ public MockFramework(File cpsFile) { } return cpsService; } + + @Override + public @NotNull IDynamicStatusStoreService getDynamicStatusStoreService(@NotNull String namespace) throws DynamicStatusStoreException { + IDynamicStatusStoreService dss = mockDss; + if (dss == null) { + dss = super.getDynamicStatusStoreService(namespace); + } + return dss; + } + + public void setMockCps(MockCPSStore mockCps) { + this.mockCps = mockCps; + } + + public void setMockDss(MockDSSStore mockDss) { + this.mockDss = mockDss; + } } \ No newline at end of file