changeset: 68115:264b7c1732cb user: Jaroslav Tulach date: Sun Feb 24 22:48:37 2008 +0100 summary: Getting ready for situation when the boot.jar is loaded by different than application classloader. diff -r 69f3a5197e94 -r 264b7c1732cb o.n.bootstrap/src/org/netbeans/ProxyClassLoader.java --- a/o.n.bootstrap/src/org/netbeans/ProxyClassLoader.java Sun Feb 24 22:45:31 2008 +0100 +++ b/o.n.bootstrap/src/org/netbeans/ProxyClassLoader.java Sun Feb 24 22:48:37 2008 +0100 @@ -75,6 +75,7 @@ public class ProxyClassLoader extends Cl private static final Logger LOGGER = Logger.getLogger(ProxyClassLoader.class.getName()); private static final boolean LOG_LOADING; + private static final ClassLoader TOP_CL = MainImpl.class.getClassLoader(); static { boolean prop1 = System.getProperty("org.netbeans.ProxyClassLoader.level") != null; @@ -90,7 +91,7 @@ public class ProxyClassLoader extends Cl private final boolean transitive; /** The base class loader that is before all ProxyClassLoaders. */ - private ClassLoader systemCL = ClassLoader.getSystemClassLoader(); + private ClassLoader systemCL = TOP_CL; /** A shared map of all packages known by all classloaders. Also covers META-INF based resources. * It contains two kinds of keys: dot-separated package names and slash-separated @@ -112,6 +113,7 @@ public class ProxyClassLoader extends Cl * automatically search through its parent list */ public ProxyClassLoader(ClassLoader[] parents, boolean transitive) { + super(TOP_CL); this.transitive = transitive; this.parents = coalesceParents(parents); changeset: 68116:65103d074e4c user: Jaroslav Tulach date: Mon Feb 25 09:15:19 2008 +0100 summary: Integration with NetBeans Runtime Container. A suite that can execute a test inside a module diff -r 264b7c1732cb -r 65103d074e4c nbjunit/src/org/netbeans/junit/NbModuleSuite.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nbjunit/src/org/netbeans/junit/NbModuleSuite.java Mon Feb 25 09:15:19 2008 +0100 @@ -0,0 +1,190 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2008 Sun Microsystems, Inc. + */ + +package org.netbeans.junit; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.LinkedHashSet; +import java.util.List; +import junit.framework.Assert; +import junit.framework.TestCase; +import junit.framework.TestResult; +import org.openide.util.Exceptions; +import org.openide.util.Lookup; + +/** + * + * @author Jaroslav Tulach + */ +public class NbModuleSuite extends NbTestSuite { + private Class clazz; + + public NbModuleSuite(Class aClass) { + super(); + clazz = aClass; + } + + @Override + public void run(TestResult result) { + try { + runInRuntimeContainer(result); + } catch (Exception ex) { + result.addError(this, ex); + } + } + + private void runInRuntimeContainer(TestResult result) throws Exception { + File platform = findPlatform(); + File[] boot = new File(platform, "lib").listFiles(); + List bootCP = new ArrayList(); + for (int i = 0; i < boot.length; i++) { + URL u = boot[i].toURL(); + if (u.toExternalForm().endsWith(".jar")) { + bootCP.add(u); + } + } + // loader that does not see our current classloader + ClassLoader parent = ClassLoader.getSystemClassLoader().getParent(); + Assert.assertNotNull("Parent", parent); + URLClassLoader loader = new URLClassLoader(bootCP.toArray(new URL[0]), parent); + Class main = loader.loadClass("org.netbeans.Main"); // NOI18N + Assert.assertEquals("Loaded by our classloader", loader, main.getClassLoader()); + Method m = main.getDeclaredMethod("main", String[].class); // NOI18N + + System.setProperty("java.util.logging.config", "-"); + System.setProperty("netbeans.home", platform.getPath()); + + File ud = new File(new File(Manager.getWorkDirPath()), "userdir"); + ud.mkdirs(); + NbTestCase.deleteSubFiles(ud); + + System.setProperty("netbeans.user", ud.getPath()); + + List args = new ArrayList(); + args.add("--nosplash"); + m.invoke(null, (Object)args.toArray(new String[0])); + + ClassLoader global = Lookup.getDefault().lookup(ClassLoader.class); + Assert.assertNotNull("Global classloader is initialized", global); + + URL[] testCP = preparePath(clazz); + JunitLoader testLoader = new JunitLoader(testCP, global, NbTestSuite.class.getClassLoader()); + Class sndClazz = testLoader.loadClass(clazz.getName()); + + new NbTestSuite(sndClazz).run(result); + } + + private URL[] preparePath(Class... classes) { + Collection cp = new LinkedHashSet(); + for (Class c : classes) { + URL test = c.getProtectionDomain().getCodeSource().getLocation(); + Assert.assertNotNull("URL found for " + c, test); + cp.add(test); + } + return cp.toArray(new URL[0]); + } + + + private File findPlatform() { + try { + File util = new File(Lookup.class.getProtectionDomain().getCodeSource().getLocation().toURI()); + Assert.assertTrue("Util exists: " + util, util.exists()); + + return util.getParentFile().getParentFile(); + } catch (URISyntaxException ex) { + Assert.fail("Cannot find utilities JAR"); + return null; + } + } + + private static final class JunitLoader extends URLClassLoader { + private final ClassLoader junit; + + public JunitLoader(URL[] urls, ClassLoader parent, ClassLoader junit) { + super(urls, parent); + this.junit = junit; + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (isUnit(name)) { + return junit.loadClass(name); + } + return super.findClass(name); + } + + @Override + public URL findResource(String name) { + if (isUnit(name)) { + return junit.getResource(name); + } + return super.findResource(name); + } + + @Override + public Enumeration findResources(String name) throws IOException { + if (isUnit(name)) { + return junit.getResources(name); + } + return super.findResources(name); + } + + private final boolean isUnit(String res) { + if (res.startsWith("junit")) { + return true; + } + if (res.startsWith("org.junit") || res.startsWith("org/junit")) { + return true; + } + if (res.startsWith("org.netbeans.junit") || res.startsWith("org/netbeans/junit")) { + return true; + } + return false; + } + } +} diff -r 264b7c1732cb -r 65103d074e4c nbjunit/src/org/netbeans/junit/NbTestCase.java --- a/nbjunit/src/org/netbeans/junit/NbTestCase.java Sun Feb 24 22:48:37 2008 +0100 +++ b/nbjunit/src/org/netbeans/junit/NbTestCase.java Mon Feb 25 09:15:19 2008 +0100 @@ -732,7 +732,7 @@ public abstract class NbTestCase extends } // private method for deleting a file/directory (and all its subdirectories/files) - private void deleteFile(File file) throws IOException { + private static void deleteFile(File file) throws IOException { if (file.isDirectory()) { // file is a directory - delete sub files first File files[] = file.listFiles(); @@ -750,7 +750,7 @@ public abstract class NbTestCase extends } // private method for deleting every subfiles/subdirectories of a file object - private void deleteSubFiles(File file) throws IOException { + static void deleteSubFiles(File file) throws IOException { if (file.isDirectory()) { File files[] = file.listFiles(); for (int i = 0; i < files.length; i++) { diff -r 264b7c1732cb -r 65103d074e4c nbjunit/test/unit/src/org/netbeans/junit/NbModuleSuiteHelper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nbjunit/test/unit/src/org/netbeans/junit/NbModuleSuiteHelper.java Mon Feb 25 09:15:19 2008 +0100 @@ -0,0 +1,17 @@ +package org.netbeans.junit; + +import junit.framework.TestCase; + +public class NbModuleSuiteHelper extends TestCase { + static { + System.err.println("here"); + } + + public NbModuleSuiteHelper(String t) { + super(t); + } + + public void testOne() { + System.setProperty("t.one", "OK"); + } +} diff -r 264b7c1732cb -r 65103d074e4c nbjunit/test/unit/src/org/netbeans/junit/NbModuleSuiteTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nbjunit/test/unit/src/org/netbeans/junit/NbModuleSuiteTest.java Mon Feb 25 09:15:19 2008 +0100 @@ -0,0 +1,74 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2008 Sun Microsystems, Inc. + */ + +package org.netbeans.junit; + +import junit.framework.TestCase; +import junit.framework.TestResult; + +/** + * + * @author Jaroslav Tulach + */ +public class NbModuleSuiteTest extends TestCase { + + public NbModuleSuiteTest(String testName) { + super(testName); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Test of run method, of class NbModuleSuite. + */ + public void testRun() { + NbModuleSuite instance = new NbModuleSuite(NbModuleSuiteHelper.class); + junit.textui.TestRunner.run(instance); + + assertEquals("OK", System.getProperty("t.one")); + } +} changeset: 68117:8053b2274cee user: Jaroslav Tulach date: Mon Feb 25 09:21:18 2008 +0100 summary: Lowering the number of classes, the helper is in fact not needed, I created it only for debugging purposes diff -r 65103d074e4c -r 8053b2274cee nbjunit/test/unit/src/org/netbeans/junit/NbModuleSuiteHelper.java --- a/nbjunit/test/unit/src/org/netbeans/junit/NbModuleSuiteHelper.java Mon Feb 25 09:15:19 2008 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -package org.netbeans.junit; - -import junit.framework.TestCase; - -public class NbModuleSuiteHelper extends TestCase { - static { - System.err.println("here"); - } - - public NbModuleSuiteHelper(String t) { - super(t); - } - - public void testOne() { - System.setProperty("t.one", "OK"); - } -} diff -r 65103d074e4c -r 8053b2274cee nbjunit/test/unit/src/org/netbeans/junit/NbModuleSuiteTest.java --- a/nbjunit/test/unit/src/org/netbeans/junit/NbModuleSuiteTest.java Mon Feb 25 09:15:19 2008 +0100 +++ b/nbjunit/test/unit/src/org/netbeans/junit/NbModuleSuiteTest.java Mon Feb 25 09:21:18 2008 +0100 @@ -66,9 +66,20 @@ public class NbModuleSuiteTest extends T * Test of run method, of class NbModuleSuite. */ public void testRun() { - NbModuleSuite instance = new NbModuleSuite(NbModuleSuiteHelper.class); + NbModuleSuite instance = new NbModuleSuite(T.class); junit.textui.TestRunner.run(instance); assertEquals("OK", System.getProperty("t.one")); } + + public static class T extends TestCase { + public T(String t) { + super(t); + } + + public void testOne() { + System.setProperty("t.one", "OK"); + } + } + } changeset: 68118:07b9b75148ae user: Jaroslav Tulach date: Mon Feb 25 15:48:51 2008 +0100 summary: One can influence the modules to be started by specifying dependencies diff -r 8053b2274cee -r 07b9b75148ae nbjunit/src/org/netbeans/junit/NbModuleSuite.java --- a/nbjunit/src/org/netbeans/junit/NbModuleSuite.java Mon Feb 25 09:21:18 2008 +0100 +++ b/nbjunit/src/org/netbeans/junit/NbModuleSuite.java Mon Feb 25 15:48:51 2008 +0100 @@ -40,7 +40,10 @@ package org.netbeans.junit; package org.netbeans.junit; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URISyntaxException; @@ -49,8 +52,13 @@ import java.util.ArrayList; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import junit.framework.Assert; import junit.framework.TestCase; import junit.framework.TestResult; @@ -105,6 +113,15 @@ public class NbModuleSuite extends NbTes System.setProperty("netbeans.user", ud.getPath()); + TreeSet modules = new TreeSet(); + modules.addAll(findEnabledModules(NbTestSuite.class.getClassLoader())); + modules.add("org.openide.filesystems"); + modules.add("org.openide.modules"); + modules.add("org.openide.util"); + modules.add("org.netbeans.core.startup"); + modules.add("org.netbeans"); + turnModules(ud, modules, platform); + List args = new ArrayList(); args.add("--nosplash"); m.invoke(null, (Object)args.toArray(new String[0])); @@ -140,6 +157,38 @@ public class NbModuleSuite extends NbTes Assert.fail("Cannot find utilities JAR"); return null; } + } + + private static Pattern CODENAME = Pattern.compile("OpenIDE-Module: *([^/$ \n\r]*)[/]?[0-9]*", Pattern.MULTILINE); + /** Looks for all modules on classpath of given loader and builds + * their list from them. + */ + static Set findEnabledModules(ClassLoader loader) throws IOException { + Set cnbs = new TreeSet(); + + Enumeration en = loader.getResources("META-INF/MANIFEST.MF"); + while (en.hasMoreElements()) { + URL url = en.nextElement(); + String manifest = asString(url.openStream(), true); + Matcher m = CODENAME.matcher(manifest); + if (m.find()) { + cnbs.add(m.group(1)); + } + } + + return cnbs; + } + + private static String asString(InputStream is, boolean close) throws IOException { + byte[] arr = new byte[is.available()]; + int len = is.read(arr); + if (len != arr.length) { + throw new IOException("Not fully read: " + arr.length + " was " + len); + } + if (close) { + is.close(); + } + return new String(arr, "UTF-8"); // NOI18N } private static final class JunitLoader extends URLClassLoader { @@ -187,4 +236,43 @@ public class NbModuleSuite extends NbTes return false; } } + + private static Pattern ENABLED = Pattern.compile("([^<]*)", Pattern.MULTILINE); + + private static void turnModules(File ud, TreeSet modules, File... clusterDirs) throws IOException { + File config = new File(new File(ud, "config"), "Modules"); + config.mkdirs(); + + for (File c : clusterDirs) { + File modulesDir = new File(new File(c, "config"), "Modules"); + for (File m : modulesDir.listFiles()) { + String n = m.getName(); + if (n.endsWith(".xml")) { + n = n.substring(0, n.length() - 4); + } + n = n.replace('-', '.'); + + String xml = asString(new FileInputStream(m), true); + Matcher matcherEnabled = ENABLED.matcher(xml); + // Matcher matcherEager = EAGER.matcher(xml); + + boolean enabled = matcherEnabled.find() && "true".equals(matcherEnabled.group(1)); + + if (modules.contains(n) != enabled) { + String out = + xml.substring(0, matcherEnabled.start(1)) + + (enabled ? "false" : "true") + + xml.substring(matcherEnabled.end(1)); + writeModule(new File(config, m.getName()), out); + } + } + } + } + + private static void writeModule(File file, String xml) throws IOException { + FileOutputStream os = new FileOutputStream(file); + os.write(xml.getBytes("UTF-8")); + os.close(); + } } + diff -r 8053b2274cee -r 07b9b75148ae nbjunit/test/unit/src/org/netbeans/junit/NbModuleSuiteTest.java --- a/nbjunit/test/unit/src/org/netbeans/junit/NbModuleSuiteTest.java Mon Feb 25 09:21:18 2008 +0100 +++ b/nbjunit/test/unit/src/org/netbeans/junit/NbModuleSuiteTest.java Mon Feb 25 15:48:51 2008 +0100 @@ -39,6 +39,7 @@ package org.netbeans.junit; +import java.util.Set; import junit.framework.TestCase; import junit.framework.TestResult; @@ -72,6 +73,15 @@ public class NbModuleSuiteTest extends T assertEquals("OK", System.getProperty("t.one")); } + public void testModulesForCL() throws Exception { + Set s = NbModuleSuite.findEnabledModules(ClassLoader.getSystemClassLoader()); + assertEquals("Three modules: " + s, 3, s.size()); + + assertTrue("Util: " + s, s.contains("org.openide.util")); + assertTrue("nbjunit: " + s, s.contains("org.netbeans.modules.nbjunit")); + assertTrue("insanse: " + s, s.contains("org.netbeans.insane")); + } + public static class T extends TestCase { public T(String t) { super(t); changeset: 68119:055e2fc9809e user: Jaroslav Tulach date: Mon Feb 25 16:39:41 2008 +0100 summary: One can specify which clusters shall be scanned diff -r 07b9b75148ae -r 055e2fc9809e nbjunit/src/org/netbeans/junit/NbModuleSuite.java --- a/nbjunit/src/org/netbeans/junit/NbModuleSuite.java Mon Feb 25 15:48:51 2008 +0100 +++ b/nbjunit/src/org/netbeans/junit/NbModuleSuite.java Mon Feb 25 16:39:41 2008 +0100 @@ -45,14 +45,12 @@ import java.io.IOException; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; -import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; -import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -60,9 +58,7 @@ import java.util.regex.Matcher; import java.util.regex.Matcher; import java.util.regex.Pattern; import junit.framework.Assert; -import junit.framework.TestCase; import junit.framework.TestResult; -import org.openide.util.Exceptions; import org.openide.util.Lookup; /** @@ -70,11 +66,17 @@ import org.openide.util.Lookup; * @author Jaroslav Tulach */ public class NbModuleSuite extends NbTestSuite { - private Class clazz; + private final Class clazz; + private final String clusterRegExp; public NbModuleSuite(Class aClass) { + this(aClass, ".*"); + } + + public NbModuleSuite(Class aClass, String clusterRegExp) { super(); - clazz = aClass; + this.clazz = aClass; + this.clusterRegExp = clusterRegExp; } @Override @@ -118,9 +120,20 @@ public class NbModuleSuite extends NbTes modules.add("org.openide.filesystems"); modules.add("org.openide.modules"); modules.add("org.openide.util"); + modules.remove("org.netbeans.insane"); modules.add("org.netbeans.core.startup"); - modules.add("org.netbeans"); + modules.add("org.netbeans.bootstrap"); turnModules(ud, modules, platform); + + StringBuilder sb = new StringBuilder(); + String sep = ""; + for (File f : findClusters()) { + turnModules(ud, modules, f); + sb.append(sep); + sb.append(f.getPath()); + sep = File.pathSeparator; + } + System.setProperty("netbeans.dirs", sb.toString()); List args = new ArrayList(); args.add("--nosplash"); @@ -157,6 +170,25 @@ public class NbModuleSuite extends NbTes Assert.fail("Cannot find utilities JAR"); return null; } + } + + private File[] findClusters() { + List clusters = new ArrayList(); + File plat = findPlatform(); + + for (File f : plat.getParentFile().listFiles()) { + if (f.equals(plat)) { + continue; + } + if (!f.getName().matches(clusterRegExp)) { + continue; + } + File m = new File(new File(f, "config"), "Modules"); + if (m.exists()) { + clusters.add(f); + } + } + return clusters.toArray(new File[0]); } private static Pattern CODENAME = Pattern.compile("OpenIDE-Module: *([^/$ \n\r]*)[/]?[0-9]*", Pattern.MULTILINE); @@ -259,11 +291,17 @@ public class NbModuleSuite extends NbTes boolean enabled = matcherEnabled.find() && "true".equals(matcherEnabled.group(1)); if (modules.contains(n) != enabled) { - String out = - xml.substring(0, matcherEnabled.start(1)) + - (enabled ? "false" : "true") + - xml.substring(matcherEnabled.end(1)); - writeModule(new File(config, m.getName()), out); + assert matcherEnabled.groupCount() == 1 : "Groups: " + matcherEnabled.groupCount() + " for:\n" + xml; + + try { + String out = + xml.substring(0, matcherEnabled.start(1)) + + (enabled ? "false" : "true") + + xml.substring(matcherEnabled.end(1)); + writeModule(new File(config, m.getName()), out); + } catch (IllegalStateException ex) { + throw (IOException)new IOException("Unparseable:\n" + xml).initCause(ex); + } } } } diff -r 07b9b75148ae -r 055e2fc9809e nbjunit/test/unit/src/org/netbeans/junit/NbModuleSuiteTest.java --- a/nbjunit/test/unit/src/org/netbeans/junit/NbModuleSuiteTest.java Mon Feb 25 15:48:51 2008 +0100 +++ b/nbjunit/test/unit/src/org/netbeans/junit/NbModuleSuiteTest.java Mon Feb 25 16:39:41 2008 +0100 @@ -67,7 +67,7 @@ public class NbModuleSuiteTest extends T * Test of run method, of class NbModuleSuite. */ public void testRun() { - NbModuleSuite instance = new NbModuleSuite(T.class); + NbModuleSuite instance = new NbModuleSuite(T.class, ""); junit.textui.TestRunner.run(instance); assertEquals("OK", System.getProperty("t.one")); changeset: 68120:f5c98ac48400 tag: tip user: Jaroslav Tulach date: Mon Feb 25 18:25:24 2008 +0100 summary: Changing the API to be minimalistic, documenting diff -r 055e2fc9809e -r f5c98ac48400 nbjunit/apichanges.xml --- a/nbjunit/apichanges.xml Mon Feb 25 16:39:41 2008 +0100 +++ b/nbjunit/apichanges.xml Mon Feb 25 18:25:24 2008 +0100 @@ -55,11 +55,32 @@ made subject to such option by the copyr + + + Support class to allow excution of unit tests inside of NetBeans Runtime Container + + + + + +

+ It always used to be hard to setup the right environment for test + execution. In case this NetBeans this is even harder. The module + system is ready to work without classpath isolation, however + not every feature is available and every behaviour stays the + same. That is why there is now the new NbModuleSuite + support class that allows to really start the whole NetBeans + Runtime Container, satisfy all the dependencies and only then + load the testing class and execute it. +

+
+ +
Support for Garbage Collecting of Log Message Arguments - + diff -r 055e2fc9809e -r f5c98ac48400 nbjunit/manifest.mf --- a/nbjunit/manifest.mf Mon Feb 25 16:39:41 2008 +0100 +++ b/nbjunit/manifest.mf Mon Feb 25 18:25:24 2008 +0100 @@ -2,4 +2,4 @@ OpenIDE-Module: org.netbeans.modules.nbj OpenIDE-Module: org.netbeans.modules.nbjunit/1 OpenIDE-Module-Localizing-Bundle: org/netbeans/junit/Bundle.properties OpenIDE-Module-Layer: org/netbeans/junit/layer.xml -OpenIDE-Module-Specification-Version: 1.45 +OpenIDE-Module-Specification-Version: 1.46 diff -r 055e2fc9809e -r f5c98ac48400 nbjunit/src/org/netbeans/junit/NbModuleSuite.java --- a/nbjunit/src/org/netbeans/junit/NbModuleSuite.java Mon Feb 25 16:39:41 2008 +0100 +++ b/nbjunit/src/org/netbeans/junit/NbModuleSuite.java Mon Feb 25 18:25:24 2008 +0100 @@ -58,259 +58,314 @@ import java.util.regex.Matcher; import java.util.regex.Matcher; import java.util.regex.Pattern; import junit.framework.Assert; +import junit.framework.Test; import junit.framework.TestResult; import org.openide.util.Lookup; /** + * Wraps a test class with proper NetBeans Runtime Container environment. + * This allows to execute tests in a very similar environment to the + * actual invocation in the NetBeans IDE. To use write your test as + * you are used to and add suite static method: + *
+ * public class YourTest extends NbTestCase {
+ *   public YourTest(String s) { super(s); }
+ * 
+ *   public static Test suite() {
+ *     return NbModuleSuite.create(YourTest.class);
+ *   }
+ * 
+ *   public void testXYZ() { ... }
+ *   public void testABC() { ... }
+ * }
+ * 
* * @author Jaroslav Tulach */ -public class NbModuleSuite extends NbTestSuite { - private final Class clazz; - private final String clusterRegExp; +public final class NbModuleSuite extends Object { - public NbModuleSuite(Class aClass) { - this(aClass, ".*"); - } - - public NbModuleSuite(Class aClass, String clusterRegExp) { - super(); - this.clazz = aClass; - this.clusterRegExp = clusterRegExp; + /** Wraps the provided class into a test that set ups properly the + * testing environment. The set of enabled modules is going to be + * determined from the actual classpath of a module, which is common + * when in all NetBeans tests. All other modules are kept disabled. + *

+ * + * Warning: because the NetBeans Runtime Environment + * plays various tricks with classloaders, the class provided as argument + * is just a template, the one that will really be executed + * is loaded by another classloader. As such it is not recommended to + * do any static initializations in the class, as that would be run twice, + * in different modes and could cause quite a big mishmash. + * + * @param clazz the class with bunch of testXYZ methods + * @return test that starts the NetBeans Runtime Container and then runs the + */ + public static Test create(Class clazz) { + return new S(clazz); } - @Override - public void run(TestResult result) { - try { - runInRuntimeContainer(result); - } catch (Exception ex) { - result.addError(this, ex); - } - } - - private void runInRuntimeContainer(TestResult result) throws Exception { - File platform = findPlatform(); - File[] boot = new File(platform, "lib").listFiles(); - List bootCP = new ArrayList(); - for (int i = 0; i < boot.length; i++) { - URL u = boot[i].toURL(); - if (u.toExternalForm().endsWith(".jar")) { - bootCP.add(u); - } - } - // loader that does not see our current classloader - ClassLoader parent = ClassLoader.getSystemClassLoader().getParent(); - Assert.assertNotNull("Parent", parent); - URLClassLoader loader = new URLClassLoader(bootCP.toArray(new URL[0]), parent); - Class main = loader.loadClass("org.netbeans.Main"); // NOI18N - Assert.assertEquals("Loaded by our classloader", loader, main.getClassLoader()); - Method m = main.getDeclaredMethod("main", String[].class); // NOI18N - - System.setProperty("java.util.logging.config", "-"); - System.setProperty("netbeans.home", platform.getPath()); - - File ud = new File(new File(Manager.getWorkDirPath()), "userdir"); - ud.mkdirs(); - NbTestCase.deleteSubFiles(ud); - - System.setProperty("netbeans.user", ud.getPath()); - - TreeSet modules = new TreeSet(); - modules.addAll(findEnabledModules(NbTestSuite.class.getClassLoader())); - modules.add("org.openide.filesystems"); - modules.add("org.openide.modules"); - modules.add("org.openide.util"); - modules.remove("org.netbeans.insane"); - modules.add("org.netbeans.core.startup"); - modules.add("org.netbeans.bootstrap"); - turnModules(ud, modules, platform); - - StringBuilder sb = new StringBuilder(); - String sep = ""; - for (File f : findClusters()) { - turnModules(ud, modules, f); - sb.append(sep); - sb.append(f.getPath()); - sep = File.pathSeparator; - } - System.setProperty("netbeans.dirs", sb.toString()); - - List args = new ArrayList(); - args.add("--nosplash"); - m.invoke(null, (Object)args.toArray(new String[0])); - - ClassLoader global = Lookup.getDefault().lookup(ClassLoader.class); - Assert.assertNotNull("Global classloader is initialized", global); - - URL[] testCP = preparePath(clazz); - JunitLoader testLoader = new JunitLoader(testCP, global, NbTestSuite.class.getClassLoader()); - Class sndClazz = testLoader.loadClass(clazz.getName()); - - new NbTestSuite(sndClazz).run(result); - } - - private URL[] preparePath(Class... classes) { - Collection cp = new LinkedHashSet(); - for (Class c : classes) { - URL test = c.getProtectionDomain().getCodeSource().getLocation(); - Assert.assertNotNull("URL found for " + c, test); - cp.add(test); - } - return cp.toArray(new URL[0]); + /** Factory method to create wrapper test that knows how to setup proper + * NetBeans Runtime Container environment. In addition to other factory + * methods, it allows one limit the clusters that shall be made available. + * For example ide.*|java.* will start the container just + * with platform, ide and java clusters. + * + * + * @param clazz the class with bunch of testXYZ methods + * @param clustersRegExp regexp to apply to name of cluster to find out if it is supposed to be included + * in the runtime container setup or not + * @return runtime container ready test + */ + public static Test create(Class clazz, String clustersRegExp) { + return new S(clazz); } - - private File findPlatform() { - try { - File util = new File(Lookup.class.getProtectionDomain().getCodeSource().getLocation().toURI()); - Assert.assertTrue("Util exists: " + util, util.exists()); + static final class S extends NbTestSuite { + private final Class clazz; + private final String clusterRegExp; - return util.getParentFile().getParentFile(); - } catch (URISyntaxException ex) { - Assert.fail("Cannot find utilities JAR"); - return null; + public S(Class aClass) { + this(aClass, ".*"); } - } - - private File[] findClusters() { - List clusters = new ArrayList(); - File plat = findPlatform(); - - for (File f : plat.getParentFile().listFiles()) { - if (f.equals(plat)) { - continue; - } - if (!f.getName().matches(clusterRegExp)) { - continue; - } - File m = new File(new File(f, "config"), "Modules"); - if (m.exists()) { - clusters.add(f); - } + + public S(Class aClass, String clusterRegExp) { + super(); + this.clazz = aClass; + this.clusterRegExp = clusterRegExp; } - return clusters.toArray(new File[0]); - } - - private static Pattern CODENAME = Pattern.compile("OpenIDE-Module: *([^/$ \n\r]*)[/]?[0-9]*", Pattern.MULTILINE); - /** Looks for all modules on classpath of given loader and builds - * their list from them. - */ - static Set findEnabledModules(ClassLoader loader) throws IOException { - Set cnbs = new TreeSet(); - - Enumeration en = loader.getResources("META-INF/MANIFEST.MF"); - while (en.hasMoreElements()) { - URL url = en.nextElement(); - String manifest = asString(url.openStream(), true); - Matcher m = CODENAME.matcher(manifest); - if (m.find()) { - cnbs.add(m.group(1)); + + @Override + public void run(TestResult result) { + try { + runInRuntimeContainer(result); + } catch (Exception ex) { + result.addError(this, ex); } } - return cnbs; - } - - private static String asString(InputStream is, boolean close) throws IOException { - byte[] arr = new byte[is.available()]; - int len = is.read(arr); - if (len != arr.length) { - throw new IOException("Not fully read: " + arr.length + " was " + len); - } - if (close) { - is.close(); - } - return new String(arr, "UTF-8"); // NOI18N - } - - private static final class JunitLoader extends URLClassLoader { - private final ClassLoader junit; + private void runInRuntimeContainer(TestResult result) throws Exception { + File platform = findPlatform(); + File[] boot = new File(platform, "lib").listFiles(); + List bootCP = new ArrayList(); + for (int i = 0; i < boot.length; i++) { + URL u = boot[i].toURL(); + if (u.toExternalForm().endsWith(".jar")) { + bootCP.add(u); + } + } + // loader that does not see our current classloader + ClassLoader parent = ClassLoader.getSystemClassLoader().getParent(); + Assert.assertNotNull("Parent", parent); + URLClassLoader loader = new URLClassLoader(bootCP.toArray(new URL[0]), parent); + Class main = loader.loadClass("org.netbeans.Main"); // NOI18N + Assert.assertEquals("Loaded by our classloader", loader, main.getClassLoader()); + Method m = main.getDeclaredMethod("main", String[].class); // NOI18N - public JunitLoader(URL[] urls, ClassLoader parent, ClassLoader junit) { - super(urls, parent); - this.junit = junit; + System.setProperty("java.util.logging.config", "-"); + System.setProperty("netbeans.home", platform.getPath()); + + File ud = new File(new File(Manager.getWorkDirPath()), "userdir"); + ud.mkdirs(); + NbTestCase.deleteSubFiles(ud); + + System.setProperty("netbeans.user", ud.getPath()); + + TreeSet modules = new TreeSet(); + modules.addAll(findEnabledModules(NbTestSuite.class.getClassLoader())); + modules.add("org.openide.filesystems"); + modules.add("org.openide.modules"); + modules.add("org.openide.util"); + modules.remove("org.netbeans.insane"); + modules.add("org.netbeans.core.startup"); + modules.add("org.netbeans.bootstrap"); + turnModules(ud, modules, platform); + + StringBuilder sb = new StringBuilder(); + String sep = ""; + for (File f : findClusters()) { + turnModules(ud, modules, f); + sb.append(sep); + sb.append(f.getPath()); + sep = File.pathSeparator; + } + System.setProperty("netbeans.dirs", sb.toString()); + + List args = new ArrayList(); + args.add("--nosplash"); + m.invoke(null, (Object)args.toArray(new String[0])); + + ClassLoader global = Lookup.getDefault().lookup(ClassLoader.class); + Assert.assertNotNull("Global classloader is initialized", global); + + URL[] testCP = preparePath(clazz); + JunitLoader testLoader = new JunitLoader(testCP, global, NbTestSuite.class.getClassLoader()); + Class sndClazz = testLoader.loadClass(clazz.getName()); + + new NbTestSuite(sndClazz).run(result); } - @Override - protected Class findClass(String name) throws ClassNotFoundException { - if (isUnit(name)) { - return junit.loadClass(name); + private URL[] preparePath(Class... classes) { + Collection cp = new LinkedHashSet(); + for (Class c : classes) { + URL test = c.getProtectionDomain().getCodeSource().getLocation(); + Assert.assertNotNull("URL found for " + c, test); + cp.add(test); } - return super.findClass(name); + return cp.toArray(new URL[0]); } - @Override - public URL findResource(String name) { - if (isUnit(name)) { - return junit.getResource(name); + + private File findPlatform() { + try { + File util = new File(Lookup.class.getProtectionDomain().getCodeSource().getLocation().toURI()); + Assert.assertTrue("Util exists: " + util, util.exists()); + + return util.getParentFile().getParentFile(); + } catch (URISyntaxException ex) { + Assert.fail("Cannot find utilities JAR"); + return null; } - return super.findResource(name); } - @Override - public Enumeration findResources(String name) throws IOException { - if (isUnit(name)) { - return junit.getResources(name); + private File[] findClusters() { + List clusters = new ArrayList(); + File plat = findPlatform(); + + for (File f : plat.getParentFile().listFiles()) { + if (f.equals(plat)) { + continue; + } + if (!f.getName().matches(clusterRegExp)) { + continue; + } + File m = new File(new File(f, "config"), "Modules"); + if (m.exists()) { + clusters.add(f); + } } - return super.findResources(name); + return clusters.toArray(new File[0]); } - - private final boolean isUnit(String res) { - if (res.startsWith("junit")) { - return true; + + private static Pattern CODENAME = Pattern.compile("OpenIDE-Module: *([^/$ \n\r]*)[/]?[0-9]*", Pattern.MULTILINE); + /** Looks for all modules on classpath of given loader and builds + * their list from them. + */ + static Set findEnabledModules(ClassLoader loader) throws IOException { + Set cnbs = new TreeSet(); + + Enumeration en = loader.getResources("META-INF/MANIFEST.MF"); + while (en.hasMoreElements()) { + URL url = en.nextElement(); + String manifest = asString(url.openStream(), true); + Matcher m = CODENAME.matcher(manifest); + if (m.find()) { + cnbs.add(m.group(1)); + } } - if (res.startsWith("org.junit") || res.startsWith("org/junit")) { - return true; + + return cnbs; + } + + private static String asString(InputStream is, boolean close) throws IOException { + byte[] arr = new byte[is.available()]; + int len = is.read(arr); + if (len != arr.length) { + throw new IOException("Not fully read: " + arr.length + " was " + len); } - if (res.startsWith("org.netbeans.junit") || res.startsWith("org/netbeans/junit")) { - return true; + if (close) { + is.close(); } - return false; + return new String(arr, "UTF-8"); // NOI18N } - } - private static Pattern ENABLED = Pattern.compile("([^<]*)", Pattern.MULTILINE); - - private static void turnModules(File ud, TreeSet modules, File... clusterDirs) throws IOException { - File config = new File(new File(ud, "config"), "Modules"); - config.mkdirs(); - - for (File c : clusterDirs) { - File modulesDir = new File(new File(c, "config"), "Modules"); - for (File m : modulesDir.listFiles()) { - String n = m.getName(); - if (n.endsWith(".xml")) { - n = n.substring(0, n.length() - 4); + private static final class JunitLoader extends URLClassLoader { + private final ClassLoader junit; + + public JunitLoader(URL[] urls, ClassLoader parent, ClassLoader junit) { + super(urls, parent); + this.junit = junit; + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (isUnit(name)) { + return junit.loadClass(name); } - n = n.replace('-', '.'); - - String xml = asString(new FileInputStream(m), true); - Matcher matcherEnabled = ENABLED.matcher(xml); - // Matcher matcherEager = EAGER.matcher(xml); - - boolean enabled = matcherEnabled.find() && "true".equals(matcherEnabled.group(1)); - - if (modules.contains(n) != enabled) { - assert matcherEnabled.groupCount() == 1 : "Groups: " + matcherEnabled.groupCount() + " for:\n" + xml; + return super.findClass(name); + } - try { - String out = - xml.substring(0, matcherEnabled.start(1)) + - (enabled ? "false" : "true") + - xml.substring(matcherEnabled.end(1)); - writeModule(new File(config, m.getName()), out); - } catch (IllegalStateException ex) { - throw (IOException)new IOException("Unparseable:\n" + xml).initCause(ex); + @Override + public URL findResource(String name) { + if (isUnit(name)) { + return junit.getResource(name); + } + return super.findResource(name); + } + + @Override + public Enumeration findResources(String name) throws IOException { + if (isUnit(name)) { + return junit.getResources(name); + } + return super.findResources(name); + } + + private final boolean isUnit(String res) { + if (res.startsWith("junit")) { + return true; + } + if (res.startsWith("org.junit") || res.startsWith("org/junit")) { + return true; + } + if (res.startsWith("org.netbeans.junit") || res.startsWith("org/netbeans/junit")) { + return true; + } + return false; + } + } + + private static Pattern ENABLED = Pattern.compile("([^<]*)", Pattern.MULTILINE); + + private static void turnModules(File ud, TreeSet modules, File... clusterDirs) throws IOException { + File config = new File(new File(ud, "config"), "Modules"); + config.mkdirs(); + + for (File c : clusterDirs) { + File modulesDir = new File(new File(c, "config"), "Modules"); + for (File m : modulesDir.listFiles()) { + String n = m.getName(); + if (n.endsWith(".xml")) { + n = n.substring(0, n.length() - 4); + } + n = n.replace('-', '.'); + + String xml = asString(new FileInputStream(m), true); + Matcher matcherEnabled = ENABLED.matcher(xml); + // Matcher matcherEager = EAGER.matcher(xml); + + boolean enabled = matcherEnabled.find() && "true".equals(matcherEnabled.group(1)); + + if (modules.contains(n) != enabled) { + assert matcherEnabled.groupCount() == 1 : "Groups: " + matcherEnabled.groupCount() + " for:\n" + xml; + + try { + String out = + xml.substring(0, matcherEnabled.start(1)) + + (enabled ? "false" : "true") + + xml.substring(matcherEnabled.end(1)); + writeModule(new File(config, m.getName()), out); + } catch (IllegalStateException ex) { + throw (IOException)new IOException("Unparseable:\n" + xml).initCause(ex); + } } } } } - } - private static void writeModule(File file, String xml) throws IOException { - FileOutputStream os = new FileOutputStream(file); - os.write(xml.getBytes("UTF-8")); - os.close(); - } + private static void writeModule(File file, String xml) throws IOException { + FileOutputStream os = new FileOutputStream(file); + os.write(xml.getBytes("UTF-8")); + os.close(); + } + } // end of S } - diff -r 055e2fc9809e -r f5c98ac48400 nbjunit/test/unit/src/org/netbeans/junit/NbModuleSuiteTest.java --- a/nbjunit/test/unit/src/org/netbeans/junit/NbModuleSuiteTest.java Mon Feb 25 16:39:41 2008 +0100 +++ b/nbjunit/test/unit/src/org/netbeans/junit/NbModuleSuiteTest.java Mon Feb 25 18:25:24 2008 +0100 @@ -40,8 +40,8 @@ package org.netbeans.junit; package org.netbeans.junit; import java.util.Set; +import junit.framework.Test; import junit.framework.TestCase; -import junit.framework.TestResult; /** * @@ -67,14 +67,14 @@ public class NbModuleSuiteTest extends T * Test of run method, of class NbModuleSuite. */ public void testRun() { - NbModuleSuite instance = new NbModuleSuite(T.class, ""); + Test instance = NbModuleSuite.create(T.class, ""); junit.textui.TestRunner.run(instance); assertEquals("OK", System.getProperty("t.one")); } public void testModulesForCL() throws Exception { - Set s = NbModuleSuite.findEnabledModules(ClassLoader.getSystemClassLoader()); + Set s = NbModuleSuite.S.findEnabledModules(ClassLoader.getSystemClassLoader()); assertEquals("Three modules: " + s, 3, s.size()); assertTrue("Util: " + s, s.contains("org.openide.util"));