• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * @license
3  * Copyright 2013 Google Inc. All rights reserved.
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 com.google.security.wycheproof;
18 
19 import java.lang.annotation.ElementType;
20 import java.lang.annotation.Retention;
21 import java.lang.annotation.RetentionPolicy;
22 import java.lang.annotation.Target;
23 import java.util.Arrays;
24 import org.junit.runner.Description;
25 import org.junit.runner.manipulation.Filter;
26 import org.junit.runner.manipulation.NoTestsRemainException;
27 import org.junit.runners.Suite;
28 import org.junit.runners.model.InitializationError;
29 import org.junit.runners.model.RunnerBuilder;
30 
31 /**
32  * <p>A custom JUnit4 runner that, with annotations, allows choosing tests to run on a specific
33  * provider. To use it, annotate a runner class with {@code RunWith(WycheproofRunner.class)}, and
34  * {@code SuiteClasses({AesGcmTest.class, ...})}. When you run this class, it will run all the tests
35  * in all the suite classes.
36  *
37  * <p>To exclude certain tests, a runner class should be annotated with {@code @Provider} which
38  * indicates the target provider. Test exclusion is defined as follows:
39  * <ul>@Fast test runners skip @SlowTest test functions.
40  * <ul>@Presubmit test runners skip @NoPresubmitTest test functions.
41  * <ul>All test runners skip @ExcludedTest test functions.
42  *
43  * @author thaidn@google.com (Thai Duong)
44  */
45 public class WycheproofRunner extends Suite {
46 
47   /** List of supported providers. */
48   public enum ProviderType {
49     BOUNCY_CASTLE,
50     CONSCRYPT,
51     OPENJDK,
52     SPONGY_CASTLE,
53   }
54 
55   // Annotations for test runners.
56 
57   /**
58    * Annotation to specify the target provider of a test runner.
59    *
60    * <p>Usage: @Provider(ProviderType.BOUNCY_CASTLE)
61    */
62   @Retention(RetentionPolicy.RUNTIME)
63   @Target({ElementType.TYPE})
64   public @interface Provider {
value()65     ProviderType value();
66   }
67 
68   /**
69    * Annotation to specify presubmit test runners that exclude {@code @NoPresubmitTets} tests.
70    *
71    * <p>Usage: @Presubmit(ProviderType.BOUNCY_CASTLE)
72    */
73   @Retention(RetentionPolicy.RUNTIME)
74   @Target({ElementType.TYPE})
75   public @interface Presubmit {}
76 
77   /**
78    * Annotation to specify fast test runners that exclude {@code @SlowTest} tests.
79    *
80    * <p>Usage: @Fast
81    */
82   @Retention(RetentionPolicy.RUNTIME)
83   @Target({ElementType.TYPE})
84   public @interface Fast {}
85 
86   // Annotations for test functions
87 
88   /**
89    * Tests that take too much time to run, should be excluded from TAP and wildcard target patterns
90    * like:..., :*, or :all.
91    *
92    * <p>Usage: @SlowTest(providers = {ProviderType.BOUNCY_CASTLE, ...})
93    */
94   @Retention(RetentionPolicy.RUNTIME)
95   @Target({ElementType.METHOD})
96   public @interface SlowTest {
providers()97     ProviderType[] providers();
98   }
99 
100   /**
101    * Tests that should be excluded from presubmit checks on specific providers.
102    *
103    * <p>Usage: @NoPresubmitTest(
104    *   providers = {ProviderType.BOUNCY_CASTLE, ...},
105    *   bugs = {"b/123456789"}
106    * )
107    */
108   @Retention(RetentionPolicy.RUNTIME)
109   @Target({ElementType.METHOD, ElementType.FIELD})
110   public @interface NoPresubmitTest {
111     /** List of providers that this test method should not run as presubmit check. */
providers()112     ProviderType[] providers();
113 
114     /** List of blocking bugs (and comments). */
bugs()115     String[] bugs();
116   }
117 
118   /**
119    * Annotation to specify test functions that should be excluded on specific providers.
120    *
121    * <p>Usage: @ExcludedTest(providers = {ProviderType.BOUNCY_CASTLE, ProviderType.OPENJDK})
122    */
123   @Retention(RetentionPolicy.RUNTIME)
124   @Target({ElementType.METHOD})
125   public @interface ExcludedTest {
providers()126     ProviderType[] providers();
comment()127     String comment();
128   }
129 
130   /**
131    * Custom filter to exclude certain test functions.
132    *
133    */
134   public static class ExcludeTestFilter extends Filter {
135 
136     Class<?> runnerClass;
137     Provider targetProvider;
138     Fast fast;
139     Presubmit presubmit;
140 
ExcludeTestFilter(Class<?> runnerClass)141     public ExcludeTestFilter(Class<?> runnerClass) {
142       this.runnerClass = runnerClass;
143       this.targetProvider = runnerClass.getAnnotation(Provider.class);
144       this.fast = runnerClass.getAnnotation(Fast.class);
145       this.presubmit = runnerClass.getAnnotation(Presubmit.class);
146     }
147 
148     @Override
describe()149     public String describe() {
150       return "exclude certain tests on specific providers";
151     }
152 
153     @Override
shouldRun(Description description)154     public boolean shouldRun(Description description) {
155       return isOkayToRunTest(description);
156     }
157 
isOkayToRunTest(Description description)158     private boolean isOkayToRunTest(Description description) {
159       if (targetProvider == null) {
160         // Run all test functions if the test runner is not annotated with {@code @Provider}.
161         return true;
162       }
163       // Skip @ExcludedTest tests
164       ExcludedTest excludedTest = description.getAnnotation(ExcludedTest.class);
165       if (excludedTest != null
166           && Arrays.asList(excludedTest.providers()).contains(targetProvider.value())) {
167         return false;
168       }
169 
170       // If the runner class is annotated with @Presubmit, skip non-presubmit tests
171       if (presubmit != null) {
172         NoPresubmitTest ignoreOn = description.getAnnotation(NoPresubmitTest.class);
173         if (ignoreOn != null
174             && Arrays.asList(ignoreOn.providers()).contains(targetProvider.value())) {
175           return false;
176         }
177       }
178 
179       // If the runner class is annotated with @Fast, skip slow tests
180       if (fast != null) {
181         SlowTest ignoreOn = description.getAnnotation(SlowTest.class);
182         if (ignoreOn != null
183             && Arrays.asList(ignoreOn.providers()).contains(targetProvider.value())) {
184           return false;
185         }
186       }
187 
188       // run everything else
189       return true;
190     }
191   }
192 
193   /** Required constructor: called by JUnit reflectively. */
WycheproofRunner(Class<?> runnerClass, RunnerBuilder builder)194   public WycheproofRunner(Class<?> runnerClass, RunnerBuilder builder) throws InitializationError {
195     super(runnerClass, builder);
196     addFilter(new ExcludeTestFilter(runnerClass));
197   }
198 
addFilter(Filter filter)199   private void addFilter(Filter filter) {
200     try {
201       filter(filter);
202     } catch (NoTestsRemainException ex) {
203       System.out.println("No tests remain exception: " + ex);
204     }
205   }
206 }
207