diff --git a/src/org/labkey/test/stress/Simulation.java b/src/org/labkey/test/stress/Simulation.java
index f18672e71d..c1907d51ae 100644
--- a/src/org/labkey/test/stress/Simulation.java
+++ b/src/org/labkey/test/stress/Simulation.java
@@ -22,6 +22,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
@@ -35,7 +36,6 @@
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.util.stream.Collectors;
/**
* Simulation: A series of activities that represents some user workflow (e.g. loading the dashboard, navigating to the sample finder, and performing a search). For simplicity, API simulations in the initial proof of concept will consist of a single activity.
@@ -230,7 +230,10 @@ private void makeRequest(Activity.RequestParams requestParams) throws Interrupte
* {@link #_connectionFactory} - used to generate an API connection for the simulation to use
*
*
- * {@link #activityDefinitions} - {@link Activity} list that defines the simulation. These are deserialized from {@link ApiTestsDocument} XML files.
+ * {@link #activityFiles} - {@link ApiTestsDocument} XML files that define the simulation. Used to generate {@link Activity} definitions.
+ *
+ *
+ * {@link #replacements} - String replacements to inject into activity definitions. e.g. 'CONTAINER' or 'USERID'
*
*
* {@link #maxActivityThreads} - the size of thread pool to use for requests
@@ -248,7 +251,8 @@ public static class Definition
{
private final Supplier _connectionFactory;
- private List activityDefinitions = Collections.emptyList();
+ private List activityFiles = new ArrayList<>();
+ private Map replacements = Collections.emptyMap();
private int maxActivityThreads = 6; // This seems to be the number of parallel requests browsers handle
private int delayBetweenActivities = 5_000;
private boolean runOnce = false;
@@ -287,15 +291,13 @@ public Definition setDelayBetweenActivities(int delayBetweenActivities)
public Definition setActivityFiles(File... activityFiles)
{
- return setActivityFilesWithReplacements(
- Arrays.stream(activityFiles).collect(Collectors.toMap(f -> f, f -> Collections.emptyMap())));
+ this.activityFiles = Arrays.asList(activityFiles);
+ return this;
}
- public Definition setActivityFilesWithReplacements(Map> activityFilesWithReplacements)
+ public Definition setReplacements(Map replacements)
{
- activityDefinitions = activityFilesWithReplacements.entrySet().stream()
- .map(entry -> new Activity(entry.getKey().getName(), Definition.parseTests(entry.getKey(), entry.getValue())))
- .toList();
+ this.replacements = new HashMap<>(replacements);
return this;
}
@@ -305,6 +307,17 @@ public Definition setRunOnce(boolean runOnce)
return this;
}
+ private List buildActivityDefinitions()
+ {
+ if (activityFiles.isEmpty())
+ {
+ throw new IllegalArgumentException("No activity files specified");
+ }
+ return activityFiles.stream()
+ .map(file -> new Activity(file.getName(), Definition.parseTests(file, replacements)))
+ .toList();
+ }
+
/**
* Start the simulation according to this definition
* @param resultCollectorFactory The simulation will submit results to the supplied {@link ResultCollector}
@@ -316,7 +329,7 @@ public Simulation startSimulation(Function
Connection connection = _connectionFactory.get();
// Prime connection before starting simulation to ensure credentials are good
new WhoAmICommand().execute(connection, null);
- return new Simulation<>(connection, activityDefinitions, delayBetweenActivities, maxActivityThreads, resultCollectorFactory.apply(connection), runOnce);
+ return new Simulation<>(connection, buildActivityDefinitions(), delayBetweenActivities, maxActivityThreads, resultCollectorFactory.apply(connection), runOnce);
}
public Simulation startSimulation() throws IOException, CommandException