#107995: trying to prevent random behavior. as_approved_by_hie_m9 cnd6_fortran_root
authorjglick@netbeans.org
Mon, 25 Jun 2007 19:12:18 +0000
changeset 286144937d35a3c
parent 285 e5a85b03adc3
child 287 d6e135d48b83
#107995: trying to prevent random behavior.
openide.util/test/unit/src/org/openide/util/test/RestrictThreadCreation.java
     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 +}