Skip to content

Commit

Permalink
backport of performance test support from master
Browse files Browse the repository at this point in the history
  • Loading branch information
virgo47 committed Dec 7, 2020
1 parent ac93f8a commit 14a6699
Show file tree
Hide file tree
Showing 14 changed files with 769 additions and 5 deletions.
Expand Up @@ -20,6 +20,7 @@
import com.evolveum.midpoint.tools.testng.MidpointTestContext;
import com.evolveum.midpoint.tools.testng.MidpointTestMixin;
import com.evolveum.midpoint.tools.testng.SimpleMidpointTestContext;
import com.evolveum.midpoint.tools.testng.TestMonitor;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;

Expand All @@ -36,6 +37,17 @@ public abstract class AbstractSpringTest extends AbstractTestNGSpringContextTest
*/
protected final Trace logger = TraceManager.getTrace(getClass());

private TestMonitor testMonitor;

// called only by tests that need it
public void initializeTestMonitor() {
testMonitor = new TestMonitor();
}

public TestMonitor testMonitor() {
return testMonitor;
}

@BeforeClass
public void displayTestClassTitle() {
displayTestTitle("Initializing TEST CLASS: " + getClass().getName());
Expand Down Expand Up @@ -77,6 +89,8 @@ public MidpointTestContext getTestContext() {
* because test class instances are not GCed immediately.
* If they hold autowired fields like sessionFactory (for example
* through SqlRepositoryService impl), their memory footprint is getting big.
* This can manifest as failed test initialization because of OOM in modules like model-intest.
* Strangely, this will not fail the Jenkins build (but makes it much slower).
* <p>
* Note that this does not work for components injected through constructor into
* final fields - if we need this cleanup, make the field non-final.
Expand All @@ -93,7 +107,9 @@ private void clearClassFields(Object object, Class<?> forClass) throws Exception
}

for (Field field : forClass.getDeclaredFields()) {
if (Modifier.isFinal(field.getModifiers())
// we need to skip testMonitor to have it non-null in PerformanceTestMixin#dumpReport
if (field.getName().equals("testMonitor")
|| Modifier.isFinal(field.getModifiers())
|| Modifier.isStatic(field.getModifiers())
|| field.getType().isPrimitive()) {
continue;
Expand Down
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2010-2020 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/
package com.evolveum.midpoint.test.util;

import java.util.Comparator;

import com.evolveum.midpoint.schema.statistics.OperationsPerformanceInformationUtil;
import com.evolveum.midpoint.tools.testng.TestMonitor;
import com.evolveum.midpoint.tools.testng.TestReportSection;
import com.evolveum.midpoint.util.statistics.OperationsPerformanceMonitor;
import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationsPerformanceInformationType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.SingleOperationPerformanceInformationType;

public class TestReportUtil {

public static void reportPerfData(TestMonitor testMonitor) {
OperationsPerformanceInformationType performanceInformation =
OperationsPerformanceInformationUtil.toOperationsPerformanceInformationType(
OperationsPerformanceMonitor.INSTANCE.getGlobalPerformanceInformation());
TestReportSection section = testMonitor.addReportSection("globalPerformanceInformation")
.withColumns("Operation", "Count", "Total time (ms)", "Min", "Max", "Avg");

performanceInformation.getOperation().stream()
.sorted(Comparator.comparing(SingleOperationPerformanceInformationType::getTotalTime).reversed())
.forEach(op -> {
int count = zeroIfNull(op.getInvocationCount());
float totalTime = zeroIfNull(op.getTotalTime()) / 1000.0f;
section.addRow(
op.getName(),
count,
totalTime,
zeroIfNull(op.getMinTime()) / 1000.0f,
zeroIfNull(op.getMaxTime()) / 1000.0f,
avg(totalTime, count));
});
// TODO: How to adapt this to the code above? See OperationsPerformanceInformationPrinter for the details.
// OperationsPerformanceInformationUtil.format(performanceInformation,
// new AbstractStatisticsPrinter.Options(CSV, TIME), null, null));
}

// TODO: cleanup! taken from AbstractStatisticsPrinter
private static int zeroIfNull(Integer n) {
return n != null ? n : 0;
}

private static long zeroIfNull(Long n) {
return n != null ? n : 0;
}

private static Number avg(Number total, int count) {
return total != null && count > 0 ? total.floatValue() / count : null;
}
}
18 changes: 18 additions & 0 deletions pom.xml
Expand Up @@ -1755,6 +1755,7 @@
<!-- Testing dependencies are not troubling us from. -->
<ignoredUsedUndeclaredDependency>org.testng:testng</ignoredUsedUndeclaredDependency>
<ignoredUsedUndeclaredDependency>org.assertj:assertj-core</ignoredUsedUndeclaredDependency>
<ignoredUsedUndeclaredDependency>org.javasimon:javasimon-core</ignoredUsedUndeclaredDependency>

<!-- Unreliable detection -->
<ignoredUsedUndeclaredDependency>javax.xml.bind:jaxb-api</ignoredUsedUndeclaredDependency>
Expand Down Expand Up @@ -2084,6 +2085,23 @@
</properties>
</profile>

<!--
See Maven modules using this profile, e.g. schema or repo-impl-sql-test.
The profile is NOT active by default and typically configures this:
- Declares the right plugin (surefire or failsafe) depending on the one normally used in the module.
Technically, even both can be used, but go with the one used in that POM.
- Test testing plugin says skipTests=false (that is to run the tests).
- It defines system property mp.perf.report.prefix=target/PERF (without it CSV goes to stdout).
- It defines suiteXmlFile=testng-perf.xml - suite file is different then normaly used ones.
Typically, perf test classes are ONLY in perf suite as they would slow down default builds.
-->
<profile>
<id>perftest</id>
<properties>
<skipTests>true</skipTests>
</properties>
</profile>

<profile>
<id>jdk-11</id>
<!-- Don't change source level here, we still need the to support globally set level. -->
Expand Down
23 changes: 22 additions & 1 deletion repo/repo-sql-impl-test/pom.xml
Expand Up @@ -208,7 +208,6 @@
<plugins>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${failsafe.version}</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>testng-integration.xml</suiteXmlFile>
Expand All @@ -219,5 +218,27 @@
</plugins>
</build>
</profile>
<profile>
<id>perftest</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<skipTests>false</skipTests>
<systemPropertyVariables>
<mp.perf.report.prefix>target/PERF</mp.perf.report.prefix>
</systemPropertyVariables>
<suiteXmlFiles>
<suiteXmlFile>testng-perf.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
Expand Up @@ -12,6 +12,7 @@
import net.ttddyy.dsproxy.listener.QueryExecutionListener;
import org.springframework.stereotype.Component;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -61,6 +62,11 @@ public List<Entry> getEntries() {
return entries.get();
}

public boolean hasNoEntries() {
List<Entry> entries = getEntries();
return entries == null || entries.isEmpty();
}

public void clear() {
entries.remove();
}
Expand All @@ -74,13 +80,22 @@ public void stop() {
running.set(false);
}

public boolean isStarted() {
Boolean runningValue = running.get();
return runningValue != null && runningValue;
}

public void dump() {
dump(System.out);
}

public void dump(PrintStream out) {
List<Entry> entries = getEntries();
if (entries != null) {
System.out.println("Queries collected (" + entries.size() + "/" + getExecutionCount() + "):");
entries.forEach(e -> System.out.println(" [" + e.batchSize + "] " + e.query));
out.println("Queries collected (" + entries.size() + "/" + getExecutionCount() + "):");
entries.forEach(e -> out.println(" [" + e.batchSize + "] " + e.query));
} else {
System.out.println("Query collection was not started for this thread.");
out.println("Query collection was not started for this thread.");
}
}

Expand Down
Expand Up @@ -32,6 +32,7 @@
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.testng.AssertJUnit;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeSuite;
import org.xml.sax.SAXException;
Expand Down Expand Up @@ -66,6 +67,7 @@
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.test.util.AbstractSpringTest;
import com.evolveum.midpoint.test.util.InfraTestMixin;
import com.evolveum.midpoint.test.util.TestReportUtil;
import com.evolveum.midpoint.test.util.TestUtil;
import com.evolveum.midpoint.util.DebugDumpable;
import com.evolveum.midpoint.util.PrettyPrinter;
Expand Down Expand Up @@ -161,6 +163,13 @@ public void afterMethod(Method method) {
}
}

@AfterClass
public void reportPerfData() {
if (testMonitor() != null) {
TestReportUtil.reportPerfData(testMonitor());
}
}

protected boolean isUsingH2() {
return baseHelper.getConfiguration().isUsingH2();
}
Expand Down

0 comments on commit 14a6699

Please sign in to comment.