Skip to content

Commit

Permalink
Merge pull request #563 from camunda-community-hub/bug/#561_no_active…
Browse files Browse the repository at this point in the history
…_run_for_manual_deployment

bug: #561 allow test method without deployment and log missing coverage
  • Loading branch information
rohwerj authored Jun 10, 2024
2 parents b72be41 + 1043afd commit 71c5cb3
Show file tree
Hide file tree
Showing 12 changed files with 146 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,18 @@
import org.camunda.bpm.engine.test.Deployment;
import org.camunda.community.process_test_coverage.junit5.platform7.ProcessEngineCoverageExtension;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;

import static org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareTests.*;

// you can either use @ExtendWith on the test class
//@ExtendWith(ProcessEngineCoverageExtension.class)
@Deployment(resources = "order-process.bpmn")
public class OrderProcessTest {

// or register the extension as a public static field
@RegisterExtension
public static ProcessEngineCoverageExtension extension = ProcessEngineExtensionProvider.extension;
// public static ProcessEngineCoverageExtension extension = ProcessEngineCoverageExtension.builder(
// new ProcessCoverageInMemProcessEngineConfiguration().setHistory(ProcessEngineConfiguration.HISTORY_FULL)).build();

@Test
public void shouldExecuteHappyPath() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
/*-
* #%L
* Camunda Process Test Coverage JUnit5 Common
* %%
* Copyright (C) 2019 - 2024 Camunda
* %%
* Licensed 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.
* #L%
*/
package org.camunda.community.process_test_coverage.junit5.common

import mu.KLogging
import org.assertj.core.api.Assertions
import org.assertj.core.api.Condition
import org.camunda.community.process_test_coverage.core.engine.ExcludeFromProcessCoverage
import org.camunda.community.process_test_coverage.core.model.DefaultCollector
import org.camunda.community.process_test_coverage.core.model.Run
import org.camunda.community.process_test_coverage.core.model.Suite
Expand Down Expand Up @@ -42,68 +62,57 @@ class ProcessEngineCoverageExtensionHelper(
private var suiteInitialized = false

fun beforeAll(context: ExtensionContext) {
if (!suiteInitialized || (context.uniqueId != context.getActiveSuiteContextId()) && !isNested(context)) {
if (!isTestClassExcluded(context)
&& (!suiteInitialized || (context.uniqueId != context.getActiveSuiteContextId()) && !isNested(context))) {
initializeSuite(context, context.displayName)
}
}

fun afterAll(context: ExtensionContext) {
if (context.uniqueId == context.getActiveSuiteContextId()) {
// only generate report and coverage if the current context is the one, that started the suite
if (!isTestClassExcluded(context) && context.uniqueId == context.getActiveSuiteContextId()) {
val suite = coverageCollector.activeSuite

// only generate report and coverage if the current context is the one, that started the suite

// Make sure the class coverage deals with the same deployments for
// every test method
// classCoverage.assertAllDeploymentsEqual();

/*-
* #%L
* Camunda Process Test Coverage JUnit5 Common
* %%
* Copyright (C) 2019 - 2024 Camunda
* %%
* Licensed 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.
* #L%
*/
val suiteCoveragePercentage = suite.calculateCoverage(coverageCollector.getModels())

// Log coverage percentage
logger.info("${suite.name} test class coverage is: $suiteCoveragePercentage")
logCoverageDetail(suite)
if (suiteCoveragePercentage.isNaN()) {
logger.warn { "${suite.name} test class coverage could not be calculated, check configuration" }
} else {

// Create graphical report
CoverageReportUtil.createReport(coverageCollector)
CoverageReportUtil.createJsonReport(coverageCollector)
// Log coverage percentage
logger.info("${suite.name} test class coverage is: $suiteCoveragePercentage")
logCoverageDetail(suite)

assertCoverage(suiteCoveragePercentage, classCoverageAssertionConditions)
// Create graphical report
CoverageReportUtil.createReport(coverageCollector)
CoverageReportUtil.createJsonReport(coverageCollector)

assertCoverage(suiteCoveragePercentage, classCoverageAssertionConditions)
}
}
}

fun beforeTestExecution(context: ExtensionContext) {
if (!suiteInitialized) {
initializeSuite(context, context.requiredTestClass.name)
if (!isTestMethodExcluded(context)) {
if (!suiteInitialized) {
initializeSuite(context, context.requiredTestClass.name)
}
// method name is set only on test methods (not on classes or suites)
val runId: String = context.uniqueId
coverageCollector.createRun(Run(runId, context.displayName), coverageCollector.activeSuite.id)
coverageCollector.activateRun(runId)
}
// method name is set only on test methods (not on classes or suites)
val runId: String = context.uniqueId
coverageCollector.createRun(Run(runId, context.displayName), coverageCollector.activeSuite.id)
coverageCollector.activateRun(runId)

}

fun isTestMethodExcluded(context: ExtensionContext) =
context.requiredTestClass.annotations.any { it is ExcludeFromProcessCoverage }
|| context.requiredTestMethod.annotations.any { it is ExcludeFromProcessCoverage }

private fun isTestClassExcluded(context: ExtensionContext) =
context.requiredTestClass.annotations.any { it is ExcludeFromProcessCoverage }

fun afterTestExecution(context: ExtensionContext) {
if (handleTestMethodCoverage) {
if (!isTestMethodExcluded(context) && handleTestMethodCoverage) {
handleTestMethodCoverage(context)
}
}
Expand Down Expand Up @@ -162,12 +171,16 @@ class ProcessEngineCoverageExtensionHelper(
val run = suite.getRun(context.uniqueId) ?: return
val coveragePercentage = run.calculateCoverage(coverageCollector.getModels())

// Log coverage percentage
logger.info("${run.name} test method coverage is $coveragePercentage")
logCoverageDetail(run)
if (coveragePercentage.isNaN()) {
logger.warn { "${run.name} test method coverage could not be calculated, check configuration" }
} else {
// Log coverage percentage
logger.info("${run.name} test method coverage is $coveragePercentage")
logCoverageDetail(run)

testMethodNameToCoverageConditions[run.name]?.let {
assertCoverage(coveragePercentage, it)
testMethodNameToCoverageConditions[run.name]?.let {
assertCoverage(coveragePercentage, it)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,15 @@
package org.camunda.community.process_test_coverage.junit5.platform7

import mu.KLogging
import org.assertj.core.api.Assertions
import org.assertj.core.api.Condition
import org.camunda.bpm.engine.ProcessEngineConfiguration
import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl
import org.camunda.bpm.engine.test.junit5.ProcessEngineExtension
import org.camunda.community.process_test_coverage.core.model.DefaultCollector
import org.camunda.community.process_test_coverage.core.model.Run
import org.camunda.community.process_test_coverage.core.model.Suite
import org.camunda.community.process_test_coverage.engine.platform7.ExecutionContextModelProvider
import org.camunda.community.process_test_coverage.engine.platform7.ProcessEngineAdapter
import org.camunda.community.process_test_coverage.junit5.common.ProcessEngineCoverageExtensionBuilder
import org.camunda.community.process_test_coverage.junit5.common.ProcessEngineCoverageExtensionHelper
import org.camunda.community.process_test_coverage.report.CoverageReportUtil
import org.junit.jupiter.api.extension.AfterAllCallback
import org.junit.jupiter.api.extension.BeforeAllCallback
import org.junit.jupiter.api.extension.ExtensionContext
Expand Down Expand Up @@ -90,6 +86,7 @@ class ProcessEngineCoverageExtension(

override fun postProcessTestInstance(testInstance: Any?, context: ExtensionContext) {
super.postProcessTestInstance(testInstance, context)
initializeServices()
ProcessEngineAdapter(processEngine, coverageCollector).initializeListeners()
}

Expand All @@ -98,16 +95,14 @@ class ProcessEngineCoverageExtension(
*/
override fun beforeTestExecution(context: ExtensionContext) {
super.beforeTestExecution(context)
if (isRelevantTestMethod()) {
processEngineCoverageExtensionHelper.beforeTestExecution(context)
}
processEngineCoverageExtensionHelper.beforeTestExecution(context)
}

/**
* Handles evaluating the test method coverage after a relevant test method is finished.
*/
override fun afterTestExecution(context: ExtensionContext) {
if (isRelevantTestMethod()) {
if (!processEngineCoverageExtensionHelper.isTestMethodExcluded(context)) {
processEngineCoverageExtensionHelper.afterTestExecution(context)
}
super.afterTestExecution(context)
Expand All @@ -127,23 +122,7 @@ class ProcessEngineCoverageExtension(
*/
override fun afterAll(context: ExtensionContext) {
processEngineCoverageExtensionHelper.afterAll(context)
}

/**
* Determines if the provided Description describes a method relevant for coverage metering. This is the case,
* if the Description is provided for an atomic test and the test has access to deployed process.
*
* @return `true` if the description is provided for the relevant method.
*/
private fun isRelevantTestMethod(): Boolean {
return super.deploymentId != null // deployment is set
// the deployed process is not excluded
&& processEngine.repositoryService
.createProcessDefinitionQuery()
.deploymentId(deploymentId)
.list().any {
!excludedProcessDefinitionKeys.contains(it.key)
}
super.afterAll(context)
}

fun addTestMethodCoverageCondition(methodName: String, condition: Condition<Double>) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class ProcessEngineCoverageExtension(
* Handles creating the run if a relevant test method is called.
*/
override fun beforeTestExecution(context: ExtensionContext) {
if (!isTestMethodExcluded(context)) {
if (!processEngineCoverageExtensionHelper.isTestMethodExcluded(context)) {
processEngineCoverageExtensionHelper.beforeTestExecution(context)
methodRecordPosition[context.requiredTestMethod.name] = BpmnAssert.getRecordStream().records().maxOfOrNull { it.position } ?: -1
}
Expand All @@ -99,16 +99,12 @@ class ProcessEngineCoverageExtension(
* Handles evaluating the test method coverage after a relevant test method is finished.
*/
override fun afterTestExecution(context: ExtensionContext) {
if (!isTestMethodExcluded(context)) {
if (!processEngineCoverageExtensionHelper.isTestMethodExcluded(context)) {
createEvents(coverageCollector, methodRecordPosition[context.requiredTestMethod.name]!!)
processEngineCoverageExtensionHelper.afterTestExecution(context)
}
}

private fun isTestMethodExcluded(context: ExtensionContext) =
context.requiredTestClass.annotations.any { it is ExcludeFromProcessCoverage }
|| context.requiredTestMethod.annotations.any { it is ExcludeFromProcessCoverage }

/**
* Initializes the suite for all upcoming tests.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,22 @@ abstract class BaseProcessEngineCoverageTestExecutionListener : TestExecutionLis

val suiteCoveragePercentage = suite.calculateCoverage(getCoverageCollector().getModels())

// Log coverage percentage
logger.info("${suite.name} test class coverage is: $suiteCoveragePercentage")
logCoverageDetail(suite)

// Create graphical report
CoverageReportUtil.createReport(getCoverageCollector())
CoverageReportUtil.createJsonReport(getCoverageCollector())

assertCoverage(suiteCoveragePercentage, processEngineCoverageProperties.classCoverageAssertionConditions)
if (suiteCoveragePercentage.isNaN()) {
logger.warn { "${suite.name} test class coverage could not be calculated, check configuration" }
} else {
// Log coverage percentage
logger.info("${suite.name} test class coverage is: $suiteCoveragePercentage")
logCoverageDetail(suite)

// Create graphical report
CoverageReportUtil.createReport(getCoverageCollector())
CoverageReportUtil.createJsonReport(getCoverageCollector())

assertCoverage(
suiteCoveragePercentage,
processEngineCoverageProperties.classCoverageAssertionConditions
)
}
}
}

Expand All @@ -139,12 +146,16 @@ abstract class BaseProcessEngineCoverageTestExecutionListener : TestExecutionLis
val run = suite.getRun(testContext.testMethod.name) ?: return
val coveragePercentage = run.calculateCoverage(getCoverageCollector().getModels())

// Log coverage percentage
logger.info("${run.name} test method coverage is $coveragePercentage")
logCoverageDetail(run)
if (coveragePercentage.isNaN()) {
logger.warn { "${run.name} test method coverage could not be calculated, check configuration" }
} else {
// Log coverage percentage
logger.info("${run.name} test method coverage is $coveragePercentage")
logCoverageDetail(run)

processEngineCoverageProperties.testMethodCoverageConditions[run.name]?.let {
assertCoverage(coveragePercentage, it)
processEngineCoverageProperties.testMethodCoverageConditions[run.name]?.let {
assertCoverage(coveragePercentage, it)
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion regression-tests/junit4-platform-7/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.camunda.community.process_test_coverage</groupId>
<artifactId>camunda-process-test-coverage-regression-tests-parent</artifactId>
<version>2.6.0</version>
<version>2.6.1-SNAPSHOT</version>
</parent>

<artifactId>camunda-process-test-coverage-regression-tests-junit4-platform-7</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion regression-tests/junit5-platform-7/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>org.camunda.community.process_test_coverage</groupId>
<artifactId>camunda-process-test-coverage-regression-tests-parent</artifactId>
<version>2.6.0</version>
<version>2.6.1-SNAPSHOT</version>
</parent>

<artifactId>camunda-process-test-coverage-regression-tests-junit5-platform-7</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ class ClassCoverageTest {
fun testPathA() {
val variables: MutableMap<String, Any> = HashMap()
variables["path"] = "A"
extension.processEngine.runtimeService.startProcessInstanceByKey(CoverageTestProcessConstants.PROCESS_DEFINITION_KEY, variables)
extension.runtimeService.startProcessInstanceByKey(CoverageTestProcessConstants.PROCESS_DEFINITION_KEY, variables)
}

@Test
@Deployment(resources = [CoverageTestProcessConstants.BPMN_PATH])
fun testPathB() {
val variables: MutableMap<String, Any> = HashMap()
variables["path"] = "B"
extension.processEngine.runtimeService.startProcessInstanceByKey(CoverageTestProcessConstants.PROCESS_DEFINITION_KEY, variables)
extension.runtimeService.startProcessInstanceByKey(CoverageTestProcessConstants.PROCESS_DEFINITION_KEY, variables)
}

}
Loading

0 comments on commit 71c5cb3

Please sign in to comment.