View Javadoc

1   // Copyright (C) 2011 Philip Aston
2   // All rights reserved.
3   //
4   // This file is part of The Grinder software distribution. Refer to
5   // the file LICENSE which is part of The Grinder distribution for
6   // licensing details. The Grinder distribution is available on the
7   // Internet at http://grinder.sourceforge.net/
8   //
9   // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
10  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
11  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
12  // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
13  // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
14  // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
15  // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16  // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
17  // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
18  // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
19  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
20  // OF THE POSSIBILITY OF SUCH DAMAGE.
21  
22  package net.grinder.testutility;
23  
24  import static java.util.Arrays.asList;
25  
26  import java.net.MalformedURLException;
27  import java.net.URL;
28  import java.util.ArrayList;
29  import java.util.Arrays;
30  import java.util.Collections;
31  import java.util.HashSet;
32  import java.util.List;
33  import java.util.Set;
34  
35  import net.grinder.util.BlockingClassLoader;
36  
37  import org.junit.runner.Description;
38  import org.junit.runner.Runner;
39  import org.junit.runner.notification.RunNotifier;
40  import org.junit.runners.BlockJUnit4ClassRunner;
41  import org.junit.runners.Suite;
42  import org.junit.runners.model.FrameworkMethod;
43  import org.junit.runners.model.InitializationError;
44  
45  
46  /**
47   * A JUnit test class runner that sets up the context for different Jython
48   * installations.
49   *
50   * @author Philip Aston
51   */
52  public abstract class JythonVersionRunner extends Suite {
53  
54    protected static List<String> getHomes(String... homesProperties) {
55      final List<String> homes = new ArrayList<String>();
56  
57      for (String property : homesProperties) {
58        final String pythonHome = System.getProperty(property);
59  
60        if (pythonHome == null) {
61          System.err.println("***** " + property +
62                             " not set, skipping tests for Jython version.");
63        }
64        else {
65          homes.add(pythonHome);
66        }
67      }
68  
69      return homes;
70    }
71  
72    private static final Set<String> ISOLATED_CLASSES =
73      new HashSet<String>(asList("net.grinder.*",
74                                 "org.python.*",
75                                 "grinder.test.*",
76                                 "org.mockito.*"));
77  
78    private static final Set<String> SHARED_CLASSES =
79      new HashSet<String>(asList("net.grinder.util.weave.agent.*"));
80  
81    public JythonVersionRunner(Class<?> testClass,
82                               List<String> pythonHomes)
83      throws ClassNotFoundException, InitializationError, MalformedURLException{
84  
85      super(testClass, createRunners(testClass, pythonHomes));
86    }
87  
88    private static List<Runner> createRunners(Class<?> testClass,
89                                              List<String> pythonHomes)
90     throws ClassNotFoundException, InitializationError, MalformedURLException {
91  
92      final List<Runner> runners = new ArrayList<Runner>();
93  
94      for (String pythonHome : pythonHomes) {
95        final URL jythonJarURL =
96          new URL("file://" + pythonHome + "/jython.jar");
97  
98        final ClassLoader loader =
99          new BlockingClassLoader(Arrays.asList(jythonJarURL),
100                                 Collections.<String>emptySet(),
101                                 ISOLATED_CLASSES,
102                                 SHARED_CLASSES,
103                                 true);
104 
105       final Class<?> isolatedClass = loader.loadClass(testClass.getName());
106 
107       runners.add(new PythonHomeRunner(isolatedClass, pythonHome));
108     }
109 
110     if (runners.size() == 0) {
111       throw new InitializationError("No python home properties set");
112     }
113 
114     return runners;
115   }
116 
117   private static class PythonHomeRunner extends BlockJUnit4ClassRunner {
118 
119     private final String m_pythonHome;
120 
121     public PythonHomeRunner(Class<?> klass, String pythonHome)
122       throws InitializationError {
123       super(klass);
124 
125       m_pythonHome = pythonHome;
126     }
127 
128     @Override public Description getDescription() {
129       final Class<?> javaClass = getTestClass().getJavaClass();
130 
131       final Description result =
132         Description.createSuiteDescription(
133           javaClass.getSimpleName() + " [" + m_pythonHome + "]",
134           javaClass.getAnnotations());
135 
136       for (Description child : super.getDescription().getChildren()) {
137         result.addChild(child);
138       }
139 
140       return result;
141     }
142 
143     @Override protected String testName(FrameworkMethod method) {
144       return super.testName(method) + " [" + m_pythonHome + "]";
145     }
146 
147     @Override protected void runChild(FrameworkMethod method,
148                                       RunNotifier notifier) {
149       final String oldPythonHome = System.getProperty("python.home");
150 
151       System.setProperty("python.home", m_pythonHome);
152 
153       try {
154         super.runChild(method, notifier);
155       }
156       finally {
157         if (oldPythonHome != null) {
158           System.setProperty("python.home", oldPythonHome);
159         }
160         else {
161           System.clearProperty("python.home");
162         }
163       }
164     }
165   }
166 }