View Javadoc
1   /*
2    * Copyright 2016 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.openehealth.ipf.commons.core.test;
18  
19  import org.junit.rules.TestRule;
20  import org.junit.runner.Description;
21  import org.junit.runners.model.Statement;
22  import org.slf4j.Logger;
23  import org.slf4j.LoggerFactory;
24  
25  import java.util.ArrayList;
26  import java.util.List;
27  import java.util.function.Predicate;
28  
29  
30  /**
31   * JUnit Rule allowing conditional execution of tests or whole test classes. The condition
32   * must implement {@link Predicate} with a {@link Void} type parameter.
33   * <p/>
34   * Example:
35   * <pre>
36   *     public class SomeTest {
37   *
38   *        &#064;Rule public Conditional rule = Conditional.skipOnWindows();
39   *
40   *        &#064;Test
41   *        public void testNotOnWindows() {
42   *           rule.verify();
43   *       }
44   *
45   *        &#064;Test
46   *        public void testOnlyWindows() {
47   *           rule.negate().verify();
48   *       }
49   *    }
50   * </pre>
51   */
52  public class ConditionalRule implements TestRule {
53  
54      private static final Logger LOG = LoggerFactory.getLogger(ConditionalRule.class);
55      private Predicate<Void> predicate;
56      private String reason;
57  
58      public ConditionalRule() {
59      }
60  
61      // Build a condition
62  
63      public ConditionalRule runIf(Predicate<Void> condition) {
64          this.predicate = condition;
65          return this;
66      }
67  
68      public ConditionalRule ifSystemProperty(final String property, final Predicate<String> condition) {
69          return runIf(source ->
70                  condition.test(System.getProperty(property))).reason("condition matches on system property " + property);
71      }
72  
73      public ConditionalRule ifSystemPropertyIs(final String property, final String value) {
74          return ifSystemProperty(property, s ->
75                  s != null && s.equalsIgnoreCase(value)).reason("system property " + property + " equals " + value);
76      }
77      public ConditionalRule negate() {
78          if (predicate == null)
79              throw new IllegalArgumentException("Must have defined a condition before negating it");
80          predicate = predicate.negate();
81          reason = "not " + reason;
82          return this;
83      }
84  
85      public ConditionalRule skipOnWindows() {
86          return ifSystemProperty("os.name", s ->
87                  s.startsWith("Windows")).negate().reason("skipped because running on Windows");
88      }
89  
90      public ConditionalRule skipOnTravis() {
91          return ifSystemPropertyIs("TRAVIS", "true")
92              .negate().reason("skipped because running on Travis");
93      }
94  
95      public ConditionalRule reason(String reason) {
96          this.reason = reason;
97          return this;
98      }
99  
100     public void verify() {
101         if (predicate != null) {
102             if (!predicate.test(null)) throw new IgnoredException();
103         }
104     }
105 
106     @Override
107     public Statement apply(Statement base, Description description) {
108         return new ConditionalStatement(this, base, description);
109     }
110 
111     public String getReason() {
112         return reason;
113     }
114 
115     private static class ConditionalStatement extends Statement {
116         private final Statement statement;
117         private final Description description;
118         private final ConditionalRule conditionalRule;
119 
120         public ConditionalStatement(ConditionalRule conditionalRule, Statement statement, Description description) {
121             this.statement = statement;
122             this.conditionalRule = conditionalRule;
123             this.description = description;
124         }
125 
126         @Override
127         public void evaluate() throws Throwable {
128             try {
129                 conditionalRule.verify();
130                 statement.evaluate();
131             } catch (Throwable e) {
132                 if (isIgnoredException(e)) {
133                     LOG.warn("Did not execute test {}: {} ", description, conditionalRule.getReason());
134                     return;
135                 }
136                 throw e;
137             }
138         }
139     }
140 
141     private static boolean isIgnoredException(Throwable throwable) {
142         Throwable t = throwable;
143         List<Throwable> list = new ArrayList<>();
144         while (t != null && !list.contains(t)) {
145             if (t instanceof IgnoredException) return true;
146             list.add(throwable);
147             t = t.getCause();
148         }
149         return false;
150     }
151 
152     private static class IgnoredException extends RuntimeException {
153 
154         public IgnoredException() {
155             super();
156         }
157     }
158 
159 }