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
042 * having @Category(IntegrationTests.class) annotation against an already deployed distributed
043 * cluster.
044 */
045public class IntegrationTestsDriver extends AbstractHBaseTool {
046  private static final String SHORT_REGEX_ARG = "r";
047  private static final String LONG_REGEX_ARG = "regex";
048  private static final Logger LOG = LoggerFactory.getLogger(IntegrationTestsDriver.class);
049  private IntegrationTestFilter intTestFilter = new IntegrationTestFilter();
050
051  public static void main(String[] args) throws Exception {
052    int ret = ToolRunner.run(new IntegrationTestsDriver(), args);
053    System.exit(ret);
054  }
055
056  private static class IntegrationTestFilter extends ClassTestFinder.TestClassFilter {
057    private Pattern testFilterRe = Pattern.compile(".*\\.IntegrationTest.*");
058
059    public IntegrationTestFilter() {
060      super(IntegrationTests.class);
061    }
062
063    public void setPattern(String pattern) {
064      testFilterRe = Pattern.compile(pattern);
065    }
066
067    @Override
068    public boolean isCandidateClass(Class<?> c) {
069      return testFilterRe.matcher(c.getName()).find() &&
070      // Our pattern will match the below NON-IntegrationTest. Rather than
071      // do exotic regex, just filter it out here
072        !c.getName().contains("IntegrationTestingUtility") && super.isCandidateClass(c);
073    }
074  }
075
076  @Override
077  protected void addOptions() {
078    addOptWithArg(SHORT_REGEX_ARG, LONG_REGEX_ARG,
079      "Java regex to use selecting tests to run: e.g. .*TestBig.*"
080        + " will select all tests that include TestBig in their name.  Default: "
081        + ".*IntegrationTest.*");
082  }
083
084  @Override
085  protected void processOptions(CommandLine cmd) {
086    String testFilterString = cmd.getOptionValue(SHORT_REGEX_ARG);
087    if (testFilterString != null) {
088      intTestFilter.setPattern(testFilterString);
089    }
090  }
091
092  /**
093   * Returns test classes annotated with @Category(IntegrationTests.class), according to the filter
094   * specific on the command line (if any).
095   */
096  private Class<?>[] findIntegrationTestClasses()
097    throws ClassNotFoundException, LinkageError, IOException {
098    ClassTestFinder.TestFileNameFilter nameFilter = new ClassTestFinder.TestFileNameFilter();
099    ClassFinder classFinder = new ClassFinder(nameFilter, nameFilter, intTestFilter);
100    Set<Class<?>> classes = classFinder.findClasses(true);
101    return classes.toArray(new Class<?>[classes.size()]);
102  }
103
104  private static int runTests(Class<?>[] classes) {
105    DiscoverySelector[] selectors = new DiscoverySelector[classes.length];
106    for (int i = 0; i < classes.length; i++) {
107      selectors[i] = DiscoverySelectors.selectClass(classes[i]);
108    }
109    LauncherDiscoveryRequest request =
110      LauncherDiscoveryRequestBuilder.request().selectors(selectors).build();
111    Launcher launcher = LauncherFactory.create();
112    SummaryGeneratingListener listener = new SummaryGeneratingListener();
113    launcher.registerTestExecutionListeners(listener);
114    launcher.execute(request);
115
116    TestExecutionSummary summary = listener.getSummary();
117    summary.printTo(new PrintWriter(System.out));
118    return summary.getTotalFailureCount() > 0 ? 1 : 0;
119  }
120
121  @Override
122  protected int doWork() throws Exception {
123    // this is called from the command line, so we should set to use the distributed cluster
124    IntegrationTestingUtility.setUseDistributedCluster(conf);
125    Class<?>[] classes = findIntegrationTestClasses();
126    LOG.info("Found " + classes.length + " integration tests to run:");
127    for (Class<?> aClass : classes) {
128      LOG.info("  " + aClass);
129    }
130    return runTests(classes);
131  }
132}