diff --git a/pom.xml b/pom.xml
index 6b91381..6d097c6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.blazemeter
jmeter-bzm-correlation-recorder
jar
- 2.3
+ 2.4
Correlation Recorder as JMeter plugin
Correlation Recorder Plugin for JMeter
https://github.com/Blazemeter/CorrelationRecorder
@@ -92,6 +92,12 @@
2.13.0
provided
+
+ com.jayway.jsonpath
+ json-path
+ 2.9.0
+ provided
+
org.assertj
assertj-core
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/core/analysis/AnalysisReporter.java b/src/main/java/com/blazemeter/jmeter/correlation/core/analysis/AnalysisReporter.java
index 6b7e083..8cc87af 100644
--- a/src/main/java/com/blazemeter/jmeter/correlation/core/analysis/AnalysisReporter.java
+++ b/src/main/java/com/blazemeter/jmeter/correlation/core/analysis/AnalysisReporter.java
@@ -151,7 +151,7 @@ public static List generateCorrelationSuggestions() {
}
if (part instanceof CorrelationExtractor) {
- RegexCorrelationExtractor> extractor = (RegexCorrelationExtractor>) part;
+ CorrelationExtractor> extractor = (CorrelationExtractor>) part;
for (ReportEntry entry : report.entries) {
ExtractionSuggestion extraction = new ExtractionSuggestion(extractor, entry.getSampler());
extraction.setValue(entry.value);
@@ -161,7 +161,7 @@ public static List generateCorrelationSuggestions() {
suggestion.addExtractionSuggestion(extraction);
}
} else {
- RegexCorrelationReplacement> replacement = (RegexCorrelationReplacement>) part;
+ CorrelationReplacement> replacement = (CorrelationReplacement>) part;
for (ReportEntry entry : report.entries) {
ReplacementSuggestion replacementSuggestion
= new ReplacementSuggestion(replacement,
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/CorrelationHistory.java b/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/CorrelationHistory.java
index 396f7b2..7b2ed70 100644
--- a/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/CorrelationHistory.java
+++ b/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/CorrelationHistory.java
@@ -32,6 +32,8 @@ public class CorrelationHistory {
public static final String AUXILIARY_STEP_MESSAGE =
"Auxiliary Iterarion (No Recording iteration found)";
public static final String ORIGINAL_RECORDING_MESSAGE = "Original Recording";
+ public static final String CUSTOM_ITERATION_MESSAGE = "Checkpoint Iteration";
+
public static final String FAILED_REPLAY_MESSAGE =
"Replay result: %s requests pending resolution.";
public static final String SUCCESS_REPLAY_TEMPLATE = "Replay %s";
@@ -69,8 +71,21 @@ public void addOriginalRecordingStep(String originalRecordingFilepath,
steps = new ArrayList<>();
Step step = new Step(ORIGINAL_RECORDING_MESSAGE);
- step.setTestPlanFilepath(originalRecordingFilepath);
- step.setRecordingTraceFilepath(originalRecordingTraceFilepath);
+ step.setTestPlanFilepath(
+ FileManagementUtils.getRelativeFatherPath(originalRecordingFilepath));
+ step.setRecordingTraceFilepath(
+ FileManagementUtils.getRelativeFatherPath(originalRecordingTraceFilepath));
+ step.setNotes("Automatically generated iteration after recording");
+ addStep(step);
+ }
+
+ public void addCustomIteration() {
+ Step step = new Step(CUSTOM_ITERATION_MESSAGE);
+ step.setTestPlanFilepath(
+ FileManagementUtils.getRelativeFatherPath(saveCurrentTestPlanSupplier.get()));
+ step.setRecordingTraceFilepath(
+ FileManagementUtils.getRelativeFatherPath(recordingFilePathSupplier.get()));
+ step.setNotes("Checkpoint generated by user. [Double click to edit]");
addStep(step);
}
@@ -80,8 +95,11 @@ public void addSuccessfulReplay(String testPlanFilepath, String replayTraceFilep
(hadErrors ? SUCCESS_REPLAY_POSTFIX_WITH_ERRORS
: SUCCESS_REPLAY_POSTFIX_WITHOUT_ERRORS)));
- step.setTestPlanFilepath(testPlanFilepath);
- step.setReplayTraceFilepath(replayTraceFilepath);
+ step.setTestPlanFilepath(
+ FileManagementUtils.getRelativeFatherPath(testPlanFilepath));
+ step.setReplayTraceFilepath(
+ FileManagementUtils.getRelativeFatherPath(replayTraceFilepath));
+ step.setNotes("Automatically generated iteration after replay");
addStep(step);
}
@@ -97,15 +115,23 @@ public List getSteps() {
public void addFailedReplay(String testPlanFilepath, String replayTraceFilepath,
Integer newErrors) {
Step step = new Step(String.format(FAILED_REPLAY_MESSAGE, newErrors));
- step.setTestPlanFilepath(testPlanFilepath);
- step.setReplayTraceFilepath(replayTraceFilepath);
+
+ step.setTestPlanFilepath(
+ FileManagementUtils.getRelativeFatherPath(testPlanFilepath));
+ step.setReplayTraceFilepath(
+ FileManagementUtils.getRelativeFatherPath(replayTraceFilepath));
+ step.setNotes("Automatically generated iteration after replay");
+
addStep(step);
}
public void addAnalysisStep(String message, String testPlanFilepath, String traceFilepath) {
Step step = new Step(message);
- step.setTestPlanFilepath(testPlanFilepath);
- step.setReplayTraceFilepath(traceFilepath);
+ step.setTestPlanFilepath(
+ FileManagementUtils.getRelativeFatherPath(testPlanFilepath));
+ step.setReplayTraceFilepath(
+ FileManagementUtils.getRelativeFatherPath(traceFilepath));
+ step.setNotes("Automatically generated iteration after correlation suggestions application");
addStep(step);
}
@@ -131,8 +157,10 @@ public Step getRecordingStep() {
if (steps.isEmpty()) {
LOG.error("CorrelationHistory has no iterations, forcing an auxiliary iteartion");
Step auxiliaryStep = new Step(AUXILIARY_STEP_MESSAGE);
- auxiliaryStep.setTestPlanFilepath(saveCurrentTestPlanSupplier.get());
- auxiliaryStep.setRecordingTraceFilepath(recordingFilePathSupplier.get());
+ auxiliaryStep.setTestPlanFilepath(
+ FileManagementUtils.getRelativeFatherPath(saveCurrentTestPlanSupplier.get()));
+ auxiliaryStep.setRecordingTraceFilepath(
+ FileManagementUtils.getRelativeFatherPath(recordingFilePathSupplier.get()));
addStep(auxiliaryStep);
}
return steps.get(0);
@@ -194,11 +222,11 @@ public void deleteSteps(List steps) {
}
public void addRestoredStep(Step step) {
- Step newStep = new Step(
- "Restored iteration with timestamp: %s", step.getTimestamp());
+ Step newStep = new Step("Restored iteration");
newStep.setTestPlanFilepath(step.getTestPlanFilepath());
newStep.setRecordingTraceFilepath(step.getRecordingTraceFilepath());
newStep.setReplayTraceFilepath(step.getReplayTraceFilepath());
+ newStep.setNotes("Reverted to the iteration with timestamp: " + step.getTimestamp());
this.steps.add(newStep);
saveToFile();
}
@@ -278,6 +306,7 @@ public static class Step {
private String replayTraceFilepath;
private String timestamp;
private String fatherTimeStamp = null;
+ private String notes;
@JsonIgnore
private Supplier saveCurrentTestPlanSupplier = saveCurrentTestPlan();
@@ -309,6 +338,14 @@ public String getStepMessage() {
return String.format(stepMessage, msgEnd);
}
+ public String getNotes() {
+ return notes;
+ }
+
+ public void setNotes(String notes) {
+ this.notes = notes;
+ }
+
@VisibleForTesting
public void setStepMessage(String stepMessage) {
this.stepMessage = stepMessage;
@@ -343,7 +380,8 @@ public void setReplayTraceFilepath(String replayTraceFilepath) {
}
public void addCurrentTestPlan() {
- setTestPlanFilepath(saveCurrentTestPlanSupplier.get());
+ setTestPlanFilepath(
+ FileManagementUtils.getRelativeFatherPath(saveCurrentTestPlanSupplier.get()));
}
public String getTimestamp() {
@@ -367,6 +405,7 @@ public String toString() {
", replayTraceFilepath='" + replayTraceFilepath + '\'' +
", time='" + timestamp + '\'' +
", fatherTimestamp='" + fatherTimeStamp + '\'' +
+ ", notes='" + notes + '\'' +
'}';
}
}
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/ExtractionSuggestion.java b/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/ExtractionSuggestion.java
index 69a758c..09e1036 100644
--- a/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/ExtractionSuggestion.java
+++ b/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/ExtractionSuggestion.java
@@ -11,7 +11,7 @@ public class ExtractionSuggestion {
private List> extractors = new ArrayList<>();
//TODO:Remove the single extractor and only use the list
- private RegexCorrelationExtractor> extractor;
+ private CorrelationExtractor> extractor;
private SampleResult sampleResult;
private String value;
private String name;
@@ -25,18 +25,13 @@ public ExtractionSuggestion(CorrelationExtractor> extractors, SampleResult sam
this.sampleResult = sampleResult;
}
- public ExtractionSuggestion(RegexCorrelationExtractor> extractor, SampleResult sampleResult) {
- this.extractor = extractor;
- this.sampleResult = sampleResult;
- }
-
- public ExtractionSuggestion(RegexCorrelationExtractor> extractor, HTTPSamplerBase sampler) {
+ public ExtractionSuggestion(CorrelationExtractor> extractor, HTTPSamplerBase sampler) {
this.extractor = extractor;
this.sampler = sampler;
this.comesFromSampleResult = false;
}
- public RegexCorrelationExtractor> getExtractor() {
+ public CorrelationExtractor> getExtractor() {
return extractor;
}
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/FileManagementUtils.java b/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/FileManagementUtils.java
index e364982..a9ef8c5 100644
--- a/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/FileManagementUtils.java
+++ b/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/FileManagementUtils.java
@@ -58,6 +58,12 @@ private static void makeFolderAtBin(String name) {
private static Path getPathInBin(String name) {
return Paths.get(JMeterUtils.getJMeterBinDir(), name);
}
+
+ public static String getRelativeFatherPath(String fullPathStr) {
+ Path fullPath = Paths.get(fullPathStr);
+ return fullPath.getParent().toString() + File.separator +
+ fullPath.getFileName().toString();
+ }
public static void makeReplayResultsFolder() {
makeFolderAtBin(REPLAY_FOLDER);
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/JMeterElementUtils.java b/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/JMeterElementUtils.java
index e12b0b8..51f4bcd 100644
--- a/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/JMeterElementUtils.java
+++ b/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/JMeterElementUtils.java
@@ -2,6 +2,8 @@
import com.blazemeter.jmeter.correlation.CorrelationProxyControl;
import com.helger.commons.annotation.VisibleForTesting;
+import com.jayway.jsonpath.InvalidPathException;
+import com.jayway.jsonpath.JsonPath;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
@@ -155,7 +157,7 @@ public static String saveTestPlanConverted(HashTree testPlan, String name) {
try {
convertSubTree(testPlan);
SaveService.saveTree(testPlan,
- Files.newOutputStream(Paths.get(name)));
+ Files.newOutputStream(Paths.get(name)));
LOG.info("Test Plan's Snapshot saved to {}", name);
return name;
} catch (IOException e) {
@@ -166,7 +168,7 @@ public static String saveTestPlanConverted(HashTree testPlan, String name) {
public static String saveTestPlanSnapshot() {
return saveTestPlanConverted(getTreeModel().getTestPlan(),
- FileManagementUtils.getSnapshotFileName());
+ FileManagementUtils.getSnapshotFileName());
}
public static String saveTestPlan(HashTree testPlan, String filename) {
@@ -241,7 +243,7 @@ private boolean isIgnoredHeader(String key) {
return configuration.getIgnoredHeaders().stream().anyMatch(key::equalsIgnoreCase);
}
- static boolean isJson(String value) {
+ public static boolean isJson(String value) {
try {
new JSONObject(value);
} catch (JSONException ex) {
@@ -466,6 +468,73 @@ public void extractParametersFromJsonArray(JSONArray array, Map> jsonFindMatches(String input, String jsonpath) {
+ Object result = null;
+ ArrayList matches = new ArrayList<>();
+ try {
+ result = JsonPath.read(input, jsonpath);
+ } catch (InvalidPathException e) {
+ // When no match, no report error, only no return any data
+ }
+ if (result == null) {
+ return Pair.of(null, matches);
+ } else if (result instanceof net.minidev.json.JSONArray) {
+ net.minidev.json.JSONArray results = (net.minidev.json.JSONArray) result;
+ for (Object value : results) {
+ matches.add(toJsonString(value));
+ }
+ } else if (canBeString(result)) {
+ matches.add(toJsonString(result));
+ } else if (result instanceof Map) {
+ LOG.warn(
+ "Valued returned by JSONPath is a json object and not a text value, " +
+ "return value is null");
+ return Pair.of(result.getClass(), matches);
+ } else {
+ LOG.warn(
+ "Valued returned by JSONPath is not supported, return value is null");
+ }
+ return Pair.of(result != null ? result.getClass() : null, matches);
+ }
+
/**
* Obtains the HTTPArgument from a JMeterProperty element.
* Note: this method requires that the JMeterProperty is an instance of HTTPArgument.
@@ -639,7 +708,7 @@ public static void refreshJMeter() {
*
* @param path The file path of the JMeter test plan to load.
* @return A HashTree representing the structure of the loaded JMeter test plan.
- * If an error occurs during loading, this method will return null.
+ * If an error occurs during loading, this method will return null.
*/
public static HashTree getTestPlan(String path) {
HashTree hashTree = new HashTree();
@@ -1105,9 +1174,9 @@ private static List getCorrelationProxyControllers(JMeterTreeMod
}
/*
- * Reminder: This method is not properly working (or at least the generated nodes
- * are not properly working)
- * */
+ * Reminder: This method is not properly working (or at least the generated nodes
+ * are not properly working)
+ * */
public static List getSamplerNodes(HashTree testPlan) {
/*
Reminder: We commented this code because we have the theory that
@@ -1139,4 +1208,5 @@ public static JMeterTreeModel getCurrentJMeterTreeModel() {
}
return model;
}
+
}
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/ReplacementSuggestion.java b/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/ReplacementSuggestion.java
index b97cda6..2bfa368 100644
--- a/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/ReplacementSuggestion.java
+++ b/src/main/java/com/blazemeter/jmeter/correlation/core/automatic/ReplacementSuggestion.java
@@ -1,22 +1,22 @@
package com.blazemeter.jmeter.correlation.core.automatic;
-import com.blazemeter.jmeter.correlation.core.replacements.RegexCorrelationReplacement;
+import com.blazemeter.jmeter.correlation.core.replacements.CorrelationReplacement;
import org.apache.jmeter.testelement.TestElement;
public class ReplacementSuggestion {
- private final RegexCorrelationReplacement> replacementSuggestion;
+ private final CorrelationReplacement> replacementSuggestion;
private final TestElement usage;
private String source;
private String value;
private String name;
- public ReplacementSuggestion(RegexCorrelationReplacement> replacementSuggestion,
+ public ReplacementSuggestion(CorrelationReplacement> replacementSuggestion,
TestElement usage) {
this.replacementSuggestion = replacementSuggestion;
this.usage = usage;
}
- public RegexCorrelationReplacement> getReplacementSuggestion() {
+ public CorrelationReplacement> getReplacementSuggestion() {
return replacementSuggestion;
}
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/core/extractors/CorrelationExtractor.java b/src/main/java/com/blazemeter/jmeter/correlation/core/extractors/CorrelationExtractor.java
index 62c1b04..00a0372 100644
--- a/src/main/java/com/blazemeter/jmeter/correlation/core/extractors/CorrelationExtractor.java
+++ b/src/main/java/com/blazemeter/jmeter/correlation/core/extractors/CorrelationExtractor.java
@@ -3,6 +3,7 @@
import com.blazemeter.jmeter.correlation.core.CorrelationContext;
import com.blazemeter.jmeter.correlation.core.CorrelationRulePartTestElement;
import com.blazemeter.jmeter.correlation.core.DescriptionContent;
+import com.blazemeter.jmeter.correlation.core.analysis.AnalysisReporter;
import com.blazemeter.jmeter.correlation.core.templates.CorrelationRuleSerializationPropertyFilter;
import com.blazemeter.jmeter.correlation.gui.CorrelationRuleTestElement;
import com.fasterxml.jackson.annotation.JsonFilter;
@@ -10,7 +11,12 @@
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.regex.Pattern;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.testelement.AbstractTestElement;
@@ -42,6 +48,10 @@ public abstract class CorrelationExtractor extends
protected static final String TARGET_FIELD_NAME = EXTRACTOR_PREFIX + "target";
protected static final String TARGET_FIELD_DESCRIPTION = "Target";
protected static final String REGEX_DEFAULT_VALUE = "param=\"(.+?)\"";
+ protected static final String DEFAULT_EXTRACTOR_SUFFIX = "_NOT_FOUND";
+
+ private static final Function VARIABLE_PATTERN_PROVIDER =
+ (variableName) -> Pattern.compile(variableName + "_(\\d|matchNr)");
private static final Logger LOG = LoggerFactory
.getLogger(CorrelationRuleSerializationPropertyFilter.class);
public transient String variableName;
@@ -156,4 +166,24 @@ public String toString() {
public List createPostProcessors(String variableName, int i) {
return new ArrayList<>();
}
+
+ protected void clearJMeterVariables(JMeterVariables vars) {
+ Set> entries = new HashSet<>(vars.entrySet());
+ entries.forEach(e -> {
+ if (VARIABLE_PATTERN_PROVIDER.apply(variableName).matcher(e.getKey()).matches()) {
+ vars.remove(e.getKey());
+ }
+ });
+ }
+
+ /**
+ * Used to provide information about the extraction of values from the response.
+ * This method would be used, when we are performing an analysis, regardless
+ * of the mode of the recording (i.e. whether we are recording or doing
+ * static analysis).
+ */
+ protected void analyze(String value, Object affectedElement, String varName) {
+ AnalysisReporter.report(this, value, affectedElement, varName, target.name());
+ }
+
}
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/core/extractors/JsonCorrelationExtractor.java b/src/main/java/com/blazemeter/jmeter/correlation/core/extractors/JsonCorrelationExtractor.java
index d7fc050..15e2ba9 100644
--- a/src/main/java/com/blazemeter/jmeter/correlation/core/extractors/JsonCorrelationExtractor.java
+++ b/src/main/java/com/blazemeter/jmeter/correlation/core/extractors/JsonCorrelationExtractor.java
@@ -1,52 +1,92 @@
package com.blazemeter.jmeter.correlation.core.extractors;
+import static com.blazemeter.jmeter.correlation.core.automatic.JMeterElementUtils.jsonFindMatches;
+
import com.blazemeter.jmeter.correlation.core.BaseCorrelationContext;
import com.blazemeter.jmeter.correlation.core.CorrelationContext;
import com.blazemeter.jmeter.correlation.core.ParameterDefinition;
+import com.blazemeter.jmeter.correlation.core.analysis.AnalysisReporter;
import com.blazemeter.jmeter.correlation.gui.CorrelationRuleTestElement;
import com.helger.commons.annotation.VisibleForTesting;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
import java.util.Objects;
-import org.apache.jmeter.extractor.json.jmespath.JMESPathExtractor;
-import org.apache.jmeter.extractor.json.jmespath.gui.JMESPathExtractorGui;
+import org.apache.commons.lang3.tuple.Pair;
import org.apache.jmeter.extractor.json.jsonpath.JSONPostProcessor;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.testelement.AbstractTestElement;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.threads.JMeterVariables;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class JsonCorrelationExtractor extends
CorrelationExtractor {
private static final String DEFAULT_MATCH_NUMBER_NAME = "match number";
private static final int DEFAULT_MATCH_NUMBER = 1;
- private static final String EXTRACTOR_PATH_NAME = EXTRACTOR_PREFIX + "path";
+ private static final String EXTRACTOR_PATH_NAME = EXTRACTOR_PREFIX + "jsonpath";
private static final String MATCH_NUMBER_NAME = EXTRACTOR_PREFIX + "matchNr";
- private static final String EXTRACTOR_DESCRIPTION = "JSON extractor";
+ private static final String MULTIVALUED_NAME = EXTRACTOR_PREFIX + "multiValued";
+ private static final String EXTRACTOR_DESCRIPTION = "JSONPath expression";
private static final String MATCH_NUMBER_DESCRIPTION = "Match number";
- private static final String PATH_DEFAULT_VALUE = "$.param";
+ private static final String MULTIVALUED_DESCRIPTION = "Multivalued";
+ private static final boolean DEFAULT_MULTIVALUED = false;
+ private static final String PATH_DEFAULT_VALUE = "$.jsonpath.expression";
private static final ResultField DEFAULT_TARGET_VALUE = ResultField.BODY;
- private String path;
- private int matchNr;
+
+ private static final Logger LOG = LoggerFactory.getLogger(JsonCorrelationExtractor.class);
+ private static final String JSON_EXTRACTOR_GUI_CLASS =
+ org.apache.jmeter.extractor.json.jsonpath.gui.JSONPostProcessorGui.class.getName();
+ protected String jsonpath;
+ protected int matchNr;
+ protected boolean multiValued;
+
+ private transient JMeterVariables currentVars;
+ private transient List currentSamplersChild;
public JsonCorrelationExtractor() {
matchNr = DEFAULT_MATCH_NUMBER;
- path = PATH_DEFAULT_VALUE;
+ jsonpath = PATH_DEFAULT_VALUE;
target = ResultField.BODY;
+ multiValued = DEFAULT_MULTIVALUED;
}
@VisibleForTesting
public JsonCorrelationExtractor(String path, String variableName) {
- this.path = path;
+ this.jsonpath = path;
this.variableName = variableName;
target = ResultField.BODY;
matchNr = DEFAULT_MATCH_NUMBER;
}
+ @VisibleForTesting
+ public JsonCorrelationExtractor(String path, int matchNr, ResultField target) {
+ this.jsonpath = path;
+ this.target = target;
+ this.matchNr = matchNr;
+ }
+
+ @VisibleForTesting
+ public JsonCorrelationExtractor(String path) {
+ this.jsonpath = path;
+ this.matchNr = DEFAULT_MATCH_NUMBER;
+ this.target = ResultField.BODY;
+ this.multiValued = DEFAULT_MULTIVALUED;
+ }
+
+ @VisibleForTesting
+ public JsonCorrelationExtractor(String path, int matchNr, String target, String multiValued) {
+ this.jsonpath = path;
+ this.matchNr = matchNr;
+ this.target = ResultField.valueOf(target);
+ this.multiValued = Boolean.parseBoolean(multiValued);
+ }
+
public void setPath(String path) {
- this.path = path;
+ this.jsonpath = path;
}
@Override
@@ -56,43 +96,51 @@ public String getDisplayName() {
@Override
public List getParams() {
- return Arrays.asList(path, Integer.toString(matchNr), target.name());
+ return Arrays.asList(jsonpath, Integer.toString(matchNr), target.name(),
+ Boolean.toString(multiValued));
}
@Override
public void setParams(List params) {
- path = params.size() > 0 ? params.get(0) : "$.param";
+ jsonpath = params.size() > 0 ? params.get(0) : "$.jsonpath.expression";
matchNr = params.size() > 1 ? parseInteger(params.get(1), DEFAULT_MATCH_NUMBER_NAME,
DEFAULT_MATCH_NUMBER) : DEFAULT_MATCH_NUMBER;
- target = params.size() > 3 && !params.get(3).isEmpty() ? ResultField.valueOf(params.get(3))
+ target = params.size() > 2 && !params.get(2).isEmpty() ? ResultField.valueOf(params.get(2))
: DEFAULT_TARGET_VALUE;
+ multiValued = params.size() >= 3 && Boolean.parseBoolean(params.get(3));
}
@Override
public List getParamsDefinition() {
+ HashMap options = new HashMap();
+ options.put(ResultField.BODY.name(), ResultField.BODY.getCode());
return Arrays.asList(new ParameterDefinition.TextParameterDefinition(EXTRACTOR_PATH_NAME,
EXTRACTOR_DESCRIPTION,
- REGEX_DEFAULT_VALUE),
+ PATH_DEFAULT_VALUE),
new ParameterDefinition.TextParameterDefinition(MATCH_NUMBER_NAME, MATCH_NUMBER_DESCRIPTION,
String.valueOf(DEFAULT_MATCH_NUMBER), true),
new ParameterDefinition.ComboParameterDefinition(TARGET_FIELD_NAME,
TARGET_FIELD_DESCRIPTION,
- ResultField.BODY.name(), ResultField.getNamesToCodesMapping(), true));
+ ResultField.BODY.name(), options, true),
+ new ParameterDefinition.CheckBoxParameterDefinition(MULTIVALUED_NAME,
+ MULTIVALUED_DESCRIPTION,
+ DEFAULT_MULTIVALUED, true));
}
@Override
public void updateTestElem(CorrelationRuleTestElement testElem) {
super.updateTestElem(testElem);
- testElem.setProperty(EXTRACTOR_PATH_NAME, path);
+ testElem.setProperty(EXTRACTOR_PATH_NAME, jsonpath);
testElem.setProperty(MATCH_NUMBER_NAME, String.valueOf(matchNr));
testElem.setProperty(TARGET_FIELD_NAME,
target != null ? target.name() : ResultField.BODY.name());
+ testElem.setProperty(MULTIVALUED_NAME, multiValued);
}
@Override
public void update(CorrelationRuleTestElement testElem) {
super.update(testElem);
- path = testElem.getPropertyAsString(EXTRACTOR_PATH_NAME);
+ jsonpath = testElem.getPropertyAsString(EXTRACTOR_PATH_NAME);
matchNr = getMatchNumber(testElem);
}
@@ -105,9 +153,85 @@ public void process(HTTPSamplerBase sampler, List children, SampleR
// If we can successfully parse the JSON and apply the path, we add a PostProcessor
// to extract the value
+ if (jsonpath.isEmpty()) {
+ return;
+ }
+ if (matchNr == 0) {
+ LOG.warn("Extracting random appearances is not supported. Returning null instead.");
+ return;
+ }
+ String field = target.getField(result);
+ if (field == null || field.isEmpty()) {
+ return;
+ }
+
+ this.currentVars = vars;
+ this.currentSamplersChild = children;
+
+ String varName = multiValued ? generateVariableName() : variableName;
+ String matchedValue = null;
+ String matchedVariable = varName;
+ String matchedVariableChildPP = varName;
+ String matchedVariablePP = varName;
+ int matchedMatchNr = matchNr;
+ if (matchNr >= 0) {
+ String match = findMatch(field, matchNr);
+ if (match != null && !match.equals(vars.get(varName))) {
+ matchedValue = match;
+ }
+ } else {
+ Pair> resultMatches = jsonFindMatches(field, jsonpath);
+ ArrayList matches = resultMatches.getRight();
+ if (matches.size() == 1) {
+ matchedValue = matches.get(0);
+ matchedMatchNr = 1;
+ } else if (matches.size() > 1) {
+ if (!multiValued) {
+ clearJMeterVariables(vars);
+ }
+ matchedValue = String.valueOf(matches.size());
+ matchedVariableChildPP = matchedVariable + "_matchNr";
+ int matchNr = 1;
+ for (String match : matches) {
+ vars.put(varName + "_" + matchNr, match);
+ matchNr++;
+ }
+ }
+ }
+ if (matchedValue != null) {
+ analyze(matchedValue, sampler, variableName);
+ addVarAndChildPostProcessor(matchedValue, matchedVariableChildPP,
+ createPostProcessor(matchedVariablePP, matchedMatchNr));
+ }
+ }
+
+ public String findMatch(String input, int matchNumber) {
+ if (!input.isEmpty()) {
+ Pair> resultMatches = jsonFindMatches(input, jsonpath);
+ ArrayList matches = resultMatches.getRight();
+ if (matches.size() == 0) {
+ return null;
+ }
+ if (matches.size() >= matchNumber) {
+ return matches.get(matchNumber - 1);
+ }
+ LOG.warn("Match number {} is bigger than actual matches {}",
+ matchNumber, matches.size());
+ }
+ return null;
+ }
+
+ public AbstractTestElement createPostProcessor(String varName, int matchNr) {
JSONPostProcessor jsonPostProcessor = new JSONPostProcessor();
- jsonPostProcessor.setJsonPathExpressions(path);
+ jsonPostProcessor.setProperty(TestElement.GUI_CLASS, JSON_EXTRACTOR_GUI_CLASS);
+ jsonPostProcessor.setName("JSON Path - " + varName);
+ jsonPostProcessor.setRefNames(varName);
+ jsonPostProcessor.setJsonPathExpressions(jsonpath);
jsonPostProcessor.setComputeConcatenation(true);
+ jsonPostProcessor.setMatchNumbers(String.valueOf(matchNr));
+ jsonPostProcessor.setDefaultValues(varName + DEFAULT_EXTRACTOR_SUFFIX);
+ jsonPostProcessor.setScopeAll();
+ return jsonPostProcessor;
}
public void setRefName(String name) {
@@ -115,7 +239,8 @@ public void setRefName(String name) {
}
private static int getMatchNumber(CorrelationRuleTestElement testElem) {
- return parseInteger(testElem.getPropertyAsString(MATCH_NUMBER_NAME), DEFAULT_MATCH_NUMBER_NAME,
+ return parseInteger(testElem.getPropertyAsString(MATCH_NUMBER_NAME),
+ DEFAULT_MATCH_NUMBER_NAME,
1);
}
@@ -125,7 +250,7 @@ public Class extends CorrelationContext> getSupportedContext() {
}
public String getPath() {
- return path;
+ return jsonpath;
}
public int getMatchNr() {
@@ -139,23 +264,33 @@ public void setMatchNr(int matchNr) {
@Override
public String toString() {
return "JsonCorrelationExtractor{"
- + "path='" + path + '\''
+ + "path='" + jsonpath + '\''
+ ", matchNr=" + matchNr
+ ", variableName='" + variableName + '\''
+ ", target=" + target
+ '}';
}
+ private void addVarAndChildPostProcessor(String match, String variableName,
+ AbstractTestElement postProcessor) {
+ if (AnalysisReporter.canCorrelate()) {
+ currentSamplersChild.add(postProcessor);
+ }
+ currentVars.put(variableName, match);
+ }
+
+ private String generateVariableName() {
+ return variableName + "#" + context.getNextVariableNr(variableName);
+ }
+
+ public void setMultiValued(boolean multiValued) {
+ this.multiValued = multiValued;
+ }
+
@Override
public List createPostProcessors(String variableName, int i) {
List extractors = new ArrayList<>();
- JMESPathExtractor extractor = new JMESPathExtractor();
- extractor.setProperty(TestElement.GUI_CLASS, JMESPathExtractorGui.class.getName());
- extractor.setName("JSON Extractor (" + variableName + ")");
- extractor.setRefName(variableName);
- extractor.setJmesPathExpression(path);
- extractor.setMatchNumber(String.valueOf(matchNr));
- extractor.setDefaultValue(variableName + "_NOT_FOUND");
+ AbstractTestElement extractor = createPostProcessor(variableName, i);
extractors.add(extractor);
return extractors;
}
@@ -170,13 +305,13 @@ public boolean equals(Object o) {
}
JsonCorrelationExtractor> that = (JsonCorrelationExtractor>) o;
return matchNr == that.matchNr
- && Objects.equals(path, that.path)
+ && Objects.equals(jsonpath, that.jsonpath)
&& Objects.equals(variableName, that.variableName)
&& target == that.target;
}
@Override
public int hashCode() {
- return Objects.hash(path, matchNr, variableName, target);
+ return Objects.hash(jsonpath, matchNr, variableName, target);
}
}
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/core/extractors/RegexCorrelationExtractor.java b/src/main/java/com/blazemeter/jmeter/correlation/core/extractors/RegexCorrelationExtractor.java
index 417d670..aa90b12 100644
--- a/src/main/java/com/blazemeter/jmeter/correlation/core/extractors/RegexCorrelationExtractor.java
+++ b/src/main/java/com/blazemeter/jmeter/correlation/core/extractors/RegexCorrelationExtractor.java
@@ -12,13 +12,8 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
-import java.util.Map.Entry;
import java.util.Objects;
-import java.util.Set;
-import java.util.function.Function;
-import java.util.regex.Pattern;
import org.apache.jmeter.extractor.RegexExtractor;
import org.apache.jmeter.extractor.gui.RegexExtractorGui;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
@@ -50,12 +45,10 @@ public class RegexCorrelationExtractor extends
protected static final String DEFAULT_MATCH_NUMBER_NAME = "match number";
protected static final String MULTIVALUED_DESCRIPTION = "Multivalued";
protected static final boolean DEFAULT_MULTIVALUED = false;
- private static final Function VARIABLE_PATTERN_PROVIDER =
- (variableName) -> Pattern.compile(variableName + "_(\\d|matchNr)");
+
private static final Logger LOG = LoggerFactory.getLogger(RegexCorrelationExtractor.class);
private static final String REGEX_EXTRACTOR_GUI_CLASS = RegexExtractorGui.class.getName();
private static final int DEFAULT_MATCH_NUMBER = 1;
- private static final String DEFAULT_REGEX_EXTRACTOR_SUFFIX = "_NOT_FOUND";
protected boolean multiValued;
protected String regex;
protected int matchNr;
@@ -250,15 +243,6 @@ public void process(HTTPSamplerBase sampler, List children, SampleR
}
- private void clearJMeterVariables(JMeterVariables vars) {
- Set> entries = new HashSet<>(vars.entrySet());
- entries.forEach(e -> {
- if (VARIABLE_PATTERN_PROVIDER.apply(variableName).matcher(e.getKey()).matches()) {
- vars.remove(e.getKey());
- }
- });
- }
-
private void addVarAndChildPostProcessor(String match, String variableName,
RegexExtractor postProcessor) {
if (AnalysisReporter.canCorrelate()) {
@@ -287,7 +271,7 @@ public RegexExtractor createPostProcessor(String varName, int matchNr) {
regexExtractor.setRegex(regex);
regexExtractor.setTemplate("$" + groupNr + "$");
regexExtractor.setMatchNumber(matchNr);
- regexExtractor.setDefaultValue(varName + DEFAULT_REGEX_EXTRACTOR_SUFFIX);
+ regexExtractor.setDefaultValue(varName + DEFAULT_EXTRACTOR_SUFFIX);
regexExtractor.setUseField(target.getCode());
regexExtractor.setScopeAll();
return regexExtractor;
@@ -302,16 +286,6 @@ public void update(CorrelationRuleTestElement testElem) {
multiValued = isMultiValued(testElem);
}
- /**
- * Used to provide information about the extraction of values from the response.
- * This method would be used, when we are performing an analysis, regardless
- * of the mode of the recording (i.e. whether we are recording or doing
- * static analysis).
- */
- public void analyze(String value, Object affectedElement, String varName) {
- AnalysisReporter.report(this, value, affectedElement, varName, target.name());
- }
-
/**
* Used to add the necessary elements to the sampler, to perform the
* extraction of values from the response.
@@ -368,7 +342,7 @@ public List createPostProcessors(String variableName, int i
regexExtractor.setRegex(regex);
regexExtractor.setTemplate("$" + groupNr + "$");
regexExtractor.setMatchNumber(matchNr);
- regexExtractor.setDefaultValue(variableName + DEFAULT_REGEX_EXTRACTOR_SUFFIX);
+ regexExtractor.setDefaultValue(variableName + DEFAULT_EXTRACTOR_SUFFIX);
regexExtractor.setUseField(target.getCode());
regexExtractor.setScopeAll();
return Collections.singletonList(regexExtractor);
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/core/replacements/CorrelationReplacement.java b/src/main/java/com/blazemeter/jmeter/correlation/core/replacements/CorrelationReplacement.java
index 2d3d639..c0dce39 100644
--- a/src/main/java/com/blazemeter/jmeter/correlation/core/replacements/CorrelationReplacement.java
+++ b/src/main/java/com/blazemeter/jmeter/correlation/core/replacements/CorrelationReplacement.java
@@ -12,8 +12,10 @@
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
+import java.util.function.Function;
import org.apache.jmeter.config.Argument;
import org.apache.jmeter.config.ConfigTestElement;
+import org.apache.jmeter.engine.util.CompoundVariable;
import org.apache.jmeter.protocol.http.control.Header;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
import org.apache.jmeter.samplers.SampleResult;
@@ -48,10 +50,29 @@ public abstract class CorrelationReplacement exten
protected static final String PROPERTIES_PREFIX =
"CorrelationRule.CorrelationReplacement.";
+ public static final String REPLACEMENT_STRING_PROPERTY_NAME = PROPERTIES_PREFIX +
+ "replacementString";
+ public static final String REPLACEMENT_IGNORE_VALUE_PROPERTY_NAME = PROPERTIES_PREFIX +
+ "ignoreValue";
protected static final String REGEX_DEFAULT_VALUE = "param=\"(.+?)\"";
+
+ protected static final String REPLACEMENT_STRING_DEFAULT_VALUE = "";
+
+ protected static final String FUNCTION_REF_PREFIX = "${"; //$NON-NLS-1$
+ /**
+ * Functions are wrapped in ${ and }.
+ */
+ protected static final String FUNCTION_REF_SUFFIX = "}"; //$NON-NLS-1$
+
private static final Logger LOG = LoggerFactory.getLogger(CorrelationReplacement.class);
+
protected String variableName;
+ protected String replacementString = REPLACEMENT_STRING_DEFAULT_VALUE;
+
+ protected Function expressionEvaluator =
+ (expression) -> new CompoundVariable(expression).execute();
+
/**
* Default constructor added in order to satisfy the JSON conversion.
@@ -243,4 +264,26 @@ public String toString() {
* @param ruleTestElement CorrelationRuleTestElement that contains the values
*/
public abstract void update(CorrelationRuleTestElement ruleTestElement);
+
+ Function replaceExpressionProvider() {
+ return s -> replacementString == null
+ || !java.util.regex.Pattern.compile("(\\$\\{.+?})").matcher(replacementString).matches()
+ || replacementString.isEmpty()
+ ? FUNCTION_REF_PREFIX + s + FUNCTION_REF_SUFFIX : s;
+ }
+
+ String computeStringReplacement(String varName) {
+ String rawReplacementString = buildReplacementStringForMultivalued(varName);
+ String computed = expressionEvaluator.apply(rawReplacementString);
+ LOG.debug("Result of {} was {}", rawReplacementString, computed);
+ return computed;
+ }
+
+ String buildReplacementStringForMultivalued(String varNameMatch) {
+ if (replacementString != null && replacementString.contains(variableName)) {
+ return replacementString.replace(variableName, varNameMatch);
+ }
+ return replacementString;
+ }
+
}
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/core/replacements/JsonCorrelationReplacement.java b/src/main/java/com/blazemeter/jmeter/correlation/core/replacements/JsonCorrelationReplacement.java
new file mode 100644
index 0000000..59f66a9
--- /dev/null
+++ b/src/main/java/com/blazemeter/jmeter/correlation/core/replacements/JsonCorrelationReplacement.java
@@ -0,0 +1,323 @@
+package com.blazemeter.jmeter.correlation.core.replacements;
+
+import static com.blazemeter.jmeter.correlation.core.automatic.JMeterElementUtils.classIsNumberOrBoolean;
+import static com.blazemeter.jmeter.correlation.core.automatic.JMeterElementUtils.jsonFindMatches;
+
+import com.blazemeter.jmeter.correlation.core.BaseCorrelationContext;
+import com.blazemeter.jmeter.correlation.core.CorrelationContext;
+import com.blazemeter.jmeter.correlation.core.ParameterDefinition;
+import com.blazemeter.jmeter.correlation.core.analysis.AnalysisReporter;
+import com.blazemeter.jmeter.correlation.core.automatic.JMeterElementUtils;
+import com.blazemeter.jmeter.correlation.gui.CorrelationRuleTestElement;
+import com.google.common.annotations.VisibleForTesting;
+import com.jayway.jsonpath.InvalidPathException;
+import com.jayway.jsonpath.JsonPath;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import net.minidev.json.JSONArray;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
+import org.apache.jmeter.samplers.SampleResult;
+import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.threads.JMeterVariables;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Correlation Replacements that applies the replacement using Json Xpath and the captured
+ * values.
+ *
+ * @param correlation context that can be used to store and share values during replay
+ */
+
+public class JsonCorrelationReplacement extends
+ CorrelationReplacement {
+
+ protected static final String JSONPATH_DEFAULT_VALUE = "$.jsonpath.expression";
+ protected static final String REPLACEMENT_JSON_PROPERTY_NAME = PROPERTIES_PREFIX + "jsonpath";
+ protected static final String REPLACEMENT_JSON_PROPERTY_DESCRIPTION =
+ "JSONPath expression";
+
+ private static final Logger LOG = LoggerFactory.getLogger(RegexCorrelationReplacement.class);
+ private static final boolean IGNORE_VALUE_DEFAULT = false;
+ private static final String REPLACEMENT_STRING_DEFAULT_VALUE = "";
+
+ private static final String ESCAPE_QUOTE_LEFT = "_CR_L_";
+ private static final String ESCAPE_QUOTE_RIGHT = "_CR_R_";
+
+ protected String jsonpath = JSONPATH_DEFAULT_VALUE;
+ protected boolean ignoreValue = IGNORE_VALUE_DEFAULT;
+
+ private Object currentSampler;
+
+ public JsonCorrelationReplacement() {
+ }
+
+ public JsonCorrelationReplacement(String jsonpath) {
+ this.jsonpath = jsonpath;
+ }
+
+ public JsonCorrelationReplacement(String jsonpath, String replacementString, String ignoreValue) {
+ this.jsonpath = jsonpath;
+ this.replacementString = replacementString;
+ this.ignoreValue = Boolean.parseBoolean(ignoreValue);
+ }
+
+ @Override
+ public String getDisplayName() {
+ return "JSON";
+ }
+
+ @Override
+ public List getParams() {
+ return Arrays.asList(jsonpath, replacementString, Boolean.toString(ignoreValue));
+ }
+
+ @Override
+ public void setParams(List params) {
+ jsonpath = !params.isEmpty() ? params.get(0) : JSONPATH_DEFAULT_VALUE;
+ replacementString = params.size() > 1 ? params.get(1) : REPLACEMENT_STRING_DEFAULT_VALUE;
+ ignoreValue = params.size() > 2 ? Boolean.parseBoolean(params.get(2)) : IGNORE_VALUE_DEFAULT;
+ }
+
+ @Override
+ public List getParamsDefinition() {
+ return Arrays.asList(
+ new ParameterDefinition.TextParameterDefinition(REPLACEMENT_JSON_PROPERTY_NAME,
+ REPLACEMENT_JSON_PROPERTY_DESCRIPTION, JSONPATH_DEFAULT_VALUE),
+ new ParameterDefinition.TextParameterDefinition(REPLACEMENT_STRING_PROPERTY_NAME,
+ "Replacement string",
+ REPLACEMENT_STRING_DEFAULT_VALUE, true),
+ new ParameterDefinition.CheckBoxParameterDefinition(REPLACEMENT_IGNORE_VALUE_PROPERTY_NAME,
+ "Ignore Value",
+ IGNORE_VALUE_DEFAULT, true));
+ }
+
+ @Override
+ protected String replaceString(String input, JMeterVariables vars) {
+ // https://github.com/json-path/JsonPath?tab=readme-ov-file#set-a-value
+ // Skip empty inputs
+ if (input == null || input.isEmpty() || jsonpath == null || jsonpath.isEmpty()
+ || variableName == null
+ || variableName.isEmpty()) {
+ return input;
+ }
+ // For previous replaced matches with variables, escape the unquoted variables
+ String inputProcessed = escapeUnquotedVariablesWithMarks(input);
+ if (JMeterElementUtils.isJson(inputProcessed)) {
+ HashSet> valuesReplaced = new HashSet();
+
+ // Test if the path of the jsonpath match
+ Pair> result =
+ jsonFindMatches(inputProcessed, jsonpath);
+ String updatedInput = inputProcessed;
+ Class resultType = result.getLeft();
+ ArrayList matches = result.getRight();
+ if (matches.size() > 0) {
+ // Ok, match, try to each match get the path and replace
+ Function expressionProvider = replaceExpressionProvider();
+ String currentVariableName = variableName;
+ for (int varNr = 0; varNr < matches.size(); varNr++) {
+ String valueStr = matches.get(varNr);
+ String varMatched = searchVariable(vars, valueStr);
+ currentVariableName = varMatched;
+ String replaceExpression = null;
+ // When ignore value, use the replacement string
+ if (!replacementString.isEmpty() && ignoreValue) {
+ replaceExpression = replacementString;
+ } else if (varMatched != null && replacementString.isEmpty()) {
+ // When no replacement string
+ replaceExpression = expressionProvider.apply(varMatched);
+ } else if (varMatched != null) { // When replacement string, use replacement string
+ replaceExpression = expressionProvider.apply(
+ buildReplacementStringForMultivalued(varMatched));
+ }
+ if (replaceExpression != null) {
+ boolean inArray = resultType == JSONArray.class;
+ String updatedJsonPath = inArray ? jsonpath + "[" + varNr + "]" : jsonpath;
+ Pair> toUpdateMatches =
+ jsonFindMatches(updatedInput, updatedJsonPath);
+ if (toUpdateMatches.getRight() != null) {
+ Class updateResultType = toUpdateMatches.getLeft();
+ boolean originIsUnQuoted = classIsNumberOrBoolean(updateResultType);
+ if (originIsUnQuoted) {
+ // When value is needed to put in the json structure without the quotes
+ // this not is allowed by jayway because generate an invalid json with free text
+ // inside, we need to post process to remove the left and the right marks to o that
+ // Remember, jayway put the value as a quoted String,
+ // and is why we need to put marks to recover the format without quotes at the end.
+ replaceExpression = ESCAPE_QUOTE_LEFT + replaceExpression + ESCAPE_QUOTE_RIGHT;
+ }
+ try {
+ updatedInput =
+ JsonPath.parse(updatedInput).set(updatedJsonPath, replaceExpression)
+ .jsonString();
+ // Store the values matched and used in the replacement
+ valuesReplaced.add(Pair.of(valueStr, variableName));
+ } catch (InvalidPathException e) {
+ LOG.debug(
+ "JSONPath used to update target value doesn't match in the set: " +
+ "value:{} jsonpath={}",
+ valueStr, updatedJsonPath);
+ }
+ } else {
+ LOG.debug(
+ "JSONPath used to update target value doesn't match in the get: " +
+ "value:{} jsonpath={}",
+ valueStr, updatedJsonPath);
+ }
+ }
+ }
+ // The json path match, replace the value with the replacement variable
+ if (updatedInput != null && !updatedInput.equals(inputProcessed)) {
+ for (Pair valueReplaced : valuesReplaced) {
+ analysis(valueReplaced.getLeft(), valueReplaced.getRight());
+ }
+
+ // Replace the start and end marks used for the values without quotes
+ // This is needed to recover the original format
+ updatedInput = unescapeQuotedVariablesWithMarks(updatedInput);
+
+ if (AnalysisReporter.canCorrelate()) {
+ return updatedInput;
+ } else {
+ return input;
+ }
+
+ }
+ }
+ }
+ return input; // When none of previous logic generate a return, return default input
+ }
+
+ private void analysis(String literalMatched, String currentVariableName) {
+ AnalysisReporter.report(this, literalMatched, currentSampler, currentVariableName);
+ }
+
+ private String searchVariable(JMeterVariables vars, String value) {
+ int varNr = 0;
+ while (varNr <= context.getVariableCount(variableName)) {
+ String varName = varNr == 0 ? variableName : variableName + "#" + varNr;
+ String varMatchesCount = vars.get(varName + "_matchNr");
+ int matchNr = varMatchesCount == null ? 0 : Integer.parseInt(varMatchesCount);
+ if (matchNr == 0) {
+ if (vars.get(varName) != null && vars.get(varName).equals(value)) {
+ return varName;
+ }
+ }
+ int varMatch = 1;
+ while (varMatch <= matchNr) {
+ String varNameMatch = varName + "_" + varMatch;
+ if (vars.get(varNameMatch) != null && vars.get(varNameMatch).equals(value)) {
+ return varNameMatch;
+ }
+ varMatch += 1;
+ }
+ varNr++;
+ }
+ return null;
+ }
+
+ private String escapeUnquotedVariablesWithMarks(String json) {
+ // Try to escape unquoted variable/function in json
+ // this try to allow a json parse without error for json path evaluation
+
+ String regex = "(\\$\\{[^}]+\\})(?=(?:[^\"\\}]*\\})|(?:[^\"\\]]*\\]))";
+
+ Pattern pattern = Pattern.compile(regex);
+ Matcher matcher = pattern.matcher(json);
+
+ StringBuffer result = new StringBuffer();
+ // Search the variable/function and escape with the particular pre-fix / sub-fix
+ // the usage of this format allow to recover the original format
+ while (matcher.find()) {
+ matcher.appendReplacement(result,
+ "\"" + ESCAPE_QUOTE_LEFT + "$1" + ESCAPE_QUOTE_RIGHT + "\"");
+ }
+ matcher.appendTail(result);
+ return result.toString();
+ }
+
+ private String unescapeQuotedVariablesWithMarks(String json) {
+ // Recover the format, values quoted with special marks
+ // are transformed to unquote value
+ return json.replace(
+ "\"" + ESCAPE_QUOTE_LEFT,
+ "").replace(
+ ESCAPE_QUOTE_RIGHT + "\"", "");
+ }
+
+ String buildReplacementStringForMultivalued(String varNameMatch) {
+ if (replacementString != null && replacementString.contains(variableName)) {
+ return replacementString.replace(variableName, varNameMatch);
+ }
+ return replacementString;
+ }
+
+ @Override
+ public Class extends CorrelationContext> getSupportedContext() {
+ return BaseCorrelationContext.class;
+ }
+
+ @Override
+ public void updateTestElem(CorrelationRuleTestElement testElem) {
+ super.updateTestElem(testElem);
+ testElem.setProperty(REPLACEMENT_JSON_PROPERTY_NAME, jsonpath);
+ testElem.setProperty(REPLACEMENT_STRING_PROPERTY_NAME, replacementString);
+ testElem.setProperty(REPLACEMENT_IGNORE_VALUE_PROPERTY_NAME, ignoreValue);
+ }
+
+ @Override
+ public void process(HTTPSamplerBase sampler, List children, SampleResult result,
+ JMeterVariables vars) {
+ if (jsonpath.isEmpty()) {
+ return;
+ }
+ currentSampler = sampler;
+ super.process(sampler, children, result, vars);
+ }
+
+ @Override
+ public void update(CorrelationRuleTestElement testElem) {
+ jsonpath = testElem.getPropertyAsString(REPLACEMENT_JSON_PROPERTY_NAME);
+ replacementString = testElem.getPropertyAsString(REPLACEMENT_STRING_PROPERTY_NAME);
+ ignoreValue = testElem.getPropertyAsBoolean(REPLACEMENT_IGNORE_VALUE_PROPERTY_NAME);
+ }
+
+ @Override
+ public String toString() {
+ return "RegexCorrelationReplacement{"
+ + ", jsonpath='" + jsonpath + "'"
+ + ", replacementString='" + replacementString + "'"
+ + ", ignoreValue=" + ignoreValue
+ + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ JsonCorrelationReplacement> that = (JsonCorrelationReplacement>) o;
+ return Objects.equals(jsonpath, that.jsonpath);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(jsonpath);
+ }
+
+ @VisibleForTesting
+ public void setExpressionEvaluator(Function expressionEvaluator) {
+ this.expressionEvaluator = expressionEvaluator;
+ }
+}
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/core/replacements/RegexCorrelationReplacement.java b/src/main/java/com/blazemeter/jmeter/correlation/core/replacements/RegexCorrelationReplacement.java
index 8a90785..b99ae2d 100644
--- a/src/main/java/com/blazemeter/jmeter/correlation/core/replacements/RegexCorrelationReplacement.java
+++ b/src/main/java/com/blazemeter/jmeter/correlation/core/replacements/RegexCorrelationReplacement.java
@@ -9,11 +9,12 @@
import com.blazemeter.jmeter.correlation.gui.CorrelationRuleTestElement;
import com.google.common.annotations.VisibleForTesting;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
-import org.apache.jmeter.engine.util.CompoundVariable;
+import org.apache.commons.lang3.tuple.Pair;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.testelement.TestElement;
@@ -37,28 +38,16 @@
public class RegexCorrelationReplacement extends
CorrelationReplacement {
- public static final String REPLACEMENT_STRING_PROPERTY_NAME = PROPERTIES_PREFIX +
- "replacementString";
- public static final String REPLACEMENT_IGNORE_VALUE_PROPERTY_NAME = PROPERTIES_PREFIX +
- "ignoreValue";
protected static final String REPLACEMENT_REGEX_PROPERTY_NAME = PROPERTIES_PREFIX + "regex";
protected static final String REPLACEMENT_REGEX_PROPERTY_DESCRIPTION =
"Regular expression " + "replacement";
- protected static final String FUNCTION_REF_PREFIX = "${"; //$NON-NLS-1$
- /**
- * Functions are wrapped in ${ and }.
- */
- protected static final String FUNCTION_REF_SUFFIX = "}"; //$NON-NLS-1$
private static final Logger LOG = LoggerFactory.getLogger(RegexCorrelationReplacement.class);
private static final boolean IGNORE_VALUE_DEFAULT = false;
- private static final String REPLACEMENT_STRING_DEFAULT_VALUE = "";
+
protected String regex = REGEX_DEFAULT_VALUE;
protected boolean ignoreValue = IGNORE_VALUE_DEFAULT;
- protected String replacementString = REPLACEMENT_STRING_DEFAULT_VALUE;
- private Function expressionEvaluator =
- (expression) -> new CompoundVariable(expression).execute();
+
private Object currentSampler;
- private String currentVariableName = "";
/**
* Default constructor added in order to satisfy the JSON conversion.
@@ -197,6 +186,7 @@ protected String replaceWithRegex(String input, String regex,
LOG.warn("Malformed pattern: {}", regex, e);
throw e;
}
+ HashSet> valuesReplaced = new HashSet();
PatternMatcherInput patternMatcherInput = new PatternMatcherInput(input);
int beginOffset = patternMatcherInput.getBeginOffset();
@@ -215,6 +205,7 @@ protected String replaceWithRegex(String input, String regex,
String varName = varNr == 0 ? variableName : variableName + "#" + varNr;
String varMatchesCount = vars.get(varName + "_matchNr");
literalMatched = match.group(1);
+ String currentVariableName = "";
String replaceExpression = null;
if (varMatchesCount == null) {
if (vars.get(varName) != null && vars.get(varName).equals(literalMatched)
@@ -237,6 +228,7 @@ protected String replaceWithRegex(String input, String regex,
if (replaceExpression != null) {
result = replaceMatch(result, patternMatcherInput, match,
beginOffset, inputBuffer, replaceExpression);
+ valuesReplaced.add(Pair.of(literalMatched, currentVariableName));
}
} else {
int matchNr = Integer.parseInt(varMatchesCount);
@@ -257,6 +249,8 @@ protected String replaceWithRegex(String input, String regex,
if (replaceExpression != null) {
result = replaceMatch(result, patternMatcherInput, match,
beginOffset, inputBuffer, expressionProvider.apply(replaceExpression));
+
+ valuesReplaced.add(Pair.of(literalMatched, currentVariableName));
}
varMatch++;
}
@@ -275,7 +269,9 @@ protected String replaceWithRegex(String input, String regex,
return input;
}
- analysis(literalMatched);
+ for (Pair valueReplaced : valuesReplaced) {
+ analysis(valueReplaced.getLeft(), valueReplaced.getRight());
+ }
if (!AnalysisReporter.canCorrelate()) {
return input;
}
@@ -283,27 +279,6 @@ protected String replaceWithRegex(String input, String regex,
return replacedInput;
}
- private Function replaceExpressionProvider() {
- return s -> replacementString == null
- || !java.util.regex.Pattern.compile("(\\$\\{.+?})").matcher(replacementString).matches()
- || replacementString.isEmpty()
- ? FUNCTION_REF_PREFIX + s + FUNCTION_REF_SUFFIX : s;
- }
-
- private String computeStringReplacement(String varName) {
- String rawReplacementString = buildReplacementStringForMultivalued(varName);
- String computed = expressionEvaluator.apply(rawReplacementString);
- LOG.debug("Result of {} was {}", rawReplacementString, computed);
- return computed;
- }
-
- private String buildReplacementStringForMultivalued(String varNameMatch) {
- if (replacementString != null && replacementString.contains(variableName)) {
- return replacementString.replace(variableName, varNameMatch);
- }
- return replacementString;
- }
-
private StringBuilder replaceMatch(StringBuilder result, PatternMatcherInput patternMatcherInput,
MatchResult match, int beginOffset, char[] inputBuffer,
String expression) {
@@ -358,7 +333,7 @@ public void update(CorrelationRuleTestElement testElem) {
ignoreValue = testElem.getPropertyAsBoolean(REPLACEMENT_IGNORE_VALUE_PROPERTY_NAME);
}
- private void analysis(String literalMatched) {
+ private void analysis(String literalMatched, String currentVariableName) {
AnalysisReporter.report(this, literalMatched, currentSampler, currentVariableName);
}
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/core/suggestions/method/ComparisonMethod.java b/src/main/java/com/blazemeter/jmeter/correlation/core/suggestions/method/ComparisonMethod.java
index b2e404b..583834f 100644
--- a/src/main/java/com/blazemeter/jmeter/correlation/core/suggestions/method/ComparisonMethod.java
+++ b/src/main/java/com/blazemeter/jmeter/correlation/core/suggestions/method/ComparisonMethod.java
@@ -88,7 +88,7 @@ private static boolean hasOrphans(CorrelationSuggestion suggestion) {
*/
private static ExtractionSuggestion generateCandidateExtractor(SampleResult result,
Appearances appearance,
- CorrelationExtractor> extractor,
+ CorrelationExtractor extractor,
StructureType structureType,
String name) {
ExtractionSuggestion suggestion = new ExtractionSuggestion(extractor, result);
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/gui/CorrelationComponentsRegistry.java b/src/main/java/com/blazemeter/jmeter/correlation/gui/CorrelationComponentsRegistry.java
index 5becbae..51e795c 100644
--- a/src/main/java/com/blazemeter/jmeter/correlation/gui/CorrelationComponentsRegistry.java
+++ b/src/main/java/com/blazemeter/jmeter/correlation/gui/CorrelationComponentsRegistry.java
@@ -10,9 +10,9 @@
import com.blazemeter.jmeter.correlation.core.extractors.CorrelationExtractor;
import com.blazemeter.jmeter.correlation.core.extractors.JsonCorrelationExtractor;
import com.blazemeter.jmeter.correlation.core.extractors.RegexCorrelationExtractor;
-import com.blazemeter.jmeter.correlation.core.extractors.XmlCorrelationExtractor;
import com.blazemeter.jmeter.correlation.core.replacements.CorrelationReplacement;
import com.blazemeter.jmeter.correlation.core.replacements.FunctionCorrelationReplacement;
+import com.blazemeter.jmeter.correlation.core.replacements.JsonCorrelationReplacement;
import com.blazemeter.jmeter.correlation.core.replacements.RegexCorrelationReplacement;
import com.google.common.annotations.VisibleForTesting;
import java.io.IOException;
@@ -45,10 +45,10 @@ public class CorrelationComponentsRegistry {
private final Set> customExtractors = new HashSet<>();
private final Set> customReplacements = new HashSet<>();
private final List> defaultExtractors =
- Arrays.asList(RegexCorrelationExtractor.class, JsonCorrelationExtractor.class,
- XmlCorrelationExtractor.class);
- private final List> defaultReplacements = Collections
- .singletonList(RegexCorrelationReplacement.class);
+ Arrays.asList(RegexCorrelationExtractor.class, JsonCorrelationExtractor.class);
+ private final List> defaultReplacements =
+ Arrays.asList(RegexCorrelationReplacement.class,
+ JsonCorrelationReplacement.class);
private final List deprecatedComponents = Collections.singletonList(
FunctionCorrelationReplacement.class.getCanonicalName());
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/gui/CorrelationRulePartPanel.java b/src/main/java/com/blazemeter/jmeter/correlation/gui/CorrelationRulePartPanel.java
index 987b807..5bee301 100644
--- a/src/main/java/com/blazemeter/jmeter/correlation/gui/CorrelationRulePartPanel.java
+++ b/src/main/java/com/blazemeter/jmeter/correlation/gui/CorrelationRulePartPanel.java
@@ -4,6 +4,7 @@
import com.blazemeter.jmeter.correlation.core.CorrelationRulePartTestElement;
import com.blazemeter.jmeter.correlation.core.ParameterDefinition;
import com.blazemeter.jmeter.correlation.gui.common.HelperDialog;
+import com.blazemeter.jmeter.correlation.gui.common.RulePartType;
import com.blazemeter.jmeter.correlation.gui.common.ThemedIcon;
import com.blazemeter.jmeter.correlation.gui.common.ThemedIconLabel;
import com.google.common.annotations.VisibleForTesting;
@@ -36,6 +37,7 @@
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
+import org.apache.jorphan.gui.ComponentUtil;
public class CorrelationRulePartPanel extends JPanel {
@@ -54,7 +56,6 @@ public class CorrelationRulePartPanel extends JPanel {
private final JLabel helper = new ThemedIconLabel("help.png");
private final List listAdvancedComponents = new ArrayList<>();
private HelperDialog helperDialog;
- private String description = "";
private Runnable fieldsListener;
private JPanel advancedPanel;
private JLabel collapsibleIcon;
@@ -150,7 +151,6 @@ private void changeEvent() {
}
removeComponents();
- this.description = getSelectedItem().getDescription();
getSelectedItem().getParamsDefinition().forEach(p -> {
Component field = buildField(p);
if (p.isAdvanced()) {
@@ -252,8 +252,12 @@ private void prepareHelper(String name) {
@Override
public void mouseClicked(MouseEvent mouseEvent) {
helperDialog = new HelperDialog(CorrelationRulePartPanel.this);
- helperDialog.setTitle("Selector Information");
- helperDialog.updateDialogContent(description);
+ CorrelationRulePartTestElement> selectedItem = getSelectedItem();
+ String helperTitle =
+ selectedItem.getDisplayName() + " " + RulePartType.fromComponent(selectedItem);
+ helperDialog.setTitle(helperTitle);
+ helperDialog.updateDialogContent(selectedItem.getDescription());
+ ComponentUtil.centerComponentInWindow(helperDialog);
helperDialog.setVisible(true);
}
});
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/gui/analysis/CorrelationTemplatesSelectionPanel.java b/src/main/java/com/blazemeter/jmeter/correlation/gui/analysis/CorrelationTemplatesSelectionPanel.java
index e51bec0..26682b7 100644
--- a/src/main/java/com/blazemeter/jmeter/correlation/gui/analysis/CorrelationTemplatesSelectionPanel.java
+++ b/src/main/java/com/blazemeter/jmeter/correlation/gui/analysis/CorrelationTemplatesSelectionPanel.java
@@ -183,7 +183,7 @@ private void onTemplateVersionFocus(Template focusedVersion) {
informationPane.setText(TemplateVersionUtils
.getInformationAsHTLM(focusedVersion, false, canUse,
- model.getRepositoryDisplayName(focusedVersion.getRepositoryId())));
+ model.getRepositoryDisplayName(focusedVersion.getRepositoryId())));
informationPane.setCaretPosition(0); // Scroll to the top
}
@@ -342,9 +342,15 @@ private void onContinue() {
= repManager.getTemplatesAndProperties(templates);
if (templatesAndProperties == null || templatesAndProperties.isEmpty()) {
-
+ // Get all the templates and properties for the local repository and filter the selected
templatesAndProperties = config
- .getCorrelationTemplatesAndPropertiesByRepositoryName(repositoryName, true);
+ .getCorrelationTemplatesAndPropertiesByRepositoryName(repositoryName, true)
+ .entrySet()
+ .stream()
+ .filter(templateEntry -> templates.stream().anyMatch(t ->
+ templateEntry.getKey().getId().equals(t.getName()) &&
+ templateEntry.getKey().getVersion().equals(t.getVersion())))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
for (Map.Entry templateEntry
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationHistoryFrame.java b/src/main/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationHistoryFrame.java
index 1bfecad..e5bc46c 100644
--- a/src/main/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationHistoryFrame.java
+++ b/src/main/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationHistoryFrame.java
@@ -61,6 +61,8 @@ public class CorrelationHistoryFrame extends JDialog implements ActionListener {
private static final String DELETE = "delete";
private static final String RESTORE = "restore";
private static final String ZIP = "zip";
+ private static final String CREATE = "create";
+
protected CorrelationHistory history;
protected JDialog runDialog;
@@ -69,6 +71,7 @@ public class CorrelationHistoryFrame extends JDialog implements ActionListener {
private JButton deleteButton;
private JButton restoreButton;
private JButton zipButton;
+ private JButton createCheckpointButton;
public CorrelationHistoryFrame(CorrelationHistory history) {
super();
@@ -117,6 +120,9 @@ private JPanel makeCorrelationHistoryPanel() {
TableColumn descColumn = table.getColumnModel().getColumn(2);
descColumn.setMinWidth(400);
+ TableColumn notesColumn = table.getColumnModel().getColumn(3);
+ notesColumn.setMinWidth(150);
+
JTableHeader header = table.getTableHeader();
header.setFont(header.getFont().deriveFont(14f));
@@ -143,12 +149,20 @@ private JPanel makeCorrelationHistoryPanel() {
.withToolTip("Export history to a zip file.")
.build();
+ createCheckpointButton = builder.withAction(CREATE)
+ .withName("createIteration")
+ .withText("Create Checkpoint")
+ .withToolTip("Create a snapshot of the jmx state as history iteration.")
+ .build();
+
JPanel buttonsPanel = new JPanel();
buttonsPanel.add(deleteButton);
buttonsPanel.add(Box.createRigidArea(new Dimension(10, 0)));
buttonsPanel.add(restoreButton);
buttonsPanel.add(Box.createRigidArea(new Dimension(10, 0)));
buttonsPanel.add(zipButton);
+ buttonsPanel.add(Box.createRigidArea(new Dimension(10, 0)));
+ buttonsPanel.add(createCheckpointButton);
JPanel displayTablePanel = new JPanel();
displayTablePanel.setLayout(new GridBagLayout());
@@ -226,6 +240,10 @@ public void actionPerformed(ActionEvent e) {
case ZIP:
this.zipHistory();
return;
+ case CREATE:
+ this.history.addCustomIteration();
+ this.loadSteps(history.getSteps());
+ return;
default:
LOG.warn("Action {} not supported", action);
}
@@ -257,7 +275,7 @@ public void zipHistory() {
}
public static class HistoryTableModel extends DefaultTableModel {
- private final List columns = Arrays.asList("", "Timestamp", "Description");
+ private final List columns = Arrays.asList("", "Timestamp", "Description", "Notes");
private final List stepList = new ArrayList<>();
private final Map> suggestionsMap =
new HashMap<>();
@@ -310,6 +328,8 @@ public Object getValueAt(int rowIndex, int columnIndex) {
return "Not available";
case 2:
return step.getStepMessage();
+ case 3:
+ return step.getNotes();
default:
return "N/A";
}
@@ -319,12 +339,19 @@ public Object getValueAt(int rowIndex, int columnIndex) {
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (!stepList.isEmpty() && columnIndex == 0) {
stepList.get(rowIndex).setSelected((boolean) aValue);
+ } else if (columnIndex == 1) {
+ stepList.get(rowIndex).getStep().setTimestamp((String) aValue);
+ } else if (columnIndex == 2) {
+ stepList.get(rowIndex).getStep().setStepMessage((String) aValue);
+ } else if (columnIndex == 3) {
+ stepList.get(rowIndex).getStep().setNotes((String) aValue);
}
+
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
- return columnIndex == 0;
+ return columnIndex != 1;
}
public List getSelectedSteps() {
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationSuggestionsPanel.java b/src/main/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationSuggestionsPanel.java
index cf02c4d..e38f139 100644
--- a/src/main/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationSuggestionsPanel.java
+++ b/src/main/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationSuggestionsPanel.java
@@ -362,8 +362,15 @@ private void exportSuggestions() {
repManager.getTemplatesAndProperties(templates);
if (templatesAndProperties == null || templatesAndProperties.isEmpty()) {
+ // Get all the templates and properties for the local repository and filter the selected
templatesAndProperties = this.wizard.getRepositoriesConfiguration()
- .getCorrelationTemplatesAndPropertiesByRepositoryName(repositoryName, true);
+ .getCorrelationTemplatesAndPropertiesByRepositoryName(repositoryName, true)
+ .entrySet()
+ .stream()
+ .filter(templateEntry -> templates.stream().anyMatch(t ->
+ templateEntry.getKey().getId().equals(t.getName()) &&
+ templateEntry.getKey().getVersion().equals(t.getVersion())))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
for (Map.Entry templateEntry
@@ -393,7 +400,7 @@ private void exportSuggestions() {
for (CorrelationSuggestion suggestion : suggestions) {
Template source = suggestion.getSource();
// Automatic or Template based
- if (source == null || canExport.contains(source)) {
+ if (source == null || templateContains(canExport, source)) {
rules.addAll(suggestion.toCorrelationRules());
}
}
@@ -406,6 +413,12 @@ private void exportSuggestions() {
JOptionPane.INFORMATION_MESSAGE);
}
+ private boolean templateContains(Set list, Template toMatch) {
+ return list.stream()
+ .anyMatch(toEvaluate -> toEvaluate.getId().equals(toMatch.getId()) &&
+ toEvaluate.getVersion().equals(toMatch.getVersion()));
+ }
+
public void displayAppliedResults() {
tabbedPane.setSelectedIndex(1);
}
diff --git a/src/main/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationWizard.java b/src/main/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationWizard.java
index d12241c..1e07139 100644
--- a/src/main/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationWizard.java
+++ b/src/main/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationWizard.java
@@ -292,10 +292,6 @@ public void logStep(String message) {
history.addStep(step);
}
- public void addStep(CorrelationHistory.Step step) {
- history.addStep(step);
- }
-
public void setHistory(CorrelationHistory history) {
this.history = history;
}
diff --git a/src/main/resources/correlation-descriptions/FunctionCorrelationReplacement.html b/src/main/resources/correlation-descriptions/FunctionCorrelationReplacement.html
index a9130b8..f33a9ad 100644
--- a/src/main/resources/correlation-descriptions/FunctionCorrelationReplacement.html
+++ b/src/main/resources/correlation-descriptions/FunctionCorrelationReplacement.html
@@ -28,5 +28,5 @@
For more information about Replacements and how to use them, check the Documentation at List
+ href="https://blazemeter.github.io/CorrelationRecorder/guide/correlation-rules.html#list-of-correlation-replacements">List
of Correlation Replacements
diff --git a/src/main/resources/correlation-descriptions/JsonCorrelationExtractor.html b/src/main/resources/correlation-descriptions/JsonCorrelationExtractor.html
index 277f03d..3ab55ff 100644
--- a/src/main/resources/correlation-descriptions/JsonCorrelationExtractor.html
+++ b/src/main/resources/correlation-descriptions/JsonCorrelationExtractor.html
@@ -6,8 +6,8 @@
-Json Correlation Extractor
-Use the Regular Expression (RegEx) to get the values from the response
+JSON Correlation Extractor
+Use the JSONPath Expression to get the values from the response
@@ -19,23 +19,18 @@
- RegEx |
- Regular Expression used to do the matching |
- param="(.+?)" |
+ JSON |
+ JSONPath Expression used to do the matching |
+ $.jsonpath.expression" |
Match Number |
determines which appearance of the RegEx will be considered for the extraction |
1 |
-
- Group Number |
- determines the group from where the information will be taken, based on the RegEx |
- 1 |
-
Target |
- determines where the RegEx will be applied |
+ determines where the JSONPath will be applied |
Response's Body |
@@ -45,8 +40,9 @@
+JMeter use JSONPath syntax from Jayway JsonPath. Use the Jayway JsonPath syntax documentation as a reference.
For more information about Extractors and how to use them, check the Documentation at List
+ href="https://blazemeter.github.io/CorrelationRecorder/guide/correlation-rules.html#list-of-correlation-extractors">List
Correlation Extractors
diff --git a/src/main/resources/correlation-descriptions/JsonCorrelationReplacement.html b/src/main/resources/correlation-descriptions/JsonCorrelationReplacement.html
new file mode 100644
index 0000000..60bfa09
--- /dev/null
+++ b/src/main/resources/correlation-descriptions/JsonCorrelationReplacement.html
@@ -0,0 +1,46 @@
+
+JSON Correlation Replacement
+Use the JSONPath Expression match the value that will be replaced. Will apply to all the matches as long as
+ the obtained value is stored.
+
+
+
+
+ Field |
+ Description |
+ Default Value |
+
+
+
+
+ JSON |
+ JSONPath Expression used to do the matching |
+ $.jsonpath.expression |
+
+
+ Replacement String |
+ This field is used to set JMeter Functions/literals to be used on the comparison of the replace match
+ value (if value is not ignored)
+ |
+ Empty |
+
+
+ Ignore value |
+ This check will determine if the match will be compared against all the JMeter Variables or even the
+ execution of a function declared on the Replacement String field (if any). If checked, the replacement
+ will occur without comparing.
+ |
+ Unchecked |
+
+
+
+JMeter use JSONPath syntax from Jayway JsonPath. Use the Jayway JsonPath syntax documentation as a reference.
+For more information about Replacements and how to use them, check the Documentation at List
+ of Correlation Replacements
diff --git a/src/main/resources/correlation-descriptions/MoreExtractor.html b/src/main/resources/correlation-descriptions/MoreExtractor.html
index 21d911f..c78ea98 100644
--- a/src/main/resources/correlation-descriptions/MoreExtractor.html
+++ b/src/main/resources/correlation-descriptions/MoreExtractor.html
@@ -6,5 +6,5 @@
complete, as long as it has either a Correlation Replacement
or a Correlation Extractor selected.
For more information about Extractors and how to use them, check the Documentation at List
+ href="https://blazemeter.github.io/CorrelationRecorder/guide/correlation-rules.html#list-of-correlation-extractors">List
Correlation Extractors
diff --git a/src/main/resources/correlation-descriptions/MoreReplacement.html b/src/main/resources/correlation-descriptions/MoreReplacement.html
index fd02399..b21de37 100644
--- a/src/main/resources/correlation-descriptions/MoreReplacement.html
+++ b/src/main/resources/correlation-descriptions/MoreReplacement.html
@@ -4,5 +4,5 @@
Notice that you don't need to pick a C. Replacement if you don't need it since a rule is
complete, as long as it has either a Correlation Replacement
or a Correlation Extractor selected.
For more information about Replacements and how to use them, check the Documentation at List
+ href="https://blazemeter.github.io/CorrelationRecorder/guide/correlation-rules.html#list-of-correlation-replacements">List
of Correlation Replacements
diff --git a/src/main/resources/correlation-descriptions/NoneExtractor.html b/src/main/resources/correlation-descriptions/NoneExtractor.html
index e1e1d31..bb7d189 100644
--- a/src/main/resources/correlation-descriptions/NoneExtractor.html
+++ b/src/main/resources/correlation-descriptions/NoneExtractor.html
@@ -6,5 +6,5 @@
complete, as long as it has either a Correlation Replacement
or a Correlation Extractor selected.
For more information about Extractors and how to use them, check the Documentation at List
+ href="https://blazemeter.github.io/CorrelationRecorder/guide/correlation-rules.html#list-of-correlation-extractors">List
Correlation Extractors
diff --git a/src/main/resources/correlation-descriptions/NoneReplacement.html b/src/main/resources/correlation-descriptions/NoneReplacement.html
index 196d951..dbcbd87 100644
--- a/src/main/resources/correlation-descriptions/NoneReplacement.html
+++ b/src/main/resources/correlation-descriptions/NoneReplacement.html
@@ -4,5 +4,5 @@
Notice that you dont need to pick a C. Replacement if you don't need it since, a rule is
complete, as long as it has either a Correlation Replacement
or a Correlation Extractor selected.
For more information about Replacements and how to use them, check the Documentation at List
+ href="https://blazemeter.github.io/CorrelationRecorder/guide/correlation-rules.html#list-of-correlation-replacements">List
of Correlation Replacements
diff --git a/src/main/resources/correlation-descriptions/RegexCorrelationExtractor.html b/src/main/resources/correlation-descriptions/RegexCorrelationExtractor.html
index 51c629f..eee0354 100644
--- a/src/main/resources/correlation-descriptions/RegexCorrelationExtractor.html
+++ b/src/main/resources/correlation-descriptions/RegexCorrelationExtractor.html
@@ -46,7 +46,7 @@
For more information about Extractors and how to use them, check the Documentation at List
+ href="https://blazemeter.github.io/CorrelationRecorder/guide/correlation-rules.html#list-of-correlation-extractors">List
Correlation Extractors
diff --git a/src/main/resources/correlation-descriptions/RegexCorrelationReplacement.html b/src/main/resources/correlation-descriptions/RegexCorrelationReplacement.html
index 02c9a91..2fa60d4 100644
--- a/src/main/resources/correlation-descriptions/RegexCorrelationReplacement.html
+++ b/src/main/resources/correlation-descriptions/RegexCorrelationReplacement.html
@@ -41,5 +41,5 @@
For more information about Replacements and how to use them, check the Documentation at List
+ href="https://blazemeter.github.io/CorrelationRecorder/guide/correlation-rules.html#list-of-correlation-replacements">List
of Correlation Replacements
diff --git a/src/main/resources/correlation-descriptions/SiebelCounterCorrelationReplacement.html b/src/main/resources/correlation-descriptions/SiebelCounterCorrelationReplacement.html
index 20757a9..4ebd04c 100644
--- a/src/main/resources/correlation-descriptions/SiebelCounterCorrelationReplacement.html
+++ b/src/main/resources/correlation-descriptions/SiebelCounterCorrelationReplacement.html
@@ -27,6 +27,6 @@
For more information about Replacements and how to use them, check the Documentation at List
+ href="https://blazemeter.github.io/CorrelationRecorder/guide/correlation-rules.html#list-of-correlation-replacements">List
of Correlation Replacements
diff --git a/src/main/resources/correlation-descriptions/SiebelRowCorrelationExtractor.html b/src/main/resources/correlation-descriptions/SiebelRowCorrelationExtractor.html
index ff60204..4faead7 100644
--- a/src/main/resources/correlation-descriptions/SiebelRowCorrelationExtractor.html
+++ b/src/main/resources/correlation-descriptions/SiebelRowCorrelationExtractor.html
@@ -47,5 +47,5 @@
For more information about Extractors and how to use them, check the Documentation at List
+ href="https://blazemeter.github.io/CorrelationRecorder/guide/correlation-rules.html#list-of-correlation-extractors">List
Correlation Extractors
diff --git a/src/main/resources/correlation-descriptions/SiebelRowIdCorrelationReplacement.html b/src/main/resources/correlation-descriptions/SiebelRowIdCorrelationReplacement.html
index f000c86..003e121 100644
--- a/src/main/resources/correlation-descriptions/SiebelRowIdCorrelationReplacement.html
+++ b/src/main/resources/correlation-descriptions/SiebelRowIdCorrelationReplacement.html
@@ -26,6 +26,6 @@
For more information about Replacements and how to use them, check the Documentation at List
+ href="https://blazemeter.github.io/CorrelationRecorder/guide/correlation-rules.html#list-of-correlation-replacements">List
of Correlation Replacements
diff --git a/src/main/resources/correlation-descriptions/SiebelRowParamsCorrelationReplacement.html b/src/main/resources/correlation-descriptions/SiebelRowParamsCorrelationReplacement.html
index 9629b3b..cba3123 100644
--- a/src/main/resources/correlation-descriptions/SiebelRowParamsCorrelationReplacement.html
+++ b/src/main/resources/correlation-descriptions/SiebelRowParamsCorrelationReplacement.html
@@ -27,6 +27,6 @@
For more information about Replacements and how to use them, check the Documentation at List
+ href="https://blazemeter.github.io/CorrelationRecorder/guide/correlation-rules.html#list-of-correlation-replacements">List
of Correlation Replacements
diff --git a/src/main/resources/correlation-descriptions/XmlCorrelationExtractor.html b/src/main/resources/correlation-descriptions/XmlCorrelationExtractor.html
index 1e3bc88..c631918 100644
--- a/src/main/resources/correlation-descriptions/XmlCorrelationExtractor.html
+++ b/src/main/resources/correlation-descriptions/XmlCorrelationExtractor.html
@@ -46,7 +46,7 @@
For more information about Extractors and how to use them, check the Documentation at List
+ href="https://blazemeter.github.io/CorrelationRecorder/guide/correlation-rules.html#list-of-correlation-extractors">List
Correlation Extractors
diff --git a/src/test/java/com/blazemeter/jmeter/correlation/core/automatic/CorrelationHistoryTest.java b/src/test/java/com/blazemeter/jmeter/correlation/core/automatic/CorrelationHistoryTest.java
index fbf3c50..24e2ee5 100644
--- a/src/test/java/com/blazemeter/jmeter/correlation/core/automatic/CorrelationHistoryTest.java
+++ b/src/test/java/com/blazemeter/jmeter/correlation/core/automatic/CorrelationHistoryTest.java
@@ -53,28 +53,28 @@ public void shouldDeleteStepsWhenDeleteSteps() throws IOException {
@Test
public void shouldAddOriginalRecordingStep() throws IOException {
CorrelationHistory history = new CorrelationHistory();
- history.addOriginalRecordingStep("originalRecordingFilepath",
- "originalRecordingTraceFilepath");
- assertEquals("originalRecordingFilepath", history.getOriginalRecordingFilepath());
- assertEquals("originalRecordingTraceFilepath", history.getOriginalRecordingTrace());
+ history.addOriginalRecordingStep("Recording"+ File.separator+"originalRecordingFilepath",
+ "Recording"+ File.separator+"originalRecordingTraceFilepath");
+ assertEquals("Recording"+ File.separator+"originalRecordingFilepath", history.getOriginalRecordingFilepath());
+ assertEquals("Recording"+ File.separator+"originalRecordingTraceFilepath", history.getOriginalRecordingTrace());
}
@Test
public void shouldAddOriginalRecordingStepWhenStepsAreNotEmpty() throws IOException {
CorrelationHistory history = new CorrelationHistory();
- history.addOriginalRecordingStep("test",
- "test");
- history.addOriginalRecordingStep("originalRecordingFilepath",
- "originalRecordingTraceFilepath");
- assertEquals("originalRecordingFilepath", history.getOriginalRecordingFilepath());
- assertEquals("originalRecordingTraceFilepath", history.getOriginalRecordingTrace());
+ history.addOriginalRecordingStep("Recording"+ File.separator+"test",
+ "Recording"+ File.separator+"test");
+ history.addOriginalRecordingStep("Recording"+ File.separator+"originalRecordingFilepath",
+ "Recording"+ File.separator+"originalRecordingTraceFilepath");
+ assertEquals("Recording"+ File.separator+"originalRecordingFilepath", history.getOriginalRecordingFilepath());
+ assertEquals("Recording"+ File.separator+"originalRecordingTraceFilepath", history.getOriginalRecordingTrace());
}
private void addSuccessfulReplay(boolean errors) {
CorrelationHistory history = new CorrelationHistory();
- history.addSuccessfulReplay("testPlanFilepath","replayTraceFilepath",
+ history.addSuccessfulReplay("Recording"+ File.separator+"testPlanFilepath","Recording"+ File.separator+"replayTraceFilepath",
errors);
- assertEquals("testPlanFilepath", history.getLastTestPlanFilepath());
- assertEquals("replayTraceFilepath", history.getLastReplayTraceFilepath());
+ assertEquals("Recording"+ File.separator+"testPlanFilepath", history.getLastTestPlanFilepath());
+ assertEquals("Recording"+ File.separator+"replayTraceFilepath", history.getLastReplayTraceFilepath());
}
@Test
@@ -89,17 +89,17 @@ public void shouldAddSuccessfulReplayWithErrors() throws IOException {
@Test
public void shouldAddFailedReplay() throws IOException {
CorrelationHistory history = new CorrelationHistory();
- history.addFailedReplay("testPlanFilepath","replayTraceFilepath", 0);
- assertEquals("testPlanFilepath", history.getLastTestPlanFilepath());
- assertEquals("replayTraceFilepath", history.getLastReplayTraceFilepath());
+ history.addFailedReplay("Recording"+ File.separator+"testPlanFilepath","Replay"+ File.separator+"replayTraceFilepath", 0);
+ assertEquals("Recording"+ File.separator+"testPlanFilepath", history.getLastTestPlanFilepath());
+ assertEquals("Replay"+ File.separator+"replayTraceFilepath", history.getLastReplayTraceFilepath());
}
@Test
public void shouldAddAnalisisStep() throws IOException {
CorrelationHistory history = new CorrelationHistory();
- history.addAnalysisStep("Test","testPlanFilepath","replayTraceFilepath");
- assertEquals("testPlanFilepath", history.getLastTestPlanFilepath());
- assertEquals("replayTraceFilepath", history.getLastReplayTraceFilepath());
+ history.addAnalysisStep("Test","Recording"+ File.separator+"testPlanFilepath","Replay"+ File.separator+"replayTraceFilepath");
+ assertEquals("Recording"+ File.separator+"testPlanFilepath", history.getLastTestPlanFilepath());
+ assertEquals("Replay"+ File.separator+"replayTraceFilepath", history.getLastReplayTraceFilepath());
}
@Test
@@ -117,9 +117,9 @@ public void shouldAddRestoreStep() throws IOException {
@Test
public void shouldGetOriginalRecordingFilepathWhenNoStepAdded() throws IOException {
- String testPlanFilepath = "testPlanFilepath";
+ String testPlanFilepath = "Recording"+ File.separator+"testPlanFilepath";
CorrelationHistory.setSaveCurrentTestPlan(() -> testPlanFilepath);
- String recordingFilepath = "recordingFilepath";
+ String recordingFilepath = "Recording"+ File.separator+"recordingFilepath";
CorrelationHistory.setRecordingFilePathSupplier(() -> recordingFilepath);
CorrelationHistory history = new CorrelationHistory();
@@ -128,9 +128,9 @@ public void shouldGetOriginalRecordingFilepathWhenNoStepAdded() throws IOExcepti
@Test
public void shouldGetOriginalRecordingTraceWhenNoStepAdded() throws IOException {
- String testPlanFilepath = "testPlanFilepath";
+ String testPlanFilepath = "Recording"+ File.separator+"testPlanFilepath";
CorrelationHistory.setSaveCurrentTestPlan(() -> testPlanFilepath);
- String recordingFilepath = "recordingFilepath";
+ String recordingFilepath = "Recording"+ File.separator+"recordingFilepath";
CorrelationHistory.setRecordingFilePathSupplier(() -> recordingFilepath);
CorrelationHistory history = new CorrelationHistory();
@@ -155,11 +155,11 @@ public void shouldReturnEmptyStringWhenGetLastReplayTraceFilepathWithEmptySteps(
@Test
public void stepShouldAddCurrentTestPlanWhenAddCurrentTestPlan() throws IOException {
- Supplier stringSupplier = () -> "testPlanFilepath";
+ Supplier stringSupplier = () -> "Recording"+ File.separator+"testPlanFilepath";
CorrelationHistory.setSaveCurrentTestPlan(stringSupplier);
CorrelationHistory.Step step = new CorrelationHistory.Step("Hello World");
step.addCurrentTestPlan();
- assertEquals("testPlanFilepath",step.getTestPlanFilepath());
+ assertEquals("Recording"+ File.separator+"testPlanFilepath",step.getTestPlanFilepath());
}
@Test
diff --git a/src/test/java/com/blazemeter/jmeter/correlation/core/automatic/extraction/method/ComparableJMeterVariables.java b/src/test/java/com/blazemeter/jmeter/correlation/core/automatic/extraction/method/ComparableJMeterVariables.java
index 325250b..f4ca549 100644
--- a/src/test/java/com/blazemeter/jmeter/correlation/core/automatic/extraction/method/ComparableJMeterVariables.java
+++ b/src/test/java/com/blazemeter/jmeter/correlation/core/automatic/extraction/method/ComparableJMeterVariables.java
@@ -1,6 +1,5 @@
package com.blazemeter.jmeter.correlation.core.automatic.extraction.method;
-import com.blazemeter.jmeter.correlation.core.extractors.RegexCorrelationExtractorTest;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
@@ -36,6 +35,6 @@ public void clear() {
@Override
public boolean equals(Object obj) {
- return vars.equals(((RegexCorrelationExtractorTest.ComparableJMeterVariables) obj).vars);
+ return vars.equals(((ComparableJMeterVariables) obj).vars);
}
}
diff --git a/src/test/java/com/blazemeter/jmeter/correlation/core/extractors/JsonCorrelationExtractorTest.java b/src/test/java/com/blazemeter/jmeter/correlation/core/extractors/JsonCorrelationExtractorTest.java
new file mode 100644
index 0000000..9662c56
--- /dev/null
+++ b/src/test/java/com/blazemeter/jmeter/correlation/core/extractors/JsonCorrelationExtractorTest.java
@@ -0,0 +1,410 @@
+package com.blazemeter.jmeter.correlation.core.extractors;
+
+import static com.blazemeter.jmeter.correlation.TestUtils.getFileContent;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.when;
+
+import com.blazemeter.jmeter.correlation.TestUtils;
+import com.blazemeter.jmeter.correlation.core.BaseCorrelationContext;
+import com.blazemeter.jmeter.correlation.core.automatic.extraction.method.ComparableJMeterVariables;
+import com.blazemeter.jmeter.correlation.gui.CorrelationComponentsRegistry;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.text.StringEscapeUtils;
+import org.apache.http.entity.ContentType;
+import org.apache.jmeter.assertions.AssertionResult;
+import org.apache.jmeter.assertions.JSR223Assertion;
+import org.apache.jmeter.extractor.json.jsonpath.JSONPostProcessor;
+import org.apache.jmeter.samplers.SampleResult;
+import org.apache.jmeter.testbeans.gui.TestBeanGUI;
+import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.threads.JMeterVariables;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.slf4j.bridge.SLF4JBridgeHandler;
+
+
+@RunWith(MockitoJUnitRunner.class)
+public class JsonCorrelationExtractorTest {
+
+
+ private static final String REFERENCE_NAME = "TEST_SWEACN";
+ private static final String RESPONSE_BODY_JSONPATH = "$.arg1";
+ private static final List PARAMS = Arrays
+ .asList(RESPONSE_BODY_JSONPATH, "1", ResultField.BODY.name()
+ , "false"); // JSONPAth, Match 1, BODY, Multivalue False
+ private static final String TEST_URL = "https://jmeter.apache.org/";
+ private static final String SUCCESS_RESPONSE_MESSAGE = HttpStatus
+ .getStatusText(HttpStatus.SC_OK);
+
+ @Mock
+ private BaseCorrelationContext baseCorrelationContext;
+
+ // we need this to avoid nasty logs about pdfbox
+ @BeforeClass
+ public static void setupClass() {
+ SLF4JBridgeHandler.removeHandlersForRootLogger();
+ SLF4JBridgeHandler.install();
+ }
+
+ protected static SampleResult createSampleResultWithResponseBody(String responseBody)
+ throws MalformedURLException {
+ SampleResult sampleResult = new SampleResult();
+ URL testUrl = new URL(TEST_URL);
+ sampleResult.setURL(testUrl);
+ sampleResult.setSamplerData("Test_SWEACn=123&Test_Path=1");
+ sampleResult.setResponseCode(String.valueOf(HttpStatus.SC_OK));
+ sampleResult.setResponseMessage(SUCCESS_RESPONSE_MESSAGE);
+ sampleResult.setResponseHeaders(TEST_URL);
+ sampleResult.setRequestHeaders(TEST_URL);
+ sampleResult.setResponseData(responseBody, SampleResult.DEFAULT_HTTP_ENCODING);
+ sampleResult.setContentType(ContentType.TEXT_HTML.toString());
+ return sampleResult;
+ }
+
+ @Test
+ public void shouldNotAddChildJsonExtractorWhenDoesNotMatch()
+ throws MalformedURLException {
+ JsonCorrelationExtractor> jsonExtractor = new JsonCorrelationExtractor<>();
+ jsonExtractor.setParams(PARAMS);
+ jsonExtractor.setVariableName(REFERENCE_NAME);
+ List children = new ArrayList<>();
+ jsonExtractor.process(null, children,
+ createSampleResultWithResponseBody("{\"arg2\":\"123\"}"), // arg2 not in jsonpath
+ new JMeterVariables());
+ assertThat(TestUtils.comparableFrom(children)).isEqualTo(Collections.emptyList());
+ }
+
+ @Test
+ public void shouldAddChildJsonExtractorWhenMatchesAgainstSampleResultBody()
+ throws MalformedURLException {
+ assertAddChildJson(RESPONSE_BODY_JSONPATH, ResultField.BODY);
+ }
+
+ private void assertAddChildJson(String responseJson, ResultField fieldToCheck)
+ throws MalformedURLException {
+ JsonCorrelationExtractor> jsonExtractor = new JsonCorrelationExtractor<>(responseJson, 1,
+ fieldToCheck);
+ jsonExtractor.setVariableName(REFERENCE_NAME);
+ List children = new ArrayList<>();
+ jsonExtractor.process(null, children, createMatchSampleResult(), new JMeterVariables());
+ assertThat(TestUtils.comparableFrom(children)).isEqualTo(
+ TestUtils.comparableFrom(
+ Collections.singletonList(createJsonExtractor(responseJson, fieldToCheck))));
+ }
+
+
+ @Test
+ public void shouldAddChildJsonExtractorWhenMatchesOnceAndMatchNumberIsLessThanZero()
+ throws MalformedURLException {
+ List children = addChildJson(RESPONSE_BODY_JSONPATH, ResultField.BODY, false);
+ JSONPostProcessor jsonExtractor =
+ createJsonExtractor(RESPONSE_BODY_JSONPATH, ResultField.BODY);
+ jsonExtractor.setMatchNumbers("1");
+ assertThat(TestUtils.comparableFrom(children)).isEqualTo(
+ TestUtils.comparableFrom(
+ Collections.singletonList(jsonExtractor)));
+ }
+
+ private List addChildJson(String responseJson, ResultField fieldToCheck,
+ boolean isMultipleMatch)
+ throws MalformedURLException {
+ JsonCorrelationExtractor> jsonExtractor = new JsonCorrelationExtractor<>(responseJson, -1,
+ fieldToCheck);
+ jsonExtractor.setVariableName(REFERENCE_NAME);
+ List children = new ArrayList<>();
+ jsonExtractor.process(null, children, isMultipleMatch ? createMultipleMatchSampleResult() :
+ createMatchSampleResult(), new JMeterVariables());
+ return children;
+ }
+
+ private SampleResult createMultipleMatchSampleResult() throws MalformedURLException {
+ return JsonCorrelationExtractorTest
+ .createSampleResultWithResponseBody(
+ "{\"arg1\":[\"123\", \"321\"]}");
+ }
+
+ private SampleResult createEmptySampleResult() throws MalformedURLException {
+ return JsonCorrelationExtractorTest
+ .createSampleResultWithResponseBody("");
+ }
+
+ private SampleResult createMatchSampleResult() throws MalformedURLException {
+ return createSampleResultWithResponseBody("{\"arg1\":\"123\"}");
+ }
+
+ private JSONPostProcessor createJsonExtractor(String responseJsonPath, ResultField fieldToCheck) {
+ JSONPostProcessor processor = new JSONPostProcessor();
+ processor.setProperty(TestElement.GUI_CLASS,
+ org.apache.jmeter.extractor.json.jsonpath.gui.JSONPostProcessorGui.class.getName());
+ processor.setName("JSON Path - " + REFERENCE_NAME);
+ processor.setRefNames(REFERENCE_NAME);
+ processor.setMatchNumbers("1");
+ processor.setDefaultValues(REFERENCE_NAME + "_NOT_FOUND");
+ processor.setComputeConcatenation(true);
+ processor.setJsonPathExpressions(responseJsonPath);
+ processor.setScopeAll();
+ return processor;
+ }
+
+ @Test
+ public void shouldAddChildJsonExtractorWhenMatchesTwiceAndMatchNumberIsLowerThanZero()
+ throws MalformedURLException {
+ List children = addChildJson(RESPONSE_BODY_JSONPATH, ResultField.BODY, true);
+ JSONPostProcessor jsonExtractor = createJsonExtractor(RESPONSE_BODY_JSONPATH, ResultField.BODY);
+ jsonExtractor.setMatchNumbers("-1");
+ assertThat(TestUtils.comparableFrom(children)).isEqualTo(
+ TestUtils.comparableFrom(
+ Collections.singletonList(jsonExtractor)));
+ }
+
+
+ @Test
+ public void shouldSetMatchNumberToDefaultValueWhenItIsEmpty() throws MalformedURLException {
+ ResultField fieldToCheck = ResultField.BODY;
+ JsonCorrelationExtractor> jsonExtractor = new JsonCorrelationExtractor<>();
+ jsonExtractor.setParams(PARAMS);
+ jsonExtractor.setVariableName(REFERENCE_NAME);
+ List children = new ArrayList<>();
+ jsonExtractor.process(null, children, createMatchSampleResult(), new JMeterVariables());
+ assertThat(TestUtils.comparableFrom(children))
+ .isEqualTo(TestUtils.comparableFrom(Collections.singletonList(createJsonExtractor(
+ RESPONSE_BODY_JSONPATH, fieldToCheck))));
+ }
+
+ @Test
+ public void shouldNotAddJsonExtractorWhenMatchedValueIsAlreadyExtracted()
+ throws MalformedURLException {
+ JsonCorrelationExtractor> jsonExtractor = new JsonCorrelationExtractor<>();
+ jsonExtractor.setParams(PARAMS);
+ jsonExtractor.setVariableName(REFERENCE_NAME);
+ List children = new ArrayList<>();
+ SampleResult firstSampleResults = createMatchSampleResult();
+ JMeterVariables vars = new JMeterVariables();
+ jsonExtractor.process(null, children, firstSampleResults, vars);
+ jsonExtractor.process(null, children, firstSampleResults, vars);
+ assertThat(TestUtils.comparableFrom(children))
+ .isEqualTo(TestUtils.comparableFrom(Collections.singletonList(createJsonExtractor(
+ RESPONSE_BODY_JSONPATH, ResultField.BODY))));
+ }
+
+ @Test
+ public void shouldFailSampleWhenProcessWithFailingExtractingVariable() throws IOException {
+ JsonCorrelationExtractor> jsonExtractor = new JsonCorrelationExtractor<>(
+ RESPONSE_BODY_JSONPATH);
+ jsonExtractor.setVariableName(REFERENCE_NAME);
+ List children = new ArrayList<>();
+
+ JSR223Assertion assertion = buildExtractionAssertion();
+ assertion.setScript(StringEscapeUtils
+ .unescapeXml(getFileContent("/templates/components/ExtractingVariableAssertion.xml",
+ jsonExtractor.getClass())));
+ children.add(assertion);
+
+ JMeterVariables vars = new JMeterVariables();
+ SampleResult firstSampleResults = createMatchSampleResult();
+ jsonExtractor.process(null, children, firstSampleResults, vars);
+
+ SampleResult sampleResult = createSampleResultWithResponseBody("Other Body");
+ sampleResult.setSuccessful(true);
+ AssertionResult result = assertion.getResult(sampleResult);
+ assertThat(result.isFailure());
+ }
+
+ private JSR223Assertion buildExtractionAssertion() {
+ JSR223Assertion assertion = new JSR223Assertion();
+ assertion.setProperty(JSR223Assertion.GUI_CLASS, TestBeanGUI.class.getName());
+ assertion.setName("Extraction assertion");
+ assertion.setProperty("cacheKey", UUID.randomUUID().toString());
+ assertion.setProperty("language", "groovy");
+
+ return assertion;
+ }
+
+ @Test
+ public void shouldSampleSucceedWhenVariableIsExtractedWithAssertion() throws IOException {
+ JsonCorrelationExtractor> jsonExtractor = new JsonCorrelationExtractor<>(
+ RESPONSE_BODY_JSONPATH);
+ jsonExtractor.setVariableName(REFERENCE_NAME);
+ List children = new ArrayList<>();
+
+ JSR223Assertion assertion = buildExtractionAssertion();
+ assertion.setScript(StringEscapeUtils
+ .unescapeXml(getFileContent("/templates/components/ExtractingVariableAssertion.xml",
+ jsonExtractor.getClass())));
+ children.add(assertion);
+
+ JMeterVariables vars = new JMeterVariables();
+ SampleResult firstSampleResults = createMatchSampleResult();
+ jsonExtractor.process(null, children, firstSampleResults, vars);
+
+ SampleResult sampleResult = createSampleResultWithResponseBody("Test_SWEACn=TestBodyInfo&");
+ sampleResult.setSuccessful(true);
+ AssertionResult result = assertion.getResult(sampleResult);
+ assertThat(!result.isFailure());
+ }
+
+ @Test
+ public void shouldNotAddChildJsonExtractorWhenDoesNotMatchAndMultiValued()
+ throws MalformedURLException {
+ setupContextForMultiValue();
+ JsonCorrelationExtractor jsonExtractor =
+ new JsonCorrelationExtractor<>(RESPONSE_BODY_JSONPATH, -1,
+ ResultField.BODY.name(), "true");
+ jsonExtractor.setVariableName(REFERENCE_NAME);
+ jsonExtractor.setContext(baseCorrelationContext);
+ List children = new ArrayList<>();
+ jsonExtractor.process(null, children,
+ JsonCorrelationExtractorTest.createSampleResultWithResponseBody("Other Body"),
+ new JMeterVariables());
+ assertThat(TestUtils.comparableFrom(children)).isEqualTo(Collections.emptyList());
+ }
+
+ private void setupContextForMultiValue() {
+ when(baseCorrelationContext.getNextVariableNr(REFERENCE_NAME)).thenReturn(1).thenReturn(2);
+ }
+
+ @Test
+ public void shouldAddChildJsonExtractorWithOneInMatchNrWhenMatchesAgainstSampleResultOnlyOnceBody()
+ throws MalformedURLException {
+ setupContextForMultiValue();
+ List children = new ArrayList<>();
+ addChildJson(RESPONSE_BODY_JSONPATH, createMatchSampleResult(), children,
+ new JMeterVariables());
+ JSONPostProcessor extractor = createJsonExtractor(RESPONSE_BODY_JSONPATH, 1);
+ assertThat(TestUtils.comparableFrom(children)).isEqualTo(
+ TestUtils.comparableFrom(
+ Collections.singletonList(extractor)));
+ }
+
+ @Test
+ public void shouldAddMatchNrVarWhenMatchesAgainstSampleResultBodyMultipleTimes()
+ throws MalformedURLException {
+ setupContextForMultiValue();
+ List children = new ArrayList<>();
+ JMeterVariables vars = new JMeterVariables();
+ addChildJson(RESPONSE_BODY_JSONPATH, createMultipleMatchSampleResult(), children, vars);
+ assertThat(vars.get(REFERENCE_NAME + "#1_matchNr")).isNotNull();
+ }
+
+ @Test
+ public void shouldAddChildWithDifferentIndexWhenMatchesAgainstMultipleSampleResultBody()
+ throws MalformedURLException {
+ setupContextForMultiValue();
+ List children = new ArrayList<>();
+ JMeterVariables vars = new JMeterVariables();
+ addChildJson(RESPONSE_BODY_JSONPATH, createMultipleMatchSampleResult(), children, vars);
+ addChildJson(RESPONSE_BODY_JSONPATH, createMultipleMatchSampleResult(), children, vars);
+ assertThat(TestUtils.comparableFrom(children)).isEqualTo(
+ TestUtils.comparableFrom(
+ Arrays.asList(createJsonExtractor(RESPONSE_BODY_JSONPATH, 1, -1),
+ createJsonExtractor(RESPONSE_BODY_JSONPATH, 2, -1))));
+ assertThat(vars.get(REFERENCE_NAME + "#1_matchNr")).isNotNull();
+ }
+
+ private void addChildJson(String responseJson, SampleResult sampleResult,
+ List children, JMeterVariables vars) {
+ JsonCorrelationExtractor jsonExtractor =
+ new JsonCorrelationExtractor<>(RESPONSE_BODY_JSONPATH, -1, ResultField.BODY.name(),
+ "true");
+
+ jsonExtractor.setContext(baseCorrelationContext);
+ jsonExtractor.setVariableName(REFERENCE_NAME);
+ jsonExtractor.process(null, children, sampleResult, vars);
+
+ }
+
+ private JSONPostProcessor createJsonExtractor(String responseJson, int varNr) {
+ JSONPostProcessor processor = new JSONPostProcessor();
+ processor.setProperty(TestElement.GUI_CLASS,
+ org.apache.jmeter.extractor.json.jsonpath.gui.JSONPostProcessorGui.class.getName());
+ processor.setName("JSON Path - " + REFERENCE_NAME + "#" + varNr);
+ processor.setRefNames(REFERENCE_NAME + "#" + varNr);
+ processor.setMatchNumbers(String.valueOf(varNr));
+ processor.setDefaultValues(REFERENCE_NAME + "#" + varNr + "_NOT_FOUND");
+ processor.setJsonPathExpressions(responseJson);
+ processor.setComputeConcatenation(true);
+ processor.setScopeAll();
+ return processor;
+ }
+
+ private JSONPostProcessor createJsonExtractor(String responseJson, int varNr, int matchNr) {
+ JSONPostProcessor processor = createJsonExtractor(responseJson, varNr);
+ processor.setMatchNumbers(String.valueOf(matchNr));
+ return processor;
+ }
+
+ @Test
+ public void shouldNotFailWhenSampleResultBodyIsEmpty()
+ throws MalformedURLException {
+ setupContextForMultiValue();
+ List children = new ArrayList<>();
+ JMeterVariables vars = new JMeterVariables();
+ addChildJson(RESPONSE_BODY_JSONPATH, createEmptySampleResult(), children, vars);
+ assertThat(TestUtils.comparableFrom(children)).isEqualTo(
+ TestUtils.comparableFrom(
+ Collections.emptyList()));
+ }
+
+
+ @Test
+ public void shouldRemoveLeftOverVariablesWhenMultipleMatchesAndMatchNrLowerThanZero()
+ throws Exception {
+ ComparableJMeterVariables vars =
+ new ComparableJMeterVariables();
+ vars.put(REFERENCE_NAME + "_1", "value1");
+ vars.put(REFERENCE_NAME + "_2", "value2");
+ vars.put(REFERENCE_NAME + "_3", "value3");
+ vars.put(REFERENCE_NAME + "_matchNr", "3");
+ JsonCorrelationExtractor jsonExtractor =
+ new JsonCorrelationExtractor<>(RESPONSE_BODY_JSONPATH, -1, ResultField.BODY.name(),
+ "false");
+ jsonExtractor.setContext(baseCorrelationContext);
+ jsonExtractor.setVariableName(REFERENCE_NAME);
+ jsonExtractor.process(null, new ArrayList<>(), createMultipleMatchSampleResult(),
+ vars);
+ assertThat(vars).isEqualTo(buildExpectedVariable());
+ }
+
+ private JMeterVariables buildExpectedVariable() {
+ ComparableJMeterVariables vars =
+ new ComparableJMeterVariables();
+ vars.put(REFERENCE_NAME + "_1", "123");
+ vars.put(REFERENCE_NAME + "_2", "321");
+ vars.put(REFERENCE_NAME + "_matchNr", "2");
+ return vars;
+ }
+
+ @Mock
+ private CorrelationComponentsRegistry registry;
+
+ @Test
+ public void shouldCatchAllMatchedValues() throws MalformedURLException {
+ ComparableJMeterVariables variables =
+ new ComparableJMeterVariables();
+
+ JsonCorrelationExtractor jsonExtractor =
+ new JsonCorrelationExtractor<>("$..arg1", -1,
+ ResultField.BODY.name(), "true");
+ jsonExtractor.setVariableName("args");
+ jsonExtractor.setMultiValued(true);
+ jsonExtractor.setContext(new BaseCorrelationContext());
+
+ String responseWithArgs = "[{\"arg1\":\"123\"},{\"arg1\":\"321\"}]";
+
+ jsonExtractor.process(null, new ArrayList<>(),
+ createSampleResultWithResponseBody(responseWithArgs), variables);
+ assertThat(variables.entrySet().size()).isEqualTo(3);
+ }
+
+}
diff --git a/src/test/java/com/blazemeter/jmeter/correlation/core/extractors/RegexCorrelationExtractorTest.java b/src/test/java/com/blazemeter/jmeter/correlation/core/extractors/RegexCorrelationExtractorTest.java
index 79ec077..e858d46 100644
--- a/src/test/java/com/blazemeter/jmeter/correlation/core/extractors/RegexCorrelationExtractorTest.java
+++ b/src/test/java/com/blazemeter/jmeter/correlation/core/extractors/RegexCorrelationExtractorTest.java
@@ -3,8 +3,10 @@
import static com.blazemeter.jmeter.correlation.TestUtils.getFileContent;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
+
import com.blazemeter.jmeter.correlation.TestUtils;
import com.blazemeter.jmeter.correlation.core.BaseCorrelationContext;
+import com.blazemeter.jmeter.correlation.core.automatic.extraction.method.ComparableJMeterVariables;
import com.blazemeter.jmeter.correlation.gui.CorrelationComponentsRegistry;
import java.io.IOException;
import java.net.MalformedURLException;
@@ -12,11 +14,8 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.UUID;
-import java.util.stream.Collectors;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.http.entity.ContentType;
@@ -420,7 +419,8 @@ public void shouldCatchAllMatchedValues() throws MalformedURLException {
regexExtractor.setMultiValued(true);
regexExtractor.setContext(new BaseCorrelationContext());
- String responseWithNonces = " Login Login ";
+ String responseWithNonces =
+ " Login Login ";
regexExtractor.process(null, new ArrayList<>(),
@@ -428,32 +428,4 @@ public void shouldCatchAllMatchedValues() throws MalformedURLException {
assertThat(variables.entrySet().size()).isEqualTo(3);
}
- public static class ComparableJMeterVariables extends JMeterVariables {
-
- public Map vars = new HashMap<>();
-
- @Override
- public void put(String key, String value) {
- vars.put(key, value);
- super.put(key, value);
- }
-
- @Override
- public Object remove(String key) {
- vars.remove(key);
- return super.remove(key);
- }
-
- @Override
- public String toString() {
- return vars.keySet().stream()
- .map(k -> "{" + k + "," + vars.get(k) + "}")
- .collect(Collectors.joining(","));
- }
-
- @Override
- public boolean equals(Object obj) {
- return vars.equals(((ComparableJMeterVariables) obj).vars);
- }
- }
}
diff --git a/src/test/java/com/blazemeter/jmeter/correlation/core/replacements/JsonCorrelationReplacementTest.java b/src/test/java/com/blazemeter/jmeter/correlation/core/replacements/JsonCorrelationReplacementTest.java
new file mode 100644
index 0000000..e5dd3c6
--- /dev/null
+++ b/src/test/java/com/blazemeter/jmeter/correlation/core/replacements/JsonCorrelationReplacementTest.java
@@ -0,0 +1,399 @@
+package com.blazemeter.jmeter.correlation.core.replacements;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
+
+import com.blazemeter.jmeter.correlation.core.BaseCorrelationContext;
+import com.blazemeter.jmeter.correlation.core.extractors.JsonCorrelationExtractor;
+import com.blazemeter.jmeter.correlation.core.extractors.ResultField;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+import org.apache.http.entity.ContentType;
+import org.apache.jmeter.config.Arguments;
+import org.apache.jmeter.extractor.json.jsonpath.JSONPostProcessor;
+import org.apache.jmeter.protocol.http.sampler.HTTPSampler;
+import org.apache.jmeter.samplers.SampleResult;
+import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.threads.JMeterContext;
+import org.apache.jmeter.threads.JMeterContextService;
+import org.apache.jmeter.threads.JMeterVariables;
+import org.assertj.core.api.Assertions;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.slf4j.bridge.SLF4JBridgeHandler;
+
+@RunWith(MockitoJUnitRunner.class)
+public class JsonCorrelationReplacementTest {
+
+ private static final String REFERENCE_NAME = "TEST_SWEACN";
+ private static final String PARAM_VALUE = "123";
+ private static final String REQUEST_JSONPATH = "$.arg1";
+ private static final String DEFAULT_SAMPLER_JSON = "{\"arg1\":\"123\"}";
+ private static final Object EXPECTED_REPLACED_JSON =
+ "{\"arg1\":\"${" + REFERENCE_NAME + "}\"}";
+ private JsonCorrelationReplacement replacer;
+ private JMeterVariables vars;
+ private HTTPSampler sampler;
+ @Mock
+ private BaseCorrelationContext replaceContext;
+ @Mock
+ private Function expressionEvaluation;
+
+ // we need this to avoid nasty logs about pdfbox
+ @BeforeClass
+ public static void setupClass() {
+ SLF4JBridgeHandler.removeHandlersForRootLogger();
+ SLF4JBridgeHandler.install();
+ }
+
+ @Before
+ public void setup() {
+ sampler = new HTTPSampler();
+ sampler.setMethod("POST");
+ sampler.setPath("/");
+ sampler.setPostBodyRaw(true);
+
+ Arguments arguments = new Arguments();
+ arguments.addArgument("", DEFAULT_SAMPLER_JSON);
+ sampler.setArguments(arguments);
+ vars = new JMeterVariables();
+ vars.put(REFERENCE_NAME, PARAM_VALUE);
+
+ }
+
+ @Test
+ public void shouldReplaceJsonValueWithReferenceWhenJsonPathMatch() {
+
+ JMeterContext context = JMeterContextService.getContext();
+ JSONPostProcessor extractor =
+ createJsonExtractor(context, "1", true);
+
+ // Execute the replacement with a valid JSON path
+ processJonReplacement(extractor, REQUEST_JSONPATH);
+
+ // Get if the value of the argument of the sample was updated wit the reference variable
+ assertThat(getFirstArgumentValue()).isEqualTo(EXPECTED_REPLACED_JSON);
+ }
+
+ @Test
+ public void shouldReplaceJsonValueWithReferenceWhenJsonPathMatchAndUseReplaceStringWithIgnoreValue() {
+
+ JMeterContext context = JMeterContextService.getContext();
+ JSONPostProcessor extractor =
+ createJsonExtractor(context, "1", true);
+
+ String replacementString = "${__changeCase(\"test\", UPPER)}";
+
+ // Execute the replacement with a valid JSON path
+ processJonReplacement(extractor, REQUEST_JSONPATH, replacementString, true);
+
+ // Get if the value of the argument of the sample was updated wit the reference variable
+ assertThat(getFirstArgumentValue()).isEqualTo(
+ "{\"arg1\":\"" + escapeJsonValue(replacementString) + "\"}");
+ }
+
+ @Test
+ public void shouldNotReplaceMatchForReplacementStringWhenNotIgnoreValueAndEvaluationNotMeet() {
+ JMeterContext context = JMeterContextService.getContext();
+ JSONPostProcessor extractor =
+ createJsonExtractor(context, "1", true);
+
+ String replacementString = "${__RandomString(5)}";
+
+ Arguments arguments = new Arguments();
+ String samplerJsonNotMatch = "{\"arg1\":\"321\"}";
+ arguments.addArgument("", samplerJsonNotMatch);
+ sampler.setArguments(arguments);
+
+ // Execute the replacement, but extractor not match with replacement and ignore is false
+ processJonReplacement(extractor, REQUEST_JSONPATH, replacementString, false);
+
+ replacer.process(sampler, Collections.emptyList(), null, new JMeterVariables());
+ Assertions.assertThat(getFirstArgumentValue()).isEqualTo(samplerJsonNotMatch);
+ }
+
+ @Test
+ public void shouldReplaceMatchWhenNotIgnoreValueAndEvaluationMeets() {
+ JMeterContext context = JMeterContextService.getContext();
+ JSONPostProcessor extractor =
+ createJsonExtractor(context, "1", true);
+
+ String replacementString = "${__javaScript('1' + '2' + '3')}";
+ processJonReplacement(extractor, REQUEST_JSONPATH, replacementString, false);
+
+ Assertions.assertThat(getFirstArgumentValue()).isEqualTo(
+ "{\"arg1\":\"" + escapeJsonValue(replacementString) + "\"}");
+ }
+
+ @Test
+ public void shouldReplaceMatchWhenNotIgnoreValueWithInnerVarsAndEvaluationMeets() {
+ JMeterContext context = JMeterContextService.getContext();
+ JSONPostProcessor extractor =
+ createJsonExtractor(context, "1", true);
+ String replacementString = "${__javaScript(${" + REFERENCE_NAME + "} + '3')}";
+ processJonReplacement(extractor, REQUEST_JSONPATH, replacementString, false);
+
+ Assertions.assertThat(getFirstArgumentValue())
+ .isEqualTo("{\"arg1\":\"" + escapeJsonValue(replacementString) + "\"}");
+ }
+
+ @Test
+ public void shouldReplaceMatchWhenNotIgnoreValueWithMultiInnerVarAndEvaluationMeets() {
+ JMeterContext context = JMeterContextService.getContext();
+ JSONPostProcessor extractor =
+ createJsonExtractor(context, "1", true);
+
+ String replacementString = "${__javaScript(${" + REFERENCE_NAME + "} + '3')}";
+
+ // Simulate multi value variables, overwrite context counter to 1
+ doReturn(1).when(replaceContext).getVariableCount(anyString());
+ JMeterVariables ctx_vars = context.getVariables();
+ vars.put(REFERENCE_NAME, "\"NOT_FOUND\"");
+ vars.put(REFERENCE_NAME + "#1_1", "213");
+ vars.put(REFERENCE_NAME + "#1_2", "123");
+ vars.put(REFERENCE_NAME + "#1_matchNr", "2");
+
+ processJonReplacement(extractor, REQUEST_JSONPATH, replacementString, false);
+
+ String replacementStringExpected = "${__javaScript(${" + REFERENCE_NAME + "#1_2} + '3')}";
+ Assertions.assertThat(getFirstArgumentValue()).isEqualTo(
+ "{\"arg1\":\"" + escapeJsonValue(replacementStringExpected) + "\"}");
+ }
+
+
+ @Test
+ public void shouldReplaceMatchWithoutQuotesWhenReplacedValueIsWithoutQuotes() {
+
+ String extractJson = "{\"arg1\": [111, 222, 333]}";
+ String extractJsonPath = "$.arg1";
+
+ String replaceJson = "{\"arg1\":[333, 222, 111]}";
+ String replaceJsonPath = "$.arg1";
+
+ String expectedJson = "{\"arg1\":[${TEST_SWEACN_3},${TEST_SWEACN_2},${TEST_SWEACN_1}]}";
+
+ SampleResult sampleResult = new SampleResult();
+ sampleResult.setResponseData(extractJson, SampleResult.DEFAULT_HTTP_ENCODING);
+ sampleResult.setContentType(ContentType.APPLICATION_JSON.toString());
+
+ List params = Arrays
+ .asList(
+ extractJsonPath, // JSONPath
+ "-1", // Match Number
+ ResultField.BODY.name(), // Body
+ "false"); // Multivalue False
+
+ JsonCorrelationExtractor> jsonExtractor = new JsonCorrelationExtractor<>();
+ jsonExtractor.setParams(params);
+ jsonExtractor.setVariableName(REFERENCE_NAME);
+ List children = new ArrayList<>();
+ JMeterVariables vars = new JMeterVariables();
+ jsonExtractor.process(null, children,
+ sampleResult,
+ vars);
+
+ replacer = new JsonCorrelationReplacement<>(replaceJsonPath);
+
+ HTTPSampler postSampler = new HTTPSampler();
+ postSampler.setMethod("POST");
+ postSampler.setPath("/");
+ postSampler.setPostBodyRaw(true);
+
+ Arguments arguments = new Arguments();
+ arguments.addArgument("", replaceJson);
+ postSampler.setArguments(arguments);
+
+ replacer.setVariableName(REFERENCE_NAME);
+ replacer.setContext(replaceContext);
+ replacer.setExpressionEvaluator(expressionEvaluation);
+ replacer.process(postSampler, Collections.singletonList(postSampler), sampleResult, vars);
+
+ String jsonUpated = postSampler.getArguments().getArgument(0).getValue();
+
+ assertThat(jsonUpated).isEqualTo(expectedJson);
+
+ }
+
+ @Test
+ public void shouldReplaceMatchWhenJsonUseVariablesWithoutQuotes() {
+
+ String extractJson = "{\"arg1\": [111, 222, 333]}";
+ String extractJsonPath = "$.arg1";
+
+ String replaceJson = "{\"arg1\":[333, 222, 111, ${var_2}], \"arg2\": ${var_1}}";
+ String replaceJsonPath = "$.arg1";
+
+ String expectedJson =
+ "{\"arg1\":[${TEST_SWEACN_3},${TEST_SWEACN_2},${TEST_SWEACN_1},${var_2}],\"arg2\":${var_1}}";
+
+ SampleResult sampleResult = new SampleResult();
+ sampleResult.setResponseData(extractJson, SampleResult.DEFAULT_HTTP_ENCODING);
+ sampleResult.setContentType(ContentType.APPLICATION_JSON.toString());
+
+ List params = Arrays
+ .asList(
+ extractJsonPath, // JSONPath
+ "-1", // Match Number
+ ResultField.BODY.name(), // Body
+ "false"); // Multivalue False
+
+ JsonCorrelationExtractor> jsonExtractor = new JsonCorrelationExtractor<>();
+ jsonExtractor.setParams(params);
+ jsonExtractor.setVariableName(REFERENCE_NAME);
+ List children = new ArrayList<>();
+ JMeterVariables vars = new JMeterVariables();
+ jsonExtractor.process(null, children,
+ sampleResult,
+ vars);
+
+ replacer = new JsonCorrelationReplacement<>(replaceJsonPath);
+
+ HTTPSampler postSampler = new HTTPSampler();
+ postSampler.setMethod("POST");
+ postSampler.setPath("/");
+ postSampler.setPostBodyRaw(true);
+
+ Arguments arguments = new Arguments();
+ arguments.addArgument("", replaceJson);
+ postSampler.setArguments(arguments);
+
+ replacer.setVariableName(REFERENCE_NAME);
+ replacer.setContext(replaceContext);
+ replacer.setExpressionEvaluator(expressionEvaluation);
+ replacer.process(postSampler, Collections.singletonList(postSampler), sampleResult, vars);
+
+ String jsonUpated = postSampler.getArguments().getArgument(0).getValue();
+
+ assertThat(jsonUpated).isEqualTo(expectedJson);
+
+ }
+
+
+ @Test
+ public void shouldNotReplaceJsonValueWithReferenceWhenJsonPathDoesNotMatch() {
+
+ JMeterContext context = JMeterContextService.getContext();
+ JSONPostProcessor extractor =
+ createJsonExtractor(context, "1", true);
+
+ // Execute the replacement with a json path that doesn't match
+ processJonReplacement(extractor, "$.arg2");
+
+ // Get if the value of the argument of the sample not was updated wit the reference variable
+ assertThat(getFirstArgumentValue()).isEqualTo(DEFAULT_SAMPLER_JSON);
+ }
+
+ @Test
+ public void shouldNotReplaceJsonValueWithReferenceWhenJsonPathIsInvalid() {
+
+ JMeterContext context = JMeterContextService.getContext();
+ JSONPostProcessor extractor =
+ createJsonExtractor(context, "1", true);
+
+ // Execute the replacement with an invalid json path
+ processJonReplacement(extractor, "Invalid.JSON.Path");
+
+ // Get if the value of the argument of the sample not was updated wit the reference variable
+ assertThat(getFirstArgumentValue()).isEqualTo(DEFAULT_SAMPLER_JSON);
+ }
+
+ @Test
+ public void shouldNotReplaceJsonValueWithReferenceWhenJsonPathIsEmpty() {
+
+ JMeterContext context = JMeterContextService.getContext();
+ JSONPostProcessor extractor =
+ createJsonExtractor(context, "1", true);
+
+ // Execute the replacement.with an empty JSON path
+ processJonReplacement(extractor, "");
+
+ // Get if the value of the argument of the sample not was updated wit the reference variable
+ assertThat(getFirstArgumentValue()).isEqualTo(DEFAULT_SAMPLER_JSON);
+ }
+
+ @Test
+ public void shouldNotReplaceJsonValueWithReferenceWhenReferenceValueIsDifferent() {
+
+ JMeterContext context = JMeterContextService.getContext();
+ JSONPostProcessor extractor =
+ createJsonExtractor(context, "1", true);
+
+ // Execute the replacement.with an empty JSON path
+ vars.put(REFERENCE_NAME, "Other");
+ processJonReplacement(extractor, "");
+
+ // Get if the value of the argument of the sample not was updated wit the reference variable
+ assertThat(getFirstArgumentValue()).isEqualTo(DEFAULT_SAMPLER_JSON);
+ }
+
+ @Test
+ public void shouldReplaceJsonValueWithReferenceWhenMatchOneTime() {
+
+ JMeterContext context = JMeterContextService.getContext();
+ JSONPostProcessor extractor =
+ createJsonExtractor(context, "1", true);
+
+ // Execute the replacement.with an empty JSON path
+ processJonReplacement(extractor, REQUEST_JSONPATH);
+
+ // Get if the value of the argument of the sample not was updated wit the reference variable
+ assertThat(getFirstArgumentValue()).isEqualTo(EXPECTED_REPLACED_JSON);
+ }
+
+ private String escapeJsonValue(String value) {
+ return value.replaceAll("\"", "\\\\\"");
+ }
+
+ private String getFirstArgumentValue() {
+ return sampler.getArguments().getArgument(0).getValue();
+ }
+
+ private void processJonReplacement(JSONPostProcessor extractor, String jsonPath) {
+ replacer = new JsonCorrelationReplacement<>(jsonPath);
+ processJonReplacement(extractor);
+ }
+
+ private void processJonReplacement(JSONPostProcessor extractor, String jsonPath,
+ String replacementString, boolean ignoreValue) {
+ replacer = new JsonCorrelationReplacement<>(jsonPath, replacementString,
+ Boolean.toString(ignoreValue));
+ processJonReplacement(extractor);
+ }
+
+ private void processJonReplacement(JSONPostProcessor extractor) {
+ replacer.setVariableName(REFERENCE_NAME);
+ replacer.setContext(replaceContext);
+ replacer.setExpressionEvaluator(expressionEvaluation);
+ replacer.process(sampler, Collections.singletonList(extractor), null, vars);
+ }
+
+ private static JSONPostProcessor createJsonExtractor(JMeterContext context, String matchNumbers,
+ boolean computeConcatenation) {
+ String VAR_NAME = "varName";
+ JSONPostProcessor processor = new JSONPostProcessor();
+ processor.setThreadContext(context);
+ processor.setRefNames(VAR_NAME);
+ processor.setMatchNumbers(matchNumbers);
+ processor.setComputeConcatenation(computeConcatenation);
+
+ // The Extractor get the value 123 from JSON path $.hello.origin
+ JMeterVariables vars = new JMeterVariables();
+ processor.setDefaultValues("NOT_FOUND");
+ processor.setJsonPathExpressions("$.hello.origin");
+ processor.setRefNames(REFERENCE_NAME);
+ processor.setScopeVariable("contentvar");
+ context.setVariables(vars);
+ String jsonResponse = "{\"hello\":{\"origin\":\"123\"}}";
+ vars.put("contentvar", jsonResponse);
+
+ return processor;
+ }
+}
diff --git a/src/test/java/com/blazemeter/jmeter/correlation/core/suggestions/method/ComparisonMethodTest.java b/src/test/java/com/blazemeter/jmeter/correlation/core/suggestions/method/ComparisonMethodTest.java
index 928ae8d..0e52773 100644
--- a/src/test/java/com/blazemeter/jmeter/correlation/core/suggestions/method/ComparisonMethodTest.java
+++ b/src/test/java/com/blazemeter/jmeter/correlation/core/suggestions/method/ComparisonMethodTest.java
@@ -12,6 +12,7 @@
import com.blazemeter.jmeter.correlation.core.automatic.FileManagementUtils;
import com.blazemeter.jmeter.correlation.core.automatic.ReplacementSuggestion;
import com.blazemeter.jmeter.correlation.core.automatic.ResultFileParser;
+import com.blazemeter.jmeter.correlation.core.replacements.CorrelationReplacement;
import com.blazemeter.jmeter.correlation.core.replacements.RegexCorrelationReplacement;
import com.blazemeter.jmeter.correlation.core.suggestions.context.AnalysisContext;
import com.blazemeter.jmeter.correlation.core.suggestions.context.ComparisonContext;
@@ -143,7 +144,7 @@ public void shouldGenerateMatchingReplacementsWhenAddReplacementSuggestions()
ReplacementSuggestion replacementSuggestion = replacements.get(0);
RegexCorrelationReplacement replacer = new RegexCorrelationReplacement<>();
- RegexCorrelationReplacement> replacement = replacementSuggestion.getReplacementSuggestion();
+ RegexCorrelationReplacement> replacement = (RegexCorrelationReplacement) replacementSuggestion.getReplacementSuggestion();
replacer.setParams(replacement.getParams());
replacer.setContext(correlationContext);
replacer.setVariableName(REFERENCE_NAME);
diff --git a/src/test/java/com/blazemeter/jmeter/correlation/gui/CorrelationComponentsRegistryTest.java b/src/test/java/com/blazemeter/jmeter/correlation/gui/CorrelationComponentsRegistryTest.java
index f0f51f9..7d7cbb6 100644
--- a/src/test/java/com/blazemeter/jmeter/correlation/gui/CorrelationComponentsRegistryTest.java
+++ b/src/test/java/com/blazemeter/jmeter/correlation/gui/CorrelationComponentsRegistryTest.java
@@ -8,6 +8,7 @@
import com.blazemeter.jmeter.correlation.core.extractors.RegexCorrelationExtractor;
import com.blazemeter.jmeter.correlation.core.extractors.XmlCorrelationExtractor;
import com.blazemeter.jmeter.correlation.core.replacements.CorrelationReplacement;
+import com.blazemeter.jmeter.correlation.core.replacements.JsonCorrelationReplacement;
import com.blazemeter.jmeter.correlation.core.replacements.RegexCorrelationReplacement;
import com.blazemeter.jmeter.correlation.siebel.SiebelContext;
import com.blazemeter.jmeter.correlation.siebel.SiebelRowCorrelationExtractor;
@@ -25,6 +26,8 @@ public class CorrelationComponentsRegistryTest {
new RegexCorrelationExtractor<>();
private static final RegexCorrelationReplacement> REGEX_REPLACEMENT =
new RegexCorrelationReplacement<>();
+ private static final JsonCorrelationReplacement> JSON_REPLACEMENT =
+ new JsonCorrelationReplacement<>();
private static final SiebelRowCorrelationExtractor SIEBEL_EXTRACTOR_EXTENSION =
new SiebelRowCorrelationExtractor();
private static final SiebelRowIdCorrelationReplacement SIEBEL_REPLACEMENT_EXTENSION =
@@ -50,7 +53,7 @@ public void shouldNotAddReplacementWhenAddComponentWithRepeatedComponent() {
.buildActiveReplacementRulePart();
registry.updateActiveComponents(REGEX_EXTRACTOR.getClass().getCanonicalName(),
new ArrayList<>());
- assertThat(initialReplacements).isEqualTo((registry.buildActiveReplacementRulePart()));
+ assertThat(initialReplacements.toString()).isEqualTo((registry.buildActiveReplacementRulePart()).toString());
}
@Test
@@ -157,7 +160,6 @@ public void shouldGetDefaultAllowedExtractorsWhenGetAllowedExtractors() {
assertThat(activeExtractor).isEqualTo(Arrays.asList(CorrelationComponentsRegistry.NONE_EXTRACTOR,
new RegexCorrelationExtractor<>(),
new JsonCorrelationExtractor<>(),
- new XmlCorrelationExtractor<>(),
CorrelationComponentsRegistry.MORE_EXTRACTOR));
}
@@ -165,9 +167,9 @@ public void shouldGetDefaultAllowedExtractorsWhenGetAllowedExtractors() {
public void shouldGetDefaultAllowedReplacementsWhenGetAllowedReplacements() {
List> expectedDefaultAllowedReplacements = Arrays
.asList(CorrelationComponentsRegistry.NONE_REPLACEMENT, REGEX_REPLACEMENT,
- CorrelationComponentsRegistry.MORE_REPLACEMENT);
- assertThat(expectedDefaultAllowedReplacements).isEqualTo(
- registry.buildActiveReplacementRulePart());
+ JSON_REPLACEMENT, CorrelationComponentsRegistry.MORE_REPLACEMENT);
+ assertThat(expectedDefaultAllowedReplacements.toString()).isEqualTo(
+ registry.buildActiveReplacementRulePart().toString());
}
@Test
diff --git a/src/test/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationHistoryFrameIT.java b/src/test/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationHistoryFrameIT.java
index 7973e5d..c9bf0b7 100644
--- a/src/test/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationHistoryFrameIT.java
+++ b/src/test/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationHistoryFrameIT.java
@@ -96,5 +96,27 @@ public void shouldShowSuccessMessageWhenZipButtonIsClicked() {
frame.button("zipSaveButton").click();
frame.optionPane().requireMessage(Pattern.compile("History zipped at: \n.*"));
}
+ @Test
+ public void shouldCreateCheckpointWhenButtonIsClicked() {
+ String testPlanFilepath = "Recording" + File.separator+ "testPlanFilepath";
+ CorrelationHistory.setSaveCurrentTestPlan(() -> testPlanFilepath);
+ String recordingFilepath = "Recording" + File.separator+ "recordingFilepath";
+ CorrelationHistory.setRecordingFilePathSupplier(() -> recordingFilepath);
+
+ frame.button("createIterationButton").click();
+
+ assertEquals(4, frame.table("historyTable").rowCount());
+ }
+ @Test
+ public void shouldEditHistoryIterationValues() {
+ frame.table("historyTable").cell(row(0).column(2)).doubleClick()
+ .enterValue("new value");
+ frame.table("historyTable").cell(row(0).column(3)).doubleClick()
+ .enterValue("new value");
+
+ assertEquals("new value", frame.table("historyTable").valueAt(row(0).column(2)));
+ assertEquals("new value", frame.table("historyTable").valueAt(row(0).column(3)));
+ }
+
}
diff --git a/src/test/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationWizardIT.java b/src/test/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationWizardIT.java
index ecef8ad..9885a1c 100644
--- a/src/test/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationWizardIT.java
+++ b/src/test/java/com/blazemeter/jmeter/correlation/gui/automatic/CorrelationWizardIT.java
@@ -7,6 +7,7 @@
import com.blazemeter.jmeter.correlation.core.templates.Repository;
import java.awt.Container;
+import java.io.File;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import org.assertj.core.api.JUnitSoftAssertions;
@@ -29,7 +30,7 @@ public void setUp() throws Exception {
wizard = new CorrelationWizard();
wizard.setVersionsSupplier(() ->
generateTemplatesWithVersions(Arrays.asList("id1", "id2", "id3"), "repId1"));
- CorrelationHistory.setSaveCurrentTestPlan(() -> "test");
+ CorrelationHistory.setSaveCurrentTestPlan(() -> "Recording"+ File.separator+"test");
CorrelationHistory history = new CorrelationHistory();
wizard.setHistory(history);
wizard.setRepositoriesSupplier(CorrelationWizardIT::getMockedRepository);
diff --git a/src/test/resources/RegexCorrelationExtractorDescription.html b/src/test/resources/RegexCorrelationExtractorDescription.html
index bd5d994..657c5f8 100644
--- a/src/test/resources/RegexCorrelationExtractorDescription.html
+++ b/src/test/resources/RegexCorrelationExtractorDescription.html
@@ -6,4 +6,4 @@
The Group Number: determines the group from where the information will be taken, based on the RegEx. Default value: 1
The Target: determines where the RegEx will be applied. Default value: Response's Body
-For more information about Extractors and how to use them, check the Documentation at List Correlation Extractors
+For more information about Extractors and how to use them, check the Documentation at List Correlation Extractors
diff --git a/src/test/resources/RegexCorrelationExtractorFullDisplay.html b/src/test/resources/RegexCorrelationExtractorFullDisplay.html
index 26f92b7..d297342 100644
--- a/src/test/resources/RegexCorrelationExtractorFullDisplay.html
+++ b/src/test/resources/RegexCorrelationExtractorFullDisplay.html
@@ -14,7 +14,7 @@
The Target: determines where the RegEx will be applied. Default value: Response's Body
For more information about Extractors and how to use them, check the Documentation at List
+ href="https://blazemeter.github.io/CorrelationRecorder/guide/correlation-rules.html#list-of-correlation-extractors">List
Correlation Extractors