View Javadoc
1   /*
2    * #%L
3    * wcm.io
4    * %%
5    * Copyright (C) 2020 wcm.io
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package io.wcm.qa.glnm.aspectj;
21  
22  import org.aspectj.lang.JoinPoint;
23  import org.aspectj.lang.ProceedingJoinPoint;
24  import org.aspectj.lang.annotation.Around;
25  import org.aspectj.lang.annotation.Aspect;
26  import org.aspectj.lang.annotation.Pointcut;
27  import org.hamcrest.Description;
28  import org.hamcrest.Matcher;
29  import org.hamcrest.StringDescription;
30  import org.slf4j.Logger;
31  import org.slf4j.LoggerFactory;
32  
33  import io.wcm.qa.glnm.configuration.GaleniumConfiguration;
34  import io.wcm.qa.glnm.exceptions.GaleniumException;
35  import io.wcm.qa.glnm.reporting.GaleniumReportUtil;
36  
37  /**
38   * Facilitates soft asserts for Hamcrest. Adds assertion step to Allure Report.
39   *
40   * @since 5.0.0
41   */
42  @Aspect
43  public class AssertAspect {
44  
45    private static final Logger LOG = LoggerFactory.getLogger(AssertAspect.class);
46  
47    /**
48     * Ignores exceptions, when {@link io.wcm.qa.glnm.configuration.GaleniumConfiguration#isSamplingVerificationIgnore()} is
49     * true.
50     *
51     * @param jp join point to be handled
52     * @return null or proceed value (advised method returns void)
53     */
54    @Around(value = "hamcrestMatcherAssert()")
55    public Object aroundAssert(final ProceedingJoinPoint jp) {
56      if (LOG.isTraceEnabled()) {
57        LOG.trace("assert aspect <" + jp + ">");
58      }
59      String stepUuid = beginAssert(jp);
60      try {
61        Object proceed = jp.proceed();
62        doneAsserting(stepUuid, jp);
63        return proceed;
64      }
65      catch (Throwable ex) {
66        failedAssert(stepUuid, jp, ex);
67        if (LOG.isDebugEnabled()) {
68          LOG.debug("when asserting.", ex);
69        }
70        if (GaleniumConfiguration.isSamplingVerificationIgnore()) {
71          return null;
72        }
73        throw new GaleniumException("assert: " + ex.getMessage(), ex);
74      }
75    }
76  
77    /**
78     * Pointcut definition. No functionality.
79     */
80    @Pointcut("call(public static void org.hamcrest.MatcherAssert.assertThat(String, Object, org.hamcrest.Matcher))")
81    public void hamcrestMatcherAssert() {
82      // pointcut body, should be empty
83    }
84  
85    /**
86     * Adds step to report.
87     * @param joinPoint only used for logging
88     * @return UUID for new report step
89     */
90    private static String beginAssert(final JoinPoint joinPoint) {
91      if (LOG.isTraceEnabled()) {
92        LOG.trace("asserting: " + joinPoint.getSignature().toLongString());
93      }
94      return GaleniumReportUtil.startStep("assert");
95    }
96  
97    /**
98     * Passes step and updates description.
99     * @param stepUuid to pass and stop
100    * @param joinPoint to supply description
101    */
102   private static void doneAsserting(String stepUuid, final JoinPoint joinPoint) {
103     if (LOG.isTraceEnabled()) {
104       LOG.trace("asserted: " + joinPoint.getSignature().toLongString());
105     }
106     String description = generateAssertDescription(joinPoint);
107     GaleniumReportUtil.updateStepName(stepUuid, description);
108     GaleniumReportUtil.passStep(stepUuid);
109     GaleniumReportUtil.stopStep();
110   }
111 
112   /**
113    * Fails step and updates description.
114    * @param stepUuid to pass and stop
115    * @param joinPoint to supply description
116    * @param e exception caught from MatcherAssert
117    */
118   private static void failedAssert(String stepUuid, final JoinPoint joinPoint, final Throwable e) {
119     if (LOG.isTraceEnabled()) {
120       LOG.trace("failed asserting: " + joinPoint.getSignature().toLongString(), e);
121     }
122     String assertDescription = generateAssertDescription(joinPoint);
123     GaleniumReportUtil.updateStepName(stepUuid, assertDescription);
124     GaleniumReportUtil.failStep(stepUuid);
125     GaleniumReportUtil.stopStep();
126   }
127 
128   /**
129    * Generates description from assert method call in join point.
130    * @param joinPoint to extract matcher from
131    * @return description from matcher and assert
132    */
133   private static String generateAssertDescription(final JoinPoint joinPoint) {
134     Object reason = joinPoint.getArgs()[0];
135     Object actual = joinPoint.getArgs()[1];
136     String matcherDescription = generateMatcherDescription(joinPoint);
137     StringBuilder assertDescription = new StringBuilder()
138         .append("assert: ")
139         .append(reason)
140         .append(" ")
141         .append(actual)
142         .append(" ")
143         .append(matcherDescription);
144     return assertDescription.toString();
145   }
146 
147   /**
148    * Generates description from matcher in join point.
149    * @param joinPoint to extract matcher from
150    * @return description from matcher
151    */
152   private static String generateMatcherDescription(final JoinPoint joinPoint) {
153     Matcher matcher = (Matcher)joinPoint.getArgs()[2];
154     Description matcherDescription = new StringDescription();
155     matcher.describeTo(matcherDescription);
156     return matcherDescription.toString();
157   }
158 
159 }