From ef8508b45b78aa871b4a6dfcef001c424a4f35af Mon Sep 17 00:00:00 2001 From: Fabio Burzigotti Date: Fri, 3 Jan 2020 00:02:11 +0100 Subject: [PATCH 1/2] Add tooling for Memory load tests Adding memory stress tests for MP OpenAPI: simple increase evaluation following multiple redeploy protocol --- arquillian.xml | 2 +- microprofile-open-api/pom.xml | 6 + ...eSubsequentDeploymentMemoryStressTest.java | 208 ++++++++++++++++++ .../IncreaseOverToleranceEvaluator.java | 80 +++++++ pom.xml | 1 + tooling-performance/pom.xml | 24 ++ .../tooling/performance/core/Gauge.java | 12 + .../core/MeasurementException.java | 23 ++ .../performance/core/MeasurementRecord.java | 7 + .../performance/core/StressTestEvaluator.java | 16 ++ .../performance/core/StressTestException.java | 23 ++ .../performance/core/StressTestOutcome.java | 8 + .../performance/core/StressTestProtocol.java | 10 + .../performance/core/StressTester.java | 37 ++++ .../memory/JMXBasedMemoryGauge.java | 181 +++++++++++++++ .../performance/memory/MemoryUsageRecord.java | 85 +++++++ .../MultipleRepeatableActionsProtocol.java | 51 +++++ 17 files changed, 773 insertions(+), 1 deletion(-) create mode 100644 microprofile-open-api/src/test/java/org/jboss/eap/qe/microprofile/openapi/performance/MultipleSubsequentDeploymentMemoryStressTest.java create mode 100644 microprofile-open-api/src/test/java/org/jboss/eap/qe/microprofile/openapi/performance/evaluation/IncreaseOverToleranceEvaluator.java create mode 100644 tooling-performance/pom.xml create mode 100644 tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/Gauge.java create mode 100644 tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/MeasurementException.java create mode 100644 tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/MeasurementRecord.java create mode 100644 tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTestEvaluator.java create mode 100644 tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTestException.java create mode 100644 tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTestOutcome.java create mode 100644 tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTestProtocol.java create mode 100644 tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTester.java create mode 100644 tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/memory/JMXBasedMemoryGauge.java create mode 100644 tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/memory/MemoryUsageRecord.java create mode 100644 tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/protocol/MultipleRepeatableActionsProtocol.java diff --git a/arquillian.xml b/arquillian.xml index 380a67fd..0b263a91 100644 --- a/arquillian.xml +++ b/arquillian.xml @@ -2,7 +2,7 @@ - + ${basedir}/target/jboss-as -server -Xms64m -Xmx512m diff --git a/microprofile-open-api/pom.xml b/microprofile-open-api/pom.xml index d2e8001d..94752efb 100644 --- a/microprofile-open-api/pom.xml +++ b/microprofile-open-api/pom.xml @@ -56,6 +56,12 @@ tooling-server-configuration test + + org.jboss.eap.qe + tooling-performance + 1.0.0.Final-SNAPSHOT + test + org.yaml snakeyaml diff --git a/microprofile-open-api/src/test/java/org/jboss/eap/qe/microprofile/openapi/performance/MultipleSubsequentDeploymentMemoryStressTest.java b/microprofile-open-api/src/test/java/org/jboss/eap/qe/microprofile/openapi/performance/MultipleSubsequentDeploymentMemoryStressTest.java new file mode 100644 index 00000000..e72d20e6 --- /dev/null +++ b/microprofile-open-api/src/test/java/org/jboss/eap/qe/microprofile/openapi/performance/MultipleSubsequentDeploymentMemoryStressTest.java @@ -0,0 +1,208 @@ +package org.jboss.eap.qe.microprofile.openapi.performance; + +import static io.restassured.RestAssured.get; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.not; + +import java.io.IOException; +import java.util.concurrent.Callable; + +import org.jboss.arquillian.container.test.api.ContainerController; +import org.jboss.arquillian.container.test.api.Deployer; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.container.test.api.RunAsClient; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.arquillian.junit.InSequence; +import org.jboss.arquillian.test.api.ArquillianResource; +import org.jboss.eap.qe.microprofile.openapi.apps.routing.provider.ProviderApplication; +import org.jboss.eap.qe.microprofile.openapi.apps.routing.provider.RoutingServiceConstants; +import org.jboss.eap.qe.microprofile.openapi.apps.routing.provider.api.DistrictService; +import org.jboss.eap.qe.microprofile.openapi.apps.routing.provider.data.DistrictEntity; +import org.jboss.eap.qe.microprofile.openapi.apps.routing.provider.model.District; +import org.jboss.eap.qe.microprofile.openapi.apps.routing.provider.rest.DistrictsResource; +import org.jboss.eap.qe.microprofile.openapi.apps.routing.provider.services.InMemoryDistrictService; +import org.jboss.eap.qe.microprofile.openapi.performance.evaluation.IncreaseOverToleranceEvaluator; +import org.jboss.eap.qe.microprofile.tooling.performance.core.*; +import org.jboss.eap.qe.microprofile.tooling.performance.memory.JMXBasedMemoryGauge; +import org.jboss.eap.qe.microprofile.tooling.performance.memory.MemoryUsageRecord; +import org.jboss.eap.qe.microprofile.tooling.performance.protocol.MultipleRepeatableActionsProtocol; +import org.jboss.eap.qe.microprofile.tooling.server.configuration.ConfigurationException; +import org.jboss.eap.qe.microprofile.tooling.server.configuration.arquillian.ArquillianContainerProperties; +import org.jboss.eap.qe.microprofile.tooling.server.configuration.arquillian.ArquillianDescriptorWrapper; +import org.jboss.eap.qe.microprofile.tooling.server.configuration.creaper.ManagementClientProvider; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.wildfly.extras.creaper.core.online.OnlineManagementClient; + +/** + * Memory stress test cases for multiple subsequent re-deployments + */ +@RunWith(Arquillian.class) +@RunAsClient +public class MultipleSubsequentDeploymentMemoryStressTest { + + private final static String PROVIDER_DEPLOYMENT_NAME = "serviceProviderDeployment"; + private final static int POST_DEPLOYMENT_GRACEFUL_WAIT_TIME_IN_MSEC = 1000; + private final static int OPENAPI_INCREASED_MEMORY_FOOTPRINT_TOLERANCE_PERCENT = 7; + private final static int SIMPLE_REDEPLOY_ITERATIONS = 100; + private final static int PROBING_INTERVAL_SIMPLE_REDEPLOY_ITERATIONS = SIMPLE_REDEPLOY_ITERATIONS; + private final static int LINEAR_FIT_SLOPE_COMPARISON_REDEPLOY_ITERATIONS = 64; + private final static int PROBING_INTERVAL_LINEAR_FIT_SLOPE_COMPARISON_REDEPLOY_ITERATIONS = 8; + private final static long MEGABYTE = 1024 * 1024; + private final static long MEMORY_INCREASE_TOLERANCE_IN_MB = 25 * MEGABYTE; + + private static ArquillianContainerProperties arquillianContainerProperties = new ArquillianContainerProperties( + ArquillianDescriptorWrapper.getArquillianDescriptor()); + private static OnlineManagementClient onlineManagementClient; + private static String openapiUrl; + + private static Gauge gauge; + + @ArquillianResource + private Deployer deployer; + + @ArquillianResource + private ContainerController contoller; + + @BeforeClass + public static void setup() + throws ConfigurationException, IOException { + + onlineManagementClient = ManagementClientProvider.onlineStandalone(); + + openapiUrl = String.format("http://%s:%d/openapi", + arquillianContainerProperties.getDefaultManagementAddress(), + 8080); + + gauge = new JMXBasedMemoryGauge(arquillianContainerProperties.getDefaultManagementAddress(), + arquillianContainerProperties.getDefaultManagementPort()); + } + + @AfterClass + public static void tearDown() throws IOException { + onlineManagementClient.close(); + } + + @Deployment(name = PROVIDER_DEPLOYMENT_NAME, managed = false, testable = false) + public static Archive serviceProviderDeployment() { + WebArchive deployment = ShrinkWrap.create( + WebArchive.class, PROVIDER_DEPLOYMENT_NAME + ".war") + .addClasses(ProviderApplication.class) + .addClasses( + District.class, + DistrictEntity.class, + DistrictService.class, + InMemoryDistrictService.class, + DistrictsResource.class, + RoutingServiceConstants.class) + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + return deployment; + } + + private Void executeSimpleRedeployActions() throws InterruptedException { + + deployer.deploy(PROVIDER_DEPLOYMENT_NAME); + Thread.sleep(POST_DEPLOYMENT_GRACEFUL_WAIT_TIME_IN_MSEC); + deployer.undeploy(PROVIDER_DEPLOYMENT_NAME); + + return null; + } + + private Void executeRedeploymentControlActions() throws InterruptedException { + + deployer.deploy(PROVIDER_DEPLOYMENT_NAME); + Thread.sleep(POST_DEPLOYMENT_GRACEFUL_WAIT_TIME_IN_MSEC); + + get(openapiUrl) + .then() + .statusCode(404); + + deployer.undeploy(PROVIDER_DEPLOYMENT_NAME); + + return null; + } + + private Void executeRedeploymentTestActions() throws InterruptedException { + + deployer.deploy(PROVIDER_DEPLOYMENT_NAME); + Thread.sleep(POST_DEPLOYMENT_GRACEFUL_WAIT_TIME_IN_MSEC); + + get(openapiUrl) + .then() + .statusCode(200) + .body(not(empty())); + + deployer.undeploy(PROVIDER_DEPLOYMENT_NAME); + + return null; + } + + /** + * @tpTestDetails Test to verify that a number of subsequent deployments doesn't cause memory leaks. + * This stress test executes the multiple subsequent re-deployments protocol and measures memory + * footprint at the beginning and at the end. + * @tpPassCrit Final value does not exceed initial value by more than + * {@link MultipleSubsequentDeploymentMemoryStressTest#MEMORY_INCREASE_TOLERANCE_IN_MB} + * @tpSince EAP 7.4.0.CD19 + */ + @Test + @InSequence(1) + public void testSimpleSeveralRedeployProtocol() throws StressTestException { + + // we have one tester which is going to take care of this stress test, it registers measurements + // as instances of MemoryUsageRecord and uses a gauge that accepts this data type + StressTester> tester = new StressTester(gauge); + + // this evaluator is intended to assess whether final value is showing an increase bigger than the + // accepted tolerance when compared to initial value + IncreaseOverToleranceEvaluator evaluator = new IncreaseOverToleranceEvaluator(MEMORY_INCREASE_TOLERANCE_IN_MB); + + // let's start with the test session: it defines a MultipleSubsequentDeploymentsProtocol to execute + // SIMPLE_REDEPLOY_ITERATIONS redeploy actions and will probe for memory footprint each + // PROBING_INTERVAL_SIMPLE_REDEPLOY_ITERATIONS attempts + StressTestProtocol simpleRedeployProtocol = new MultipleRepeatableActionsProtocol( + SIMPLE_REDEPLOY_ITERATIONS, + PROBING_INTERVAL_SIMPLE_REDEPLOY_ITERATIONS, + new Callable() { + @Override + public Void call() throws Exception { + return executeSimpleRedeployActions(); + } + }); + // start the container + contoller.start("jboss"); + + // initial value + try { + tester.probe(); + } catch (MeasurementException e) { + throw new StressTestException(e); + } + + // let the tester execute its test session following the protocol + tester.executeSession(simpleRedeployProtocol); + // stop the container + contoller.stop("jboss"); + + // report control values to the evaluator + evaluator.setInitialValue(tester.getCollectedValues().get(0).getHeapSpaceUsed()); + evaluator.setFinalValue(tester.getCollectedValues().get(tester.getCollectedValues().size() - 1).getHeapSpaceUsed()); + + // let's evaluate results for this initial stress test session using IncreaseOverToleranceEvaluator + IncreaseOverToleranceEvaluator.Outcome outcome = evaluator.evaluate(); + Long initialValue = outcome.getInitialValue(), finalValue = outcome.getFinalValue(); + Assert.assertTrue( + String.format( + "Memory consumption increase exceeds tolerance: (%s - %s) = %s > %s", + initialValue, finalValue, finalValue - initialValue, MEMORY_INCREASE_TOLERANCE_IN_MB, + OPENAPI_INCREASED_MEMORY_FOOTPRINT_TOLERANCE_PERCENT), + outcome.isPassed()); + } +} diff --git a/microprofile-open-api/src/test/java/org/jboss/eap/qe/microprofile/openapi/performance/evaluation/IncreaseOverToleranceEvaluator.java b/microprofile-open-api/src/test/java/org/jboss/eap/qe/microprofile/openapi/performance/evaluation/IncreaseOverToleranceEvaluator.java new file mode 100644 index 00000000..2db516a1 --- /dev/null +++ b/microprofile-open-api/src/test/java/org/jboss/eap/qe/microprofile/openapi/performance/evaluation/IncreaseOverToleranceEvaluator.java @@ -0,0 +1,80 @@ +package org.jboss.eap.qe.microprofile.openapi.performance.evaluation; + +import org.jboss.eap.qe.microprofile.tooling.performance.core.StressTestEvaluator; +import org.jboss.eap.qe.microprofile.tooling.performance.core.StressTestOutcome; + +/** + * This evaluator is intended to assess whether final value is showing an increase bigger than the + * accepted tolerance when compared to initial value + */ +public class IncreaseOverToleranceEvaluator implements StressTestEvaluator { + + private final Long tolerance; + private Long initialValue; + private Long finalValue; + + public IncreaseOverToleranceEvaluator(final Long tolerance) { + this.tolerance = tolerance; + } + + public Long getInitialValue() { + return initialValue; + } + + public void setInitialValue(Long initialValue) { + this.initialValue = initialValue; + } + + public Long getFinalValue() { + return finalValue; + } + + public void setFinalValue(Long finalValue) { + this.finalValue = finalValue; + } + + /** + * Outcome for this evaluator execution + */ + public static class Outcome implements StressTestOutcome { + + private final Long initialValue; + private final Long tolerance; + private final Long finalValue; + private final boolean passed; + + Outcome(final Long initialValue, final Long finalValue, final Long tolerance, final boolean passed) { + this.initialValue = initialValue; + this.tolerance = tolerance; + this.finalValue = finalValue; + this.passed = passed; + } + + public Long getInitialValue() { + return initialValue; + } + + public Long getFinalValue() { + return finalValue; + } + + public boolean isPassed() { + return passed; + } + + static Outcome success(final Long initialValue, final Long finalValue, final Long tolerance) { + return new Outcome(initialValue, finalValue, tolerance, true); + } + + static Outcome fail(final Long initialValue, final Long finalValue, final Long tolerance) { + return new Outcome(initialValue, finalValue, tolerance, false); + } + } + + public Outcome evaluate() { + if ((finalValue - initialValue) > tolerance) { + return Outcome.fail(initialValue, finalValue, tolerance); + } + return Outcome.success(initialValue, finalValue, tolerance); + } +} diff --git a/pom.xml b/pom.xml index b34903f1..1970449e 100644 --- a/pom.xml +++ b/pom.xml @@ -21,6 +21,7 @@ tooling-mp-jwt-auth-tool tooling-server-configuration microprofile-fault-tolerance + tooling-performance microprofile-health microprofile-jwt microprofile-metrics diff --git a/tooling-performance/pom.xml b/tooling-performance/pom.xml new file mode 100644 index 00000000..4665ce77 --- /dev/null +++ b/tooling-performance/pom.xml @@ -0,0 +1,24 @@ + + + + microprofile-test-suite + org.jboss.eap.qe + 1.0.0.Final-SNAPSHOT + + 4.0.0 + + tooling-performance + + + + junit + junit + + + org.fusesource.jansi + jansi + + + \ No newline at end of file diff --git a/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/Gauge.java b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/Gauge.java new file mode 100644 index 00000000..737bac59 --- /dev/null +++ b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/Gauge.java @@ -0,0 +1,12 @@ +package org.jboss.eap.qe.microprofile.tooling.performance.core; + +/** + * Defines the contract to implement a Gauge which is able to perform a measurement and return the results in + * a given data type * + * + * @param The data type to be used to register measurements + */ +public interface Gauge { + + R measure() throws MeasurementException; +} diff --git a/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/MeasurementException.java b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/MeasurementException.java new file mode 100644 index 00000000..793f2a64 --- /dev/null +++ b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/MeasurementException.java @@ -0,0 +1,23 @@ +package org.jboss.eap.qe.microprofile.tooling.performance.core; + +/** + * Represents memory footprint measurements related exceptions + */ +public class MeasurementException extends Exception { + + public MeasurementException() { + this(""); + } + + public MeasurementException(String message) { + super(message); + } + + public MeasurementException(String message, Throwable cause) { + super(message, cause); + } + + public MeasurementException(Throwable cause) { + super(cause); + } +} diff --git a/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/MeasurementRecord.java b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/MeasurementRecord.java new file mode 100644 index 00000000..79d4039f --- /dev/null +++ b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/MeasurementRecord.java @@ -0,0 +1,7 @@ +package org.jboss.eap.qe.microprofile.tooling.performance.core; + +/** + * Represents a measurement record. + */ +public interface MeasurementRecord { +} diff --git a/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTestEvaluator.java b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTestEvaluator.java new file mode 100644 index 00000000..5b927fe9 --- /dev/null +++ b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTestEvaluator.java @@ -0,0 +1,16 @@ +package org.jboss.eap.qe.microprofile.tooling.performance.core; + +/** + * Defines the contract to implement an evaluator for stress test results + * + * @param Type of outcome to be returned when {@link StressTestEvaluator#evaluate()} is called + */ +public interface StressTestEvaluator { + + /** + * Evaluates stress test results and returns an {@link StressTestOutcome} instance + * + * @return {@link StressTestOutcome} instance storing the test session results + */ + O evaluate(); +} diff --git a/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTestException.java b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTestException.java new file mode 100644 index 00000000..e0e824dc --- /dev/null +++ b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTestException.java @@ -0,0 +1,23 @@ +package org.jboss.eap.qe.microprofile.tooling.performance.core; + +/** + * Represents stress test related exceptions + */ +public class StressTestException extends Exception { + + public StressTestException() { + this(""); + } + + public StressTestException(String message) { + super(message); + } + + public StressTestException(String message, Throwable cause) { + super(message, cause); + } + + public StressTestException(Throwable cause) { + super(cause); + } +} diff --git a/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTestOutcome.java b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTestOutcome.java new file mode 100644 index 00000000..298e3f33 --- /dev/null +++ b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTestOutcome.java @@ -0,0 +1,8 @@ +package org.jboss.eap.qe.microprofile.tooling.performance.core; + +/** + * Defines the contract to implement an object storing stress test results + */ +public interface StressTestOutcome { + boolean isPassed(); +} diff --git a/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTestProtocol.java b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTestProtocol.java new file mode 100644 index 00000000..28e5a2fc --- /dev/null +++ b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTestProtocol.java @@ -0,0 +1,10 @@ +package org.jboss.eap.qe.microprofile.tooling.performance.core; + +/** + * Defines the contract to implement a stress test protocol that can communicate with an owning {@link StressTester} + * instance + */ +public interface StressTestProtocol { + + void run(StressTester owner) throws StressTestException; +} diff --git a/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTester.java b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTester.java new file mode 100644 index 00000000..aad97324 --- /dev/null +++ b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/core/StressTester.java @@ -0,0 +1,37 @@ +package org.jboss.eap.qe.microprofile.tooling.performance.core; + +import java.util.ArrayList; +import java.util.List; + +/** + * A stress tester that registers measurements as instances of {@link MemoryUsageRecord} and uses a + * {@link Gauge} that accepts this data type + * + * @param The data type to be used to register measurements + * @param The gauge type to be used to perform measurements + */ +public class StressTester> { + + private final G gauge; + private final List collectedValues = new ArrayList<>(); + + public StressTester(G gauge) { + this.gauge = gauge; + } + + public void probe() throws MeasurementException { + collectedValues.add(gauge.measure()); + } + + public void reset() { + collectedValues.clear(); + } + + public List getCollectedValues() { + return collectedValues; + } + + public void executeSession(StressTestProtocol protocol) throws StressTestException { + protocol.run(this); + } +} diff --git a/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/memory/JMXBasedMemoryGauge.java b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/memory/JMXBasedMemoryGauge.java new file mode 100644 index 00000000..30b4906c --- /dev/null +++ b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/memory/JMXBasedMemoryGauge.java @@ -0,0 +1,181 @@ +package org.jboss.eap.qe.microprofile.tooling.performance.memory; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.HashMap; +import java.util.Map; + +import javax.management.AttributeNotFoundException; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +import org.fusesource.jansi.Ansi; +import org.jboss.eap.qe.microprofile.tooling.performance.core.Gauge; +import org.jboss.eap.qe.microprofile.tooling.performance.core.MeasurementException; +import org.junit.Assert; + +/** + * JMX based implementation of {@link Gauge} + */ +public class JMXBasedMemoryGauge implements Gauge { + + private final static int GC_CALLS = 2; + private final static int POST_GC_GRACEFUL_WAIT_TIME_IN_MSEC = 1024 * (2); + + private final String address; + private final int port; + private final String url; + private final JMXServiceURL jmxServiceURL; + + public JMXBasedMemoryGauge(String address, int port) throws MalformedURLException { + this.address = address; + this.port = port; + this.url = String.format( + "service:jmx:remote+http://%s:%d", + address, + port); + jmxServiceURL = new JMXServiceURL(url); + } + + private static void forceGC(MBeanServerConnection mbeanConn) + throws MalformedObjectNameException, ReflectionException, MBeanException, InstanceNotFoundException, IOException { + Object ret = mbeanConn.invoke(new ObjectName("java.lang:type=Memory"), "gc", null, null); + Assert.assertNull(ret); + } + + private static MemoryUsageRecord performOneMeasurement(MBeanServerConnection mbeanConn) + throws MalformedObjectNameException, AttributeNotFoundException, MBeanException, + ReflectionException, IOException, InstanceNotFoundException { + + Map results = new HashMap<>(); + CompositeDataSupport edenSpace; + try { + edenSpace = (CompositeDataSupport) mbeanConn + .getAttribute(new ObjectName("java.lang:type=MemoryPool,name=PS Eden Space"), "Usage"); + } catch (InstanceNotFoundException ex) { + try { + edenSpace = (CompositeDataSupport) mbeanConn + .getAttribute(new ObjectName("java.lang:type=MemoryPool,name=Eden Space"), "Usage"); + } catch (InstanceNotFoundException probablyJdk11) { + edenSpace = (CompositeDataSupport) mbeanConn + .getAttribute(new ObjectName("java.lang:type=MemoryPool,name=G1 Eden Space"), "Usage"); + } + } + Long edenSpaceUsed = (Long) edenSpace.get("used"); + + CompositeDataSupport oldGen; + try { + oldGen = (CompositeDataSupport) mbeanConn.getAttribute(new ObjectName("java.lang:type=MemoryPool,name=PS Old Gen"), + "Usage"); + } catch (InstanceNotFoundException ex) { + try { + oldGen = (CompositeDataSupport) mbeanConn + .getAttribute(new ObjectName("java.lang:type=MemoryPool,name=Tenured Gen"), "Usage"); + } catch (InstanceNotFoundException probablyJdk11) { + oldGen = (CompositeDataSupport) mbeanConn + .getAttribute(new ObjectName("java.lang:type=MemoryPool,name=G1 Old Gen"), "Usage"); + } + } + Long oldGenUsed = (Long) oldGen.get("used"); + + CompositeDataSupport survivorSpace; + try { + survivorSpace = (CompositeDataSupport) mbeanConn + .getAttribute(new ObjectName("java.lang:type=MemoryPool,name=PS Survivor Space"), "Usage"); + } catch (InstanceNotFoundException ex) { + try { + survivorSpace = (CompositeDataSupport) mbeanConn + .getAttribute(new ObjectName("java.lang:type=MemoryPool,name=Survivor Space"), "Usage"); + } catch (InstanceNotFoundException probablyJdk11) { + survivorSpace = (CompositeDataSupport) mbeanConn + .getAttribute(new ObjectName("java.lang:type=MemoryPool,name=G1 Survivor Space"), "Usage"); + } + } + Long survivorSpaceUsed = (Long) survivorSpace.get("used"); + + CompositeDataSupport metaSpace; + try { + metaSpace = (CompositeDataSupport) mbeanConn + .getAttribute(new ObjectName("java.lang:type=MemoryPool,name=PS Perm Gen"), "Usage"); + } catch (InstanceNotFoundException ex) { + try { + metaSpace = (CompositeDataSupport) mbeanConn + .getAttribute(new ObjectName("java.lang:type=MemoryPool,name=Perm Gen"), "Usage"); + } catch (InstanceNotFoundException probablyJava8) { + // Java 8 doesn't have perm gen, it has meta space + metaSpace = (CompositeDataSupport) mbeanConn + .getAttribute(new ObjectName("java.lang:type=MemoryPool,name=Metaspace"), "Usage"); + } + } + Long metaSpaceUsed = (Long) metaSpace.get("used"); + + System.out.println( + "***************************************** Measurement report **************************"); + System.out.println(Ansi.ansi().reset().a("[Gauge]: ").fgCyan() + .a(String.format("Eden space:\t\t%s", edenSpaceUsed)).reset()); + System.out.println(Ansi.ansi().reset().a("[Gauge]: ").fgCyan() + .a(String.format("Old gen space:\t\t%s", oldGenUsed)).reset()); + System.out.println(Ansi.ansi().reset().a("[Gauge]: ").fgCyan() + .a(String.format("Survivor space:\t%s", survivorSpaceUsed)).reset()); + System.out.println(Ansi.ansi().reset().a("[Gauge]: ").fgCyan() + .a(String.format("Metaspace:\t\t%s", metaSpaceUsed)).reset()); + + MemoryUsageRecord record = new MemoryUsageRecord() + .edenGenSpaceUsed(edenSpaceUsed) + .oldGenSpaceUsed(oldGenUsed) + .metaSpaceUsed(metaSpaceUsed) + .survivorSpaceUsed(survivorSpaceUsed); + + System.out.println( + "***************************************** Used heap: " + record.getHeapSpaceUsed() + + " *************************"); + System.out.println( + "***************************************** Measured total: " + record.getTotalSpaceUsed() + + " *******************"); + return record; + } + + /** + * Measures current memory footprint for JVM server process. + * + * Performs a measurement using JMX MBeans. + * Current implementation must consider https://issues.redhat.com/projects/REMJMX/issues/REMJMX-168 + * thus we must set up a connection each time... + * + * @return Instance of {@link MemoryUsageRecord} storing results for different JVM memory segments (old gen, + * metaspace etc.) + * @throws MeasurementException Wrapper for exceptions thrown during memory measurement + */ + public MemoryUsageRecord measure() throws MeasurementException { + MemoryUsageRecord result = null; + + final JMXConnector jmxConnector; + try { + jmxConnector = JMXConnectorFactory.connect(jmxServiceURL, null); + final MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection(); + try { + for (int i = 0; i < GC_CALLS; i++) { + forceGC(mBeanServerConnection); + Thread.sleep(POST_GC_GRACEFUL_WAIT_TIME_IN_MSEC); + } + forceGC(mBeanServerConnection); + Thread.sleep(POST_GC_GRACEFUL_WAIT_TIME_IN_MSEC); + result = performOneMeasurement(mBeanServerConnection); + } finally { + jmxConnector.close(); + } + return result; + } catch (IOException | InterruptedException | AttributeNotFoundException | InstanceNotFoundException | MBeanException + | MalformedObjectNameException | ReflectionException e) { + throw new MeasurementException(e); + } + } +} diff --git a/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/memory/MemoryUsageRecord.java b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/memory/MemoryUsageRecord.java new file mode 100644 index 00000000..56f2df7f --- /dev/null +++ b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/memory/MemoryUsageRecord.java @@ -0,0 +1,85 @@ +package org.jboss.eap.qe.microprofile.tooling.performance.memory; + +import org.jboss.eap.qe.microprofile.tooling.performance.core.MeasurementRecord; + +/** + * Represents a record of data resulting from a memory footprint probe. + */ +public class MemoryUsageRecord implements MeasurementRecord { + + private Long edenGenSpaceUsed; + private Long metaSpaceUsed; + private Long oldGenSpaceUsed; + private Long survivorSpaceUsed; + + public MemoryUsageRecord() { + this(0L, 0L, 0L, 0L); + } + + public MemoryUsageRecord(Long edenGenSpaceUsed, Long metaSpaceUsed, Long oldGenSpaceUsed, Long surevivorSpace) { + this.edenGenSpaceUsed = edenGenSpaceUsed; + this.metaSpaceUsed = metaSpaceUsed; + this.oldGenSpaceUsed = oldGenSpaceUsed; + this.survivorSpaceUsed = surevivorSpace; + } + + public Long getEdenGenSpaceUsed() { + return edenGenSpaceUsed; + } + + public void setEdenGenSpaceUsed(Long edenGenSpaceUsed) { + this.edenGenSpaceUsed = edenGenSpaceUsed; + } + + public MemoryUsageRecord edenGenSpaceUsed(Long edenGenSpaceUsed) { + this.edenGenSpaceUsed = edenGenSpaceUsed; + return this; + } + + public Long getMetaSpaceUsed() { + return metaSpaceUsed; + } + + public void setMetaSpaceUsed(Long metaSpaceUsed) { + this.metaSpaceUsed = metaSpaceUsed; + } + + public MemoryUsageRecord metaSpaceUsed(Long metaSpaceUsed) { + this.metaSpaceUsed = metaSpaceUsed; + return this; + } + + public Long getOldGenSpaceUsed() { + return oldGenSpaceUsed; + } + + public void setOldGenSpaceUsed(Long oldGenSpaceUsed) { + this.oldGenSpaceUsed = oldGenSpaceUsed; + } + + public MemoryUsageRecord oldGenSpaceUsed(Long oldGenSpaceUsed) { + this.oldGenSpaceUsed = oldGenSpaceUsed; + return this; + } + + public Long getSurvivorSpaceUsed() { + return survivorSpaceUsed; + } + + public void setSurvivorSpaceUsed(Long survivorSpaceUsed) { + this.survivorSpaceUsed = survivorSpaceUsed; + } + + public MemoryUsageRecord survivorSpaceUsed(Long survivorSpaceUsed) { + this.survivorSpaceUsed = survivorSpaceUsed; + return this; + } + + public Long getHeapSpaceUsed() { + return edenGenSpaceUsed + oldGenSpaceUsed + survivorSpaceUsed; + } + + public Long getTotalSpaceUsed() { + return edenGenSpaceUsed + oldGenSpaceUsed + survivorSpaceUsed + metaSpaceUsed; + } +} diff --git a/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/protocol/MultipleRepeatableActionsProtocol.java b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/protocol/MultipleRepeatableActionsProtocol.java new file mode 100644 index 00000000..6cf325ea --- /dev/null +++ b/tooling-performance/src/main/java/org/jboss/eap/qe/microprofile/tooling/performance/protocol/MultipleRepeatableActionsProtocol.java @@ -0,0 +1,51 @@ +package org.jboss.eap.qe.microprofile.tooling.performance.protocol; + +import java.util.concurrent.Callable; + +import org.fusesource.jansi.Ansi; +import org.jboss.eap.qe.microprofile.tooling.performance.core.MeasurementException; +import org.jboss.eap.qe.microprofile.tooling.performance.core.StressTestException; +import org.jboss.eap.qe.microprofile.tooling.performance.core.StressTestProtocol; +import org.jboss.eap.qe.microprofile.tooling.performance.core.StressTester; + +/** + * A stress test protocol that performs multiple subsequent actions and asks the tester to perform a + * measurement every number of attempts + */ +public class MultipleRepeatableActionsProtocol implements StressTestProtocol { + + private final int redeployIterations; + private final int probingIntervalAttempts; + private final Callable repeatableActions; + + public MultipleRepeatableActionsProtocol(int redeployIterations, int probingIntervalAttempts, + Callable repeatableActions) { + this.redeployIterations = redeployIterations; + this.probingIntervalAttempts = probingIntervalAttempts; + this.repeatableActions = repeatableActions; + } + + @Override + public void run(StressTester tester) throws StressTestException { + + // run the whole specific protocol - i.e. deploy/updeploy several times and probe intermittently + for (int i = 1; i <= redeployIterations; i++) { + // actions to be done at each iteration + try { + repeatableActions.call(); + } catch (Exception e) { + throw new StressTestException(e); + } + System.out.println(Ansi.ansi().reset().a("[Protocol]: ").fgCyan() + .a(String.format("Attempt %d done...", i)).reset()); + if (i % (probingIntervalAttempts) == 0) { + // probe each PROBING_INTERVAL_ATTEMPTS + try { + tester.probe(); + } catch (MeasurementException e) { + throw new StressTestException(e); + } + } + } + } +} From 8b99917c244bb4884f44a429885b8859777c7980 Mon Sep 17 00:00:00 2001 From: Fabio Burzigotti Date: Wed, 19 Feb 2020 11:16:08 +0100 Subject: [PATCH 2/2] Adding memory leak stress test for MP Health, based on multiple re-deployments --- microprofile-health/pom.xml | 6 + ...eSubsequentDeploymentMemoryStressTest.java | 178 ++++++++++++++++++ .../IncreaseOverToleranceEvaluator.java | 80 ++++++++ ...eSubsequentDeploymentMemoryStressTest.java | 6 +- 4 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 microprofile-health/src/test/java/org/jboss/eap/qe/microprofile/health/performance/MultipleSubsequentDeploymentMemoryStressTest.java create mode 100644 microprofile-health/src/test/java/org/jboss/eap/qe/microprofile/health/performance/evaluation/IncreaseOverToleranceEvaluator.java diff --git a/microprofile-health/pom.xml b/microprofile-health/pom.xml index a412151c..5073d0e3 100644 --- a/microprofile-health/pom.xml +++ b/microprofile-health/pom.xml @@ -44,5 +44,11 @@ tooling-server-configuration test + + org.jboss.eap.qe + tooling-performance + 1.0.0.Final-SNAPSHOT + test + \ No newline at end of file diff --git a/microprofile-health/src/test/java/org/jboss/eap/qe/microprofile/health/performance/MultipleSubsequentDeploymentMemoryStressTest.java b/microprofile-health/src/test/java/org/jboss/eap/qe/microprofile/health/performance/MultipleSubsequentDeploymentMemoryStressTest.java new file mode 100644 index 00000000..f434db5a --- /dev/null +++ b/microprofile-health/src/test/java/org/jboss/eap/qe/microprofile/health/performance/MultipleSubsequentDeploymentMemoryStressTest.java @@ -0,0 +1,178 @@ +package org.jboss.eap.qe.microprofile.health.performance; + +import static io.restassured.RestAssured.get; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.not; + +import java.io.IOException; +import java.util.concurrent.Callable; + +import org.jboss.arquillian.container.test.api.ContainerController; +import org.jboss.arquillian.container.test.api.Deployer; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.container.test.api.RunAsClient; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.arquillian.junit.InSequence; +import org.jboss.arquillian.test.api.ArquillianResource; +import org.jboss.eap.qe.microprofile.health.BothHealthCheck; +import org.jboss.eap.qe.microprofile.health.LivenessHealthCheck; +import org.jboss.eap.qe.microprofile.health.ReadinessHealthCheck; +import org.jboss.eap.qe.microprofile.health.performance.evaluation.IncreaseOverToleranceEvaluator; +import org.jboss.eap.qe.microprofile.tooling.performance.core.Gauge; +import org.jboss.eap.qe.microprofile.tooling.performance.core.MeasurementException; +import org.jboss.eap.qe.microprofile.tooling.performance.core.StressTestException; +import org.jboss.eap.qe.microprofile.tooling.performance.core.StressTestProtocol; +import org.jboss.eap.qe.microprofile.tooling.performance.core.StressTester; +import org.jboss.eap.qe.microprofile.tooling.performance.memory.JMXBasedMemoryGauge; +import org.jboss.eap.qe.microprofile.tooling.performance.memory.MemoryUsageRecord; +import org.jboss.eap.qe.microprofile.tooling.performance.protocol.MultipleRepeatableActionsProtocol; +import org.jboss.eap.qe.microprofile.tooling.server.configuration.ConfigurationException; +import org.jboss.eap.qe.microprofile.tooling.server.configuration.arquillian.ArquillianContainerProperties; +import org.jboss.eap.qe.microprofile.tooling.server.configuration.arquillian.ArquillianDescriptorWrapper; +import org.jboss.eap.qe.microprofile.tooling.server.configuration.creaper.ManagementClientProvider; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.wildfly.extras.creaper.core.online.OnlineManagementClient; + +/** + * Memory stress test cases for multiple subsequent re-deployments + */ +@RunWith(Arquillian.class) +@RunAsClient +public class MultipleSubsequentDeploymentMemoryStressTest { + + private final static String DEPLOYMENT_NAME = "deployment-1"; + private final static int POST_DEPLOYMENT_GRACEFUL_WAIT_TIME_IN_MSEC = 1000; + private final static int INCREASED_MEMORY_FOOTPRINT_TOLERANCE_PERCENT = 7; + private final static int SIMPLE_REDEPLOY_ITERATIONS = 100; + private final static int PROBING_INTERVAL_SIMPLE_REDEPLOY_ITERATIONS = SIMPLE_REDEPLOY_ITERATIONS; + private final static int LINEAR_FIT_SLOPE_COMPARISON_REDEPLOY_ITERATIONS = 64; + private final static int PROBING_INTERVAL_LINEAR_FIT_SLOPE_COMPARISON_REDEPLOY_ITERATIONS = 8; + private final static long MEGABYTE = 1024 * 1024; + private final static long MEMORY_INCREASE_TOLERANCE_IN_MB = 25 * MEGABYTE; + + private static ArquillianContainerProperties arquillianContainerProperties = new ArquillianContainerProperties( + ArquillianDescriptorWrapper.getArquillianDescriptor()); + private static OnlineManagementClient onlineManagementClient; + private static String healthUrl; + + private static Gauge gauge; + + @ArquillianResource + private Deployer deployer; + + @ArquillianResource + private ContainerController contoller; + + @BeforeClass + public static void setup() + throws ConfigurationException, IOException { + + onlineManagementClient = ManagementClientProvider.onlineStandalone(); + + healthUrl = String.format("http://%s:%d/health", + arquillianContainerProperties.getDefaultManagementAddress(), + arquillianContainerProperties.getDefaultManagementPort()); + + gauge = new JMXBasedMemoryGauge(arquillianContainerProperties.getDefaultManagementAddress(), + arquillianContainerProperties.getDefaultManagementPort()); + } + + @AfterClass + public static void tearDown() throws IOException { + onlineManagementClient.close(); + } + + @Deployment(name = DEPLOYMENT_NAME, managed = false, testable = false) + public static Archive serviceProviderDeployment() { + WebArchive deployment = ShrinkWrap.create( + WebArchive.class, DEPLOYMENT_NAME + ".war") + .addClasses(BothHealthCheck.class, LivenessHealthCheck.class, ReadinessHealthCheck.class) + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + return deployment; + } + + private Void executeSimpleRedeployActions() throws InterruptedException { + + deployer.deploy(DEPLOYMENT_NAME); + Thread.sleep(POST_DEPLOYMENT_GRACEFUL_WAIT_TIME_IN_MSEC); + String response = get(healthUrl) + .then() + .statusCode(200) + .body(not(empty())) + .extract().asString(); + System.out.println(response); + deployer.undeploy(DEPLOYMENT_NAME); + + return null; + } + + /** + * @tpTestDetails Test to verify that a number of subsequent deployments doesn't cause memory leaks. + * This stress test executes the multiple subsequent re-deployments protocol and measures memory + * footprint at the beginning and at the end. + * @tpPassCrit Final value does not exceed initial value by more than + * {@link MultipleSubsequentDeploymentMemoryStressTest#MEMORY_INCREASE_TOLERANCE_IN_MB} + * @tpSince EAP 7.4.0.CD19 + */ + @Test + @InSequence(1) + public void testSimpleSeveralRedeployProtocol() throws StressTestException { + + // we have one tester which is going to take care of this stress test, it registers measurements + // as instances of MemoryUsageRecord and uses a gauge that accepts this data type + StressTester> tester = new StressTester(gauge); + + // this evaluator is intended to assess whether final value is showing an increase bigger than the + // accepted tolerance when compared to initial value + IncreaseOverToleranceEvaluator evaluator = new IncreaseOverToleranceEvaluator(MEMORY_INCREASE_TOLERANCE_IN_MB); + + // let's start with the test session: it defines a MultipleSubsequentDeploymentsProtocol to execute + // SIMPLE_REDEPLOY_ITERATIONS redeploy actions and will probe for memory footprint each + // PROBING_INTERVAL_SIMPLE_REDEPLOY_ITERATIONS attempts + StressTestProtocol simpleRedeployProtocol = new MultipleRepeatableActionsProtocol( + SIMPLE_REDEPLOY_ITERATIONS, + PROBING_INTERVAL_SIMPLE_REDEPLOY_ITERATIONS, + new Callable() { + @Override + public Void call() throws Exception { + return executeSimpleRedeployActions(); + } + }); + // start the container + contoller.start("jboss"); + + // initial value + try { + tester.probe(); + } catch (MeasurementException e) { + throw new StressTestException(e); + } + + // let the tester execute its test session following the protocol + tester.executeSession(simpleRedeployProtocol); + // stop the container + contoller.stop("jboss"); + + // report control values to the evaluator + evaluator.setInitialValue(tester.getCollectedValues().get(0).getHeapSpaceUsed()); + evaluator.setFinalValue(tester.getCollectedValues().get(tester.getCollectedValues().size() - 1).getHeapSpaceUsed()); + + // let's evaluate results for this initial stress test session using IncreaseOverToleranceEvaluator + IncreaseOverToleranceEvaluator.Outcome outcome = evaluator.evaluate(); + Long initialValue = outcome.getInitialValue(), finalValue = outcome.getFinalValue(); + Assert.assertTrue( + String.format( + "Memory consumption increase exceeds tolerance: (%s - %s) = %s > %s", + initialValue, finalValue, finalValue - initialValue, MEMORY_INCREASE_TOLERANCE_IN_MB, + INCREASED_MEMORY_FOOTPRINT_TOLERANCE_PERCENT), + outcome.isPassed()); + } +} diff --git a/microprofile-health/src/test/java/org/jboss/eap/qe/microprofile/health/performance/evaluation/IncreaseOverToleranceEvaluator.java b/microprofile-health/src/test/java/org/jboss/eap/qe/microprofile/health/performance/evaluation/IncreaseOverToleranceEvaluator.java new file mode 100644 index 00000000..76d4ea49 --- /dev/null +++ b/microprofile-health/src/test/java/org/jboss/eap/qe/microprofile/health/performance/evaluation/IncreaseOverToleranceEvaluator.java @@ -0,0 +1,80 @@ +package org.jboss.eap.qe.microprofile.health.performance.evaluation; + +import org.jboss.eap.qe.microprofile.tooling.performance.core.StressTestEvaluator; +import org.jboss.eap.qe.microprofile.tooling.performance.core.StressTestOutcome; + +/** + * This evaluator is intended to assess whether final value is showing an increase bigger than the + * accepted tolerance when compared to initial value + */ +public class IncreaseOverToleranceEvaluator implements StressTestEvaluator { + + private final Long tolerance; + private Long initialValue; + private Long finalValue; + + public IncreaseOverToleranceEvaluator(final Long tolerance) { + this.tolerance = tolerance; + } + + public Long getInitialValue() { + return initialValue; + } + + public void setInitialValue(Long initialValue) { + this.initialValue = initialValue; + } + + public Long getFinalValue() { + return finalValue; + } + + public void setFinalValue(Long finalValue) { + this.finalValue = finalValue; + } + + /** + * Outcome for this evaluator execution + */ + public static class Outcome implements StressTestOutcome { + + private final Long initialValue; + private final Long tolerance; + private final Long finalValue; + private final boolean passed; + + Outcome(final Long initialValue, final Long finalValue, final Long tolerance, final boolean passed) { + this.initialValue = initialValue; + this.tolerance = tolerance; + this.finalValue = finalValue; + this.passed = passed; + } + + public Long getInitialValue() { + return initialValue; + } + + public Long getFinalValue() { + return finalValue; + } + + public boolean isPassed() { + return passed; + } + + static Outcome success(final Long initialValue, final Long finalValue, final Long tolerance) { + return new Outcome(initialValue, finalValue, tolerance, true); + } + + static Outcome fail(final Long initialValue, final Long finalValue, final Long tolerance) { + return new Outcome(initialValue, finalValue, tolerance, false); + } + } + + public Outcome evaluate() { + if ((finalValue - initialValue) > tolerance) { + return Outcome.fail(initialValue, finalValue, tolerance); + } + return Outcome.success(initialValue, finalValue, tolerance); + } +} diff --git a/microprofile-open-api/src/test/java/org/jboss/eap/qe/microprofile/openapi/performance/MultipleSubsequentDeploymentMemoryStressTest.java b/microprofile-open-api/src/test/java/org/jboss/eap/qe/microprofile/openapi/performance/MultipleSubsequentDeploymentMemoryStressTest.java index e72d20e6..778249fa 100644 --- a/microprofile-open-api/src/test/java/org/jboss/eap/qe/microprofile/openapi/performance/MultipleSubsequentDeploymentMemoryStressTest.java +++ b/microprofile-open-api/src/test/java/org/jboss/eap/qe/microprofile/openapi/performance/MultipleSubsequentDeploymentMemoryStressTest.java @@ -22,7 +22,11 @@ import org.jboss.eap.qe.microprofile.openapi.apps.routing.provider.rest.DistrictsResource; import org.jboss.eap.qe.microprofile.openapi.apps.routing.provider.services.InMemoryDistrictService; import org.jboss.eap.qe.microprofile.openapi.performance.evaluation.IncreaseOverToleranceEvaluator; -import org.jboss.eap.qe.microprofile.tooling.performance.core.*; +import org.jboss.eap.qe.microprofile.tooling.performance.core.Gauge; +import org.jboss.eap.qe.microprofile.tooling.performance.core.MeasurementException; +import org.jboss.eap.qe.microprofile.tooling.performance.core.StressTestException; +import org.jboss.eap.qe.microprofile.tooling.performance.core.StressTestProtocol; +import org.jboss.eap.qe.microprofile.tooling.performance.core.StressTester; import org.jboss.eap.qe.microprofile.tooling.performance.memory.JMXBasedMemoryGauge; import org.jboss.eap.qe.microprofile.tooling.performance.memory.MemoryUsageRecord; import org.jboss.eap.qe.microprofile.tooling.performance.protocol.MultipleRepeatableActionsProtocol;