From 4e0b4a4506c1bb2c284363f9bf04ad75ff453ea0 Mon Sep 17 00:00:00 2001 From: Dmitry Baev Date: Mon, 20 May 2019 22:26:31 +0300 Subject: [PATCH] add support for recursive meta annotations (via #359) --- .../allure/cucumber4jvm/LabelBuilder.java | 2 +- .../io/qameta/allure/test/AllureFeatures.java | 52 ++- .../src/main/java/io/qameta/allure/Issue.java | 3 + .../src/main/java/io/qameta/allure/Link.java | 1 + .../java/io/qameta/allure/LinkAnnotation.java | 14 +- .../io/qameta/allure/LinkAnnotations.java | 36 ++ .../main/java/io/qameta/allure/TmsLink.java | 3 + .../qameta/allure/util/AnnotationUtils.java | 148 ++++---- .../io/qameta/allure/util/ResultsUtils.java | 2 +- .../allure/util/AnnotationUtilsTest.java | 356 ++++++++++++------ 10 files changed, 380 insertions(+), 237 deletions(-) create mode 100644 allure-java-commons/src/main/java/io/qameta/allure/LinkAnnotations.java diff --git a/allure-cucumber4-jvm/src/main/java/io/qameta/allure/cucumber4jvm/LabelBuilder.java b/allure-cucumber4-jvm/src/main/java/io/qameta/allure/cucumber4jvm/LabelBuilder.java index 609fecdf1..465f4c1e3 100644 --- a/allure-cucumber4-jvm/src/main/java/io/qameta/allure/cucumber4jvm/LabelBuilder.java +++ b/allure-cucumber4-jvm/src/main/java/io/qameta/allure/cucumber4jvm/LabelBuilder.java @@ -50,7 +50,7 @@ /** * Scenario labels and links builder. */ -@SuppressWarnings({"CyclomaticComplexity", "PMD.CyclomaticComplexity", "PMD.NcssCount"}) +@SuppressWarnings({"CyclomaticComplexity", "PMD.CyclomaticComplexity", "PMD.NcssCount", "MultipleStringLiterals"}) class LabelBuilder { private static final Logger LOGGER = LoggerFactory.getLogger(LabelBuilder.class); private static final String COMPOSITE_TAG_DELIMITER = "="; diff --git a/allure-java-commons-test/src/main/java/io/qameta/allure/test/AllureFeatures.java b/allure-java-commons-test/src/main/java/io/qameta/allure/test/AllureFeatures.java index f50e2672f..53a040a09 100644 --- a/allure-java-commons-test/src/main/java/io/qameta/allure/test/AllureFeatures.java +++ b/allure-java-commons-test/src/main/java/io/qameta/allure/test/AllureFeatures.java @@ -15,7 +15,7 @@ */ package io.qameta.allure.test; -import io.qameta.allure.LabelAnnotation; +import io.qameta.allure.Feature; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -24,8 +24,6 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import static io.qameta.allure.util.ResultsUtils.FEATURE_LABEL_NAME; - /** * @author charlie (Dmitry Baev). */ @@ -37,7 +35,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Basic framework support") + @Feature("Basic framework support") @interface Base { } @@ -45,7 +43,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Parallel test execution support") + @Feature("Parallel test execution support") @interface Parallel { } @@ -53,7 +51,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Full name") + @Feature("Full name") @interface FullName { } @@ -61,7 +59,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Display name") + @Feature("Display name") @interface DisplayName { } @@ -69,7 +67,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Descriptions") + @Feature("Descriptions") @interface Descriptions { } @@ -77,7 +75,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Timings") + @Feature("Timings") @interface Timings { } @@ -85,7 +83,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Steps") + @Feature("Steps") @interface Steps { } @@ -93,7 +91,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Attachments") + @Feature("Attachments") @interface Attachments { } @@ -101,7 +99,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Parameters") + @Feature("Parameters") @interface Parameters { } @@ -109,7 +107,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Fixtures") + @Feature("Fixtures") @interface Fixtures { } @@ -117,7 +115,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Links") + @Feature("Links") @interface Links { } @@ -125,7 +123,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Marker annotations") + @Feature("Marker annotations") @interface MarkerAnnotations { } @@ -133,7 +131,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Failed tests") + @Feature("Failed tests") @interface FailedTests { } @@ -141,7 +139,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Broken tests") + @Feature("Broken tests") @interface BrokenTests { } @@ -149,7 +147,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Passed tests") + @Feature("Passed tests") @interface PassedTests { } @@ -157,7 +155,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Skipped tests") + @Feature("Skipped tests") @interface SkippedTests { } @@ -165,7 +163,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Ignored tests") + @Feature("Ignored tests") @interface IgnoredTests { } @@ -173,7 +171,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Not implemented tests") + @Feature("Not implemented tests") @interface NotImplementedTests { } @@ -181,7 +179,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "History") + @Feature("History") @interface History { } @@ -189,7 +187,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Retries") + @Feature("Retries") @interface Retries { } @@ -197,7 +195,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Stages") + @Feature("Stages") @interface Stages { } @@ -205,7 +203,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Trees") + @Feature("Trees") @interface Trees { } @@ -213,7 +211,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Timeline") + @Feature("Timeline") @interface Timeline { } @@ -221,7 +219,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) - @LabelAnnotation(name = FEATURE_LABEL_NAME, value = "Timeline") + @Feature("Timeline") @interface Severity { } } diff --git a/allure-java-commons/src/main/java/io/qameta/allure/Issue.java b/allure-java-commons/src/main/java/io/qameta/allure/Issue.java index 675366ad7..f795897c7 100644 --- a/allure-java-commons/src/main/java/io/qameta/allure/Issue.java +++ b/allure-java-commons/src/main/java/io/qameta/allure/Issue.java @@ -23,6 +23,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import static io.qameta.allure.util.ResultsUtils.ISSUE_LINK_TYPE; + /** * Used to link tests with issues. */ @@ -30,6 +32,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) +@LinkAnnotation(type = ISSUE_LINK_TYPE) @Repeatable(Issues.class) public @interface Issue { diff --git a/allure-java-commons/src/main/java/io/qameta/allure/Link.java b/allure-java-commons/src/main/java/io/qameta/allure/Link.java index 666da86a4..b0b4dacb6 100644 --- a/allure-java-commons/src/main/java/io/qameta/allure/Link.java +++ b/allure-java-commons/src/main/java/io/qameta/allure/Link.java @@ -38,6 +38,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) +@LinkAnnotation @Repeatable(Links.class) public @interface Link { diff --git a/allure-java-commons/src/main/java/io/qameta/allure/LinkAnnotation.java b/allure-java-commons/src/main/java/io/qameta/allure/LinkAnnotation.java index 6b5ee1220..e646de636 100644 --- a/allure-java-commons/src/main/java/io/qameta/allure/LinkAnnotation.java +++ b/allure-java-commons/src/main/java/io/qameta/allure/LinkAnnotation.java @@ -18,6 +18,7 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; +import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -36,15 +37,18 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.ANNOTATION_TYPE}) +@Repeatable(LinkAnnotations.class) public @interface LinkAnnotation { + String DEFAULT_VALUE = "$$$$$$$$__value__$$$$$$$$"; + /** * The value of link. In not specified will take value from value() * method of target annotation. * * @return the value of the link to add. */ - String value() default ""; + String value() default DEFAULT_VALUE; /** * This type is used for create an icon for link. Also there is few reserved types such as issue and tms. @@ -52,4 +56,12 @@ * @return the link type. */ String type() default CUSTOM_LINK_TYPE; + + /** + * Url for link. By default will search for system property `allure.link.{type}.pattern`, and use it + * to generate url. + * + * @return the link url. + */ + String url() default ""; } diff --git a/allure-java-commons/src/main/java/io/qameta/allure/LinkAnnotations.java b/allure-java-commons/src/main/java/io/qameta/allure/LinkAnnotations.java new file mode 100644 index 000000000..50428d1c8 --- /dev/null +++ b/allure-java-commons/src/main/java/io/qameta/allure/LinkAnnotations.java @@ -0,0 +1,36 @@ +/* + * Copyright 2019 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; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Wrapper annotation for {@link LinkAnnotation}. + */ +@Documented +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.ANNOTATION_TYPE}) +public @interface LinkAnnotations { + + LinkAnnotation[] value(); + +} diff --git a/allure-java-commons/src/main/java/io/qameta/allure/TmsLink.java b/allure-java-commons/src/main/java/io/qameta/allure/TmsLink.java index d80d7139f..d5e839017 100644 --- a/allure-java-commons/src/main/java/io/qameta/allure/TmsLink.java +++ b/allure-java-commons/src/main/java/io/qameta/allure/TmsLink.java @@ -23,6 +23,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import static io.qameta.allure.util.ResultsUtils.TMS_LINK_TYPE; + /** * Used to link tests with test cases in external test management system. */ @@ -30,6 +32,7 @@ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) +@LinkAnnotation(type = TMS_LINK_TYPE) @Repeatable(TmsLinks.class) public @interface TmsLink { diff --git a/allure-java-commons/src/main/java/io/qameta/allure/util/AnnotationUtils.java b/allure-java-commons/src/main/java/io/qameta/allure/util/AnnotationUtils.java index c547d44ca..906c505a5 100644 --- a/allure-java-commons/src/main/java/io/qameta/allure/util/AnnotationUtils.java +++ b/allure-java-commons/src/main/java/io/qameta/allure/util/AnnotationUtils.java @@ -28,15 +28,15 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.ArrayList; +import java.util.HashSet; import java.util.Objects; import java.util.Set; -import java.util.function.Function; +import java.util.function.BiFunction; import java.util.stream.Collectors; import java.util.stream.Stream; +import static io.qameta.allure.util.ResultsUtils.createLabel; +import static io.qameta.allure.util.ResultsUtils.createLink; import static java.util.Arrays.asList; /** @@ -56,18 +56,13 @@ private AnnotationUtils() { } /** - * Returns links created from Allure annotations specified on annotated element. + * Returns links created from Allure meta annotations specified on annotated element. * * @param annotatedElement the element to search annotations on. * @return discovered links. */ - public static List getLinks(final AnnotatedElement annotatedElement) { - final List result = new ArrayList<>(); - result.addAll(extractLinks(annotatedElement, io.qameta.allure.Link.class, ResultsUtils::createLink)); - result.addAll(extractLinks(annotatedElement, io.qameta.allure.Issue.class, ResultsUtils::createLink)); - result.addAll(extractLinks(annotatedElement, io.qameta.allure.TmsLink.class, ResultsUtils::createLink)); - result.addAll(extractCustomLinks(asList(annotatedElement.getDeclaredAnnotations()))); - return result; + public static Set getLinks(final AnnotatedElement annotatedElement) { + return getLinks(annotatedElement.getDeclaredAnnotations()); } /** @@ -76,7 +71,7 @@ public static List getLinks(final AnnotatedElement annotatedElement) { * @param annotations annotations to analyse. * @return discovered links. */ - public static List getLinks(final Annotation... annotations) { + public static Set getLinks(final Annotation... annotations) { return getLinks(asList(annotations)); } @@ -86,17 +81,13 @@ public static List getLinks(final Annotation... annotations) { * @param annotations annotations to analyse. * @return discovered links. */ - public static List getLinks(final Collection annotations) { - final List result = new ArrayList<>(); - result.addAll(extractLinks(annotations, io.qameta.allure.Link.class, ResultsUtils::createLink)); - result.addAll(extractLinks(annotations, io.qameta.allure.Issue.class, ResultsUtils::createLink)); - result.addAll(extractLinks(annotations, io.qameta.allure.TmsLink.class, ResultsUtils::createLink)); - result.addAll(extractCustomLinks(annotations)); - return result; + public static Set getLinks(final Collection annotations) { + return extractMetaAnnotations(LinkAnnotation.class, AnnotationUtils::extractLinks, annotations) + .collect(Collectors.toSet()); } /** - * Returns labels created from Allure annotations specified on annotated element. + * Returns labels created from Allure meta annotations specified on annotated element. * Shortcut for {@link #getLinks(Annotation...)} * * @param annotatedElement the element to search annotations on. @@ -123,84 +114,71 @@ public static Set