Skip to content

Commit

Permalink
- provided ability to handle package annotations
Browse files Browse the repository at this point in the history
- add package target to Epic(s), Feature(s), Flaky, Issue(s), Link(s), Muted, Owner, Severity, Story(es), TmsLink(s)
  • Loading branch information
s.tikhomirov committed Sep 10, 2024
1 parent 3d361dd commit ea39035
Show file tree
Hide file tree
Showing 25 changed files with 195 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE})
@Repeatable(Epics.class)
@LabelAnnotation(name = EPIC_LABEL_NAME)
public @interface Epic {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE})
public @interface Epics {

Epic[] value();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE})
@Repeatable(Features.class)
@LabelAnnotation(name = FEATURE_LABEL_NAME)
public @interface Feature {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE})
public @interface Features {

Feature[] value();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE})
public @interface Flaky {
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE})
@LinkAnnotation(type = ISSUE_LINK_TYPE)
@Repeatable(Issues.class)
public @interface Issue {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE})
public @interface Issues {

Issue[] value();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE})
@LinkAnnotation
@Repeatable(Links.class)
public @interface Link {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE})
public @interface Links {

Link[] value();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE})
public @interface Muted {
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE})
@LabelAnnotation(name = OWNER_LABEL_NAME)
public @interface Owner {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE})
public @interface Severity {

SeverityLevel value();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE})
public @interface Stories {

Story[] value();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE})
@Repeatable(Stories.class)
@LabelAnnotation(name = STORY_LABEL_NAME)
public @interface Story {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE})
@LinkAnnotation(type = TMS_LINK_TYPE)
@Repeatable(TmsLinks.class)
public @interface TmsLink {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE})
public @interface TmsLinks {

TmsLink[] value();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiFunction;
Expand All @@ -39,7 +41,11 @@

import static io.qameta.allure.util.ResultsUtils.createLabel;
import static io.qameta.allure.util.ResultsUtils.createLink;
import static java.lang.String.join;
import static java.util.Arrays.asList;
import static java.util.Arrays.copyOfRange;
import static java.util.Arrays.stream;
import static java.util.Optional.ofNullable;

/**
* Collection of utils used by Allure integration to extract meta information from
Expand All @@ -64,7 +70,7 @@ private AnnotationUtils() {
* @return true if {@link io.qameta.allure.Flaky} annotation is present, false otherwise.
*/
public static boolean isFlaky(final AnnotatedElement annotatedElement) {
return annotatedElement.isAnnotationPresent(Flaky.class);
return isAnnotationPresent(annotatedElement, Flaky.class);
}

/**
Expand All @@ -74,7 +80,7 @@ public static boolean isFlaky(final AnnotatedElement annotatedElement) {
* @return true if {@link io.qameta.allure.Muted} annotation is present, false otherwise.
*/
public static boolean isMuted(final AnnotatedElement annotatedElement) {
return annotatedElement.isAnnotationPresent(Muted.class);
return isAnnotationPresent(annotatedElement, Muted.class);
}

/**
Expand All @@ -84,7 +90,7 @@ public static boolean isMuted(final AnnotatedElement annotatedElement) {
* @return discovered links.
*/
public static Set<Link> getLinks(final AnnotatedElement annotatedElement) {
return getLinks(annotatedElement.getAnnotations());
return getLinks(getAnnotationsFrom(annotatedElement));
}

/**
Expand Down Expand Up @@ -116,7 +122,7 @@ public static Set<Link> getLinks(final Collection<Annotation> annotations) {
* @return discovered labels.
*/
public static Set<Label> getLabels(final AnnotatedElement annotatedElement) {
return getLabels(annotatedElement.getAnnotations());
return getLabels(getAnnotationsFrom(annotatedElement));
}

/**
Expand All @@ -140,6 +146,29 @@ public static Set<Label> getLabels(final Collection<Annotation> annotations) {
.collect(Collectors.toSet());
}

private static <T extends Annotation> boolean isAnnotationPresent(final AnnotatedElement annotatedElement, Class<T> annotationClass) {
boolean isPresent = annotatedElement.isAnnotationPresent(annotationClass);
if (!isPresent && annotatedElement instanceof Class<?>) {
Annotation[] packageAnnotations = PackageUtil.getPackageAnnotations((Class<?>) annotatedElement);
return stream(packageAnnotations).anyMatch(a -> a.annotationType().equals(annotationClass));
}

return isPresent;
}

private static Annotation[] getAnnotationsFrom(AnnotatedElement annotatedElement) {
Annotation[] result = annotatedElement.getAnnotations();
if (annotatedElement instanceof Class<?>) {
Annotation[] packageAnnotations = PackageUtil.getPackageAnnotations((Class<?>) annotatedElement);
List<Annotation> annotationList = new ArrayList<>(asList(result));
List<Annotation> packageAnnotationList = new ArrayList<>(asList(packageAnnotations));
annotationList.addAll(packageAnnotationList);
result = annotationList.toArray(new Annotation[]{});
}

return result;
}

private static <T, U extends Annotation> Stream<T> extractMetaAnnotations(
final Class<U> annotationType,
final BiFunction<U, Annotation, Stream<T>> mapper,
Expand Down Expand Up @@ -262,4 +291,41 @@ private static boolean isInJavaLangAnnotationPackage(final Class<? extends Annot
return annotationType != null && annotationType.getName().startsWith("java.lang.annotation");
}

/**
* Extracts annotations from packages hierarchically by given classes
*
* @author TikhomirovSergey (Sergey Tikhomirov).
*/
static class PackageUtil {

static Annotation[] getPackageAnnotations(Class<?> clz) {
Objects.requireNonNull(clz, "Class should not be a null value");
return getPackageAnnotations(clz.getPackage().getName());
}

static Annotation[] getPackageAnnotations(String packageName) {
Objects.requireNonNull(packageName, "Package name should not be a null value");

//the code below would look better if allure supported Java from 9 and higher versions
Class<?> packInfo;
try {
packInfo = Class.forName(packageName + ".package-info", false, PackageUtil.class.getClassLoader());
} catch (ClassNotFoundException e) {
packInfo = null;
}

Annotation[] annotations = ofNullable(packInfo).map(clazz -> clazz.getPackage().getAnnotations()).orElse(new Annotation[]{});
String[] pathElements = packageName.split("[.]");
if (pathElements.length == 1) {
return annotations;
}

Annotation[] upperPackageAnnotations = getPackageAnnotations(join(".", copyOfRange(pathElements, 0, pathElements.length - 1)));
List<Annotation> annotationList = new ArrayList<>(asList(annotations));
List<Annotation> result = new ArrayList<>(asList(upperPackageAnnotations));
result.addAll(annotationList);
return result.toArray(new Annotation[] {});
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.qameta.allure.annotatedpack;

import io.qameta.allure.Flaky;
import io.qameta.allure.Muted;

@Muted
@Flaky
public class MutedAndFlakyTest {

@Muted
@Flaky
public void mutedAndFlakyMethod() {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.qameta.allure.annotatedpack;

public class NotMutedAndFlakyTest {

public void notMutedAndFlakyMethod() {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.qameta.allure.annotatedpack.muted.and.flaky;

public class MutedAndFlakyByPackageTest {

public void notMutedAndFlakyMethod() {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@Muted
@Flaky
package io.qameta.allure.annotatedpack.muted.and.flaky;

import io.qameta.allure.Flaky;
import io.qameta.allure.Muted;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@Epic("High level epic")
@Link("General link")
package io.qameta.allure.annotatedpack;

import io.qameta.allure.Epic;
import io.qameta.allure.Link;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.qameta.allure.annotatedpack.subpack.innerpack;

import io.qameta.allure.Story;

@Story("Marked pack story")
public class SomeTest {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@Feature("Some general feature")
@Link("Some second level link")
package io.qameta.allure.annotatedpack.subpack;

import io.qameta.allure.Feature;
import io.qameta.allure.Link;
Loading

0 comments on commit ea39035

Please sign in to comment.