2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.odlparent.featuretest;
11 import java.io.IOException;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.List;
16 import javax.xml.bind.JAXBException;
17 import org.apache.karaf.features.internal.model.Feature;
18 import org.apache.karaf.features.internal.model.Features;
19 import org.apache.karaf.features.internal.model.JaxbUtil;
20 import org.junit.runner.Description;
21 import org.junit.runner.notification.RunNotifier;
22 import org.junit.runners.ParentRunner;
23 import org.junit.runners.model.InitializationError;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
27 public class PerRepoTestRunner extends ParentRunner<PerFeatureRunner> {
29 private static final Logger LOG = LoggerFactory.getLogger(PerRepoTestRunner.class);
31 private static final String REPO_RECURSE = "repo.recurse";
32 private static final String[] FEATURES_FILENAMES = new String[] { "features.xml", "feature.xml" };
34 private static boolean isURLStreamHandlerFactorySet = false;
35 // Do NOT static { URL.setURLStreamHandlerFactory(new CustomBundleUrlStreamHandlerFactory()); }
36 // This is VERY BAD practice, because it leads to VERY HARD TO TRACK errors in case ANYTHING
37 // goes wrong in this. For example, we had a case where (following an upgrade of PAX Exam)
38 // a dependency was missing. This appeared as a confusing error because the root cause
39 // of static initialization errors is typically lost in Java; so best is NOT to use it!
40 // ("NoClassDefFoundError: Could not initialize class ...PerRepoTestRunner")
42 private final List<PerFeatureRunner> children = new ArrayList<>();
47 * @param testClass The test class.
48 * @throws InitializationError if an error occurs.
50 public PerRepoTestRunner(final Class<?> testClass) throws InitializationError {
52 setURLStreamHandlerFactory();
54 for (String filename : FEATURES_FILENAMES) {
55 final URL repoUrl = getClass().getClassLoader().getResource(filename);
56 if (repoUrl != null) {
57 final boolean recursive = Boolean.getBoolean(REPO_RECURSE);
58 LOG.info("Creating test runners for repoUrl {} recursive {}", repoUrl, recursive);
59 children.addAll(runnersFromRepoUrl(repoUrl, testClass, recursive));
62 if (children.isEmpty()) {
63 LOG.error("No features found to test; looked for {}", Arrays.toString(FEATURES_FILENAMES));
65 } catch (final IOException | JAXBException e) {
66 throw new InitializationError(e);
70 // We have to exceptionally suppress IllegalCatch just because URL.setURLStreamHandlerFactory stupidly throws Error
71 @SuppressWarnings("checkstyle:IllegalCatch")
72 // see doc on isURLStreamHandlerFactorySet for why we do NOT want to do this in a static block
73 private static synchronized void setURLStreamHandlerFactory() {
74 if (!isURLStreamHandlerFactorySet) {
76 URL.setURLStreamHandlerFactory(new CustomBundleUrlStreamHandlerFactory());
77 isURLStreamHandlerFactorySet = true;
79 LOG.warn("Failed to setURLStreamHandlerFactory to CustomBundleUrlStreamHandlerFactory "
80 + "(depending on which is already set, this may or may not actually be a problem"
81 + "; e.g. Karaf 4 already registers the neccessary handlers, so OK to ignore)", e);
86 protected List<PerFeatureRunner> runnersFromRepoUrl(
87 final URL repoUrl, final Class<?> testClass, final boolean recursive)
88 throws JAXBException, IOException, InitializationError {
90 return recursiveRunnersFromRepoUrl(repoUrl, testClass);
92 return runnersFromRepoUrl(repoUrl, testClass);
96 protected List<PerFeatureRunner> runnersFromRepoUrl(final URL repoUrl, final Class<?> testClass)
97 throws JAXBException, IOException, InitializationError {
98 final List<PerFeatureRunner> runners = new ArrayList<>();
99 final Features features = getFeatures(repoUrl);
100 runners.addAll(runnersFromFeatures(repoUrl, features, testClass));
104 protected List<PerFeatureRunner> recursiveRunnersFromRepoUrl(final URL repoUrl, final Class<?> testClass)
105 throws JAXBException, IOException, InitializationError {
106 final List<PerFeatureRunner> runners = new ArrayList<>();
107 final Features features = getFeatures(repoUrl);
108 runners.addAll(runnersFromRepoUrl(repoUrl, testClass));
109 for (final String repoString : features.getRepository()) {
110 final URL subRepoUrl = new URL(repoString);
111 runners.addAll(recursiveRunnersFromRepoUrl(subRepoUrl, testClass));
116 protected List<PerFeatureRunner> runnersFromFeatures(
117 final URL repoUrl, final Features features, final Class<?> testClass) throws InitializationError {
118 final List<PerFeatureRunner> runners = new ArrayList<>();
119 final List<Feature> featureList = features.getFeature();
120 for (final Feature f : featureList) {
121 runners.add(new PerFeatureRunner(repoUrl, f.getName(), f.getVersion(), testClass));
126 protected Features getFeatures(final URL repoUrl) throws JAXBException, IOException {
127 return JaxbUtil.unmarshal(repoUrl.toExternalForm(), false);
131 protected List<PerFeatureRunner> getChildren() {
136 protected Description describeChild(final PerFeatureRunner child) {
137 return child.getDescription();
141 @SuppressWarnings("checkstyle:RegexpSinglelineJava")
142 protected void runChild(final PerFeatureRunner child, final RunNotifier notifier) {
143 LOG.info("[LOG] About to run test: {}", child.getDescription());
144 System.out.println("[sys.out] About to run test: " + child.getDescription());
149 * @see org.junit.runner.Runner#testCount()
152 public int testCount() {
153 return super.testCount() * children.size();