eea226a5fd2cc1c3a872a8ddc354421745968e7f
[odlparent.git] / features4-test / src / main / java / org / opendaylight / odlparent / featuretest / PerRepoTestRunner.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.odlparent.featuretest;
10
11 import java.io.IOException;
12 import java.net.URL;
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;
25
26 public class PerRepoTestRunner extends ParentRunner<PerFeatureRunner> {
27
28     private static final Logger LOG = LoggerFactory.getLogger(PerRepoTestRunner.class);
29
30     private static final String REPO_RECURSE = "repo.recurse";
31     private static final String[] FEATURES_FILENAMES = new String[] { "features.xml", "feature.xml" };
32
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")
40
41     private final List<PerFeatureRunner> children = new ArrayList<>();
42
43     /**
44      * Create a runner.
45      *
46      * @param testClass The test class.
47      * @throws InitializationError if an error occurs.
48      */
49     public PerRepoTestRunner(final Class<?> testClass) throws InitializationError {
50         super(testClass);
51         setURLStreamHandlerFactory();
52         try {
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));
59                 } else {
60                     LOG.error("getClass().getClassLoader().getResource(\"{}\") returned null", filename);
61                 }
62             }
63         } catch (final IOException | JAXBException e) {
64             throw new InitializationError(e);
65         }
66     }
67
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) {
73             try {
74                 URL.setURLStreamHandlerFactory(new CustomBundleUrlStreamHandlerFactory());
75                 isURLStreamHandlerFactorySet = true;
76             } catch (Error e) {
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);
80             }
81         }
82     }
83
84     protected List<PerFeatureRunner> runnersFromRepoUrl(
85             final URL repoUrl, final Class<?> testClass, final boolean recursive)
86             throws JAXBException, IOException, InitializationError {
87         if (recursive) {
88             return recursiveRunnersFromRepoUrl(repoUrl, testClass);
89         } else {
90             return runnersFromRepoUrl(repoUrl, testClass);
91         }
92     }
93
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));
99         return runners;
100     }
101
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));
110         }
111         return runners;
112     }
113
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));
120         }
121         return runners;
122     }
123
124     protected Features getFeatures(final URL repoUrl) throws JAXBException, IOException {
125         return JaxbUtil.unmarshal(repoUrl.toExternalForm(), false);
126     }
127
128     @Override
129     protected List<PerFeatureRunner> getChildren() {
130         return children;
131     }
132
133     @Override
134     protected Description describeChild(final PerFeatureRunner child) {
135         return child.getDescription();
136     }
137
138     @Override
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());
143         child.run(notifier);
144     }
145
146     /* (non-Javadoc)
147      * @see org.junit.runner.Runner#testCount()
148      */
149     @Override
150     public int testCount() {
151         return super.testCount() * children.size();
152     }
153 }