refactor: migrate :src:components Groovy tests to Kotlin
diff --git a/src/components/build.gradle.kts b/src/components/build.gradle.kts
index 7595fb9..1e5052a 100644
--- a/src/components/build.gradle.kts
+++ b/src/components/build.gradle.kts
@@ -90,6 +90,7 @@
testImplementation(testFixtures(projects.src.testkitWiremock))
testFixturesImplementation(testFixtures(projects.src.core))
testFixturesImplementation("junit:junit")
+ testImplementation("io.mockk:mockk")
testFixturesImplementation("org.spockframework:spock-core")
}
diff --git a/src/components/src/main/java/org/apache/jmeter/assertions/MD5HexAssertion.java b/src/components/src/main/java/org/apache/jmeter/assertions/MD5HexAssertion.java
index ae350c8..c8cc943 100644
--- a/src/components/src/main/java/org/apache/jmeter/assertions/MD5HexAssertion.java
+++ b/src/components/src/main/java/org/apache/jmeter/assertions/MD5HexAssertion.java
@@ -27,6 +27,7 @@
import org.apache.jmeter.testelement.property.StringProperty;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.util.JOrphanUtils;
+import org.jetbrains.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -90,7 +91,8 @@
return getPropertyAsString(MD5HexAssertion.MD5HEX_KEY);
}
- private static String md5Hex(byte[] bytes) {
+ @VisibleForTesting
+ static String md5Hex(byte[] bytes) {
byte[] md5Result = {};
try {
diff --git a/src/components/src/main/java/org/apache/jmeter/extractor/BoundaryExtractor.java b/src/components/src/main/java/org/apache/jmeter/extractor/BoundaryExtractor.java
index 1438293..ac64abe 100644
--- a/src/components/src/main/java/org/apache/jmeter/extractor/BoundaryExtractor.java
+++ b/src/components/src/main/java/org/apache/jmeter/extractor/BoundaryExtractor.java
@@ -34,6 +34,7 @@
import org.apache.jmeter.threads.JMeterVariables;
import org.apache.jmeter.util.Document;
import org.apache.jmeter.util.JMeterUtils;
+import org.jetbrains.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -236,7 +237,8 @@
return result.getResponseDataAsString(); // Bug 36898
}
- private static List<String> extract(
+ @VisibleForTesting
+ static List<String> extract(
String leftBoundary, String rightBoundary, int matchNumber, Stream<String> previousResults) {
boolean allItems = matchNumber <= 0;
return previousResults
@@ -257,7 +259,8 @@
* @param inputString text in which to look for the fragments
* @return list where the found text fragments will be placed
*/
- private static List<String> extract(String leftBoundary, String rightBoundary, int matchNumber, String inputString) {
+ @VisibleForTesting
+ static List<String> extract(String leftBoundary, String rightBoundary, int matchNumber, String inputString) {
if (StringUtils.isBlank(inputString)) {
return Collections.emptyList();
}
diff --git a/src/components/src/main/java/org/apache/jmeter/visualizers/backend/graphite/PickleGraphiteMetricsSender.java b/src/components/src/main/java/org/apache/jmeter/visualizers/backend/graphite/PickleGraphiteMetricsSender.java
index 0f6ae38..99267ae 100644
--- a/src/components/src/main/java/org/apache/jmeter/visualizers/backend/graphite/PickleGraphiteMetricsSender.java
+++ b/src/components/src/main/java/org/apache/jmeter/visualizers/backend/graphite/PickleGraphiteMetricsSender.java
@@ -24,6 +24,7 @@
import java.util.List;
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
+import org.jetbrains.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -86,6 +87,11 @@
this.prefix = prefix;
}
+ @VisibleForTesting
+ List<MetricTuple> getMetrics() {
+ return metrics;
+ }
+
/*
* (non-Javadoc)
*
@@ -160,7 +166,8 @@
}
/** See: https://graphite.readthedocs.io/en/1.0.0/feeding-carbon.html */
- private static String convertMetricsToPickleFormat(List<MetricTuple> metrics) {
+ @VisibleForTesting
+ static String convertMetricsToPickleFormat(List<MetricTuple> metrics) {
StringBuilder pickled = new StringBuilder(metrics.size() * 75);
pickled.append(MARK).append(LIST);
diff --git a/src/components/src/main/java/org/apache/jmeter/visualizers/backend/graphite/TextGraphiteMetricsSender.java b/src/components/src/main/java/org/apache/jmeter/visualizers/backend/graphite/TextGraphiteMetricsSender.java
index e24bb68..a653fe5 100644
--- a/src/components/src/main/java/org/apache/jmeter/visualizers/backend/graphite/TextGraphiteMetricsSender.java
+++ b/src/components/src/main/java/org/apache/jmeter/visualizers/backend/graphite/TextGraphiteMetricsSender.java
@@ -23,6 +23,7 @@
import java.util.List;
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
+import org.jetbrains.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -70,6 +71,11 @@
this.prefix = prefix;
}
+ @VisibleForTesting
+ List<MetricTuple> getMetrics() {
+ return metrics;
+ }
+
/* (non-Javadoc)
* @see org.apache.jmeter.visualizers.backend.graphite.GraphiteMetricsSender#addMetric(long, java.lang.String, java.lang.String, java.lang.String)
*/
diff --git a/src/components/src/main/java/org/apache/jmeter/visualizers/backend/influxdb/InfluxDBRawBackendListenerClient.java b/src/components/src/main/java/org/apache/jmeter/visualizers/backend/influxdb/InfluxDBRawBackendListenerClient.java
index 57be7a8..2d18049 100644
--- a/src/components/src/main/java/org/apache/jmeter/visualizers/backend/influxdb/InfluxDBRawBackendListenerClient.java
+++ b/src/components/src/main/java/org/apache/jmeter/visualizers/backend/influxdb/InfluxDBRawBackendListenerClient.java
@@ -26,6 +26,7 @@
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.visualizers.backend.BackendListenerClient;
import org.apache.jmeter.visualizers.backend.BackendListenerContext;
+import org.jetbrains.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -76,6 +77,16 @@
influxDBMetricsManager = sender;
}
+ @VisibleForTesting
+ String getMeasurement() {
+ return measurement;
+ }
+
+ @VisibleForTesting
+ InfluxdbMetricsSender getInfluxDBMetricsManager() {
+ return influxDBMetricsManager;
+ }
+
@Override
public void setupTest(BackendListenerContext context) throws Exception {
initInfluxDBMetricsManager(context);
@@ -119,7 +130,8 @@
influxDBMetricsManager.addMetric(measurement, tags, fields, timestamp);
}
- private static String createTags(SampleResult sampleResult) {
+ @VisibleForTesting
+ static String createTags(SampleResult sampleResult) {
boolean isError = sampleResult.getErrorCount() != 0;
String status = isError ? TAG_KO : TAG_OK;
// remove surrounding quotes and spaces from sample label
@@ -131,7 +143,8 @@
+ ",threadName=" + threadName;
}
- private static String createFields(SampleResult sampleResult) {
+ @VisibleForTesting
+ static String createFields(SampleResult sampleResult) {
long duration = sampleResult.getTime();
long latency = sampleResult.getLatency();
long connectTime = sampleResult.getConnectTime();
diff --git a/src/components/src/test/kotlin/org/apache/jmeter/assertions/CompareAssertionTest.kt b/src/components/src/test/kotlin/org/apache/jmeter/assertions/CompareAssertionTest.kt
index 333970c..c33bac5 100644
--- a/src/components/src/test/kotlin/org/apache/jmeter/assertions/CompareAssertionTest.kt
+++ b/src/components/src/test/kotlin/org/apache/jmeter/assertions/CompareAssertionTest.kt
@@ -17,60 +17,65 @@
package org.apache.jmeter.assertions
-import java.nio.charset.StandardCharsets
-
-import org.apache.commons.lang3.StringUtils
import org.apache.jmeter.samplers.SampleResult
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.MethodSource
-import spock.lang.Specification
-import spock.lang.Unroll
+class CompareAssertionTest {
+ val sut = CompareAssertion()
-@Unroll
-class CompareAssertionSpec extends Specification {
+ data class AssertCase(
+ val compareContent: Boolean,
+ val compareTime: Long,
+ val content: String,
+ val elapsed: Long,
+ val skip: String?,
+ val isFailure: Boolean
+ )
- def sut = new CompareAssertion()
-
- def "Result is simple assertionResult when only one response is given"() {
- given:
- sut.setName("myName")
- sut.iterationStart(null)
- when:
- def assertionResult = sut.getResult(null)
- then:
- assertionResult.getName() == "myName"
- }
-
- def "content '#content' with compareContent==#compareContent, skip=#skip, elapsed=#elapsed and compareTime==#compareTime"() {
- given:
- sut.setName("myName")
- def firstResponse = simpleResult("OK", 100)
- sut.iterationStart(null)
- sut.getResult(firstResponse)
- sut.setCompareContent(compareContent)
- sut.setCompareTime(compareTime)
- if (skip != null) {
- def subst = new SubstitutionElement()
- subst.setRegex(skip)
- sut.setStringsToSkip(Arrays.asList(subst))
+ companion object {
+ fun simpleResult(data: String, elapsed: Long) =
+ SampleResult(0, elapsed).apply {
+ setResponseData(data, Charsets.UTF_8.name())
+ sampleEnd()
}
- when:
- def assertionResult = sut.getResult(simpleResult(content, elapsed))
- then:
- assertionResult.isFailure() == isFailure
- where:
- compareContent | compareTime | content | elapsed | skip | isFailure
- true | -1 | "OK" | 100 | null | false
- true | -1 | "different" | 100 | null | true
- false | -1 | "different" | 100 | null | false
- false | -1 | "different OK" | 100 | "d\\w+\\s" | false
- true | 10 | "OK" | 120 | null | true
- true | 10 | "OK" | 110 | null | false
+
+ @JvmStatic
+ fun assertCases() = listOf(
+ AssertCase(true, -1, "OK", 100, null, false),
+ AssertCase(true, -1, "different", 100, null, true),
+ AssertCase(false, -1, "different", 100, null, false),
+ AssertCase(false, -1, "different OK", 100, "d\\w+\\s", false),
+ AssertCase(true, 10, "OK", 120, null, true),
+ AssertCase(true, 10, "OK", 110, null, false),
+ )
}
- private SampleResult simpleResult(String data, long elapsed) {
- def result = new SampleResult(0L, elapsed)
- result.setResponseData(data, StandardCharsets.UTF_8.name())
- result.sampleEnd()
- return result
+ @Test
+ fun `Result is simple assertionResult when only one response is given`() {
+ sut.name = "myName"
+ sut.iterationStart(null)
+ val assertionResult = sut.getResult(null)
+ assertEquals("myName", assertionResult.name)
+ }
+
+ @ParameterizedTest
+ @MethodSource("assertCases")
+ fun isFailure(case: AssertCase) {
+ sut.name = "myName"
+ val firstResponse = simpleResult("OK", 100)
+ sut.iterationStart(null)
+ sut.getResult(firstResponse)
+ sut.isCompareContent = case.compareContent
+ sut.compareTime = case.compareTime
+ case.skip?.let {
+ val subst = SubstitutionElement()
+ subst.regex = it
+ sut.stringsToSkip = listOf(subst)
+ }
+ val assertionResult = sut.getResult(simpleResult(case.content, case.elapsed))
+ assertEquals(case.isFailure, assertionResult.isFailure)
}
}
diff --git a/src/components/src/test/kotlin/org/apache/jmeter/assertions/MD5HexAssertionTest.kt b/src/components/src/test/kotlin/org/apache/jmeter/assertions/MD5HexAssertionTest.kt
index 4923af6..56740ce 100644
--- a/src/components/src/test/kotlin/org/apache/jmeter/assertions/MD5HexAssertionTest.kt
+++ b/src/components/src/test/kotlin/org/apache/jmeter/assertions/MD5HexAssertionTest.kt
@@ -17,65 +17,64 @@
package org.apache.jmeter.assertions
-import java.nio.charset.StandardCharsets
-
-import org.apache.commons.lang3.StringUtils
import org.apache.jmeter.samplers.SampleResult
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertFalse
+import org.junit.jupiter.api.Assertions.assertNull
+import org.junit.jupiter.api.Assertions.assertTrue
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.MethodSource
-import spock.lang.Specification
-import spock.lang.Unroll
+class MD5HexAssertionTest {
+ val sut = MD5HexAssertion()
-@Unroll
-class MD5HexAssertionSpec extends Specification {
+ data class MD5HexAssertionCase(
+ val sampleData: String,
+ val allowedHex: String? = null,
+ val success: Boolean,
+ )
- def sut = new MD5HexAssertion()
-
- def "unset allowable hash with empty response fails"() {
- when:
- def result = sut.getResult(sampleResult(""))
- then:
- result.isFailure()
- StringUtils.isNotBlank(result.getFailureMessage())
+ companion object {
+ @JvmStatic
+ fun md5Cases() = listOf(
+ // success
+ MD5HexAssertionCase("anything", "f0e166dc34d14d6c228ffac576c9a43c", true),
+ MD5HexAssertionCase("anything", "F0e166Dc34D14d6c228ffac576c9a43c", true),
+ // failure
+ MD5HexAssertionCase("", "", false),
+ MD5HexAssertionCase("anything", "anything", false),
+ MD5HexAssertionCase("anything", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", false),
+ )
}
- def "incorrect hash #allowedHex causes result failure"() {
- given:
- sut.setAllowedMD5Hex(allowedHex)
- when:
- def result = sut.getResult(sampleResult("anything"))
- then:
- result.isFailure()
- StringUtils.isNotBlank(result.getFailureMessage())
- where:
- allowedHex << ["", "anything", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
+ @ParameterizedTest
+ @MethodSource("md5Cases")
+ fun md5HexAssertion(case: MD5HexAssertionCase) {
+ sut.allowedMD5Hex = case.allowedHex
+ val result = sut.getResult(sampleResult(case.sampleData))
+
+ if (case.success) {
+ assertFalse(result.isFailure, ".isFailure()")
+ assertFalse(result.isError, ".isError()")
+ assertNull(result.failureMessage, "result.failureMessage")
+ } else {
+ assertTrue(result.isFailure, ".isFailure()")
+ assertTrue(result.failureMessage.isNotBlank(), "result.failureMessage should not be blank for failure case")
+ }
}
- def "example MD5s - '#sampleData' == '#hash'"() {
- given:
- sut.setAllowedMD5Hex(hash)
- when:
- def result = sut.getResult(sampleResult(sampleData))
- then:
- !result.isFailure()
- !result.isError()
- result.getFailureMessage() == null
- where:
- sampleData | hash
- "anything" | "f0e166dc34d14d6c228ffac576c9a43c"
- "anything" | "F0e166Dc34D14d6c228ffac576c9a43c"
- }
-
- def "empty array has MD5 hash of D41D8CD98F00B204E9800998ECF8427E"() {
- given:
- def emptyByteArray = [] as byte[]
- expect:
- MD5HexAssertion.md5Hex(emptyByteArray)
- .toUpperCase(Locale.ENGLISH) == "D41D8CD98F00B204E9800998ECF8427E"
- }
-
- def sampleResult(String data) {
- SampleResult response = new SampleResult()
- response.setResponseData(data.getBytes(StandardCharsets.UTF_8))
- return response
+ @Test
+ fun `empty array has MD5 hash of D41D8CD98F00B204E9800998ECF8427E`() {
+ val emptyByteArray = byteArrayOf()
+ assertEquals(
+ "D41D8CD98F00B204E9800998ECF8427E",
+ MD5HexAssertion.md5Hex(emptyByteArray).uppercase()
+ )
}
}
+
+private fun sampleResult(data: String) =
+ SampleResult().apply {
+ responseData = data.toByteArray()
+ }
diff --git a/src/components/src/test/kotlin/org/apache/jmeter/control/RandomOrderControllerTest.kt b/src/components/src/test/kotlin/org/apache/jmeter/control/RandomOrderControllerTest.kt
index a8db72c..c31efcd 100644
--- a/src/components/src/test/kotlin/org/apache/jmeter/control/RandomOrderControllerTest.kt
+++ b/src/components/src/test/kotlin/org/apache/jmeter/control/RandomOrderControllerTest.kt
@@ -17,80 +17,80 @@
package org.apache.jmeter.control
+import io.mockk.mockk
import org.apache.jmeter.junit.stubs.TestSampler
import org.apache.jmeter.testelement.TestElement
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertNotEquals
+import org.junit.jupiter.api.Assertions.assertNull
+import org.junit.jupiter.api.Assertions.assertTrue
+import org.junit.jupiter.api.Test
-import spock.lang.Specification
+class RandomOrderControllerTest {
+ val sut = RandomOrderController()
-class RandomOrderControllerSpec extends Specification {
-
- def sut = new RandomOrderController()
-
- def "next() on an empty controller returns null"() {
- given:
- sut.initialize()
- when:
- def nextSampler = sut.next()
- then:
- nextSampler == null
+ @Test
+ fun `next() on an empty controller returns null`() {
+ sut.initialize()
+ val nextSampler = sut.next()
+ assertNull(nextSampler)
}
- def "next() returns only provided sampler"() {
- given:
- def sampler = new TestSampler("the one and only")
- sut.addTestElement(sampler)
- sut.initialize()
- when:
- def nextSampler = sut.next()
- def nextSamplerAfterEnd = sut.next()
- then:
- nextSampler == sampler
- nextSamplerAfterEnd == null
+ @Test
+ fun `next() returns only provided sampler`() {
+ val sampler = TestSampler("the one and only")
+ sut.addTestElement(sampler)
+ sut.initialize()
+
+ val nextSampler = sut.next()
+ val nextSamplerAfterEnd = sut.next()
+
+ assertEquals(sampler, nextSampler, "there's only one sampler, so it should be returned from .next()")
+ assertNull(nextSamplerAfterEnd, "nextSamplerAfterEnd")
}
- def "next() returns exactly all added elements in random order"() {
- given:
- def samplerNames = (1..50).collect { it.toString() }
- samplerNames.each {
- sut.addTestElement(new TestSampler(it))
- }
- sut.initialize()
- when:
- def elements = getAllTestElements(sut)
- then: "the same elements are returned but in a different order"
- def elementNames = elements.collect { it.getName() }
- elementNames.toSet() == samplerNames.toSet() // same elements
- elementNames != samplerNames // not the same order
+ @Test
+ fun `next() returns exactly all added elements in random order`() {
+ val samplerNames = (1..50).map { it.toString() }
+ samplerNames.forEach {
+ sut.addTestElement(TestSampler(it))
+ }
+ sut.initialize()
+ val elements = sut.getAllTestElements()
+
+ // then: "the same elements are returned but in a different order"
+ // val
+ val elementNames = elements.map { it.name }
+ assertEquals(samplerNames.toSet(), elementNames.toSet(), "controller should return the same elements")
+ assertNotEquals(samplerNames, elementNames, "The order of elements should be randomized")
}
- def "next() is null if isDone() is true"() {
- given:
- sut.addTestElement(Mock(TestElement))
- sut.initialize()
- sut.setDone(true)
- when:
- def nextSampler = sut.next()
- then:
- sut.isDone()
- nextSampler == null
+ @Test
+ fun `next() is null if isDone() is true`() {
+ sut.addTestElement(mockk<TestElement>())
+ sut.initialize()
+ sut.isDone = true
+
+ val nextSampler = sut.next()
+ assertTrue(sut.isDone, ".isDone()")
+ assertNull(nextSampler, "nextSampler")
}
/**
* Builds and returns a list by 'iterating' through the
- * {@link GenericController}, using {@link GenericController#next()},
- * placing each item in a list until <code>null</code> is encountered.
+ * [GenericController], using [GenericController.next()],
+ * placing each item in a list until `null` is encountered.
*
- * @param controller the {@link GenericController} to 'iterate' though
+ * @param controller the [GenericController] to 'iterate' though
* @return a list of all items (in order) returned from next()
* method, excluding null
*/
- def getAllTestElements(GenericController controller) {
- def sample
- def samplers = []
- while ((sample = controller.next()) != null) {
- samplers.add(sample)
+ fun GenericController.getAllTestElements() =
+ buildList {
+ while (true) {
+ val sampler = next() ?: break
+ add(sampler)
+ }
}
- return samplers
- }
}
diff --git a/src/components/src/test/kotlin/org/apache/jmeter/control/RunTimeTest.kt b/src/components/src/test/kotlin/org/apache/jmeter/control/RunTimeTest.kt
index 52b6ee2..679fa85 100644
--- a/src/components/src/test/kotlin/org/apache/jmeter/control/RunTimeTest.kt
+++ b/src/components/src/test/kotlin/org/apache/jmeter/control/RunTimeTest.kt
@@ -17,104 +17,117 @@
package org.apache.jmeter.control
+import io.mockk.every
+import io.mockk.mockk
import org.apache.jmeter.junit.stubs.TestSampler
import org.apache.jmeter.samplers.Sampler
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertNull
+import org.junit.jupiter.api.Disabled
+import org.junit.jupiter.api.Test
+import kotlin.math.ceil
+import kotlin.system.measureTimeMillis
-import spock.lang.Ignore
-import spock.lang.Specification
+class RunTimeTest {
+ val sut = RunTime()
-class RunTimeSpec extends Specification {
+ @Test
+ @Disabled("It fails too often due to timing issues")
+ fun `RunTime stops within a tolerance after specified runtime`() {
+ sut.runtime = 1
+ val runTimeMillis = 1000L
+ val expectedLoops = 5
+ val tolerance = ceil(0.1 * expectedLoops)
+ val samplerWaitTime: Long = runTimeMillis / expectedLoops
+ val samp1 = TestSampler("Sample 1", samplerWaitTime)
+ val samp2 = TestSampler("Sample 2", samplerWaitTime)
- def sut = new RunTime()
+ val sampler1Loops = 2
+ val loop1 = LoopController().apply {
+ loops = sampler1Loops
+ setContinueForever(false)
+ addTestElement(samp1)
+ }
- @Ignore("It fails too often due to timing issues")
- def "RunTime stops within a tolerance after specified runtime"() {
- given:
- sut.setRuntime(1)
+ val loop2 = LoopController().apply {
+ loops = expectedLoops * 2
+ setContinueForever(false)
+ addTestElement(samp2)
+ }
- def runTimeMillis = 1000
- def expectedLoops = 5
- def tolerance = Math.ceil(0.1f * expectedLoops)
- int samplerWaitTime = runTimeMillis / expectedLoops
- TestSampler samp1 = new TestSampler("Sample 1", samplerWaitTime)
- TestSampler samp2 = new TestSampler("Sample 2", samplerWaitTime)
+ sut.addTestElement(loop1)
+ sut.addTestElement(loop2)
+ sut.isRunningVersion = true
+ loop1.isRunningVersion = true
+ loop2.isRunningVersion = true
+ sut.initialize()
- def sampler1Loops = 2
- LoopController loop1 = new LoopController()
- loop1.setLoops(sampler1Loops)
- loop1.setContinueForever(false)
- loop1.addTestElement(samp1)
-
- LoopController loop2 = new LoopController()
- loop2.setLoops(expectedLoops * 2)
- loop2.setContinueForever(false)
- loop2.addTestElement(samp2)
-
- sut.addTestElement(loop1)
- sut.addTestElement(loop2)
- sut.setRunningVersion(true)
- loop1.setRunningVersion(true)
- loop2.setRunningVersion(true)
- sut.initialize()
- when:
- def sampler
- int loopCount = 0
- long now = System.currentTimeMillis()
- while ((sampler = sut.next()) != null) {
+ // when:
+ var loopCount = 0
+ val elapsed = measureTimeMillis {
+ while (true) {
+ val sampler = sut.next() ?: break
loopCount++
sampler.sample(null)
}
- long elapsed = System.currentTimeMillis() - now
- then:
- sut.getIterCount() == 1
- loopCount >= expectedLoops - tolerance
- loopCount <= expectedLoops + tolerance
- elapsed >= runTimeMillis - (tolerance * samplerWaitTime)
- elapsed <= runTimeMillis + (tolerance * samplerWaitTime)
- samp1.getSamples() == sampler1Loops
- samp2.getSamples() >= expectedLoops - sampler1Loops - tolerance
- samp2.getSamples() <= expectedLoops - sampler1Loops + tolerance
+ }
+ // then:
+ assertEquals(1, sut.iterCount, ".iterCount")
+ assertEquals(expectedLoops.toDouble(), loopCount.toDouble(), tolerance, "loopCount")
+ assertEquals(elapsed.toDouble(), runTimeMillis.toDouble(), tolerance * samplerWaitTime, "elapsedMillis")
+ assertEquals(sampler1Loops, samp1.samples, "samp1.samples")
+ assertEquals(
+ (expectedLoops - sampler1Loops).toDouble(),
+ samp2.samples.toDouble(),
+ tolerance,
+ "samp2.samples should be expectedLoops - sampler1Loops"
+ )
}
- def "Immediately returns null when runtime is set to 0"() {
- given:
- sut.setRuntime(0)
- sut.addTestElement(Mock(Sampler))
- when:
- def sampler = sut.next()
- then:
- sampler == null
+ @Test
+ fun `Immediately returns null when runtime is set to 0`() {
+ sut.runtime = 0
+ sut.addTestElement(mockk<Sampler>())
+
+ assertNull(sut.next(), ".next()")
}
- def "Immediately returns null if only Controllers are present"() {
- given:
- sut.setRuntime(10)
- sut.addTestElement(Mock(Controller))
- sut.addTestElement(Mock(Controller))
- when:
- def sampler = sut.next()
- then:
- sampler == null
- }
- def "within time limit samplers are returned until empty"() {
- given:
- def mockSampler = Mock(Sampler)
- sut.setRuntime(10)
- sut.addTestElement(mockSampler)
- sut.addTestElement(mockSampler)
- when:
- def samplers = [sut.next(), sut.next(), sut.next()]
- then:
- samplers == [mockSampler, mockSampler, null]
+ @Test
+ fun `Immediately returns null if only Controllers are present`() {
+ sut.runtime = 10
+ sut.addTestElement(
+ mockk<Controller> {
+ every { next() } returns null
+ every { isDone } returns true
+ }
+ )
+ sut.addTestElement(
+ mockk<Controller> {
+ every { next() } returns null
+ every { isDone } returns true
+ }
+ )
+
+ assertNull(sut.next(), ".next()")
}
- def "RunTime immediately returns null when there are no test elements"() {
- given:
- sut.setRuntime(10)
- when:
- def sampler = sut.next()
- then:
- sampler == null
+ @Test
+ fun `within time limit samplers are returned until empty`() {
+ val mockSampler = mockk<Sampler>()
+ sut.runtime = 10
+ sut.addTestElement(mockSampler)
+ sut.addTestElement(mockSampler)
+
+ assertEquals(
+ listOf(mockSampler, mockSampler, null),
+ listOf(sut.next(), sut.next(), sut.next()),
+ "there are two elements, so first two .next() should return them, then null"
+ )
}
+ @Test
+ fun `RunTime immediately returns null when there are no test elements`() {
+ sut.runtime = 10
+ assertNull(sut.next(), ".next()")
+ }
}
diff --git a/src/components/src/test/kotlin/org/apache/jmeter/control/ThroughputControllerTest.kt b/src/components/src/test/kotlin/org/apache/jmeter/control/ThroughputControllerTest.kt
index 2f9c918..84112a4 100644
--- a/src/components/src/test/kotlin/org/apache/jmeter/control/ThroughputControllerTest.kt
+++ b/src/components/src/test/kotlin/org/apache/jmeter/control/ThroughputControllerTest.kt
@@ -18,66 +18,70 @@
package org.apache.jmeter.control
import org.apache.jmeter.junit.stubs.TestSampler
+import org.apache.jmeter.threads.TestCompiler
+import org.apache.jmeter.treebuilder.dsl.testTree
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertNull
+import org.junit.jupiter.api.Assertions.assertTrue
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
-import spock.lang.Specification
+class ThroughputControllerTest {
+ val sut = ThroughputController()
-class ThroughputControllerSpec extends Specification {
-
- def sut = new ThroughputController()
-
- def setup() {
- sut.addTestElement(new TestSampler("one"))
- sut.addTestElement(new TestSampler("two"))
+ @BeforeEach
+ fun setup() {
+ sut.addTestElement(TestSampler("one"))
+ sut.addTestElement(TestSampler("two"))
}
- def "new TC isDone is true"() {
- given:
- def newTC = new ThroughputController()
- expect:
- newTC.isDone()
+ @Test
+ fun `TC isDone is true`() {
+ val newTC = ThroughputController()
+ assertTrue(newTC.isDone, ".isDone")
}
- def "2 maxThroughput runs samplers inside the TC only twice"() {
- given:
- sut.setStyle(ThroughputController.BYNUMBER)
- sut.setMaxThroughput(2)
+ @Test
+ fun `2 maxThroughput runs samplers inside the TC only twice`() {
+ sut.style = ThroughputController.BYNUMBER
+ sut.setMaxThroughput(2)
- def expectedNames =
- ["zero", "one", "two", "three",
- "zero", "one", "two", "three",
- "zero", "three",
- "zero", "three",
- "zero", "three",]
+ val expectedNames =
+ listOf(
+ "zero", "one", "two", "three",
+ "zero", "one", "two", "three",
+ "zero", "three",
+ "zero", "three",
+ "zero", "three",
+ )
- def loop = createLoopController(5)
- when:
- def actualNames = expectedNames.collect({
- loop.next().getName()
- })
- then:
- loop.next() == null
- actualNames == expectedNames
- sut.isDone()
- sut.testEnded()
+ val loop = createLoopController(5)
+
+ val actualNames = expectedNames.map {
+ loop.next()?.name
+ }
+
+ assertEquals(expectedNames, actualNames, "actualNames")
+ assertNull(loop.next(), "loop.next()")
+ assertTrue(sut.isDone, ".isDone")
+ sut.testEnded()
}
- def "0 maxThroughput does not run any samplers inside the TC"() {
- given:
- sut.setStyle(ThroughputController.BYNUMBER)
- sut.setMaxThroughput(0)
+ @Test
+ fun `0 maxThroughput does not run any samplers inside the TC`() {
+ sut.style = ThroughputController.BYNUMBER
+ sut.setMaxThroughput(0)
+ val loops = 3
+ val loop = createLoopController(loops)
+ val expectedNames = (1..loops).flatMap { listOf("zero", "three") }
- def loops = 3
- def loop = createLoopController(loops)
+ val actualNames = expectedNames.map {
+ loop.next().name
+ }
- def expectedNames = ["zero", "three"] * loops
- when:
- def actualNames = expectedNames.collect({
- loop.next().getName()
- })
- then:
- loop.next() == null
- actualNames == expectedNames
- sut.testEnded()
+ assertEquals(expectedNames, actualNames, "actualNames")
+ assertNull(loop.next(), "loop.next()")
+ sut.testEnded()
}
/**
@@ -88,25 +92,24 @@
* - sampler two
* </pre>
*/
- def "0 maxThroughput does not run any sampler inside the TC and does not cause StackOverFlowError"() {
- given:
- sut.setStyle(ThroughputController.BYNUMBER)
- sut.setMaxThroughput(0)
+ @Test
+ fun `0 maxThroughput does not run any sampler inside the TC and does not cause StackOverFlowError`() {
+ sut.style = ThroughputController.BYNUMBER
+ sut.setMaxThroughput(0)
- LoopController innerLoop = new LoopController()
- innerLoop.setLoops(10000)
- innerLoop.addTestElement(sut)
- innerLoop.addIterationListener(sut)
- innerLoop.initialize()
- innerLoop.setRunningVersion(true)
- sut.testStarted()
- sut.setRunningVersion(true)
+ val innerLoop = LoopController().apply {
+ setLoops(10000)
+ addTestElement(sut)
+ addIterationListener(sut)
+ initialize()
+ isRunningVersion = true
+ }
+ sut.testStarted()
+ sut.isRunningVersion = true
- when:
- innerLoop.next() == null
- innerLoop.next() == null
- then:
- sut.testEnded()
+ assertNull(innerLoop.next(), "innerLoop.next()")
+ assertNull(innerLoop.next(), "innerLoop.next(), second call")
+ sut.testEnded()
}
/**
@@ -117,98 +120,93 @@
* - sampler two
* </pre>
*/
- def "0.0 percentThroughput does not run any sampler inside the TC and does not cause StackOverFlowError"() {
- given:
- sut.setStyle(ThroughputController.BYPERCENT)
- sut.setPercentThroughput("0.0")
+ @Test
+ fun `0 percentThroughput does not run any sampler inside the TC and does not cause StackOverFlowError`() {
+ sut.style = ThroughputController.BYPERCENT
+ sut.percentThroughput = "0.0"
- LoopController innerLoop = new LoopController()
- innerLoop.setLoops(10000)
- innerLoop.addTestElement(sut)
- innerLoop.addIterationListener(sut)
- innerLoop.initialize()
- innerLoop.setRunningVersion(true)
- sut.testStarted()
- sut.setRunningVersion(true)
+ val innerLoop = LoopController().apply {
+ loops = 10000
+ addTestElement(sut)
+ addIterationListener(sut)
+ initialize()
+ isRunningVersion = true
+ }
+ sut.testStarted()
+ sut.isRunningVersion = true
- when:
- innerLoop.next() == null
- innerLoop.next() == null
- then:
- sut.testEnded()
+ assertNull(innerLoop.next(), "innerLoop.next()")
+ assertNull(innerLoop.next(), "innerLoop.next(), second call")
+
+ sut.testEnded()
}
- def "33.33% will run all the samplers inside the TC every 3 iterations"() {
- given:
- sut.setStyle(ThroughputController.BYPERCENT)
- sut.setPercentThroughput(33.33f)
+ @Test
+ fun `33 percentThroughput will run all the samplers inside the TC every 3 iterations`() {
+ sut.style = ThroughputController.BYPERCENT
+ sut.setPercentThroughput(33.33f)
- def loop = createLoopController(9)
- // Expected results established using the DDA algorithm - see:
- // http://www.siggraph.org/education/materials/HyperGraph/scanline/outprims/drawline.htm
- def expectedNames =
- ["zero", "three", // 0/1 vs. 1/1 -> 0 is closer to 33.33
- "zero", "one", "two", "three", // 0/2 vs. 1/2 -> 50.0 is closer to 33.33
- "zero", "three", // 1/3 vs. 2/3 -> 33.33 is closer to 33.33
- "zero", "three", // 1/4 vs. 2/4 -> 25.0 is closer to 33.33
- "zero", "one", "two", "three", // 1/5 vs. 2/5 -> 40.0 is closer to 33.33
- "zero", "three", // 2/6 vs. 3/6 -> 33.33 is closer to 33.33
- "zero", "three", // 2/7 vs. 3/7 -> 0.2857 is closer to 33.33
- "zero", "one", "two", "three", // 2/8 vs. 3/8 -> 0.375 is closer to 33.33
- "zero", "three", // ...
- ]
- when:
- def actualNames = expectedNames.collect({
- loop.next().getName()
- })
- then:
- loop.next() == null
- actualNames == expectedNames
- sut.testEnded()
+ val loop = createLoopController(9)
+ // Expected results established using the DDA algorithm - see:
+ // http://www.siggraph.org/education/materials/HyperGraph/scanline/outprims/drawline.htm
+ val expectedNames = listOf(
+ "zero", "three", // 0/1 vs. 1/1 -> 0 is closer to 33.33
+ "zero", "one", "two", "three", // 0/2 vs. 1/2 -> 50.0 is closer to 33.33
+ "zero", "three", // 1/3 vs. 2/3 -> 33.33 is closer to 33.33
+ "zero", "three", // 1/4 vs. 2/4 -> 25.0 is closer to 33.33
+ "zero", "one", "two", "three", // 1/5 vs. 2/5 -> 40.0 is closer to 33.33
+ "zero", "three", // 2/6 vs. 3/6 -> 33.33 is closer to 33.33
+ "zero", "three", // 2/7 vs. 3/7 -> 0.2857 is closer to 33.33
+ "zero", "one", "two", "three", // 2/8 vs. 3/8 -> 0.375 is closer to 33.33
+ "zero", "three", // ...
+ )
+ val actualNames = expectedNames.map {
+ loop.next()?.name
+ }
+ assertEquals(expectedNames, actualNames, "actualNames")
+ assertNull(loop.next(), "loop.next()")
+ sut.testEnded()
}
- def "0% does not run any samplers inside the TC"() {
- given:
- sut.setStyle(ThroughputController.BYPERCENT)
- sut.setPercentThroughput(0.0f)
+ @Test
+ fun `0 percentThroughput does not run any samplers inside the TC`() {
+ sut.style = ThroughputController.BYPERCENT
+ sut.setPercentThroughput(0.0f)
- def loops = 3
- def loop = createLoopController(loops)
+ val loops = 3
+ val loop = createLoopController(loops)
- def expectedNames = ["zero", "three",] * loops
- when:
- def actualNames = expectedNames.collect({
- loop.next().getName()
- })
- then:
- loop.next() == null
- actualNames == expectedNames
- sut.testEnded()
+ val expectedNames = (1..loops).flatMap { listOf("zero", "three") }
+ val actualNames = expectedNames.map {
+ loop.next().name
+ }
+
+ assertEquals(expectedNames, actualNames, "actualNames")
+ assertNull(loop.next(), "loop.next()")
+ sut.testEnded()
}
- def "100% always runs all samplers inside the TC"() {
- given:
- sut.setStyle(ThroughputController.BYPERCENT)
- sut.setPercentThroughput(100.0f)
+ @Test
+ fun `100 percentThroughput always runs all samplers inside the TC`() {
+ sut.style = ThroughputController.BYPERCENT
+ sut.setPercentThroughput(100.0f)
- def loops = 3
- def loop = createLoopController(loops)
+ val loops = 3
+ val loop = createLoopController(loops)
- def expectedNames = ["zero", "one", "two", "three",] * loops
- when:
- def actualNames = expectedNames.collect({
- loop.next().getName()
- })
- then:
- loop.next() == null
- actualNames == expectedNames
- sut.testEnded()
+ val expectedNames = (1..loops).flatMap { listOf("zero", "one", "two", "three") }
+ val actualNames = expectedNames.map {
+ loop.next()?.name
+ }
+ assertEquals(expectedNames, actualNames, "actualNames")
+ assertNull(loop.next(), "loop.next()")
+ sut.testEnded()
}
/**
* Create a LoopController, executed once, which contains an inner loop that
- * runs {@code innerLoops} times, this inner loop contains a TestSampler ("zero")
- * the {@link ThroughputController} which contains two test samplers
+ * runs [innerLoops] times, this inner loop contains a TestSampler ("zero")
+ * the [ThroughputController] which contains two test samplers
* ("one" and "two") followed by a final TestSampler ("three"):
*
* <pre>
@@ -221,25 +219,31 @@
* - sampler three
* </pre>
*
- * @param innerLoops number of times to loop the {@link ThroughputController}
- * @return the{@link LoopController}
+ * @param innerLoops number of times to loop the [ThroughputController]
+ * @return the [LoopController]
*/
- def createLoopController(int innerLoops) {
- LoopController innerLoop = new LoopController()
- innerLoop.setLoops(innerLoops)
- innerLoop.addTestElement(new TestSampler("zero"))
- innerLoop.addTestElement(sut)
- innerLoop.addIterationListener(sut)
- innerLoop.addTestElement(new TestSampler("three"))
-
- def outerLoop = new LoopController()
- outerLoop.setLoops(1)
- outerLoop.addTestElement(innerLoop)
+ private fun createLoopController(innerLoops: Int): LoopController {
sut.testStarted()
- outerLoop.setRunningVersion(true)
- sut.setRunningVersion(true)
- innerLoop.setRunningVersion(true)
+ val tree = testTree {
+ LoopController::class {
+ loops = 1
+ LoopController::class {
+ loops = innerLoops
+ +TestSampler("zero")
+ +sut
+ +TestSampler("three")
+ }
+ }
+ }
+ val compiler = TestCompiler(tree)
+ tree.traverse(compiler)
+
+ val outerLoop = tree.list().first() as LoopController
outerLoop.initialize()
- outerLoop
+
+ sut.isRunningVersion = true
+ sut.testStarted()
+
+ return outerLoop
}
}
diff --git a/src/components/src/test/kotlin/org/apache/jmeter/extractor/BoundaryExtractorTest.kt b/src/components/src/test/kotlin/org/apache/jmeter/extractor/BoundaryExtractorTest.kt
index c38944d..4bbe7a8 100644
--- a/src/components/src/test/kotlin/org/apache/jmeter/extractor/BoundaryExtractorTest.kt
+++ b/src/components/src/test/kotlin/org/apache/jmeter/extractor/BoundaryExtractorTest.kt
@@ -17,384 +17,362 @@
package org.apache.jmeter.extractor
-import java.util.stream.Stream
-
import org.apache.jmeter.samplers.SampleResult
import org.apache.jmeter.threads.JMeterContext
import org.apache.jmeter.threads.JMeterContextService
import org.apache.jmeter.threads.JMeterVariables
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertNull
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.assertThrows
+import org.junit.jupiter.api.fail
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.MethodSource
+import org.junit.jupiter.params.provider.ValueSource
+import java.util.stream.Stream
-import spock.lang.Specification
-import spock.lang.Unroll
+class BoundaryExtractorTest {
+ data class ExtractCase(val occurrences: IntRange, val matchNumber: Int, val expected: List<String>)
+ companion object {
+ const val LEFT = "LB"
+ const val RIGHT = "RB"
+ const val DEFAULT_VAL = "defaultVal"
+ const val VAR_NAME = "varName"
-@Unroll
-class BoundaryExtractorSpec extends Specification {
+ /**
+ * Creates a string with a "match" for each number in the list.
+ *
+ * @param occurrences list of numbers to be the "body" of a match
+ * @return a string with a start, end and then a left boundary + number + right boundary
+ * e.g. "... LB1RB LB2RB ..."
+ */
+ fun createInputString(occurrences: IntRange) =
+ occurrences.joinToString(" ", prefix = "start \t\r\n", postfix = "\n\t end") {
+ LEFT + it + RIGHT
+ }
- static LEFT = "LB"
- static RIGHT = "RB"
- static DEFAULT_VAL = "defaultVal"
- static VAR_NAME = "varName"
+ fun createSampleResult(responseData: String) = SampleResult().apply {
+ sampleStart()
+ setResponseData(responseData, "ISO-8859-1")
+ sampleEnd()
+ }
- def sut = new BoundaryExtractor()
+ @JvmStatic
+ fun extractCases() = listOf(
+ ExtractCase(1..1, -1, listOf("1")),
+ ExtractCase(1..1, 0, listOf("1")),
+ ExtractCase(1..1, 1, listOf("1")),
+ ExtractCase(1..1, 2, listOf()),
+ ExtractCase(1..2, -1, listOf("1", "2")),
+ ExtractCase(1..2, 1, listOf("1")),
+ ExtractCase(1..2, 2, listOf("2")),
+ ExtractCase(1..3, 3, listOf("3")),
+ )
- SampleResult prevResult
- JMeterVariables vars
- JMeterContext context
+ @JvmStatic
+ fun extractCasesStream() = listOf(
+ ExtractCase(1..1, -1, List(10) { "1" }),
+ ExtractCase(1..1, 0, List(10) { "1" }),
+ ExtractCase(1..1, 1, listOf("1")),
+ ExtractCase(1..1, 10, listOf("1")),
+ ExtractCase(1..1, 11, listOf()),
+ ExtractCase(1..2, -1, (1..10).flatMap { listOf("1", "2") }),
+ ExtractCase(1..2, 1, listOf("1")),
+ ExtractCase(1..2, 2, listOf("2")),
+ ExtractCase(1..3, 3, listOf("3")),
+ )
+ }
- def setup() {
- vars = new JMeterVariables()
+ val sut = BoundaryExtractor()
+
+ private lateinit var prevResult: SampleResult
+ lateinit var vars: JMeterVariables
+ private lateinit var context: JMeterContext
+
+ @BeforeEach
+ fun setup() {
+ vars = JMeterVariables()
context = JMeterContextService.getContext()
- context.setVariables(vars)
+ context.variables = vars
- sut.setThreadContext(context)
- sut.setRefName(VAR_NAME)
- sut.setLeftBoundary(LEFT)
- sut.setRightBoundary(RIGHT)
- sut.setDefaultValue(DEFAULT_VAL)
- sut.setMatchNumber(1)
+ sut.threadContext = context
+ sut.refName = VAR_NAME
+ sut.leftBoundary = LEFT
+ sut.rightBoundary = RIGHT
+ sut.defaultValue = DEFAULT_VAL
+ sut.matchNumber = 1
- prevResult = new SampleResult()
- prevResult.sampleStart()
- prevResult.setResponseData(createInputString(1..2), null)
- prevResult.sampleEnd()
- context.setPreviousResult(prevResult)
+ prevResult = SampleResult().apply {
+ sampleStart()
+ setResponseData(createInputString(1..2), null)
+ sampleEnd()
+ }
+ context.previousResult = prevResult
}
- def "Extract, where pattern exists, with matchNumber=#matchNumber from #occurrences returns #expected"() {
- given:
- def input = createInputString(occurrences)
- when:
- def matches = sut.extract(LEFT, RIGHT, matchNumber, input)
- then:
- matches == expected
- where:
- occurrences | matchNumber || expected
- 1..1 | -1 || ['1']
- 1..1 | 0 || ['1']
- 1..1 | 1 || ['1']
- 1..1 | 2 || []
- 1..2 | -1 || ['1', '2']
- 1..2 | 1 || ['1']
- 1..2 | 2 || ['2']
- 1..3 | 3 || ['3']
+ private fun assertVarValueEquals(expected: String?) {
+ assertEquals(expected, vars.get(VAR_NAME), "vars.get($VAR_NAME)")
+ }
+ private fun assertVarNameMatchNrEquals(expected: String?) {
+ assertEquals(expected, vars.get("${VAR_NAME}_matchNr"), "vars.get(${VAR_NAME}_matchNr)")
}
- def "Extract, where pattern does not exist, with matchNumber=#matchNumber returns an empty list"() {
- expect:
- sut.extract(LEFT, RIGHT, matchNumber, 'start end') == []
- where:
- matchNumber << [-1, 0, 1, 2, 100]
+ private fun assertAllVars(expected: List<String>) {
+ assertEquals(expected, getAllVars(), "getAllVars()")
}
- def "Extract, where pattern exists in the stream, with matchNumber=#matchNumber from #occurrences returns #expected"() {
- given:
- def input = createInputString(occurrences)
- Stream<String> stream = ([input, "", null] * 10).stream()
- when:
- def matches = sut.extract(LEFT, RIGHT, matchNumber, stream)
- then:
- matches == expected
- where:
- occurrences | matchNumber || expected
- 1..1 | -1 || ['1'] * 10
- 1..1 | 0 || ['1'] * 10
- 1..1 | 1 || ['1']
- 1..1 | 10 || ['1']
- 1..1 | 11 || []
- 1..2 | -1 || ['1', '2'] * 10
- 1..2 | 1 || ['1']
- 1..2 | 2 || ['2']
- 1..3 | 3 || ['3']
+ @ParameterizedTest
+ @MethodSource("extractCases")
+ fun `Extract, where pattern exists, with matchNumber=#matchNumber from #occurrences returns #expected`(case: ExtractCase) {
+ val input = createInputString(case.occurrences)
+ val matches = BoundaryExtractor.extract(LEFT, RIGHT, case.matchNumber, input)
+
+ assertEquals(case.expected, matches)
}
- def "Extract, where pattern does not exist in the stream, with matchNumber=#matchNumber returns an empty list"() {
- given:
- Stream<String> stream = (['start end'] * 10).stream()
- expect:
- sut.extract(LEFT, RIGHT, matchNumber, stream) == []
- where:
- matchNumber << [-1, 0, 1, 2, 100]
+ @ParameterizedTest
+ @ValueSource(ints = [-1, 0, 1, 2, 100])
+ fun `Extract, where pattern does not exist, with matchNumber=#matchNumber returns an empty list`(matchNumber: Int) {
+ assertEquals(listOf<Any>(), BoundaryExtractor.extract(LEFT, RIGHT, matchNumber, "start end"))
}
- def "IllegalArgumentException when name (#name) is null"() {
- given:
- sut.setLeftBoundary(lb)
- sut.setRightBoundary(rb)
- sut.setRefName(name)
- when:
- sut.process()
- then:
- thrown(IllegalArgumentException)
- where:
- lb | rb | name
- "l" | "r" | null
+ @ParameterizedTest
+ @MethodSource("extractCasesStream")
+ fun `Extract, where pattern exists in the stream, with matchNumber=#matchNumber from #occurrences returns #expected`(case: ExtractCase) {
+ val input = createInputString(case.occurrences)
+ val stream = (1..10).flatMap { listOf(input, "", null) }.stream()
+ val matches = BoundaryExtractor.extract(LEFT, RIGHT, case.matchNumber, stream)
+
+ assertEquals(case.expected, matches)
}
- def "matching only on left boundary returns default"() {
- given:
- sut.setRightBoundary("does-not-exist")
- when:
- sut.process()
- then:
- vars.get(VAR_NAME) == DEFAULT_VAL
+ @ParameterizedTest
+ @ValueSource(ints = [-1, 0, 1, 2, 100])
+ fun `Extract, where pattern does not exist in the stream, with matchNumber=#matchNumber returns an empty list`(matchNumber: Int) {
+ val stream: Stream<String> = (1..10).flatMap { listOf("start end") }.stream()
+
+ assertEquals(listOf<Any>(), BoundaryExtractor.extract(LEFT, RIGHT, matchNumber, stream))
}
- def "matching only on right boundary returns default"() {
- given:
- sut.setLeftBoundary("does-not-exist")
- when:
+ @Test
+ fun `IllegalArgumentException when name (#name) is null`() {
+ sut.leftBoundary = "l"
+ sut.rightBoundary = "r"
+ sut.refName = null
+
+ assertThrows<IllegalArgumentException> {
sut.process()
- then:
- vars.get(VAR_NAME) == DEFAULT_VAL
+ }
}
- def "variables from a previous extraction are removed"() {
- given:
- sut.setMatchNumber(-1)
- sut.process()
- assert vars.get("${VAR_NAME}_1") == "1"
- assert vars.get("${VAR_NAME}_matchNr") == "2"
- when:
- // Now rerun with match fail
- sut.setMatchNumber(10)
- sut.process()
- then:
- vars.get(VAR_NAME) == DEFAULT_VAL
- vars.get("${VAR_NAME}_1") == null
- vars.get("${VAR_NAME}_matchNr") == null
+ @Test
+ fun `matching only on left boundary returns default`() {
+ sut.rightBoundary = "does-not-exist"
+ sut.process()
+ assertVarValueEquals(DEFAULT_VAL)
}
- def "with no sub-samples parent and all scope return data but children scope does not"() {
- given:
- sut.setScopeParent()
- when:
- sut.process()
- then:
- vars.get(VAR_NAME) == "1"
-
- and:
- sut.setScopeAll()
- when:
- sut.process()
- then:
- vars.get(VAR_NAME) == "1"
-
- and:
- sut.setScopeChildren()
- when:
- sut.process()
- then:
- vars.get(VAR_NAME) == DEFAULT_VAL
+ @Test
+ fun `matching only on right boundary returns default`() {
+ sut.leftBoundary = "does-not-exist"
+ sut.process()
+ assertVarValueEquals(DEFAULT_VAL)
}
- def "with sub-samples parent, all and children scope return expected item"() {
- given:
- prevResult.addSubResult(createSampleResult("${LEFT}sub1${RIGHT}"))
- prevResult.addSubResult(createSampleResult("${LEFT}sub2${RIGHT}"))
- prevResult.addSubResult(createSampleResult("${LEFT}sub3${RIGHT}"))
- sut.setScopeParent()
- when:
- sut.process()
- then:
- vars.get(VAR_NAME) == "1"
+ @Test
+ fun `variables from a previous extraction are removed`() {
+ sut.matchNumber = -1
+ sut.process()
+ assertEquals("1", vars.get("${VAR_NAME}_1"))
+ assertEquals("2", vars.get("${VAR_NAME}_matchNr"))
- and:
- sut.setScopeAll()
- sut.setMatchNumber(3) // skip 2 in parent sample
- when:
- sut.process()
- then:
- vars.get(VAR_NAME) == "sub1"
-
- and:
- sut.setScopeChildren()
- sut.setMatchNumber(3)
- when:
- sut.process()
- then:
- vars.get(VAR_NAME) == "sub3"
+ // Now rerun with match fail
+ sut.matchNumber = 10
+ sut.process()
+ assertVarValueEquals(DEFAULT_VAL)
+ assertNull(vars.get("${VAR_NAME}_1"), "vars.get(${VAR_NAME}_1)")
+ assertVarNameMatchNrEquals(null)
}
- def "with sub-samples parent, all and children scope return expected data"() {
- given:
- prevResult.addSubResult(createSampleResult("${LEFT}sub1${RIGHT}"))
- prevResult.addSubResult(createSampleResult("${LEFT}sub2${RIGHT}"))
- prevResult.addSubResult(createSampleResult("${LEFT}sub3${RIGHT}"))
- sut.setMatchNumber(-1)
+ @Test
+ fun `with no sub-samples parent and all scope return data but children scope does not`() {
+ sut.setScopeParent()
+ sut.process()
+ assertVarValueEquals("1")
- sut.setScopeParent()
- when:
- sut.process()
- then:
- vars.get("${VAR_NAME}_matchNr") == "2"
- getAllVars() == ["1", "2"]
+ sut.setScopeAll()
+ sut.process()
+ assertVarValueEquals("1")
- and:
- sut.setScopeAll()
- when:
- sut.process()
- then:
- vars.get("${VAR_NAME}_matchNr") == "5"
- getAllVars() == ["1", "2", "sub1", "sub2", "sub3"]
-
- and:
- sut.setScopeChildren()
- when:
- sut.process()
- then:
- vars.get("${VAR_NAME}_matchNr") == "3"
- getAllVars() == ["sub1", "sub2", "sub3"]
+ sut.setScopeChildren()
+ sut.process()
+ assertVarValueEquals(DEFAULT_VAL)
}
- def "when 'default empty value' is true the default value is allowed to be empty"() {
- given:
- sut.setMatchNumber(10) // no matches
- sut.setDefaultValue("")
- sut.setDefaultEmptyValue(true)
- when:
- sut.process()
- then:
- vars.get(VAR_NAME) == ""
+ @Test
+ fun `with sub-samples parent, all and children scope return expected item`() {
+ prevResult.addSubResult(createSampleResult("${LEFT}sub1$RIGHT"))
+ prevResult.addSubResult(createSampleResult("${LEFT}sub2$RIGHT"))
+ prevResult.addSubResult(createSampleResult("${LEFT}sub3$RIGHT"))
+ sut.setScopeParent()
+
+ sut.process()
+
+ assertVarValueEquals("1")
+
+ sut.setScopeAll()
+ sut.matchNumber = 3 // skip 2 in parent sample
+ sut.process()
+ assertVarValueEquals("sub1")
+
+ sut.setScopeChildren()
+ sut.matchNumber = 3
+ sut.process()
+ assertVarValueEquals("sub3")
}
- def "when default value is empty but not allowed null is returned"() {
- given:
- sut.setMatchNumber(10) // no matches
- sut.setDefaultValue("")
- sut.setDefaultEmptyValue(false)
- when:
- sut.process()
- then:
- vars.get(VAR_NAME) == null
+ @Test
+ fun `with sub-samples parent, all and children scope return expected data`() {
+ prevResult.addSubResult(createSampleResult("${LEFT}sub1$RIGHT"))
+ prevResult.addSubResult(createSampleResult("${LEFT}sub2$RIGHT"))
+ prevResult.addSubResult(createSampleResult("${LEFT}sub3$RIGHT"))
+ sut.matchNumber = -1
+
+ sut.setScopeParent()
+ sut.process()
+
+ assertVarNameMatchNrEquals("2")
+ assertAllVars(listOf("1", "2"))
+
+ sut.setScopeAll()
+ sut.process()
+ assertVarNameMatchNrEquals("5")
+ assertAllVars(listOf("1", "2", "sub1", "sub2", "sub3"))
+
+ sut.setScopeChildren()
+ sut.process()
+ assertVarNameMatchNrEquals("3")
+ assertAllVars(listOf("sub1", "sub2", "sub3"))
}
- def "with no previous results result is null"() {
- given:
- context.setPreviousResult(null)
- sut.setDefaultEmptyValue(true)
- when:
- sut.process()
- then:
- vars.get(VAR_NAME) == null
+ @Test
+ fun `when 'default empty value' is true the default value is allowed to be empty`() {
+ sut.matchNumber = 10 // no matches
+ sut.defaultValue = ""
+ sut.setDefaultEmptyValue(true)
+ sut.process()
+ assertVarValueEquals("")
}
- def "with non-existent variable result is null"() {
- given:
- sut.setDefaultValue(null)
- sut.setScopeVariable("empty-var-name")
- when:
- sut.process()
- then:
- vars.get(VAR_NAME) == null
+ @Test
+ fun `when default value is empty but not allowed null is returned`() {
+ sut.matchNumber = 10 // no matches
+ sut.defaultValue = ""
+ sut.setDefaultEmptyValue(false)
+ sut.process()
+ assertVarValueEquals(null)
}
- def "not allowing blank default value returns null upon no matches"() {
- given:
- sut.setMatchNumber(10) // no matches
- sut.setDefaultValue("")
- sut.setDefaultEmptyValue(false)
- when:
- sut.process()
- then:
- vars.get(VAR_NAME) == null
+ @Test
+ fun `with no previous results result is null`() {
+ context.previousResult = null
+ sut.setDefaultEmptyValue(true)
+ sut.process()
+ assertVarValueEquals(null)
}
- def "extract all matches from variable input"() {
- given:
- sut.setMatchNumber(-1)
- sut.setScopeVariable("contentvar")
- vars.put("contentvar", createInputString(1..2))
- when:
- sut.process()
- then:
- getAllVars() == ["1", "2"]
- vars.get("${VAR_NAME}_matchNr") == "2"
+ @Test
+ fun `with non-existent variable result is null`() {
+ sut.defaultValue = null
+ sut.setScopeVariable("empty-var-name")
+ sut.process()
+ assertVarValueEquals(null)
}
- def "extract random from variable returns one of the matches"() {
- given:
- sut.setMatchNumber(0)
- sut.setScopeVariable("contentvar")
- vars.put("contentvar", createInputString(1..42))
- when:
- sut.process()
- then:
- (1..42).collect({ it.toString() }).contains(vars.get(VAR_NAME))
- vars.get("${VAR_NAME}_matchNr") == null
+ @Test
+ fun `not allowing blank default value returns null upon no matches`() {
+ sut.matchNumber = 10 // no matches
+ sut.defaultValue = ""
+ sut.setDefaultEmptyValue(false)
+ sut.process()
+ assertVarValueEquals(null)
}
- def "extract all from an empty variable returns no results"() {
- given:
- sut.setMatchNumber(-1)
- sut.setScopeVariable("contentvar")
- vars.put("contentvar", "")
- when:
- sut.process()
- then:
- vars.get("${VAR_NAME}_matchNr") == "0"
- vars.get("${VAR_NAME}_1") == null
+ @Test
+ fun `extract all matches from variable input`() {
+ sut.matchNumber = -1
+ sut.setScopeVariable("contentvar")
+ vars.put("contentvar", createInputString(1..2))
+ sut.process()
+ assertAllVars(listOf("1", "2"))
+ assertVarNameMatchNrEquals("2")
}
- def "previous extractions are cleared"() {
- given:
- sut.setMatchNumber(-1)
- sut.setScopeVariable("contentvar")
- vars.put("contentvar", createInputString(1..10))
- sut.process()
- assert getAllVars() == (1..10).collect({ it.toString() })
- assert vars.get("${VAR_NAME}_matchNr") == "10"
- vars.put("contentvar", createInputString(11..15))
- sut.setMatchNumber("-1")
- def expectedMatches = (11..15).collect({ it.toString() })
- when:
- sut.process()
- then:
- getAllVars() == expectedMatches
- vars.get("${VAR_NAME}_matchNr") == "5"
- (6..10).collect { vars.get("${VAR_NAME}_${it}") } == [null] * 5
+ @Test
+ fun `extract random from variable returns one of the matches`() {
+ sut.matchNumber = 0
+ sut.setScopeVariable("contentvar")
+ vars.put("contentvar", createInputString(1..42))
- and:
- sut.setMatchNumber(0)
- when:
- sut.process()
- then:
- expectedMatches.contains(vars.get(VAR_NAME))
+ sut.process()
+
+ (1..42).map { it.toString() }.contains(vars.get(VAR_NAME))
+ assertVarNameMatchNrEquals(null)
}
- /**
- * Creates a string with a "match" for each number in the list.
- *
- * @param occurrences list of numbers to be the "body" of a match
- * @return a string with a start, end and then a left boundary + number + right boundary
- * e.g. "... LB1RB LB2RB ..."
- */
- static createInputString(List<Integer> occurrences) {
- def middle = occurrences.collect({ LEFT + it + RIGHT }).join(" ")
- return 'start \t\r\n' + middle + '\n\t end'
+ @Test
+ fun `extract all from an empty variable returns no results`() {
+ sut.matchNumber = -1
+ sut.setScopeVariable("contentvar")
+ vars.put("contentvar", "")
+
+ sut.process()
+ assertVarNameMatchNrEquals("0")
+ assertNull(vars.get("${VAR_NAME}_1"), "vars.get(${VAR_NAME}_1)")
}
- static createSampleResult(String responseData) {
- SampleResult child = new SampleResult()
- child.sampleStart()
- child.setResponseData(responseData, "ISO-8859-1")
- child.sampleEnd()
- return child
+ @Test
+ fun `previous extractions are cleared`() {
+ sut.matchNumber = -1
+ sut.setScopeVariable("contentvar")
+ vars.put("contentvar", createInputString(1..10))
+ sut.process()
+ assertAllVars((1..10).map { it.toString() })
+ assertVarNameMatchNrEquals("10")
+ vars.put("contentvar", createInputString(11..15))
+ sut.setMatchNumber("-1")
+ val expectedMatches = (11..15).map { it.toString() }
+
+ sut.process()
+
+ assertAllVars(expectedMatches)
+ assertVarNameMatchNrEquals("5")
+ assertEquals(
+ List(5) { null },
+ (6..10).map { vars.get("${VAR_NAME}_$it") },
+ "vars.get(${VAR_NAME}_6..10)"
+ )
+
+ sut.matchNumber = 0
+ sut.process()
+
+ val varValue = vars.get(VAR_NAME)
+ if (varValue !in expectedMatches) {
+ fail("expectedMatches ($expectedMatches) should contain value of $VAR_NAME variable $varValue")
+ }
}
/**
* @return a list of all the variables in the format ${VAR_NAME}_${i}
* starting at i = 1 until null is returned
*/
- def getAllVars() {
- def allVars = []
- def i = 1
- def var = vars.get("${VAR_NAME}_${i}")
- while (var != null) {
- allVars.add(var)
+ private fun getAllVars(): List<String> = buildList {
+ var i = 1
+ while (true) {
+ val value = vars.get("${VAR_NAME}_$i") ?: break
+ add(value)
i++
- var = vars.get("${VAR_NAME}_${i}")
}
- return allVars
}
-
}
diff --git a/src/components/src/test/kotlin/org/apache/jmeter/extractor/JoddExtractorTest.kt b/src/components/src/test/kotlin/org/apache/jmeter/extractor/JoddExtractorTest.kt
index 52da3dd..fa143b3 100644
--- a/src/components/src/test/kotlin/org/apache/jmeter/extractor/JoddExtractorTest.kt
+++ b/src/components/src/test/kotlin/org/apache/jmeter/extractor/JoddExtractorTest.kt
@@ -17,35 +17,56 @@
package org.apache.jmeter.extractor
-import spock.lang.Specification
-import spock.lang.Unroll
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.MethodSource
-@Unroll
-class JoddExtractorSpec extends Specification {
+class JoddExtractorTest {
+ data class ExtractCase(
+ val expression: String,
+ val attribute: String,
+ val matchNumber: Int,
+ val expectedList: List<String>,
+ val found: Int,
+ val expected: Int,
+ val cacheKey: String
+ )
- def "extract #expression and #attribute"() {
- given:
- def resultList = []
- def input = """
-<html>
- <head><title>Test</title></head>
- <body>
- <h1 class="title">TestTitle</h1>
- <p>Some text</p>
- <h1>AnotherTitle</h1>
- </body>
-</html>
-"""
- when:
- def foundCount = new JoddExtractor().extract(expression, attribute, matchNumber, input, resultList, found, cacheKey)
- then:
- foundCount == expected
- resultList == expectedList
- where:
- expression | attribute | matchNumber | expectedList | found | expected | cacheKey
- "p" | "" | 1 | ["Some text"] | -1 | 0 | "key"
- "h1[class=title]" | "class" | 1 | ["title"] | -1 | 0 | "key"
- "h1" | "" | 0 | ["TestTitle", "AnotherTitle"] | -1 | 1 | "key"
- "notthere" | "" | 0 | [] | -1 | -1 | "key"
+ companion object {
+ @JvmStatic
+ fun extractCases() = listOf(
+ ExtractCase("p", "", 1, listOf("Some text"), -1, 0, "key"),
+ ExtractCase("h1[class=title]", "class", 1, listOf("title"), -1, 0, "key"),
+ ExtractCase("h1", "", 0, listOf("TestTitle", "AnotherTitle"), -1, 1, "key"),
+ ExtractCase("notthere", "", 0, listOf(), -1, -1, "key"),
+ )
+ }
+
+ @ParameterizedTest
+ @MethodSource("extractCases")
+ fun extract(case: ExtractCase) {
+ val resultList = mutableListOf<String>()
+ val input = /* language=xml */
+ """
+ <html>
+ <head><title>Test</title></head>
+ <body>
+ <h1 class="title">TestTitle</h1>
+ <p>Some text</p>
+ <h1>AnotherTitle</h1>
+ </body>
+ </html>
+ """.trimIndent()
+ val foundCount = JoddExtractor().extract(
+ case.expression,
+ case.attribute,
+ case.matchNumber,
+ input,
+ resultList,
+ case.found,
+ case.cacheKey
+ )
+ assertEquals(case.expectedList, resultList, "resultList")
+ assertEquals(case.expected, foundCount, "foundCount")
}
}
diff --git a/src/components/src/test/kotlin/org/apache/jmeter/extractor/json/render/JsonRendererExtensions.kt b/src/components/src/test/kotlin/org/apache/jmeter/extractor/json/render/JsonRendererExtensions.kt
new file mode 100644
index 0000000..d989fa9
--- /dev/null
+++ b/src/components/src/test/kotlin/org/apache/jmeter/extractor/json/render/JsonRendererExtensions.kt
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jmeter.extractor.json.render
+
+import org.junit.jupiter.api.Assertions
+
+internal fun AbstractRenderAsJsonRenderer.assertJsonDataFieldEquals(expected: String?) {
+ Assertions.assertEquals(expected, jsonDataField.getText(), ".jsonDataField.text")
+}
diff --git a/src/components/src/test/kotlin/org/apache/jmeter/extractor/json/render/RenderAsJmesPathRendererTest.kt b/src/components/src/test/kotlin/org/apache/jmeter/extractor/json/render/RenderAsJmesPathRendererTest.kt
index 25eb575..b217758 100644
--- a/src/components/src/test/kotlin/org/apache/jmeter/extractor/json/render/RenderAsJmesPathRendererTest.kt
+++ b/src/components/src/test/kotlin/org/apache/jmeter/extractor/json/render/RenderAsJmesPathRendererTest.kt
@@ -17,119 +17,134 @@
package org.apache.jmeter.extractor.json.render
+import org.apache.jmeter.junit.JMeterTestCase
+import org.apache.jmeter.samplers.SampleResult
+import org.apache.jmeter.test.gui.DisabledIfHeadless
+import org.apache.jmeter.util.JMeterUtils
+import org.intellij.lang.annotations.Language
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertNotNull
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.MethodSource
+import java.nio.charset.StandardCharsets
import javax.swing.JTabbedPane
-import org.apache.jmeter.extractor.json.render.RenderAsJmesPathRenderer
-import org.apache.jmeter.junit.categories.NeedGuiTests
-import org.apache.jmeter.junit.spock.JMeterSpec
-import org.apache.jmeter.samplers.SampleResult
-import org.apache.jmeter.util.JMeterUtils
-import org.junit.experimental.categories.Category
+class RenderAsJmesPathRendererTest : JMeterTestCase() {
+ val sut = RenderAsJmesPathRenderer()
-import spock.lang.IgnoreIf
+ data class RenderCase(
+ @param:Language("json") val input: String,
+ @param:Language("json") val output: String
+ )
-class RenderAsJmesPathRendererSpec extends JMeterSpec {
- def sut = new RenderAsJmesPathRenderer()
+ data class ExecuteCase(
+ @param:Language("json") val input: String,
+ val expression: String,
+ val output: String
+ )
- def "init of component doesn't fail"() {
- when:
- sut.init()
- then:
- noExceptionThrown()
- sut.jsonWithExtractorPanel != null;
+ companion object {
+ @JvmStatic
+ fun renderCases() = listOf(
+ RenderCase("This is not json", "This is not json"),
+ RenderCase(
+ """{name:"Ludwig",age: 23,city: "Bonn"}""",
+ """
+ {
+ "city": "Bonn",
+ "name": "Ludwig",
+ "age": 23
+ }
+ """.trimIndent()
+ ),
+ )
+
+ @JvmStatic
+ fun executeCases() = listOf(
+ ExecuteCase("{\"name\":\"Ludwig\",\"age\": 23,\"city\": \"Bonn\"}", "name", "Result[0]=Ludwig\n"),
+ ExecuteCase("{\"name\":\"Ludwig\",\"age\": 23,\"city\": \"Bonn\"}", "age", "Result[0]=23\n"),
+ ExecuteCase("{\"name\":\"Ludwig\",\"age\": 23,\"city\": \"Bonn\"}", "name1", "NO MATCH"),
+ )
}
- @IgnoreIf({ JMeterSpec.isHeadless() })
- def "render image"() {
- given:
- sut.init()
- def sampleResult = new SampleResult();
- when:
- sut.renderImage(sampleResult)
- then:
- sut.jsonDataField.getText() == JMeterUtils.getResString("render_no_text")
+ @Test
+ fun `init of component doesn't fail`() {
+ sut.init()
+ assertNotNull(sut.jsonWithExtractorPanel, ".jsonWithExtractorPanel")
}
- def "render null Response"() {
- given:
- sut.init()
- def sampleResult = new SampleResult();
- when:
- sut.renderResult(sampleResult)
- then:
- sut.jsonDataField.getText() == ""
+ @Test
+ @DisabledIfHeadless
+ fun `render image`() {
+ sut.init()
+ val sampleResult = SampleResult()
+ sut.renderImage(sampleResult)
+ sut.assertJsonDataFieldEquals(JMeterUtils.getResString("render_no_text"))
}
- @IgnoreIf({ JMeterSpec.isHeadless() })
- def "render '#input' as JSON Response to '#output'"() {
- given:
- sut.init();
- def sampleResult = new SampleResult();
- when:
- sampleResult.setResponseData(input);
- sut.renderResult(sampleResult)
- then:
- output == sut.jsonDataField.getText()
- where:
- input | output
- "This is not json" | "This is not json"
- "{name:\"Ludwig\",age: 23,city: \"Bonn\"}" | '''{
- "city": "Bonn",
- "name": "Ludwig",
- "age": 23
-}'''
+ @Test
+ fun `render null Response`() {
+ sut.init()
+ val sampleResult = SampleResult()
+ sut.renderResult(sampleResult)
+ sut.assertJsonDataFieldEquals("")
}
- def "execute '#expression' on '#input' results into '#output'"() {
- given:
- sut.init();
- sut.expressionField.setText(expression);
- def sampleResult = new SampleResult();
- when:
- sut.executeTester(input);
- then:
- output == sut.resultField.getText()
- where:
- input | expression | output
- "{\"name\":\"Ludwig\",\"age\": 23,\"city\": \"Bonn\"}" | "name" | "Result[0]=Ludwig\n"
- "{\"name\":\"Ludwig\",\"age\": 23,\"city\": \"Bonn\"}" | "age" | "Result[0]=23\n"
- "{\"name\":\"Ludwig\",\"age\": 23,\"city\": \"Bonn\"}" | "name1" | "NO MATCH"
+ @DisabledIfHeadless
+ @ParameterizedTest
+ @MethodSource("renderCases")
+ fun `render JSON Response`(case: RenderCase) {
+ sut.init()
+ val sampleResult = SampleResult()
+ sampleResult.setResponseData(case.input, StandardCharsets.UTF_8.name())
+ sut.renderResult(sampleResult)
+
+ sut.assertJsonDataFieldEquals(case.output)
}
- def "clearData clears expected fields"() {
- given:
- sut.init()
- sut.jsonDataField.setText("blabla")
- sut.resultField.setText("blabla")
- when:
- sut.clearData()
- then:
- sut.jsonDataField.getText() == ""
- sut.resultField.getText() == ""
+ @ParameterizedTest
+ @MethodSource("executeCases")
+ fun `execute expression`(case: ExecuteCase) {
+ sut.init()
+ sut.expressionField.text = case.expression
+ sut.executeTester(case.input)
+
+ assertEquals(case.output, sut.resultField.getText(), ".resultField.text")
}
- def "setupTabPane adds the tab to rightSide"() {
- given:
- sut.init()
- def rightSideTabbedPane = new JTabbedPane();
- sut.setRightSide(rightSideTabbedPane)
- when:
- sut.setupTabPane()
- then:
- sut.rightSide.getTabCount() == 1
- // Investigate why it's failing
- // sut.rightSide.getTabComponentAt(0) == sut.jsonWithExtractorPanel
+ @Test
+ fun `clearData clears expected fields`() {
+ sut.init()
+ sut.jsonDataField.setText("blabla")
+ sut.resultField.setText("blabla")
+
+ sut.clearData()
+
+ assertEquals("", sut.resultField.getText(), ".resultField.text")
+ sut.assertJsonDataFieldEquals("")
}
- def "setupTabPane called twice does not add twice the tab"() {
- given:
- sut.init()
- def rightSideTabbedPane = new JTabbedPane();
- sut.setRightSide(rightSideTabbedPane)
- sut.setupTabPane()
- when:
- sut.setupTabPane()
- then:
- sut.rightSide.getTabCount() == 1
+ @Test
+ fun `setupTabPane adds the tab to rightSide`() {
+ sut.init()
+ val rightSideTabbedPane = JTabbedPane()
+ sut.rightSide = rightSideTabbedPane
+
+ sut.setupTabPane()
+ assertEquals(1, sut.rightSide.getTabCount(), ".rightSide.getTabCount()")
+
+ // Investigate why it's failing
+ // sut.rightSide.getTabComponentAt(0) == sut.jsonWithExtractorPanel
+ }
+
+ @Test
+ fun `setupTabPane called twice does not add twice the tab`() {
+ sut.init()
+ val rightSideTabbedPane = JTabbedPane()
+ sut.rightSide = rightSideTabbedPane
+ sut.setupTabPane()
+ sut.setupTabPane()
+ assertEquals(1, sut.rightSide.getTabCount(), ".rightSide.getTabCount()")
}
}
diff --git a/src/components/src/test/kotlin/org/apache/jmeter/extractor/json/render/RenderAsJsonRendererTest.kt b/src/components/src/test/kotlin/org/apache/jmeter/extractor/json/render/RenderAsJsonRendererTest.kt
index c6404aa..c046707 100644
--- a/src/components/src/test/kotlin/org/apache/jmeter/extractor/json/render/RenderAsJsonRendererTest.kt
+++ b/src/components/src/test/kotlin/org/apache/jmeter/extractor/json/render/RenderAsJsonRendererTest.kt
@@ -17,115 +17,134 @@
package org.apache.jmeter.extractor.json.render
+import org.apache.jmeter.junit.JMeterTestCase
+import org.apache.jmeter.samplers.SampleResult
+import org.apache.jmeter.test.gui.DisabledIfHeadless
+import org.apache.jmeter.util.JMeterUtils
+import org.intellij.lang.annotations.Language
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertNotNull
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.MethodSource
+import java.nio.charset.StandardCharsets
import javax.swing.JTabbedPane
-import org.apache.jmeter.junit.spock.JMeterSpec
-import org.apache.jmeter.samplers.SampleResult
-import org.apache.jmeter.util.JMeterUtils
+class RenderAsJsonRendererTest : JMeterTestCase() {
+ val sut = RenderAsJsonRenderer()
-import spock.lang.IgnoreIf
+ data class RenderCase(
+ @param:Language("json") val input: String,
+ @param:Language("json") val output: String
+ )
-class RenderAsJsonRendererSpec extends JMeterSpec {
- def sut = new RenderAsJsonRenderer()
+ data class ExecuteCase(
+ @param:Language("json") val input: String,
+ @param:Language("jsonpath") val expression: String,
+ val output: String
+ )
- def "init of component doesn't fail"() {
- when:
- sut.init()
- then:
- noExceptionThrown()
- sut.jsonWithExtractorPanel != null
+ companion object {
+ @JvmStatic
+ fun renderCases() = listOf(
+ RenderCase("This is not json", "This is not json"),
+ RenderCase(
+ """{name:"Ludwig",age: 23,city: "Bonn"}""",
+ """
+ {
+ "city": "Bonn",
+ "name": "Ludwig",
+ "age": 23
+ }
+ """.trimIndent()
+ ),
+ )
+
+ @JvmStatic
+ fun executeCases() = listOf(
+ ExecuteCase("{\"name\":\"Ludwig\",\"age\": 23,\"city\": \"Bonn\"}", "$..name", "Result[0]=Ludwig\n"),
+ ExecuteCase("This is not json", "$..name", "NO MATCH"),
+ ExecuteCase(
+ "{\"name\":\"Ludwig\",\"age\": 23,\"city\": \"Bonn\"}",
+ "$..",
+ "Exception: Path must not end with a '.' or '..'"
+ ),
+ )
}
- @IgnoreIf({ JMeterSpec.isHeadless() })
- def "render image"() {
- given:
- sut.init()
- def sampleResult = new SampleResult()
- when:
- sut.renderImage(sampleResult)
- then:
- sut.jsonDataField.getText() == JMeterUtils.getResString("render_no_text")
+ @Test
+ fun `init of component doesn't fail`() {
+ sut.init()
+ assertNotNull(sut.jsonWithExtractorPanel, "jsonWithExtractorPanel")
}
- def "render null Response"() {
- given:
- sut.init()
- def sampleResult = new SampleResult()
- when:
- sut.renderResult(sampleResult)
- then:
- sut.jsonDataField.getText() == ""
+ @Test
+ @DisabledIfHeadless
+ fun `render image`() {
+ sut.init()
+ val sampleResult = SampleResult()
+ sut.renderImage(sampleResult)
+ sut.assertJsonDataFieldEquals(JMeterUtils.getResString("render_no_text"))
}
- @IgnoreIf({ JMeterSpec.isHeadless() })
- def "render '#input' as JSON Response to '#output'"() {
- given:
- sut.init()
- def sampleResult = new SampleResult()
- sampleResult.setResponseData(input)
- when:
- sut.renderResult(sampleResult)
- then:
- output == sut.jsonDataField.getText()
- where:
- input | output
- "This is not json" | "This is not json"
- "{name:\"Ludwig\",age: 23,city: \"Bonn\"}" | '''{
- "city": "Bonn",
- "name": "Ludwig",
- "age": 23
-}'''
+ @Test
+ fun `render null Response`() {
+ sut.init()
+ val sampleResult = SampleResult()
+ sut.renderResult(sampleResult)
+ sut.assertJsonDataFieldEquals("")
}
- def "execute '#expression' on '#input' results into '#output'"() {
- given:
- sut.init()
- sut.expressionField.setText(expression)
- when:
- sut.executeTester(input)
- then:
- output == sut.resultField.getText()
- where:
- input | expression | output
- "{name:\"Ludwig\",age: 23,city: \"Bonn\"}" | "\$..name" | "Result[0]=Ludwig\n"
- "This is not json" | "\$..name" | "NO MATCH"
- "{name:\"Ludwig\",age: 23,city: \"Bonn\"}" | "\$.." | "Exception: Path must not end with a '.' or '..'"
+ @DisabledIfHeadless
+ @ParameterizedTest
+ @MethodSource("renderCases")
+ fun `render JSON Response`(case: RenderCase) {
+ sut.init()
+ val sampleResult = SampleResult()
+ sampleResult.setResponseData(case.input, StandardCharsets.UTF_8.name())
+ sut.renderResult(sampleResult)
+
+ sut.assertJsonDataFieldEquals(case.output)
}
- def "clearData clears expected fields"() {
- given:
- sut.init()
- sut.jsonDataField.setText("blabla")
- sut.resultField.setText("blabla")
- when:
- sut.clearData()
- then:
- sut.jsonDataField.getText() == ""
- sut.resultField.getText() == ""
+ @ParameterizedTest
+ @MethodSource("executeCases")
+ fun `execute expression`(case: ExecuteCase) {
+ sut.init()
+ sut.expressionField.text = case.expression
+ sut.executeTester(case.input)
+
+ assertEquals(case.output, sut.resultField.getText(), ".resultField.text")
}
- def "setupTabPane adds the tab to rightSide"() {
- given:
- sut.init()
- def rightSideTabbedPane = new JTabbedPane()
- sut.setRightSide(rightSideTabbedPane)
- when:
- sut.setupTabPane()
- then:
- sut.rightSide.getTabCount() == 1
- // Investigate why it's failing
- // sut.rightSide.getTabComponentAt(0) == sut.jsonWithExtractorPanel
+ @Test
+ fun `clearData clears expected fields`() {
+ sut.init()
+ sut.jsonDataField.text = "blabla"
+ sut.resultField.text = "blabla"
+ sut.clearData()
+ assertEquals("", sut.resultField.getText(), ".resultField.text")
+ sut.assertJsonDataFieldEquals("")
}
- def "setupTabPane called twice does not add twice the tab"() {
- given:
- sut.init()
- def rightSideTabbedPane = new JTabbedPane()
- sut.setRightSide(rightSideTabbedPane)
- sut.setupTabPane()
- when:
- sut.setupTabPane()
- then:
- sut.rightSide.getTabCount() == 1
+ @Test
+ fun `setupTabPane adds the tab to rightSide`() {
+ sut.init()
+ val rightSideTabbedPane = JTabbedPane()
+ sut.rightSide = rightSideTabbedPane
+ sut.setupTabPane()
+ assertEquals(1, sut.rightSide.tabCount, ".rightSide.getTabCount()")
+ // Investigate why it's failing
+ // sut.rightSide.getTabComponentAt(0) == sut.jsonWithExtractorPanel
+ }
+
+ @Test
+ fun `setupTabPane called twice does not add twice the tab`() {
+ sut.init()
+ val rightSideTabbedPane = JTabbedPane()
+ sut.rightSide = rightSideTabbedPane
+ sut.setupTabPane()
+ sut.setupTabPane()
+ assertEquals(1, sut.rightSide.tabCount, ".rightSide.getTabCount()")
}
}
diff --git a/src/components/src/test/kotlin/org/apache/jmeter/timers/UniformRandomTimerTest.kt b/src/components/src/test/kotlin/org/apache/jmeter/timers/UniformRandomTimerTest.kt
index dae6286..f78afd6 100644
--- a/src/components/src/test/kotlin/org/apache/jmeter/timers/UniformRandomTimerTest.kt
+++ b/src/components/src/test/kotlin/org/apache/jmeter/timers/UniformRandomTimerTest.kt
@@ -17,50 +17,52 @@
package org.apache.jmeter.timers
-import spock.lang.Specification
-import spock.lang.Unroll
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.fail
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.MethodSource
-class UniformRandomTimerSpec extends Specification {
+class UniformRandomTimerTest {
+ data class RangeCase(val delay: String, val range: Double, val min: Long, val max: Long)
- def sut = new UniformRandomTimer()
+ val sut = UniformRandomTimer()
- def "default delay is 0"() {
- when:
- def computedDelay = sut.delay()
- then:
- computedDelay == 0L
+ companion object {
+ @JvmStatic
+ fun rangeCases() = listOf(
+ RangeCase("1", 10.5, 1, 11),
+ RangeCase("1", 0.1, 1, 1),
+ RangeCase("0", -50.0, 0, 50),
+ )
}
- def "default range is 0"() {
- when:
- def actualRange = sut.range
- then:
- actualRange == 0L
+ @Test
+ fun `default delay is 0`() {
+ assertEquals(0L, sut.delay(), ".delay()")
}
- def "delay can be set via a String"() {
- given:
- sut.setDelay("1")
- when:
- def computedDelay = sut.delay()
- then:
- computedDelay == 1L
+ @Test
+ fun `default range is 0`() {
+ assertEquals(0.0, sut.range, ".range")
}
- @Unroll
- def "#delay <= computedDelay <= trunc(#delay + abs(#range))"() {
- given:
- sut.setDelay(delay)
- sut.setRange(range)
- when:
- def computedDelay = sut.delay()
- then:
- min <= computedDelay
- computedDelay <= max
- where:
- delay | range | min | max
- "1" | 10.5 | 1 | 11
- "1" | 0.1 | 1 | 1
- "0" | -50.0 | 0 | 50
+ @Test
+ fun `delay can be set via a String`() {
+ sut.delay = "1"
+ assertEquals(1L, sut.delay(), ".delay()")
+ }
+
+ @ParameterizedTest
+ @MethodSource("rangeCases")
+ fun `computed delay should be within range`(case: RangeCase) {
+ sut.delay = case.delay
+ sut.range = case.range
+
+ val computedDelay = sut.delay()
+
+ if (computedDelay < case.min || computedDelay > case.max) {
+ fail("computed delay $computedDelay should be within [${case.min}..${case.max}]")
+ }
}
}
diff --git a/src/components/src/test/kotlin/org/apache/jmeter/visualizers/backend/graphite/PickleGraphiteMetricsSenderTest.kt b/src/components/src/test/kotlin/org/apache/jmeter/visualizers/backend/graphite/PickleGraphiteMetricsSenderTest.kt
index 1e6a628..af9a46f 100644
--- a/src/components/src/test/kotlin/org/apache/jmeter/visualizers/backend/graphite/PickleGraphiteMetricsSenderTest.kt
+++ b/src/components/src/test/kotlin/org/apache/jmeter/visualizers/backend/graphite/PickleGraphiteMetricsSenderTest.kt
@@ -17,106 +17,109 @@
package org.apache.jmeter.visualizers.backend.graphite
+import io.mockk.mockk
+import io.mockk.verify
+import org.apache.commons.pool2.impl.GenericKeyedObjectPool
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertTrue
+import org.junit.jupiter.api.Test
import java.time.Instant
-import org.apache.commons.pool2.impl.GenericKeyedObjectPool
+class PickleGraphiteMetricsSenderTest {
-import spock.lang.Specification
+ private val sut = PickleGraphiteMetricsSender()
-class PickleGraphiteMetricsSenderSpec extends Specification {
-
- def sut = new PickleGraphiteMetricsSender()
-
- def "new sender has no metrics"() {
- expect:
- sut.metrics.isEmpty()
+ private fun assertMetricsIsEmpty() {
+ assertTrue(sut.metrics.isEmpty(), ".metrics.isEmpty()")
}
- def "adding metric to sender creates correct MetricTuple"() {
- given:
- def expectedName = "prefix-contextName.metricName"
- def expectedTS = 1000000
- def expectedVal = "value"
-
- sut.setup("host", 1024, "prefix-")
- when:
- sut.addMetric(expectedTS, "contextName", "metricName", expectedVal)
- then:
- def actualMetrics = sut.metrics
- actualMetrics.size() == 1
- def actualMetric = actualMetrics.get(0)
- actualMetric.name == expectedName
- actualMetric.timestamp == expectedTS
- actualMetric.value == expectedVal
+ @Test
+ fun `new sender has no metrics`() {
+ assertMetricsIsEmpty()
}
- def "writeAndSendMetrics does not attempt connection if there's nothing to send"() {
- given:
- sut.setup("non-existant-host", 1024, "prefix-")
- when:
- sut.writeAndSendMetrics()
- then:
- sut.metrics.isEmpty()
- noExceptionThrown()
+ @Test
+ fun `adding metric to sender creates correct MetricTuple`() {
+ val expectedTS = 1000000L
+ val expectedVal = "value"
+
+ sut.setup("host", 1024, "prefix-")
+
+ sut.addMetric(expectedTS, "contextName", "metricName", expectedVal)
+
+ assertEquals(
+ "MetricTuple(name=prefix-contextName.metricName, timestamp=1000000, value=value)",
+ sut.metrics.joinToString { "MetricTuple(name=${it.name}, timestamp=${it.timestamp}, value=${it.value})" },
+ ".metrics"
+ )
}
- def "writeAndSendMetrics connects and sends if there's something to send, dropping metrics on connection failure, without throwing exceptions"() {
- given:
- SocketConnectionInfos socketConnInfoMock = Mock()
- GenericKeyedObjectPool<SocketConnectionInfos, SocketOutputStream> objectPoolStub = Mock()
- sut.setup(socketConnInfoMock, objectPoolStub, "prefix-")
- sut.addMetric(1, "contextName", "metricName", "val")
- when:
- sut.writeAndSendMetrics()
- then:
- 1 * objectPoolStub.borrowObject(socketConnInfoMock)
- sut.metrics.isEmpty()
- noExceptionThrown()
+ @Test
+ fun `writeAndSendMetrics does not attempt connection if there's nothing to send`() {
+ sut.setup("non-existant-host", 1024, "prefix-")
+ sut.writeAndSendMetrics()
+ assertMetricsIsEmpty()
}
- def "destroy closes outputStreamPool"() {
- given:
- GenericKeyedObjectPool<SocketConnectionInfos, SocketOutputStream> objectPoolStub = Mock()
- sut.setup(Mock(SocketConnectionInfos), objectPoolStub, "prefix-")
- sut.addMetric(1, "contextName", "metricName", "val")
- when:
- sut.destroy()
- then:
- 1 * objectPoolStub.close()
- // TODO: should destroy also set metrics to null or are we relying on the original reference to be removed after destroy is called?
- sut.metrics.size() == 1
- noExceptionThrown()
+ @Test
+ fun `writeAndSendMetrics connects and sends if there's something to send, dropping metrics on connection failure, without throwing exceptions`() {
+ val socketConnInfoMock = mockk<SocketConnectionInfos>()
+ val objectPoolStub = mockk<GenericKeyedObjectPool<SocketConnectionInfos, SocketOutputStream>>()
+ sut.setup(socketConnInfoMock, objectPoolStub, "prefix-")
+ sut.addMetric(1, "contextName", "metricName", "val")
+
+ sut.writeAndSendMetrics()
+ verify(exactly = 1) { objectPoolStub.borrowObject(socketConnInfoMock) }
+ assertMetricsIsEmpty()
}
- def static newMetric(String name, long timestamp, String value) {
- return new GraphiteMetricsSender.MetricTuple(name, timestamp, value)
+ @Test
+ fun `destroy closes outputStreamPool`() {
+ val objectPoolStub = mockk<GenericKeyedObjectPool<SocketConnectionInfos, SocketOutputStream>>(relaxed = true)
+ sut.setup(mockk<SocketConnectionInfos>(), objectPoolStub, "prefix-")
+ sut.addMetric(1, "contextName", "metricName", "val")
+
+ sut.destroy()
+
+ verify(exactly = 1) { objectPoolStub.close() }
+ // TODO: should destroy also set metrics to null or are we relying on the original reference to be removed after destroy is called?
+ assertEquals(1, sut.metrics.size, ".metrics.size")
}
- def "convertMetricsToPickleFormat produces expected result for one metric"() {
- given:
- def name = "name"
- def timeStamp = Instant.now().getEpochSecond()
- def value = "value-1.23"
- def metric = newMetric(name, timeStamp, value)
- def metrics = Collections.singletonList(metric)
- when:
- def result = sut.convertMetricsToPickleFormat(metrics)
- then:
- result == "(l(S'${name}'\n(L${timeStamp}L\nS'${value}'\ntta."
+ private fun newMetric(name: String, timestamp: Long, value: String) =
+ GraphiteMetricsSender.MetricTuple(name, timestamp, value)
+
+ @Test
+ fun `convertMetricsToPickleFormat produces expected result for one metric`() {
+ val name = "name"
+ val timeStamp = Instant.now().getEpochSecond()
+ val value = "value-1.23"
+ val metric = newMetric(name, timeStamp, value)
+ val metrics = listOf(metric)
+
+ val result = PickleGraphiteMetricsSender.convertMetricsToPickleFormat(metrics)
+
+ assertEquals(
+ "(l(S'$name'\n(L${timeStamp}L\nS'$value'\ntta.",
+ result,
+ )
}
- def "convertMetricsToPickleFormat produces expected result for multiple metrics"() {
- given:
- def name = "name"
- def timeStamp = Instant.now().getEpochSecond()
- def value = "value-1.23"
- def metric = newMetric(name, timeStamp, value)
- def metrics = Arrays.asList(metric, metric)
- when:
- def result = sut.convertMetricsToPickleFormat(metrics)
- then:
- result == "(l" +
- "(S'${name}'\n(L${timeStamp}L\nS'${value}'\ntta" +
- "(S'${name}'\n(L${timeStamp}L\nS'${value}'\ntta."
+ @Test
+ fun `convertMetricsToPickleFormat produces expected result for multiple metrics`() {
+ val name = "name"
+ val timeStamp = Instant.now().getEpochSecond()
+ val value = "value-1.23"
+ val metric = newMetric(name, timeStamp, value)
+ val metrics = listOf(metric, metric)
+
+ val result = PickleGraphiteMetricsSender.convertMetricsToPickleFormat(metrics)
+
+ assertEquals(
+ "(l" +
+ "(S'$name'\n(L${timeStamp}L\nS'$value'\ntta" +
+ "(S'$name'\n(L${timeStamp}L\nS'$value'\ntta.",
+ result,
+ )
}
}
diff --git a/src/components/src/test/kotlin/org/apache/jmeter/visualizers/backend/graphite/TextGraphiteMetricsSenderTest.kt b/src/components/src/test/kotlin/org/apache/jmeter/visualizers/backend/graphite/TextGraphiteMetricsSenderTest.kt
index 067e3d1..2112f08 100644
--- a/src/components/src/test/kotlin/org/apache/jmeter/visualizers/backend/graphite/TextGraphiteMetricsSenderTest.kt
+++ b/src/components/src/test/kotlin/org/apache/jmeter/visualizers/backend/graphite/TextGraphiteMetricsSenderTest.kt
@@ -17,73 +17,66 @@
package org.apache.jmeter.visualizers.backend.graphite
+import io.mockk.mockk
+import io.mockk.verify
import org.apache.commons.pool2.impl.GenericKeyedObjectPool
+import org.junit.jupiter.api.Assertions
+import org.junit.jupiter.api.Test
-import spock.lang.Specification
+class TextGraphiteMetricsSenderTest {
-class TextGraphiteMetricsSenderSpec extends Specification {
+ private val sut = TextGraphiteMetricsSender()
- def sut = new TextGraphiteMetricsSender()
-
- def "new sender has no metrics"() {
- expect:
- sut.metrics.isEmpty()
+ private fun assertMetricsIsEmpty() {
+ Assertions.assertTrue(sut.metrics.isEmpty(), ".metrics.isEmpty()")
}
- def "adding metric to sender creates correct MetricTuple"() {
- given:
- def expectedName = "prefix-contextName.metricName"
- def expectedTS = 1000000
- def expectedVal = "value"
-
- sut.setup("host", 1024, "prefix-")
- when:
- sut.addMetric(expectedTS, "contextName", "metricName", expectedVal)
- then:
- def actualMetrics = sut.metrics
- actualMetrics.size() == 1
- def actualMetric = actualMetrics.get(0)
- actualMetric.name == expectedName
- actualMetric.timestamp == expectedTS
- actualMetric.value == expectedVal
+ @Test
+ fun `new sender has no metrics`() {
+ assertMetricsIsEmpty()
}
- def "writeAndSendMetrics does not attempt connection if there's nothing to send"() {
- given:
- sut.setup("non-existant-host", 1024, "prefix-")
- when:
- sut.writeAndSendMetrics()
- then:
- sut.metrics.isEmpty()
- noExceptionThrown()
+ @Test
+ fun `adding metric to sender creates correct MetricTuple`() {
+ val expectedTS = 1000000L
+ val expectedVal = "value"
+
+ sut.setup("host", 1024, "prefix-")
+ sut.addMetric(expectedTS, "contextName", "metricName", expectedVal)
+
+ Assertions.assertEquals(
+ "MetricTuple(name=prefix-contextName.metricName, timestamp=1000000, value=value)",
+ sut.metrics.joinToString { "MetricTuple(name=${it.name}, timestamp=${it.timestamp}, value=${it.value})" },
+ ".metrics"
+ )
}
- def "writeAndSendMetrics connects and sends if there's something to send, dropping metrics on connection failure, without throwing exceptions"() {
- given:
- SocketConnectionInfos socketConnInfoMock = Mock()
- GenericKeyedObjectPool<SocketConnectionInfos, SocketOutputStream> objectPoolStub = Mock()
- sut.setup(socketConnInfoMock, objectPoolStub, "prefix-")
- sut.addMetric(1, "contextName", "metricName", "val")
- when:
- sut.writeAndSendMetrics()
- then:
- 1 * objectPoolStub.borrowObject(socketConnInfoMock)
- sut.metrics.isEmpty()
- noExceptionThrown()
+ @Test
+ fun `writeAndSendMetrics does not attempt connection if there's nothing to send`() {
+ sut.setup("non-existant-host", 1024, "prefix-")
+ sut.writeAndSendMetrics()
+ assertMetricsIsEmpty()
}
- def "destroy closes outputStreamPool"() {
- given:
- GenericKeyedObjectPool<SocketConnectionInfos, SocketOutputStream> objectPoolStub = Mock()
- sut.setup(Mock(SocketConnectionInfos), objectPoolStub, "prefix-")
- sut.addMetric(1, "contextName", "metricName", "val")
- when:
- sut.destroy()
- then:
- 1 * objectPoolStub.close()
- // TODO: should destroy also set metrics to null or are we relying on the original reference to be removed after destroy is called?
- sut.metrics.size() == 1
- noExceptionThrown()
+ @Test
+ fun `writeAndSendMetrics connects and sends if there's something to send, dropping metrics on connection failure, without throwing exceptions`() {
+ val socketConnInfoMock = mockk<SocketConnectionInfos>()
+ val objectPoolStub = mockk<GenericKeyedObjectPool<SocketConnectionInfos, SocketOutputStream>>()
+ sut.setup(socketConnInfoMock, objectPoolStub, "prefix-")
+ sut.addMetric(1, "contextName", "metricName", "val")
+ sut.writeAndSendMetrics()
+ verify(exactly = 1) { objectPoolStub.borrowObject(socketConnInfoMock) }
+ assertMetricsIsEmpty()
}
+ @Test
+ fun `destroy closes outputStreamPool`() {
+ val objectPoolStub = mockk<GenericKeyedObjectPool<SocketConnectionInfos, SocketOutputStream>>(relaxed = true)
+ sut.setup(mockk<SocketConnectionInfos>(), objectPoolStub, "prefix-")
+ sut.addMetric(1, "contextName", "metricName", "val")
+
+ sut.destroy()
+
+ verify(exactly = 1) { objectPoolStub.close() }
+ }
}
diff --git a/src/components/src/test/kotlin/org/apache/jmeter/visualizers/backend/influxdb/InfluxDBRawBackendListenerClientTest.kt b/src/components/src/test/kotlin/org/apache/jmeter/visualizers/backend/influxdb/InfluxDBRawBackendListenerClientTest.kt
index 5390a25..283b21a 100644
--- a/src/components/src/test/kotlin/org/apache/jmeter/visualizers/backend/influxdb/InfluxDBRawBackendListenerClientTest.kt
+++ b/src/components/src/test/kotlin/org/apache/jmeter/visualizers/backend/influxdb/InfluxDBRawBackendListenerClientTest.kt
@@ -17,83 +17,102 @@
package org.apache.jmeter.visualizers.backend.influxdb
+import io.mockk.mockk
+import io.mockk.verify
+import io.mockk.verifyOrder
import org.apache.jmeter.samplers.SampleResult
import org.apache.jmeter.visualizers.backend.BackendListenerContext
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.fail
-import spock.lang.Specification
+class InfluxDBRawBackendListenerClientTest {
-class InfluxDBRawBackendListenerClientSpec extends Specification {
+ val sut = InfluxDBRawBackendListenerClient()
+ private val defaultContext = BackendListenerContext(sut.getDefaultParameters())
- def sut = new InfluxDBRawBackendListenerClient()
- def defaultContext = new BackendListenerContext(sut.getDefaultParameters())
-
- def createOkSample() {
- def t = 1600123456789
- def okSample = SampleResult.createTestSample(t - 100, t)
- okSample.setLatency(42)
- okSample.setConnectTime(7)
- okSample.setSampleLabel("myLabel")
- okSample.setThreadName("myThread")
- okSample.setResponseOK()
- return okSample
+ private fun createOkSample(): SampleResult {
+ val t = 1600123456789
+ return SampleResult.createTestSample(t - 100, t).apply {
+ latency = 42
+ connectTime = 7
+ sampleLabel = "myLabel"
+ threadName = "myThread"
+ setResponseOK()
+ }
}
- def "Default parameters contain minimum required options"() {
- expect:
- sut.getDefaultParameters()
- .getArgumentsAsMap()
- .keySet()
- .containsAll([
- "influxdbMetricsSender", "influxdbUrl",
- "influxdbToken", "measurement"])
+ @Test
+ fun `Default parameters contain minimum required options`() {
+ val actualKeys = sut.getDefaultParameters()
+ .getArgumentsAsMap()
+ .keys
+ val expectedKeys = setOf(
+ "influxdbMetricsSender", "influxdbUrl",
+ "influxdbToken", "measurement"
+ )
+ if (!actualKeys.containsAll(expectedKeys)) {
+ fail("Default arguments $actualKeys should include all keys of $expectedKeys")
+ }
}
- def "Provided args are used during setup"() {
- when:
- sut.setupTest(defaultContext)
- then:
- sut.measurement == sut.DEFAULT_MEASUREMENT
- sut.influxDBMetricsManager.class.isAssignableFrom(HttpMetricsSender.class)
+ @Test
+ fun `Provided args are used during setup`() {
+ sut.setupTest(defaultContext)
+ assertEquals("jmeter", sut.measurement, ".measurement")
+ assertEquals(
+ HttpMetricsSender::class.java,
+ sut.influxDBMetricsManager::class.java,
+ ".influxDBMetricsManager.class"
+ )
}
- def "OK sample data is mapped correctly to InfluxDB tags and fields"() {
- given:
- def okSample = createOkSample()
- when:
- def tags = sut.createTags(okSample)
- def fields = sut.createFields(okSample)
- then:
- tags == "status=ok,transaction=myLabel,threadName=myThread"
- fields == "duration=100,ttfb=42,connectTime=7"
+ @Test
+ fun `OK sample data is mapped correctly to InfluxDB tags and fields`() {
+ val okSample = createOkSample()
+ assertEquals(
+ "status=ok,transaction=myLabel,threadName=myThread",
+ InfluxDBRawBackendListenerClient.createTags(okSample),
+ "createTags($okSample)"
+ )
+ assertEquals(
+ "duration=100,ttfb=42,connectTime=7",
+ InfluxDBRawBackendListenerClient.createFields(okSample),
+ "createFields($okSample)"
+ )
}
- def "Failed sample data is mapped correctly to InfluxDB tags and fields"() {
- given:
- def koSample = new SampleResult()
- koSample.setSampleLabel("myLabel")
- koSample.setThreadName("myThread")
- expect:
- sut.createTags(koSample) == "status=ko,transaction=myLabel,threadName=myThread"
+ @Test
+ fun `Failed sample data is mapped correctly to InfluxDB tags and fields`() {
+ val koSample = SampleResult().apply {
+ sampleLabel = "myLabel"
+ threadName = "myThread"
+ }
+ assertEquals(
+ "status=ko,transaction=myLabel,threadName=myThread",
+ InfluxDBRawBackendListenerClient.createTags(koSample),
+ "createTags($koSample)"
+ )
}
- def "Upon handling sample result data is added to influxDBMetricsManager and written"() {
- given:
- def mockSender = Mock(InfluxdbMetricsSender)
- def sut = new InfluxDBRawBackendListenerClient(mockSender)
- when:
- sut.handleSampleResults([createOkSample()], defaultContext)
- then:
- 1 * mockSender.addMetric(_, _, _, _)
- 1 * mockSender.writeAndSendMetrics()
+ @Test
+ fun `Upon handling sample result data is added to influxDBMetricsManager and written`() {
+ val mockSender = mockk<InfluxdbMetricsSender>(relaxed = true)
+ val sut = InfluxDBRawBackendListenerClient(mockSender)
+ sut.handleSampleResults(listOf(createOkSample()), defaultContext)
+ verifyOrder {
+ mockSender.addMetric(any(), any(), any(), any())
+ mockSender.writeAndSendMetrics()
+ }
}
- def "teardownTest calls destroy on influxDBMetricsManager"() {
- given:
- def mockSender = Mock(InfluxdbMetricsSender)
- def sut = new InfluxDBRawBackendListenerClient(mockSender)
- when:
- sut.teardownTest()
- then:
- 1 * mockSender.destroy()
+ @Test
+ fun `teardownTest calls destroy on influxDBMetricsManager`() {
+ val mockSender = mockk<InfluxdbMetricsSender>(relaxed = true)
+ val sut = InfluxDBRawBackendListenerClient(mockSender)
+ sut.teardownTest(defaultContext)
+ verify(exactly = 1) {
+ mockSender.destroy()
+ }
}
}
diff --git a/src/components/src/test/kotlin/org/apache/jmeter/visualizers/backend/influxdb/InfluxdbBackendListenerClientTest.kt b/src/components/src/test/kotlin/org/apache/jmeter/visualizers/backend/influxdb/InfluxdbBackendListenerClientTest.kt
index bb78784..03b5b53 100644
--- a/src/components/src/test/kotlin/org/apache/jmeter/visualizers/backend/influxdb/InfluxdbBackendListenerClientTest.kt
+++ b/src/components/src/test/kotlin/org/apache/jmeter/visualizers/backend/influxdb/InfluxdbBackendListenerClientTest.kt
@@ -18,32 +18,40 @@
package org.apache.jmeter.visualizers.backend.influxdb
import org.apache.jmeter.visualizers.backend.BackendListenerContext
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Test
-import spock.lang.Specification
+class InfluxdbBackendListenerClientTest {
-class InfluxdbBackendListenerClientSpec extends Specification {
+ val sut = InfluxdbBackendListenerClient()
+ private val defaultContext = BackendListenerContext(sut.getDefaultParameters())
- def sut = new InfluxdbBackendListenerClient()
- def defaultContext = new BackendListenerContext(sut.getDefaultParameters())
-
- def "setupTest with default config does not raise an exception"() {
- when:
- sut.setupTest(defaultContext)
- then:
- noExceptionThrown()
+ @Test
+ fun `setupTest with default config does not raise an exception`() {
+ sut.setupTest(defaultContext)
}
- def "Sending metrics when empty does not raise an exception"() {
- given:
- sut.setupTest(defaultContext)
- when:
- sut.run()
- then:
- noExceptionThrown()
+ @Test
+ fun `Sending metrics when empty does not raise an exception`() {
+ sut.setupTest(defaultContext)
+ sut.run()
}
- def "Default parameters are equal to default args"() {
- expect:
- sut.getDefaultParameters().getArgumentsAsMap() == InfluxdbBackendListenerClient.DEFAULT_ARGS
+ @Test
+ fun `Default parameters are equal to default args`() {
+ assertEquals(
+ mapOf(
+ "influxdbMetricsSender" to "org.apache.jmeter.visualizers.backend.influxdb.HttpMetricsSender",
+ "influxdbUrl" to "http://host_to_change:8086/write?db=jmeter",
+ "application" to "application name",
+ "measurement" to "jmeter",
+ "summaryOnly" to "false",
+ "samplersRegex" to ".*",
+ "percentiles" to "99;95;90",
+ "testTitle" to "Test name",
+ "eventTags" to ""
+ ),
+ sut.getDefaultParameters().getArgumentsAsMap()
+ )
}
}