001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase;
019
020import java.io.IOException;
021import java.io.PrintWriter;
022import java.util.Set;
023import java.util.regex.Pattern;
024import org.apache.hadoop.hbase.testclassification.IntegrationTests;
025import org.apache.hadoop.hbase.util.AbstractHBaseTool;
026import org.apache.hadoop.util.ToolRunner;
027import org.junit.platform.engine.DiscoverySelector;
028import org.junit.platform.engine.discovery.DiscoverySelectors;
029import org.junit.platform.launcher.Launcher;
030import org.junit.platform.launcher.LauncherDiscoveryRequest;
031import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
032import org.junit.platform.launcher.core.LauncherFactory;
033import org.junit.platform.launcher.listeners.SummaryGeneratingListener;
034import org.junit.platform.launcher.listeners.TestExecutionSummary;
035import org.slf4j.Logger;
036import org.slf4j.LoggerFactory;
037
038import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLine;
039
040/**
041 * This class drives the Integration test suite execution. Executes all tests having
042 *
043 * <pre>
044 * &#64;Tag(IntegrationTests.TAG)
045 * </pre>
046 *
047 * annotation against an already deployed distributed cluster.
048 */
049public class IntegrationTestsDriver extends AbstractHBaseTool {
050  private static final String SHORT_REGEX_ARG = "r";
051  private static final String LONG_REGEX_ARG = "regex";
052  private static final Logger LOG = LoggerFactory.getLogger(IntegrationTestsDriver.class);
053  private IntegrationTestFilter intTestFilter = new IntegrationTestFilter();
054
055  public static void main(String[] args) throws Exception {
056    int ret = ToolRunner.run(new IntegrationTestsDriver(), args);
057    System.exit(ret);
058  }
059
060  private static class IntegrationTestFilter extends ClassTestFinder.TestClassFilter {
061    private Pattern testFilterRe = Pattern.compile(".*\\.IntegrationTest.*");
062
063    public IntegrationTestFilter() {
064      super(IntegrationTests.class);
065    }
066
067    public void setPattern(String pattern) {
068      testFilterRe = Pattern.compile(pattern);
069    }
070
071    @Override
072    public boolean isCandidateClass(Class<?> c) {
073      return testFilterRe.matcher(c.getName()).find() &&
074      // Our pattern will match the below NON-IntegrationTest. Rather than
075      // do exotic regex, just filter it out here
076        !c.getName().contains("IntegrationTestingUtility") && super.isCandidateClass(c);
077    }
078  }
079
080  @Override
081  protected void addOptions() {
082    addOptWithArg(SHORT_REGEX_ARG, LONG_REGEX_ARG,
083      "Java regex to use selecting tests to run: e.g. .*TestBig.*"
084        + " will select all tests that include TestBig in their name.  Default: "
085        + ".*IntegrationTest.*");
086  }
087
088  @Override
089  protected void processOptions(CommandLine cmd) {
090    String testFilterString = cmd.getOptionValue(SHORT_REGEX_ARG);
091    if (testFilterString != null) {
092      intTestFilter.setPattern(testFilterString);
093    }
094  }
095
096  /**
097   * Returns test classes annotated with @Category(IntegrationTests.class), according to the filter
098   * specific on the command line (if any).
099   */
100  private Class<?>[] findIntegrationTestClasses()
101    throws ClassNotFoundException, LinkageError, IOException {
102    ClassTestFinder.TestFileNameFilter nameFilter = new ClassTestFinder.TestFileNameFilter();
103    ClassFinder classFinder = new ClassFinder(nameFilter, nameFilter, intTestFilter);
104    Set<Class<?>> classes = classFinder.findClasses(true);
105    return classes.toArray(new Class<?>[classes.size()]);
106  }
107
108  private static int runTests(Class<?>[] classes) {
109    DiscoverySelector[] selectors = new DiscoverySelector[classes.length];
110    for (int i = 0; i < classes.length; i++) {
111      selectors[i] = DiscoverySelectors.selectClass(classes[i]);
112    }
113    LauncherDiscoveryRequest request =
114      LauncherDiscoveryRequestBuilder.request().selectors(selectors).build();
115    Launcher launcher = LauncherFactory.create();
116    SummaryGeneratingListener listener = new SummaryGeneratingListener();
117    launcher.registerTestExecutionListeners(listener);
118    launcher.execute(request);
119
120    TestExecutionSummary summary = listener.getSummary();
121    summary.printTo(new PrintWriter(System.out));
122    return summary.getTotalFailureCount() > 0 ? 1 : 0;
123  }
124
125  @Override
126  protected int doWork() throws Exception {
127    // this is called from the command line, so we should set to use the distributed cluster
128    IntegrationTestingUtility.setUseDistributedCluster(conf);
129    Class<?>[] classes = findIntegrationTestClasses();
130    LOG.info("Found " + classes.length + " integration tests to run:");
131    for (Class<?> aClass : classes) {
132      LOG.info("  " + aClass);
133    }
134    return runTests(classes);
135  }
136}