package ru.yandex.qatools.allure.utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ru.yandex.qatools.allure.annotations.Description; import ru.yandex.qatools.allure.annotations.Features; import ru.yandex.qatools.allure.annotations.Issue; import ru.yandex.qatools.allure.annotations.Issues; import ru.yandex.qatools.allure.annotations.Severity; import ru.yandex.qatools.allure.annotations.Stories; import ru.yandex.qatools.allure.annotations.TestCaseId; import ru.yandex.qatools.allure.annotations.Title; import ru.yandex.qatools.allure.events.TestCaseStartedEvent; import ru.yandex.qatools.allure.events.TestSuiteStartedEvent; import ru.yandex.qatools.allure.model.Label; import ru.yandex.qatools.allure.model.SeverityLevel; import java.lang.annotation.Annotation; import java.lang.management.ManagementFactory; import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import static java.lang.String.format; import static ru.yandex.qatools.allure.config.AllureModelUtils.createFeatureLabel; import static ru.yandex.qatools.allure.config.AllureModelUtils.createHostLabel; import static ru.yandex.qatools.allure.config.AllureModelUtils.createIssueLabel; import static ru.yandex.qatools.allure.config.AllureModelUtils.createSeverityLabel; import static ru.yandex.qatools.allure.config.AllureModelUtils.createStoryLabel; import static ru.yandex.qatools.allure.config.AllureModelUtils.createTestLabel; import static ru.yandex.qatools.allure.config.AllureModelUtils.createThreadLabel; /** * Util, using to collect information from class and method annotations * * @author Dmitry Baev charlie@yandex-team.ru * Date: 13.12.13 * <p/> */ public class AnnotationManager { private static final Logger LOGGER = LoggerFactory.getLogger(AnnotationManager.class); private Map<Class<? extends Annotation>, Annotation> annotations = new HashMap<>(); private static String Hostname = null; /** * Construct AnnotationManager using given annotations * * @param annotations initial value for annotations */ public AnnotationManager(Collection<Annotation> annotations) { populateAnnotations(annotations); } /** * Construct AnnotationManager using given annotations * * @param annotations initial value for annotations */ public AnnotationManager(Annotation... annotations) { populateAnnotations(Arrays.asList(annotations)); } /** * Used to populate Map with given annotations * * @param annotations initial value for annotations */ private void populateAnnotations(Collection<Annotation> annotations) { for (Annotation each : annotations) { this.annotations.put(each.annotationType(), each); } } /** * Set default values for annotations. * Initial annotation take precedence over the default annotation when both annotation types are present * * @param defaultAnnotations default value for annotations */ public void setDefaults(Annotation[] defaultAnnotations) { if (defaultAnnotations == null) { return; } for (Annotation each : defaultAnnotations) { Class<? extends Annotation> key = each.annotationType(); if (Title.class.equals(key) || Description.class.equals(key)) { continue; } if (!annotations.containsKey(key)) { annotations.put(key, each); } } } /** * Save current hostname and reuse it. * * @return hostname as String */ private static String getHostname() { if (Hostname == null) { try { Hostname = InetAddress.getLocalHost().getHostName(); } catch (Exception e) { Hostname = "default"; LOGGER.warn("Can not get current hostname", e); } } return Hostname; } /** * Sets into specified {@link ru.yandex.qatools.allure.events.TestSuiteStartedEvent} * information from Allure annotations. * * @param event to change */ public void update(TestSuiteStartedEvent event) { if (isTitleAnnotationPresent()) { event.setTitle(getTitle()); } if (isDescriptionAnnotationPresent()) { event.setDescription(getDescription()); } if (isIssueAnnotationPresent()) { event.getLabels().add(createIssueLabel(getIssueKey())); } if (isIssuesAnnotationPresent()) { for (String issueKey : getIssueKeys()) { event.getLabels().add(createIssueLabel(issueKey)); } } event.getLabels().addAll(getStoryLabels()); event.getLabels().addAll(getFeatureLabels()); } /** * Sets into specified {@link ru.yandex.qatools.allure.events.TestCaseStartedEvent} * information from Allure annotations. * * @param event to change */ public void update(TestCaseStartedEvent event) { if (isTitleAnnotationPresent()) { event.setTitle(getTitle()); } if (isDescriptionAnnotationPresent()) { event.setDescription(getDescription()); } if (isSeverityAnnotationPresent()) { event.getLabels().add(createSeverityLabel(getSeverity())); } if (isIssueAnnotationPresent()) { event.getLabels().add(createIssueLabel(getIssueKey())); } if (isIssuesAnnotationPresent()) { for (String issueKey : getIssueKeys()) { event.getLabels().add(createIssueLabel(issueKey)); } } if (isTestCaseIdAnnotationPresent()) { event.getLabels().add(createTestLabel(getTestCaseId())); } event.getLabels().addAll(getStoryLabels()); event.getLabels().addAll(getFeatureLabels()); withExecutorInfo(event); } /** * Add information about host and thread to specified test case started event * * @param event given event to update * @return updated event */ public static TestCaseStartedEvent withExecutorInfo(TestCaseStartedEvent event) { event.getLabels().add(createHostLabel(getHostname())); event.getLabels().add(createThreadLabel(format("%s.%s(%s)", ManagementFactory.getRuntimeMXBean().getName(), Thread.currentThread().getName(), Thread.currentThread().getId()) )); return event; } /** * @return true if {@link ru.yandex.qatools.allure.annotations.Title} * annotation present in {@link #annotations} and false otherwise */ public boolean isTitleAnnotationPresent() { return isAnnotationPresent(Title.class); } /** * @return true if {@link ru.yandex.qatools.allure.annotations.Description} * annotation present in {@link #annotations} and false otherwise */ public boolean isDescriptionAnnotationPresent() { return isAnnotationPresent(Description.class); } /** * @return true if {@link ru.yandex.qatools.allure.annotations.Severity} * annotation present in {@link #annotations} and false otherwise */ public boolean isSeverityAnnotationPresent() { return isAnnotationPresent(Severity.class); } /** * @return true if {@link ru.yandex.qatools.allure.annotations.Stories} * annotation present in {@link #annotations} and false otherwise */ public boolean isStoriesAnnotationPresent() { return isAnnotationPresent(Stories.class); } /** * @return true if {@link ru.yandex.qatools.allure.annotations.Features} * annotation present in {@link #annotations} and false otherwise */ public boolean isFeaturesAnnotationPresent() { return isAnnotationPresent(Features.class); } /** * @return true if {@link ru.yandex.qatools.allure.annotations.Issues} * annotation present in {@link #annotations} and false otherwise */ public boolean isIssuesAnnotationPresent() { return isAnnotationPresent(Issues.class); } /** * @return true if {@link ru.yandex.qatools.allure.annotations.Issue} * annotation present in {@link #annotations} and false otherwise */ public boolean isIssueAnnotationPresent() { return isAnnotationPresent(Issue.class); } public boolean isTestCaseIdAnnotationPresent() { return isAnnotationPresent(TestCaseId.class); } /** * Find first {@link ru.yandex.qatools.allure.annotations.Title} annotation * * @return title or null if annotation doesn't present */ public String getTitle() { Title title = getAnnotation(Title.class); return title == null ? null : title.value(); } /** * Find first {@link ru.yandex.qatools.allure.annotations.Description} annotation * * @return {@link ru.yandex.qatools.allure.model.Description} or null if * annotation doesn't present */ public ru.yandex.qatools.allure.model.Description getDescription() { Description description = getAnnotation(Description.class); return description == null ? null : new ru.yandex.qatools.allure.model.Description() .withValue(description.value()) .withType(description.type()); } /** * Find first {@link ru.yandex.qatools.allure.annotations.Severity} annotation * * @return {@link ru.yandex.qatools.allure.model.SeverityLevel} or null if * annotation doesn't present */ public SeverityLevel getSeverity() { Severity severity = getAnnotation(Severity.class); return severity == null ? null : severity.value(); } /** * Find first {@link ru.yandex.qatools.allure.annotations.Issue} annotation * * @return issue key or null if annotation is not present */ public String getIssueKey() { Issue issue = getAnnotation(Issue.class); return issue == null ? null : issue.value(); } private String getTestCaseId() { TestCaseId testCaseId = getAnnotation(TestCaseId.class); return testCaseId == null ? null : testCaseId.value(); } /** * Construct label for all {@link ru.yandex.qatools.allure.annotations.Stories} annotations * using {@link ru.yandex.qatools.allure.config.AllureModelUtils#createStoryLabel(String)} * * @return {@link java.util.List} of created labels */ public List<Label> getStoryLabels() { if (!isAnnotationPresent(Stories.class)) { return Collections.emptyList(); } List<Label> result = new ArrayList<>(); for (String story : getAnnotation(Stories.class).value()) { result.add(createStoryLabel(story)); } return result; } /** * Construct label for all {@link ru.yandex.qatools.allure.annotations.Features} annotations * using {@link ru.yandex.qatools.allure.config.AllureModelUtils#createFeatureLabel(String)} * * @return {@link java.util.List} of created labels */ public List<Label> getFeatureLabels() { if (!isAnnotationPresent(Features.class)) { return Collections.emptyList(); } List<Label> result = new ArrayList<>(); for (String feature : getAnnotation(Features.class).value()) { result.add(createFeatureLabel(feature)); } return result; } /** * Find {@link ru.yandex.qatools.allure.annotations.Issues} annotation and return respective key * * @return issue keys or empty array if annotation isn't present */ public String[] getIssueKeys() { Issues issues = getAnnotation(Issues.class); if (issues == null) { return new String[0]; } List<String> keys = new ArrayList<>(); for (Issue issue : issues.value()) { keys.add(issue.value()); } return keys.toArray(new String[keys.size()]); } /** * Returns true if {@link #annotations} contains annotation with specified type, * false otherwise * * @param annotationType annotation type to find * @return true if {@link #annotations} contains annotation with specified type, * false otherwise */ public <T extends Annotation> boolean isAnnotationPresent(Class<T> annotationType) { return annotations.containsKey(annotationType); } /** * Find annotation with specified type into {@link #annotations} * * @param annotationType annotation type to find * @return the first found annotation with specified type, of null if * {@link #annotations} doesn't contains such */ public <T extends Annotation> T getAnnotation(Class<T> annotationType) { Annotation value = annotations.get(annotationType); return annotationType.cast(value); } }