Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/labels-verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ jobs:
steps:
- uses: zwaldowski/match-label-action@v2
with:
allowed: 'type:bug, type:enhancement, type:improvement, type:dependencies, type:internal, type:invalid'
allowed: 'type:bug, type:new feature, type:improvement, type:dependencies, type:internal, type:invalid'
Original file line number Diff line number Diff line change
Expand Up @@ -222,4 +222,12 @@
@Feature("Timeline")
@interface Severity {
}

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Feature("Filtration")
@interface Filtration {
}
}
1 change: 1 addition & 0 deletions allure-junit-platform/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ dependencies {
api(project(":allure-java-commons"))
implementation("org.junit.jupiter:junit-jupiter-api")
implementation("org.junit.platform:junit-platform-launcher")
implementation(project(":allure-test-filter"))
testAnnotationProcessor("org.slf4j:slf4j-simple")
testAnnotationProcessor(project(":allure-descriptions-javadoc"))
testImplementation("io.github.glytching:junit-extensions")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,10 @@ private void startTestCase(final TestIdentifier testIdentifier) {
final String uuid = tests.getOrCreate(testIdentifier);

final Optional<TestSource> testSource = testIdentifier.getSource();
final Optional<Method> testMethod = testSource.flatMap(this::getTestMethod);
final Optional<Class<?>> testClass = testSource.flatMap(this::getTestClass);
final Optional<Method> testMethod = testSource
.flatMap(AllureJunitPlatformUtils::getTestMethod);
final Optional<Class<?>> testClass = testSource
.flatMap(AllureJunitPlatformUtils::getTestClass);

final TestResult result = new TestResult()
.setUuid(uuid)
Expand All @@ -384,7 +386,7 @@ private void startTestCase(final TestIdentifier testIdentifier) {
createLanguageLabel("java")
));

testSource.flatMap(this::getFullName).ifPresent(result::setFullName);
testSource.flatMap(AllureJunitPlatformUtils::getFullName).ifPresent(result::setFullName);
testSource.map(this::getSourceLabels).ifPresent(result.getLabels()::addAll);
testClass.ifPresent(aClass -> {
final String suiteName = getDisplayName(aClass).orElse(aClass.getCanonicalName());
Expand Down Expand Up @@ -508,56 +510,6 @@ private List<Label> getSourceLabels(final TestSource source) {
return Collections.emptyList();
}

private Optional<String> getFullName(final TestSource source) {
if (source instanceof MethodSource) {
final MethodSource ms = (MethodSource) source;
return Optional.of(String.format("%s.%s", ms.getClassName(), ms.getMethodName()));
}
if (source instanceof ClassSource) {
final ClassSource cs = (ClassSource) source;
return Optional.ofNullable(cs.getClassName());
}
return Optional.empty();
}

private Optional<Class<?>> getTestClass(final TestSource source) {
if (source instanceof MethodSource) {
return getTestClass(((MethodSource) source).getClassName());
}
if (source instanceof ClassSource) {
return Optional.of(((ClassSource) source).getJavaClass());
}
return Optional.empty();
}

private Optional<Class<?>> getTestClass(final String className) {
try {
return Optional.of(Class.forName(className));
} catch (ClassNotFoundException e) {
LOGGER.trace("Could not get test class from test source {}", className, e);
}
return Optional.empty();
}

private Optional<Method> getTestMethod(final TestSource source) {
if (source instanceof MethodSource) {
return getTestMethod((MethodSource) source);
}
return Optional.empty();
}

private Optional<Method> getTestMethod(final MethodSource source) {
try {
final Class<?> aClass = Class.forName(source.getClassName());
return Stream.of(aClass.getDeclaredMethods())
.filter(method -> MethodSource.from(method).equals(source))
.findAny();
} catch (ClassNotFoundException e) {
LOGGER.trace("Could not get test method from method source {}", source, e);
}
return Optional.empty();
}

private static class Uuids {

private final Map<TestIdentifier, String> storage = new ConcurrentHashMap<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright 2020 Qameta Software OÜ
*
* 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.
*/
package io.qameta.allure.junitplatform;

import org.junit.platform.engine.TestSource;
import org.junit.platform.engine.support.descriptor.ClassSource;
import org.junit.platform.engine.support.descriptor.MethodSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.util.Optional;
import java.util.stream.Stream;

/**
* @author charlie (Dmitry Baev).
*/
/* package-private */ final class AllureJunitPlatformUtils {

private static final Logger LOGGER = LoggerFactory.getLogger(AllureJunitPlatformUtils.class);

private AllureJunitPlatformUtils() {
throw new IllegalStateException("do not instance");
}

public static Optional<String> getFullName(final TestSource source) {
if (source instanceof MethodSource) {
final MethodSource ms = (MethodSource) source;
return Optional.of(String.format("%s.%s", ms.getClassName(), ms.getMethodName()));
}
if (source instanceof ClassSource) {
final ClassSource cs = (ClassSource) source;
return Optional.ofNullable(cs.getClassName());
}
return Optional.empty();
}

public static Optional<Class<?>> getTestClass(final TestSource source) {
if (source instanceof MethodSource) {
return getTestClass(((MethodSource) source).getClassName());
}
if (source instanceof ClassSource) {
return Optional.of(((ClassSource) source).getJavaClass());
}
return Optional.empty();
}

public static Optional<Class<?>> getTestClass(final String className) {
try {
return Optional.of(Class.forName(className));
} catch (ClassNotFoundException e) {
LOGGER.trace("Could not get test class from test source {}", className, e);
}
return Optional.empty();
}

public static Optional<Method> getTestMethod(final TestSource source) {
if (source instanceof MethodSource) {
return getTestMethod((MethodSource) source);
}
return Optional.empty();
}

public static Optional<Method> getTestMethod(final MethodSource source) {
try {
final Class<?> aClass = Class.forName(source.getClassName());
return Stream.of(aClass.getDeclaredMethods())
.filter(method -> MethodSource.from(method).equals(source))
.findAny();
} catch (ClassNotFoundException e) {
LOGGER.trace("Could not get test method from method source {}", source, e);
}
return Optional.empty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Copyright 2020 Qameta Software OÜ
*
* 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.
*/
package io.qameta.allure.junitplatform;

import io.qameta.allure.model.Label;
import io.qameta.allure.testfilter.FileTestPlanSupplier;
import io.qameta.allure.testfilter.TestPlan;
import io.qameta.allure.testfilter.TestPlanV1_0;
import io.qameta.allure.util.AnnotationUtils;
import org.junit.platform.engine.FilterResult;
import org.junit.platform.engine.TestDescriptor;
import org.junit.platform.engine.TestTag;
import org.junit.platform.launcher.PostDiscoveryFilter;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static io.qameta.allure.util.ResultsUtils.ALLURE_ID_LABEL_NAME;

/**
* @author charlie (Dmitry Baev).
*/
public class AllurePostDiscoveryFilter implements PostDiscoveryFilter {

private static final Pattern ID_TAG = Pattern.compile("^@?allure\\.id[:=](?<id>.+)$");

private final TestPlan testPlan;

public AllurePostDiscoveryFilter() {
this(new FileTestPlanSupplier().supply().orElse(null));
}

public AllurePostDiscoveryFilter(final TestPlan testPlan) {
this.testPlan = testPlan;
}

@Override
public FilterResult apply(final TestDescriptor object) {
if (Objects.isNull(testPlan)) {
return FilterResult.included("test plan is empty");
}
if (!object.isTest()) {
return FilterResult.included("filter only applied for tests");
}

final String allureId = findAllureId(object);
final String uniqueId = object.getUniqueId().toString();
final String fullName = object.getSource()
.flatMap(AllureJunitPlatformUtils::getFullName)
.orElse(null);

return FilterResult.includedIf(
isIncluded(testPlan, allureId, uniqueId, fullName)
);
}

private boolean isIncluded(final TestPlan testPlan,
final String allureId,
final String uniqueId,
final String fullName) {
if (testPlan instanceof TestPlanV1_0) {
final TestPlanV1_0 tp = (TestPlanV1_0) testPlan;
return Objects.isNull(tp.getTests()) || tp.getTests()
.stream()
.filter(Objects::nonNull)
.anyMatch(tc -> match(tc, allureId, uniqueId, fullName));
}
return true;
}

@SuppressWarnings("BooleanExpressionComplexity")
private boolean match(final TestPlanV1_0.TestCase tc,
final String allureId,
final String uniqueId,
final String fullName) {
return Objects.nonNull(tc.getId()) && tc.getId().equals(allureId)
|| Objects.nonNull(tc.getSelector()) && tc.getSelector().equals(uniqueId)
|| Objects.nonNull(tc.getSelector()) && tc.getSelector().equals(fullName);
}

private String findAllureId(final TestDescriptor object) {
return object.getSource()
.flatMap(AllureJunitPlatformUtils::getTestMethod)
.flatMap(this::findAllureId)
.orElseGet(() -> findAllureId(object.getTags()));
}

private String findAllureId(final Collection<TestTag> tags) {
return tags.stream()
.map(TestTag::getName)
.map(t -> {
final Matcher matcher = ID_TAG.matcher(t);
return matcher.matches()
? Optional.ofNullable(matcher.group("id"))
: Optional.<String>empty();
})
.filter(Optional::isPresent)
.map(Optional::get)
.filter(Objects::nonNull)
.findAny()
.orElse(null);
}

private Optional<String> findAllureId(final Method value) {
return AnnotationUtils.getLabels(value)
.stream()
.filter(l -> ALLURE_ID_LABEL_NAME.equals(l.getName()))
.map(Label::getValue)
.findAny();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
io.qameta.allure.junitplatform.AllurePostDiscoveryFilter
Loading