#107995: trying to prevent random behavior.
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/openide.util/test/unit/src/org/openide/util/test/RestrictThreadCreation.java Mon Jun 25 19:12:18 2007 +0000
1.3 @@ -0,0 +1,107 @@
1.4 +/*
1.5 + * The contents of this file are subject to the terms of the Common Development
1.6 + * and Distribution License (the License). You may not use this file except in
1.7 + * compliance with the License.
1.8 + *
1.9 + * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
1.10 + * or http://www.netbeans.org/cddl.txt.
1.11 + *
1.12 + * When distributing Covered Code, include this CDDL Header Notice in each file
1.13 + * and include the License file at http://www.netbeans.org/cddl.txt.
1.14 + * If applicable, add the following below the CDDL Header, with the fields
1.15 + * enclosed by brackets [] replaced by your own identifying information:
1.16 + * "Portions Copyrighted [year] [name of copyright owner]"
1.17 + *
1.18 + * Portions Copyrighted 2007 Sun Microsystems, Inc.
1.19 + */
1.20 +
1.21 +package org.openide.util.test;
1.22 +
1.23 +import java.security.Permission;
1.24 +import java.util.Arrays;
1.25 +import java.util.HashSet;
1.26 +import java.util.Set;
1.27 +
1.28 +/**
1.29 + * Permits unit tests to limit creation of threads.
1.30 + * Unexpected thread creation can make tests fail randomly, which makes debugging difficult.
1.31 + * <p>Start off calling {@link #permitStandard} and {@link #forbidNewThreads}.
1.32 + * To determine which methods to permit, just try running the test;
1.33 + * if you see any {@link SecurityException}s which look like harmless thread creation
1.34 + * activities, just copy the appropriate part of the stack trace and pass to {@link #permit}.
1.35 + * <p>Use non-strict mode for {@link #forbidNewThreads} if you suspect some code
1.36 + * might be catching and not reporting {@link SecurityException}s; or you may prefer
1.37 + * to simply use non-strict mode while developing the test and then switch to strict
1.38 + * mode once it begins passing.
1.39 + * <p>Place calls to this class early in your test's initialization, e.g. in a static block.
1.40 + * (Not suitable for use from {@link junit.framework.TestCase#setUp}.)
1.41 + */
1.42 +public class RestrictThreadCreation {
1.43 +
1.44 + private RestrictThreadCreation() {}
1.45 +
1.46 + private static Set<String> currentlyPermitted = new HashSet<String>();
1.47 +
1.48 + /**
1.49 + * Explicitly permits one or more thread creation idioms.
1.50 + * Each entry is of the form <samp>fully.qualified.Clazz.methodName</samp>
1.51 + * and if such a method can be found on the call stack the thread creation
1.52 + * is permitted.
1.53 + * @param permitted one or more fully qualified method names to accept
1.54 + */
1.55 + public static void permit(String... permitted) {
1.56 + currentlyPermitted.addAll(Arrays.asList(permitted));
1.57 + }
1.58 +
1.59 + /**
1.60 + * Permits a standard set of thread creation idioms which are normally harmless to unit tests.
1.61 + * Feel free to add to this list if it seems appropriate.
1.62 + */
1.63 + public static void permitStandard() {
1.64 + permit(// Found experimentally:
1.65 + "sun.java2d.Disposer.<clinit>",
1.66 + "java.awt.Toolkit.getDefaultToolkit",
1.67 + "org.netbeans.core.startup.Splash$SplashComponent.setText",
1.68 + "org.openide.loaders.FolderInstance.waitFinished",
1.69 + "org.openide.loaders.FolderInstance.postCreationTask",
1.70 + "org.netbeans.modules.java.source.usages.RepositoryUpdater.getDefault",
1.71 + "org.netbeans.api.java.source.JavaSource.<clinit>",
1.72 + "org.netbeans.api.java.source.JavaSourceTaskFactory.fileObjectsChanged",
1.73 + "org.netbeans.progress.module.Controller.resetTimer",
1.74 + "org.netbeans.modules.timers.InstanceWatcher$FinalizingToken.finalize",
1.75 + "javax.swing.JComponent.revalidate",
1.76 + "javax.swing.ImageIcon.<init>");
1.77 + }
1.78 +
1.79 + /**
1.80 + * Install a security manager which prevents new threads from being created
1.81 + * unless they were explicitly permitted.
1.82 + * @param strict if true, throw a security exception; if false, just print stack traces
1.83 + */
1.84 + public static void forbidNewThreads(final boolean strict) {
1.85 + System.setSecurityManager(new SecurityManager() {
1.86 + public @Override void checkAccess(ThreadGroup g) {
1.87 + boolean inThreadInit = false;
1.88 + for (StackTraceElement line : Thread.currentThread().getStackTrace()) {
1.89 + String id = line.getClassName() + "." + line.getMethodName();
1.90 + if (currentlyPermitted.contains(id)) {
1.91 + return;
1.92 + } else if (id.equals("java.lang.Thread.init")) {
1.93 + inThreadInit = true;
1.94 + }
1.95 + }
1.96 + if (inThreadInit) {
1.97 + SecurityException x = new SecurityException("Unauthorized thread creation");
1.98 + if (strict) {
1.99 + throw x;
1.100 + } else {
1.101 + x.printStackTrace();
1.102 + }
1.103 + }
1.104 + }
1.105 + public @Override void checkPermission(Permission perm) {}
1.106 + public @Override void checkPermission(Permission perm, Object context) {}
1.107 + });
1.108 + }
1.109 +
1.110 +}