1 /* 2 1;2c * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package vm.runtime.defmeth.shared; 25 26 import java.lang.reflect.InvocationTargetException; 27 import java.lang.reflect.Method; 28 import java.lang.reflect.Modifier; 29 import java.util.ArrayList; 30 import java.util.List; 31 import java.util.TreeSet; 32 import java.util.regex.Pattern; 33 import nsk.share.TestFailure; 34 import nsk.share.log.Log; 35 import nsk.share.test.TestBase; 36 import vm.runtime.defmeth.AccessibilityFlagsTest; 37 import vm.runtime.defmeth.BasicTest; 38 import vm.runtime.defmeth.ConflictingDefaultsTest; 39 import vm.runtime.defmeth.DefaultVsAbstractTest; 40 import vm.runtime.defmeth.MethodResolutionTest; 41 import vm.runtime.defmeth.ObjectMethodOverridesTest; 42 import vm.runtime.defmeth.PrivateMethodsTest; 43 import vm.runtime.defmeth.StaticMethodsTest; 44 import vm.runtime.defmeth.SuperCallTest; 45 import vm.runtime.defmeth.shared.annotation.Crash; 46 import vm.runtime.defmeth.shared.annotation.KnownFailure; 47 import vm.runtime.defmeth.shared.annotation.NotApplicableFor; 48 import vm.runtime.defmeth.shared.builder.TestBuilderFactory; 49 import vm.share.options.Option; 50 import vm.share.options.OptionSupport; 51 import vm.share.options.Options; 52 import static java.lang.String.format; 53 import java.util.Collections; 54 import vm.runtime.defmeth.RedefineTest; 55 import vm.runtime.defmeth.shared.annotation.NotTest; 56 57 /** 58 * Parent class for all default method tests. 59 * 60 * Contains common settings and code to run individual tests. 61 * 62 * Provides command-line interface to run arbitrary subset of 63 * tests on default methods with some customizations. 64 */ 65 public abstract class DefMethTest extends TestBase { 66 /** Classes that contain tests on default methods */ 67 static private final List<Class<? extends DefMethTest>> classes; 68 69 // the number of tests has failed 70 // note that if more than one sub-test has failed within a test, 71 // it will be counted as 1 failure for that test 72 private int numFailures; 73 74 static { 75 List<Class<? extends DefMethTest>> intlList = new ArrayList<>(); 76 77 intlList.add(AccessibilityFlagsTest.class); 78 intlList.add(BasicTest.class); 79 intlList.add(ConflictingDefaultsTest.class); 80 intlList.add(DefaultVsAbstractTest.class); 81 intlList.add(MethodResolutionTest.class); 82 intlList.add(ObjectMethodOverridesTest.class); 83 intlList.add(SuperCallTest.class); 84 intlList.add(PrivateMethodsTest.class); 85 intlList.add(StaticMethodsTest.class); 86 intlList.add(RedefineTest.class); 87 88 classes = Collections.unmodifiableList(intlList); 89 } 90 91 public static List<Class<? extends DefMethTest>> getTests() { 92 return classes; 93 } 94 95 @Option(name="list", default_value="false", description="list tests w/o executing them") 96 boolean listTests; 97 98 @Option(name="filter", default_value="", description="filter executed tests") 99 String filterString; 100 101 @Option(name="ignoreKnownFailures", default_value="false", description="ignore tests with known failures") 102 boolean ignoreKnownFailures; 103 104 @Option(name="runOnlyFailingTests", default_value="false", description="run only failing tests") 105 boolean runOnlyFailingTests; 106 107 @Option(name="ignoreCrashes", default_value="false", description="don't run tests with crash VM") 108 boolean ignoreCrashes; 109 110 @Option(name="silent", default_value="false", description="silent mode - don't print anything") 111 boolean isSilent; 112 113 @Option(name="failfast", default_value="false", description="fail the whole set of test on first failure") 114 boolean failFast; 115 116 @Option(name="testAllModes", default_value="false", description="run each test in all possible modes") 117 boolean testAllModes; 118 119 @Option(name="mode", description="invocation mode (direct, reflect, invoke)", default_value="direct") 120 private String mode; 121 122 private Pattern filter; // Precompiled pattern for filterString 123 124 /** 125 * Used from individual tests to get TestBuilder instances, 126 * which is aware of current testing configuration 127 */ 128 @Options 129 protected TestBuilderFactory factory = new TestBuilderFactory(this); 130 131 private void init() { 132 if (isSilent) { 133 getLog().setInfoEnabled(false); 134 getLog().setWarnEnabled(false); 135 getLog().setDebugEnabled(false); 136 } 137 138 if (filterString != null && !"".equals(filterString)) { 139 filter = Pattern.compile(".*" + filterString + ".*"); 140 } else { 141 filter = Pattern.compile(".*"); // match everything 142 } 143 144 // Test-specific config 145 configure(); 146 } 147 148 @Override 149 public final void run() { 150 init(); 151 152 boolean success = runTest(); 153 if (!success) { 154 getLog().info("TEST FAILED"); 155 setFailed(true); 156 } else { 157 getLog().info("TEST PASSED"); 158 } 159 } 160 161 protected void configure() { 162 // Is overriden by specific tests to do test-specific setup 163 } 164 165 public Log getLog() { 166 return log; 167 } 168 169 @Override 170 public String toString() { 171 return format("%s%s", 172 getClass().getSimpleName(), factory); 173 } 174 175 /** Enumerate invocation modes to be tested */ 176 private ExecutionMode[] getInvocationModes() { 177 if (factory.getExecutionMode() != null) { 178 return new ExecutionMode[] { ExecutionMode.valueOf(factory.getExecutionMode()) }; 179 } 180 181 if (testAllModes) { 182 return ExecutionMode.values(); 183 } 184 185 switch(mode) { 186 case "direct": return new ExecutionMode[] { ExecutionMode.DIRECT }; 187 case "reflect": return new ExecutionMode[] { ExecutionMode.REFLECTION }; 188 case "invoke_exact": return new ExecutionMode[] { ExecutionMode.INVOKE_EXACT }; 189 case "invoke_generic": return new ExecutionMode[] { ExecutionMode.INVOKE_GENERIC }; 190 case "indy": return new ExecutionMode[] { ExecutionMode.INDY }; 191 case "invoke": return new ExecutionMode[] { ExecutionMode.INVOKE_WITH_ARGS, 192 ExecutionMode.INVOKE_EXACT, 193 ExecutionMode.INVOKE_GENERIC, 194 ExecutionMode.INDY }; 195 case "redefinition": 196 throw new Error("redefinition is only a pseudo-mode"); 197 default: 198 throw new Error("Unknown mode: " + mode); 199 } 200 } 201 202 // Check whether the test is applicable to selected execution mode 203 private boolean shouldExecute(Method m, ExecutionMode mode) { 204 Class<? extends DefMethTest> test = this.getClass(); 205 206 int acc = m.getModifiers(); 207 if (m.isAnnotationPresent(NotTest.class) 208 || (ignoreCrashes && m.isAnnotationPresent(Crash.class)) 209 || !Modifier.isPublic(acc) || Modifier.isStatic(acc) 210 //|| m.getReturnType() != Void.class 211 || m.getParameterTypes().length != 0) 212 { 213 return false; // not a test 214 } 215 216 String testName = format("%s.%s", test.getName(), m.getName()); 217 if (!filter.matcher(testName).matches()) { 218 return false; // test is filtered out 219 } 220 221 if (m.isAnnotationPresent(NotApplicableFor.class)) { 222 for (ExecutionMode excludeFromMode : m.getAnnotation(NotApplicableFor.class).modes()) { 223 if (mode == excludeFromMode) { 224 return false; // not applicable to current execution mode 225 } else if (excludeFromMode == ExecutionMode.REDEFINITION && 226 (factory.isRedefineClasses() || factory.isRetransformClasses())) { 227 return false; // Can't redefine some tests. 228 } 229 230 } 231 } 232 233 if (ignoreKnownFailures && 234 m.isAnnotationPresent(KnownFailure.class)) { 235 ExecutionMode[] modes = m.getAnnotation(KnownFailure.class).modes(); 236 237 if (modes.length == 0) return false; // by default, matches all modes 238 239 for (ExecutionMode knownFailingMode : modes) { 240 if (mode == knownFailingMode) { 241 return false; // known failure in current mode 242 } 243 } 244 } 245 246 return true; 247 } 248 249 /** Information about the test being executed */ 250 public String shortTestName; 251 252 public static class ComparableMethod implements Comparable<ComparableMethod> { 253 final java.lang.reflect.Method m; 254 ComparableMethod(java.lang.reflect.Method m) { this.m = m; } 255 public int compareTo(ComparableMethod mo) { 256 String name = m.getName(); 257 String mo_name = mo.m.getName(); 258 return name.compareTo(mo_name); 259 } 260 } 261 262 /** helper method for subclass to report the number of test failures. 263 * It is more important for the reflection case as an exception thrown 264 * deep in the call stack may not be propagated to this level. 265 * 266 * @param failures 267 */ 268 public void addFailureCount(int failures) { 269 numFailures += failures; 270 } 271 272 /** 273 * Execute all tests from current class and report status. 274 * 275 * The following execution customization is supported: 276 * - filter tests by name using regex 277 * - ignore tests marked as @KnownFailure 278 * - ignore tests marked as @Crash 279 * - only run tests marked as @KnownFailure 280 * 281 * @return any failures occurred? 282 */ 283 public final boolean runTest() { 284 if (ignoreKnownFailures && runOnlyFailingTests) { 285 throw new IllegalArgumentException("conflicting parameters"); 286 } 287 288 ExecutionMode[] invocationModes = getInvocationModes(); 289 290 try { 291 int totalTests = 0; 292 int passedTests = 0; 293 294 Class<? extends DefMethTest> test = this.getClass(); 295 296 getLog().info(format("\n%s %s", test.getSimpleName(), factory.toString())); 297 298 TreeSet<ComparableMethod> ts = new TreeSet<ComparableMethod>(); 299 for (java.lang.reflect.Method m : test.getDeclaredMethods()) { 300 ts.add(new ComparableMethod(m)); 301 } 302 303 for (ComparableMethod cm : ts) { 304 java.lang.reflect.Method m = cm.m; 305 for (ExecutionMode mode : invocationModes) { 306 shortTestName = format("%s.%s", test.getSimpleName(), m.getName()); 307 308 if (!shouldExecute(m, mode)) { 309 continue; // skip the test due to current configuration 310 } 311 312 totalTests++; 313 314 getLog().info(shortTestName); 315 316 if (listTests) { 317 continue; // just print test info 318 } 319 320 // Iterate over all test modes 321 try { 322 factory.setExecutionMode(mode.name()); 323 getLog().info(format(" %s: ", mode)); 324 m.invoke(this); 325 } catch (IllegalAccessException | IllegalArgumentException e) { 326 throw new TestFailure(e); 327 } catch (InvocationTargetException e) { 328 if (e.getCause() instanceof TestFailure) { 329 // Failure details were printed in GeneratedTest.run()/ReflectionTest.run() 330 } else { 331 if (Constants.PRINT_STACK_TRACE) { 332 e.printStackTrace(); 333 } 334 } 335 336 if (failFast) { 337 throw new TestFailure(e.getCause()); 338 } 339 } 340 } 341 } 342 343 passedTests = totalTests - numFailures; 344 getLog().info(format("%d test run: %d passed, %d failed", totalTests, passedTests, numFailures)); 345 if (numFailures == 0) { 346 return true; 347 } else { 348 return false; 349 } 350 } catch (Exception | Error e) { 351 throw new RuntimeException(e); 352 } 353 } 354 355 /** Command-line interface to initiate test run */ 356 public static void main(String[] args) { 357 for (Class<? extends DefMethTest> clz : classes) { 358 try { 359 DefMethTest test = clz.newInstance(); 360 OptionSupport.setupAndRun(test, args); 361 } catch (InstantiationException | IllegalAccessException e) { 362 throw new TestFailure(e); 363 } 364 } 365 } 366 }