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.List;
15 import javax.xml.bind.JAXBException;
16 import org.apache.karaf.features.internal.model.Feature;
17 import org.apache.karaf.features.internal.model.Features;
18 import org.apache.karaf.features.internal.model.JaxbUtil;
19 import org.junit.runner.Description;
20 import org.junit.runner.notification.RunNotifier;
21 import org.junit.runners.ParentRunner;
22 import org.junit.runners.model.InitializationError;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
26 public class PerRepoTestRunner extends ParentRunner<PerFeatureRunner> {
28 private static final Logger LOG = LoggerFactory.getLogger(PerRepoTestRunner.class);
30 private static final String REPO_RECURSE = "repo.recurse";
31 private static final String[] FEATURES_FILENAMES = new String[] { "features.xml", "feature.xml" };
33 private static boolean isURLStreamHandlerFactorySet = false;
34 // Do NOT static { URL.setURLStreamHandlerFactory(new CustomBundleUrlStreamHandlerFactory()); }
35 // This is VERY BAD practice, because it leads to VERY HARD TO TRACK errors in case ANYTHING
36 // goes wrong in this. For example, we had a case where (following an upgrade of PAX Exam)
37 // a dependency was missing. This appeared as a confusing error because the root cause
38 // of static initialization errors is typically lost in Java; so best is NOT to use it!
39 // ("NoClassDefFoundError: Could not initialize class ...PerRepoTestRunner")
41 private final List<PerFeatureRunner> children = new ArrayList<>();
46 * @param testClass The test class.
47 * @throws InitializationError if an error occurs.
49 public PerRepoTestRunner(final Class<?> testClass) throws InitializationError {
51 setURLStreamHandlerFactory();
53 for (String filename : FEATURES_FILENAMES) {
54 final URL repoUrl = getClass().getClassLoader().getResource(filename);
55 if (repoUrl != null) {
56 final boolean recursive = Boolean.getBoolean(REPO_RECURSE);
57 LOG.info("Creating test runners for repoUrl {} recursive {}", repoUrl, recursive);
58 children.addAll(runnersFromRepoUrl(repoUrl, testClass, recursive));
60 LOG.error("getClass().getClassLoader().getResource(\"{}\") returned null", filename);
63 } catch (final IOException | JAXBException e) {
64 throw new InitializationError(e);
68 // We have to exceptionally suppress IllegalCatch just because URL.setURLStreamHandlerFactory stupidly throws Error
69 @SuppressWarnings("checkstyle:IllegalCatch")
70 // see doc on isURLStreamHandlerFactorySet for why we do NOT want to do this in a static block
71 private static synchronized void setURLStreamHandlerFactory() {
72 if (!isURLStreamHandlerFactorySet) {
74 URL.setURLStreamHandlerFactory(new CustomBundleUrlStreamHandlerFactory());
75 isURLStreamHandlerFactorySet = true;
77 LOG.warn("Failed to setURLStreamHandlerFactory to CustomBundleUrlStreamHandlerFactory "
78 + "(depending on which is already set, this may or may not actually be a problem"
79 + "; e.g. Karaf 4 already registers the neccessary handlers, so OK to ignore)", e);
84 protected List<PerFeatureRunner> runnersFromRepoUrl(
85 final URL repoUrl, final Class<?> testClass, final boolean recursive)
86 throws JAXBException, IOException, InitializationError {
88 return recursiveRunnersFromRepoUrl(repoUrl, testClass);
90 return runnersFromRepoUrl(repoUrl, testClass);
94 protected List<PerFeatureRunner> runnersFromRepoUrl(final URL repoUrl, final Class<?> testClass)
95 throws JAXBException, IOException, InitializationError {
96 final List<PerFeatureRunner> runners = new ArrayList<>();
97 final Features features = getFeatures(repoUrl);
98 runners.addAll(runnersFromFeatures(repoUrl, features, testClass));
102 protected List<PerFeatureRunner> recursiveRunnersFromRepoUrl(final URL repoUrl, final Class<?> testClass)
103 throws JAXBException, IOException, InitializationError {
104 final List<PerFeatureRunner> runners = new ArrayList<>();
105 final Features features = getFeatures(repoUrl);
106 runners.addAll(runnersFromRepoUrl(repoUrl, testClass));
107 for (final String repoString : features.getRepository()) {
108 final URL subRepoUrl = new URL(repoString);
109 runners.addAll(recursiveRunnersFromRepoUrl(subRepoUrl, testClass));
114 protected List<PerFeatureRunner> runnersFromFeatures(
115 final URL repoUrl, final Features features, final Class<?> testClass) throws InitializationError {
116 final List<PerFeatureRunner> runners = new ArrayList<>();
117 final List<Feature> featureList = features.getFeature();
118 for (final Feature f : featureList) {
119 runners.add(new PerFeatureRunner(repoUrl, f.getName(), f.getVersion(), testClass));
124 protected Features getFeatures(final URL repoUrl) throws JAXBException, IOException {
125 return JaxbUtil.unmarshal(repoUrl.toExternalForm(), false);
129 protected List<PerFeatureRunner> getChildren() {
134 protected Description describeChild(final PerFeatureRunner child) {
135 return child.getDescription();
139 @SuppressWarnings("checkstyle:RegexpSinglelineJava")
140 protected void runChild(final PerFeatureRunner child, final RunNotifier notifier) {
141 LOG.info("[LOG] About to run test: {}", child.getDescription());
142 System.out.println("[sys.out] About to run test: " + child.getDescription());
147 * @see org.junit.runner.Runner#testCount()
150 public int testCount() {
151 return super.testCount() * children.size();