/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule; import static java.lang.System.getProperty; import static java.util.Collections.EMPTY_MAP; import static org.hamcrest.Matchers.lessThanOrEqualTo; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import org.mule.tck.junit4.AbstractMuleTestCase; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import org.openjdk.jmh.profile.GCProfiler; import org.openjdk.jmh.results.RunResult; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.ChainedOptionsBuilder; import org.openjdk.jmh.runner.options.OptionsBuilder; /** * Base class for creating benchmark assertion tests allowing JMH benchmark results to be asserted using JUnit tests with * Hamcrest. */ public abstract class AbstractBenchmarkAssertionTestCase extends AbstractMuleTestCase { private static final String ENABLE_PERFORMANCE_TESTS_SYSTEM_PROPERTY = "enablePerformanceTests"; private static final String NORM_ALLOCATION_RESULT_KEY = "�gc.alloc.rate.norm"; @Override public int getTestTimeoutSecs() { return 5 * 60; } /** * Run a JMH benchmark and assert that the primary result is less than or equal to an expected value. * * @param clazz the JMS benchmark class. * @param testName the name of the test method. * @param expectedResult the expected minimum minimum result value. * @param timeUnit the time unit of the expected result value. */ protected void runAndAssertBenchmark(Class clazz, String testName, final double expectedResult, TimeUnit timeUnit) { runAndAssertBenchmark(clazz, testName, 1, expectedResult, timeUnit); } /** * Run a JMH benchmark and assert that the primary result is less than or equal to an expected value. * * @param clazz the JMS benchmark class. * @param testName the name of the test method. * @param expectedResult the expected minimum minimum result value. * @param timeUnit the time unit of the expected result value. * @param expectedAllocation the expected maximum allocation in bytes per benchmark iteration. */ protected void runAndAssertBenchmark(Class clazz, String testName, final double expectedResult, TimeUnit timeUnit, double expectedAllocation) { runAndAssertBenchmark(clazz, testName, 1, EMPTY_MAP, expectedResult, timeUnit, expectedAllocation); } /** * Run a JMH benchmark and assert that the primary result is less than or equal to an expected value. * * @param clazz the JMS benchmark class. * @param testName the name of the test method. * @param threads the number of threads to run benchmark with. * @param expectedResult the expected minimum minimum result value. * @param timeUnit the time unit of the expected result value. */ protected void runAndAssertBenchmark(Class clazz, String testName, int threads, final double expectedResult, TimeUnit timeUnit) { runAndAssertBenchmark(clazz, testName, threads, EMPTY_MAP, timeUnit, false, runResult -> assertThat(runResult.getPrimaryResult().getScore(), lessThanOrEqualTo(expectedResult))); } /** * Run a JMH benchmark and assert that the primary result is less than or equal to an expected value. * * @param clazz the JMS benchmark class. * @param testName the name of the test method. * @param threads the number of threads to run benchmark with. * @param params parameters along with array of parameters values to be applied to the benchmark. * @param expectedResult the expected minimum minimum result value. * @param timeUnit the time unit of the expected result value. * @param expectedAllocation the expected maximum allocation in bytes per benchmark iteration. */ protected void runAndAssertBenchmark(Class clazz, String testName, int threads, Map<String, String[]> params, final double expectedResult, TimeUnit timeUnit, final double expectedAllocation) { runAndAssertBenchmark(clazz, testName, threads, params, timeUnit, true, runResult -> { assertThat(runResult.getPrimaryResult().getScore(), lessThanOrEqualTo(expectedResult)); assertThat(runResult.getSecondaryResults().get(NORM_ALLOCATION_RESULT_KEY).getScore(), lessThanOrEqualTo(expectedAllocation)); }); } /** * Run a JMH benchmark and assert that the primary result is less than or equal to an expected value. * * @param clazz the JMS benchmark class. * @param testName the name of the test method. * @param threads the number of threads to run benchmark with. * @param params parameters along with array of parameters values to be applied to the benchmark. * @param timeUnit the time unit of the expected result value. * @param assertions assertion consumer. */ protected void runAndAssertBenchmark(Class clazz, String testName, int threads, Map<String, String[]> params, TimeUnit timeUnit, boolean profileGC, Consumer<RunResult> assertions) { try { if (getProperty(ENABLE_PERFORMANCE_TESTS_SYSTEM_PROPERTY) != null) { ChainedOptionsBuilder optionsBuilder = createCommonOptionsBuilder(clazz, testName, params, timeUnit, profileGC); optionsBuilder = optionsBuilder .forks(1) .threads(threads) .warmupIterations(10) .measurementIterations(10); assertions.accept(new Runner(optionsBuilder.build()).runSingle()); } else { ChainedOptionsBuilder optionsBuilder = createCommonOptionsBuilder(clazz, testName, params, timeUnit, profileGC); optionsBuilder = optionsBuilder .forks(0) .warmupIterations(0) .measurementIterations(1); new Runner(optionsBuilder.build()).runSingle(); } } catch (RunnerException e) { fail(e.getMessage()); e.printStackTrace(); } } private ChainedOptionsBuilder createCommonOptionsBuilder(Class clazz, String testName, Map<String, String[]> params, TimeUnit timeUnit, boolean profileGC) { ChainedOptionsBuilder optionsBuilder = new OptionsBuilder(); optionsBuilder = optionsBuilder .include(clazz.getSimpleName() + "." + testName + "$") .timeUnit(timeUnit); if (profileGC) { optionsBuilder = optionsBuilder.addProfiler(GCProfiler.class); } for (Entry<String, String[]> entries : params.entrySet()) { optionsBuilder = optionsBuilder.param(entries.getKey(), entries.getValue()); } return optionsBuilder; } }