diff --git a/src/jorphan/org/apache/jorphan/reflect/ClassFilter.java b/src/jorphan/org/apache/jorphan/reflect/ClassFilter.java new file mode 100644 index 00000000000..112a6980ed6 --- /dev/null +++ b/src/jorphan/org/apache/jorphan/reflect/ClassFilter.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.jorphan.reflect; + +/** + * filter class when visiting the search path with {@link ClassFinder} + */ +public interface ClassFilter { + + boolean accept(String className); +} diff --git a/src/jorphan/org/apache/jorphan/reflect/ClassFinder.java b/src/jorphan/org/apache/jorphan/reflect/ClassFinder.java index 6db763644e9..2ae2e438c07 100644 --- a/src/jorphan/org/apache/jorphan/reflect/ClassFinder.java +++ b/src/jorphan/org/apache/jorphan/reflect/ClassFinder.java @@ -56,13 +56,10 @@ private ClassFinder() { } /** - * Filter updates to TreeSet by only storing classes + * Filter updates by only storing classes * that extend one of the parent classes - * - * */ - private static class FilterTreeSet extends TreeSet{ - private static final long serialVersionUID = 234L; + private static class ExtendsClassFilter implements ClassFilter { private final Class[] parents; // parent classes to check private final boolean inner; // are inner classes OK? @@ -75,73 +72,50 @@ private static class FilterTreeSet extends TreeSet{ private final transient ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); // Potentially expensive; do it once - FilterTreeSet(Class []parents, boolean inner, String contains, String notContains){ - super(); - this.parents=parents; - this.inner=inner; - this.contains=contains; - this.notContains=notContains; + ExtendsClassFilter(Class []parents, boolean inner, String contains, String notContains){ + this.parents = parents; + this.inner = inner; + this.contains = contains; + this.notContains = notContains; } - /** - * Override the superclass so we only add classnames that - * meet the criteria. - * - * @param s - classname (must be a String) - * @return true if it is a new entry - * - * @see java.util.TreeSet#add(java.lang.Object) - */ @Override - public boolean add(String s){ - if (contains(s)) { - return false;// No need to check it again - } - if (contains!=null && s.indexOf(contains) == -1){ + public boolean accept(String className) { + + if (contains!=null && className.indexOf(contains) == -1){ return false; // It does not contain a required string } - if (notContains!=null && s.indexOf(notContains) != -1){ + if (notContains!=null && className.indexOf(notContains) != -1){ return false; // It contains a banned string } - if ((s.indexOf('$') == -1) || inner) { // $NON-NLS-1$ - if (isChildOf(parents,s, contextClassLoader)) { - return super.add(s); + if ((className.indexOf('$') == -1) || inner) { // $NON-NLS-1$ + if (isChildOf(parents,className, contextClassLoader)) { + return true; } } return false; } } - private static class AnnoFilterTreeSet extends TreeSet{ - private static final long serialVersionUID = 240L; - + + private static class AnnoClassFilter implements ClassFilter { + private final boolean inner; // are inner classes OK? private final Class[] annotations; // annotation classes to check private final transient ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); // Potentially expensive; do it once - AnnoFilterTreeSet(Class []annotations, boolean inner){ - super(); + + AnnoClassFilter(Class []annotations, boolean inner){ this.annotations = annotations; - this.inner=inner; + this.inner = inner; } - /** - * Override the superclass so we only add classnames that - * meet the criteria. - * - * @param s - classname (must be a String) - * @return true if it is a new entry - * - * @see java.util.TreeSet#add(java.lang.Object) - */ + @Override - public boolean add(String s){ - if (contains(s)) { - return false;// No need to check it again - } - if ((s.indexOf('$') == -1) || inner) { // $NON-NLS-1$ - if (hasAnnotationOnMethod(annotations,s, contextClassLoader)) { - return super.add(s); + public boolean accept(String className) { + if ((className.indexOf('$') == -1) || inner) { // $NON-NLS-1$ + if (hasAnnotationOnMethod(annotations,className, contextClassLoader)) { + return true; } } return false; @@ -276,12 +250,31 @@ public static List findClassesThatExtend(String[] searchPathsOrJars, log.debug("contains: " + contains + " notContains: " + notContains); } + + ClassFilter filter = null; + if(annotations) { + @SuppressWarnings("unchecked") // Should only be called with classes that extend annotations + final Class[] annoclassNames = (Class[]) classNames; + filter = new AnnoClassFilter(annoclassNames, innerClasses); + } + else { + filter = new ExtendsClassFilter(classNames, innerClasses, contains, notContains); + } + + return findClasses(searchPathsOrJars, filter); + } + + public static List findClasses(String[] searchPathsOrJars, ClassFilter filter) throws IOException { + if (log.isDebugEnabled()) { + log.debug("searchPathsOrJars : " + Arrays.toString(searchPathsOrJars)); + } + // Find all jars in the search path String[] strPathsOrJars = addJarsInPath(searchPathsOrJars); for (int k = 0; k < strPathsOrJars.length; k++) { strPathsOrJars[k] = fixPathEntry(strPathsOrJars[k]); } - + // Now eliminate any classpath entries that do not "match" the search List listPaths = getClasspathMatches(strPathsOrJars); if (log.isDebugEnabled()) { @@ -289,16 +282,13 @@ public static List findClassesThatExtend(String[] searchPathsOrJars, log.debug("listPaths : " + path); } } - - @SuppressWarnings("unchecked") // Should only be called with classes that extend annotations - final Class[] annoclassNames = (Class[]) classNames; - Set listClasses = - annotations ? - new AnnoFilterTreeSet(annoclassNames, innerClasses) - : - new FilterTreeSet(classNames, innerClasses, contains, notContains); + + Set listClasses = new TreeSet<>(); // first get all the classes - findClassesInPaths(listPaths, listClasses); + for (String path : listPaths) { + findClassesInOnePath(path, listClasses, filter); + } + if (log.isDebugEnabled()) { log.debug("listClasses.size()="+listClasses.size()); for (String clazz : listClasses) { @@ -440,10 +430,11 @@ private static String fixClassName(String strClassName) { return strClassName; } - private static void findClassesInOnePath(String strPath, Set listClasses) throws IOException { + + private static void findClassesInOnePath(String strPath, Set listClasses, ClassFilter filter) throws IOException { File file = new File(strPath); if (file.isDirectory()) { - findClassesInPathsDir(strPath, file, listClasses); + findClassesInPathsDir(strPath, file, listClasses, filter); } else if (file.exists()) { ZipFile zipFile = null; try { @@ -452,7 +443,10 @@ private static void findClassesInOnePath(String strPath, Set listClasses while (entries.hasMoreElements()) { String strEntry = entries.nextElement().toString(); if (strEntry.endsWith(DOT_CLASS)) { - listClasses.add(fixClassName(strEntry)); + String fixedClassName = fixClassName(strEntry); + if(filter.accept(fixedClassName)) { + listClasses.add(fixedClassName); + } } } } catch (IOException e) { @@ -466,29 +460,30 @@ private static void findClassesInOnePath(String strPath, Set listClasses } } - private static void findClassesInPaths(List listPaths, Set listClasses) throws IOException { - for (String path : listPaths) { - findClassesInOnePath(path, listClasses); - } - } - private static void findClassesInPathsDir(String strPathElement, File dir, Set listClasses) throws IOException { + private static void findClassesInPathsDir(String strPathElement, File dir, Set listClasses, ClassFilter filter) throws IOException { String[] list = dir.list(); - if(list==null) { + if(list == null) { log.warn(dir.getAbsolutePath()+" is not a folder"); return; } + for (String aList : list) { File file = new File(dir, aList); if (file.isDirectory()) { // Recursive call - findClassesInPathsDir(strPathElement, file, listClasses); - } else if (aList.endsWith(DOT_CLASS) && file.exists() && (file.length() != 0)) { + findClassesInPathsDir(strPathElement, file, listClasses, filter); + } + else if (aList.endsWith(DOT_CLASS) && file.exists() && (file.length() != 0)) { final String path = file.getPath(); - listClasses.add(path.substring(strPathElement.length() + 1, + String className = path.substring(strPathElement.length() + 1, path.lastIndexOf('.')) // $NON-NLS-1$ - .replace(File.separator.charAt(0), '.')); // $NON-NLS-1$ + .replace(File.separator.charAt(0), '.');// $NON-NLS-1$ + if(filter.accept(className)) { + listClasses.add(className); + } } } } + } diff --git a/test/src/org/apache/jmeter/gui/util/TestMenuFactory.java b/test/src/org/apache/jmeter/gui/util/TestMenuFactory.java index 1de0355a357..c969d251a55 100644 --- a/test/src/org/apache/jmeter/gui/util/TestMenuFactory.java +++ b/test/src/org/apache/jmeter/gui/util/TestMenuFactory.java @@ -18,10 +18,16 @@ package org.apache.jmeter.gui.util; +import java.awt.GraphicsEnvironment; + import org.apache.jmeter.junit.JMeterTestCase; +import org.apache.jorphan.logging.LoggingManager; +import org.apache.log.Logger; public final class TestMenuFactory extends JMeterTestCase { + private static final Logger log = LoggingManager.getLoggerForClass(); + public TestMenuFactory() { super(); } @@ -35,6 +41,11 @@ private static void check(String s, int i) throws Exception { } public void testMenu() throws Exception { + if(GraphicsEnvironment.isHeadless()) { + System.out.println("Skipping test:"+getClass().getName()+"#testCloneSampler"+", cannot run in Headless mode"); + log.warn("Skipping test:"+getClass().getName()+"#testCloneSampler"+", cannot run in Headless mode"); + return; + } check("menumap", MenuFactory.menuMap_size()); check("assertions", MenuFactory.assertions_size()); diff --git a/test/src/org/apache/jmeter/junit/JMeterTest.java b/test/src/org/apache/jmeter/junit/JMeterTest.java index b9f7b05615c..04d27c9e888 100644 --- a/test/src/org/apache/jmeter/junit/JMeterTest.java +++ b/test/src/org/apache/jmeter/junit/JMeterTest.java @@ -19,6 +19,7 @@ package org.apache.jmeter.junit; import java.awt.Component; +import java.awt.GraphicsEnvironment; import java.awt.HeadlessException; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -129,12 +130,18 @@ public JMeterTest(String testName, Function fi) { * Use a suite to allow the tests to be generated at run-time */ public static Test suite() throws Exception { + TestSuite suite = new TestSuite("JMeterTest"); + if(GraphicsEnvironment.isHeadless()) { + System.out.println("Skipping test:"+JMeterTest.class.getName()+", cannot run in Headless mode"); + log.warn("Skipping test:"+JMeterTest.class.getName()+", cannot run in Headless mode"); + return suite; + } + // The Locale used to instantiate the GUI objects JMeterUtils.setLocale(TEST_LOCALE); Locale.setDefault(TEST_LOCALE); // Needs to be done before any GUI classes are instantiated - TestSuite suite = new TestSuite("JMeterTest"); suite.addTest(new JMeterTest("readAliases")); suite.addTest(new JMeterTest("createTitleSet")); suite.addTest(new JMeterTest("createTagSet")); diff --git a/test/src/org/apache/jorphan/test/AllTests.java b/test/src/org/apache/jorphan/test/AllTests.java index 48074746784..a66ce31d13f 100644 --- a/test/src/org/apache/jorphan/test/AllTests.java +++ b/test/src/org/apache/jorphan/test/AllTests.java @@ -24,24 +24,26 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.nio.charset.Charset; import java.util.List; import java.util.Locale; import java.util.Properties; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestResult; -import junit.framework.TestSuite; -import junit.textui.TestRunner; - import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.jmeter.util.JMeterUtils; import org.apache.jorphan.logging.LoggingManager; +import org.apache.jorphan.reflect.ClassFilter; import org.apache.jorphan.reflect.ClassFinder; import org.apache.jorphan.util.JOrphanUtils; import org.apache.log.Logger; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestResult; +import junit.framework.TestSuite; +import junit.textui.TestRunner; + /** * Provides a quick and easy way to run all junit unit tests in your java @@ -181,78 +183,18 @@ public static void main(String[] args) { } log.info(sb.toString()); - // ++ - // GUI tests throw the error - // testArgumentCreation(org.apache.jmeter.config.gui.ArgumentsPanel$Test)java.lang.NoClassDefFoundError - // at java.lang.Class.forName0(Native Method) - // at java.lang.Class.forName(Class.java:141) - // at - // java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:62) - // - // Try to find out why this is ... - System.out.println("+++++++++++"); logprop("java.awt.headless", true); logprop("java.awt.graphicsenv", true); - // - // try {// - // Class c = Class.forName(n); - // System.out.println("Found class: "+n); - // // c.newInstance(); - // // System.out.println("Instantiated: "+n); - // } catch (Exception e1) { - // System.out.println("Error finding class "+n+" "+e1); - // } catch (java.lang.InternalError e1){ - // System.out.println("Error finding class "+n+" "+e1); - // } - // + System.out.println("------------"); - // don't call isHeadless() here, as it has a side effect. - // -- System.out.println("Creating test suite"); TestSuite suite = suite(args[0]); + int countTestCases = suite.countTestCases(); System.out.println("Starting test run, test count = "+countTestCases); -// for (int i=0;i classList = ClassFinder.findClassesThatExtend(JOrphanUtils.split(searchPaths, ","), - new Class[] { TestCase.class }, true); + List classList = findJMeterJUnitTests(searchPaths); int sz=classList.size(); log.info("ClassFinder(TestCase) found: "+sz+ " TestCase classes"); System.out.println("ClassFinder found: "+sz+ " TestCase classes"); @@ -382,4 +323,42 @@ private static TestSuite suite(String searchPaths) { System.out.println("Created: "+tests+" tests including "+suites+" suites"); return suite; } + + private static List findJMeterJUnitTests(String searchPaths) throws IOException { + List classList = ClassFinder.findClasses(JOrphanUtils.split(searchPaths, ","), new JunitTestFilter()); + + return classList; + } + + /** + * find the junit tests in the test search path + */ + private static class JunitTestFilter implements ClassFilter { + + private final transient ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + + @Override + public boolean accept(String className) { + + boolean isJunitTest = false; + try { + Class c = Class.forName(className, false, contextClassLoader); + + if (!c.isInterface() && !Modifier.isAbstract(c.getModifiers())) { + if (TestCase.class.isAssignableFrom(c)) { + isJunitTest = true; + } + } + } catch (UnsupportedClassVersionError ignored) { + log.debug(ignored.getLocalizedMessage()); + } catch (NoClassDefFoundError ignored) { + log.debug(ignored.getLocalizedMessage()); + } catch (ClassNotFoundException ignored) { + log.debug(ignored.getLocalizedMessage()); + } + + return isJunitTest; + } + + } }