aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google/devtools/build/lib/testutil/BlazeTestSuiteBuilder.java
blob: 3c645f0200c2613dae8b79a92e4ad0d274c3e77f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright 2014 The Bazel Authors. All rights reserved.
//
// 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 com.google.devtools.build.lib.testutil;

import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.util.OS;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * A base class for constructing test suites by searching the classpath for
 * tests, possibly restricted to a predicate.
 */
public class BlazeTestSuiteBuilder {

  /**
   * @return a TestSuiteBuilder configured for Blaze.
   */
  protected TestSuiteBuilder getBuilder() {
    return new TestSuiteBuilder()
        .addPackageRecursive("com.google.devtools.build.lib");
  }

  /** A predicate that succeeds only for LARGE tests. */
  public static final Predicate<Class<?>> TEST_IS_LARGE =
      hasSize(Suite.LARGE_TESTS);

  /** A predicate that succeeds only for MEDIUM tests. */
  public static final Predicate<Class<?>> TEST_IS_MEDIUM =
      hasSize(Suite.MEDIUM_TESTS);

  /** A predicate that succeeds only for SMALL tests. */
  public static final Predicate<Class<?>> TEST_IS_SMALL =
      hasSize(Suite.SMALL_TESTS);

  /** A predicate that succeeds only for non-flaky tests. */
  public static final Predicate<Class<?>> TEST_IS_FLAKY = new Predicate<Class<?>>() {
    @Override
    public boolean apply(Class<?> testClass) {
      return Suite.isFlaky(testClass);
    }
  };

  /** A predicate that succeeds only for non-local-only tests. */
  public static final Predicate<Class<?>> TEST_IS_LOCAL_ONLY =
      new Predicate<Class<?>>() {
        @Override
        public boolean apply(Class<?> testClass) {
          return Suite.isLocalOnly(testClass);
        }
      };

  /** A predicate that succeeds only if the test supports the current operating system. */
  public static final Predicate<Class<?>> TEST_SUPPORTS_CURRENT_OS =
      new Predicate<Class<?>>() {
        @Override
        public boolean apply(Class<?> testClass) {
          ImmutableSet<OS> supportedOs = ImmutableSet.copyOf(Suite.getSupportedOs(testClass));
          return supportedOs.isEmpty() || supportedOs.contains(OS.getCurrent());
        }
      };


  private static Predicate<Class<?>> hasSize(final Suite size) {
    return new Predicate<Class<?>>() {
      @Override
      public boolean apply(Class<?> testClass) {
        return Suite.getSize(testClass) == size;
      }
    };
  }

  protected static Predicate<Class<?>> inSuite(final String suiteName) {
    return new Predicate<Class<?>>() {
      @Override
      public boolean apply(Class<?> testClass) {
        return Suite.getSuiteName(testClass).equalsIgnoreCase(suiteName);
      }
    };
  }

  /**
   * Given a TestCase subclass, returns its designated suite annotation, if
   * any, or the empty string otherwise.
   */
  public static String getSuite(Class<?> clazz) {
    TestSpec spec = clazz.getAnnotation(TestSpec.class);
    return spec == null ? "" : spec.suite();
  }

  /**
   * Returns a predicate over TestCases that is true iff the TestCase has a
   * TestSpec annotation whose suite="..." value (a comma-separated list of
   * tags) matches all of the query operators specified in the system property
   * {@code blaze.suite}.  The latter is also a comma-separated list, but of
   * query operators, each of which is either the name of a tag which must be
   * present (e.g. "foo"), or the !-prefixed name of a tag that must be absent
   * (e.g. "!foo").
   */
  public static Predicate<Class<?>> matchesSuiteQuery() {
    final String suiteProperty = System.getProperty("blaze.suite");
    if (suiteProperty == null) {
      throw new IllegalArgumentException("blaze.suite property not found");
    }
    final Set<String> queryTokens = splitCommas(suiteProperty);
    return new Predicate<Class<?>>() {
      @Override
      public boolean apply(Class<?> testClass) {
        // Return true iff every queryToken is satisfied by suiteTags.
        Set<String> suiteTags = splitCommas(getSuite(testClass));
        for (String queryToken : queryTokens) {
          if (queryToken.startsWith("!")) { // forbidden tag
            if (suiteTags.contains(queryToken.substring(1))) {
              return false;
            }
          } else { // mandatory tag
            if (!suiteTags.contains(queryToken)) {
              return false;
            }
          }
        }
        return true;
      }
    };
  }

  private static Set<String> splitCommas(String s) {
    return new HashSet<>(Arrays.asList(s.split(",")));
  }

}