Browse Source

SEC-904: Moved multi-threaded tests into sandbox

Luke Taylor 17 years ago
parent
commit
2cda6242c8

+ 0 - 214
core/src/test/java/org/springframework/security/context/SecurityContextHolderTests.java

@@ -15,14 +15,10 @@
 
 package org.springframework.security.context;
 
-import junit.framework.ComparisonFailure;
 import junit.framework.TestCase;
 
 import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
 
-import java.util.Random;
-
-
 /**
  * Tests {@link SecurityContextHolder}.
  *
@@ -30,193 +26,13 @@ import java.util.Random;
  * @version $Id$
  */
 public class SecurityContextHolderTests extends TestCase {
-    //~ Static fields/initializers =====================================================================================
-
-    private static int errors = 0;
-
-    private static final int NUM_OPS = 5;
-    private static final int NUM_THREADS = 5;
-
-    //~ Constructors ===================================================================================================
-
-    public SecurityContextHolderTests() {
-        super();
-    }
-
-    public SecurityContextHolderTests(String arg0) {
-        super(arg0);
-    }
 
     //~ Methods ========================================================================================================
 
-    private void loadStartAndWaitForThreads(boolean topLevelThread, String prefix, int createThreads,
-        boolean expectAllThreadsToUseIdenticalAuthentication, boolean expectChildrenToShareAuthenticationWithParent) {
-        Thread[] threads = new Thread[createThreads];
-        errors = 0;
-
-        if (topLevelThread) {
-            // PARENT (TOP-LEVEL) THREAD CREATION
-            if (expectChildrenToShareAuthenticationWithParent) {
-                // An InheritableThreadLocal
-                for (int i = 0; i < threads.length; i++) {
-                    if ((i % 2) == 0) {
-                        // Don't inject auth into current thread; neither current thread or child will have authentication
-                        threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, false, true, null);
-                    } else {
-                        // Inject auth into current thread, but not child; current thread will have auth, child will also have auth
-                        threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, false, true,
-                                prefix + "Auth_Parent_" + i);
-                    }
-                }
-            } else if (expectAllThreadsToUseIdenticalAuthentication) {
-                // A global
-                SecurityContextHolder.getContext()
-                                     .setAuthentication(new UsernamePasswordAuthenticationToken("GLOBAL_USERNAME",
-                        "pass"));
-
-                for (int i = 0; i < threads.length; i++) {
-                    if ((i % 2) == 0) {
-                        // Don't inject auth into current thread;both current thread and child will have same authentication
-                        threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, true, true,
-                                "GLOBAL_USERNAME");
-                    } else {
-                        // Inject auth into current thread; current thread will have auth, child will also have auth
-                        threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, true, true, "GLOBAL_USERNAME");
-                    }
-                }
-            } else {
-                // A standard ThreadLocal
-                for (int i = 0; i < threads.length; i++) {
-                    if ((i % 2) == 0) {
-                        // Don't inject auth into current thread; neither current thread or child will have authentication
-                        threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, false, false, null);
-                    } else {
-                        // Inject auth into current thread, but not child; current thread will have auth, child will not have auth
-                        threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, false, false,
-                                prefix + "Auth_Parent_" + i);
-                    }
-                }
-            }
-        } else {
-            // CHILD THREAD CREATION
-            if (expectChildrenToShareAuthenticationWithParent || expectAllThreadsToUseIdenticalAuthentication) {
-                // The children being created are all expected to have security (ie an InheritableThreadLocal/global AND auth was injected into parent)
-                for (int i = 0; i < threads.length; i++) {
-                    String expectedUsername = prefix;
-
-                    if (expectAllThreadsToUseIdenticalAuthentication) {
-                        expectedUsername = "GLOBAL_USERNAME";
-                    }
-
-                    // Don't inject auth into current thread; the current thread will obtain auth from its parent
-                    // NB: As topLevelThread = true, no further child threads will be created
-                    threads[i] = makeThread(prefix + "->child->Inherited_Auth_Child_" + i, false, false,
-                            expectAllThreadsToUseIdenticalAuthentication, false, expectedUsername);
-                }
-            } else {
-                // The children being created are NOT expected to have security (ie not an InheritableThreadLocal OR auth was not injected into parent)
-                for (int i = 0; i < threads.length; i++) {
-                    // Don't inject auth into current thread; neither current thread or child will have authentication
-                    // NB: As topLevelThread = true, no further child threads will be created
-                    threads[i] = makeThread(prefix + "->child->Unauth_Child_" + i, false, false, false, false, null);
-                }
-            }
-        }
-
-        // Start and execute the threads
-        startAndRun(threads);
-    }
-
-    public static void main(String[] args) {
-        junit.textui.TestRunner.run(SecurityContextHolderTests.class);
-    }
-
-    private Thread makeThread(final String threadIdentifier, final boolean topLevelThread,
-        final boolean injectAuthIntoCurrentThread, final boolean expectAllThreadsToUseIdenticalAuthentication,
-        final boolean expectChildrenToShareAuthenticationWithParent, final String expectedUsername) {
-        final Random rnd = new Random();
-
-        Thread t = new Thread(new Runnable() {
-                   public void run() {
-                        if (injectAuthIntoCurrentThread) {
-                            // Set authentication in this thread
-                            SecurityContextHolder.getContext()
-                                                 .setAuthentication(new UsernamePasswordAuthenticationToken(
-                                    expectedUsername, "pass"));
-
-                            //System.out.println(threadIdentifier + " - set to " + SecurityContextHolder.getContext().getAuthentication());
-                        } else {
-                            //System.out.println(threadIdentifier + " - not set (currently " + SecurityContextHolder.getContext().getAuthentication() + ")");
-                        }
-
-                        // Do some operations in current thread, checking authentication is as expected in the current thread (ie another thread doesn't change it)
-                        for (int i = 0; i < NUM_OPS; i++) {
-                            String currentUsername = (SecurityContextHolder.getContext().getAuthentication() == null)
-                                ? null : SecurityContextHolder.getContext().getAuthentication().getName();
-
-                            if ((i % 7) == 0) {
-                                System.out.println(threadIdentifier + " at " + i + " username " + currentUsername);
-                            }
-
-                            try {
-                                TestCase.assertEquals("Failed on iteration " + i + "; Authentication was '"
-                                    + currentUsername + "' but principal was expected to contain username '"
-                                    + expectedUsername + "'", expectedUsername, currentUsername);
-                            } catch (ComparisonFailure err) {
-                                errors++;
-                                throw err;
-                            }
-
-                            try {
-                                Thread.sleep(rnd.nextInt(250));
-                            } catch (InterruptedException ignore) {}
-                        }
-
-                        // Load some children threads, checking the authentication is as expected in the children (ie another thread doesn't change it)
-                        if (topLevelThread) {
-                            // Make four children, but we don't want the children to have any more children (so anti-nature, huh?)
-                            if (injectAuthIntoCurrentThread && expectChildrenToShareAuthenticationWithParent) {
-                                loadStartAndWaitForThreads(false, threadIdentifier, 4,
-                                    expectAllThreadsToUseIdenticalAuthentication, true);
-                            } else {
-                                loadStartAndWaitForThreads(false, threadIdentifier, 4,
-                                    expectAllThreadsToUseIdenticalAuthentication, false);
-                            }
-                        }
-                    }
-                }, threadIdentifier);
-
-        return t;
-    }
-
     public final void setUp() throws Exception {
         SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
     }
 
-    private void startAndRun(Thread[] threads) {
-        // Start them up
-        for (int i = 0; i < threads.length; i++) {
-            threads[i].start();
-        }
-
-        // Wait for them to finish
-        while (stillRunning(threads)) {
-            try {
-                Thread.sleep(250);
-            } catch (InterruptedException ignore) {}
-        }
-    }
-
-    private boolean stillRunning(Thread[] threads) {
-        for (int i = 0; i < threads.length; i++) {
-            if (threads[i].isAlive()) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
     public void testContextHolderGetterSetterClearer() {
         SecurityContext sc = new SecurityContextImpl();
         sc.setAuthentication(new UsernamePasswordAuthenticationToken("Foobar", "pass"));
@@ -240,34 +56,4 @@ public class SecurityContextHolderTests extends TestCase {
             assertTrue(true);
         }
     }
-
-    public void testSynchronizationCustomStrategyLoading() {
-        SecurityContextHolder.setStrategyName(InheritableThreadLocalSecurityContextHolderStrategy.class.getName());
-        assertTrue(new SecurityContextHolder().toString()
-                                              .lastIndexOf("SecurityContextHolder[strategy='org.springframework.security.context.InheritableThreadLocalSecurityContextHolderStrategy'") != -1);
-        loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, true);
-        assertEquals("Thread errors detected; review log output for details", 0, errors);
-    }
-
-    public void testSynchronizationGlobal() throws Exception {
-        SecurityContextHolder.clearContext();
-        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_GLOBAL);
-        loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, true, false);
-        assertEquals("Thread errors detected; review log output for details", 0, errors);
-    }
-
-    public void testSynchronizationInheritableThreadLocal()
-        throws Exception {
-        SecurityContextHolder.clearContext();
-        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
-        loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, true);
-        assertEquals("Thread errors detected; review log output for details", 0, errors);
-    }
-
-    public void testSynchronizationThreadLocal() throws Exception {
-        SecurityContextHolder.clearContext();
-        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_THREADLOCAL);
-        loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, false);
-        assertEquals("Thread errors detected; review log output for details", 0, errors);
-    }
 }

+ 29 - 0
sandbox/itest/misc/pom.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.security</groupId>
+        <artifactId>spring-security-itest</artifactId>
+        <version>2.0.4-SNAPSHOT</version>
+    </parent>
+    <artifactId>spring-security-itest-misc</artifactId>
+    <name>Spring Security - Miscellaneous Integration Tests</name>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-test</artifactId>
+            <version>2.5.5</version>
+            <scope>test</scope>
+        </dependency>
+<!--         
+        <dependency>
+            <groupId>org.springframework.security</groupId>
+            <artifactId>spring-security</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+         -->
+    </dependencies>
+</project>

+ 8 - 0
sandbox/itest/misc/src/main/resources/log4j.properties

@@ -0,0 +1,8 @@
+log4j.rootCategory=INFO, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d %p %c - %m%n
+
+log4j.category.org.mortbay.log=INFO
+log4j.category.org.springframework.security=DEBUG

+ 0 - 0
core/src/test/java/org/springframework/security/concurrent/SessionRegistryImplMultithreadedTests.java → sandbox/itest/misc/src/test/java/org/springframework/security/concurrent/SessionRegistryImplMultithreadedTests.java


+ 216 - 0
sandbox/itest/misc/src/test/java/org/springframework/security/context/SecurityContextHolderMTTests.java

@@ -0,0 +1,216 @@
+package org.springframework.security.context;
+
+import java.util.Random;
+
+import junit.framework.ComparisonFailure;
+import junit.framework.TestCase;
+
+
+
+import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
+
+/**
+ * Multi-threaded tests for SecurityContextHolder
+ * 
+ * @author Ben Alex
+ * @Author Luke Taylor
+ */
+public class SecurityContextHolderMTTests extends TestCase{
+    private int errors = 0;
+
+    private static final int NUM_OPS = 25;
+    private static final int NUM_THREADS = 25;
+
+    public final void setUp() throws Exception {
+        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
+    }    
+    
+    public void testSynchronizationCustomStrategyLoading() {
+        SecurityContextHolder.setStrategyName(InheritableThreadLocalSecurityContextHolderStrategy.class.getName());
+        assertTrue(new SecurityContextHolder().toString()
+                                              .lastIndexOf("SecurityContextHolder[strategy='org.springframework.security.context.InheritableThreadLocalSecurityContextHolderStrategy'") != -1);
+        loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, true);
+        assertEquals("Thread errors detected; review log output for details", 0, errors);
+    }
+
+    public void testSynchronizationGlobal() throws Exception {
+        SecurityContextHolder.clearContext();
+        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_GLOBAL);
+        loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, true, false);
+        assertEquals("Thread errors detected; review log output for details", 0, errors);
+    }
+
+    public void testSynchronizationInheritableThreadLocal()
+        throws Exception {
+        SecurityContextHolder.clearContext();
+        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
+        loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, true);
+        assertEquals("Thread errors detected; review log output for details", 0, errors);
+    }
+
+    public void testSynchronizationThreadLocal() throws Exception {
+        SecurityContextHolder.clearContext();
+        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_THREADLOCAL);
+        loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, false);
+        assertEquals("Thread errors detected; review log output for details", 0, errors);
+    }    
+    
+    private void startAndRun(Thread[] threads) {
+        // Start them up
+        for (int i = 0; i < threads.length; i++) {
+            threads[i].start();
+        }
+
+        // Wait for them to finish
+        while (stillRunning(threads)) {
+            try {
+                Thread.sleep(250);
+            } catch (InterruptedException ignore) {}
+        }
+    }
+
+    private boolean stillRunning(Thread[] threads) {
+        for (int i = 0; i < threads.length; i++) {
+            if (threads[i].isAlive()) {
+                return true;
+            }
+        }
+
+        return false;
+    }    
+    
+    private void loadStartAndWaitForThreads(boolean topLevelThread, String prefix, int createThreads,
+            boolean expectAllThreadsToUseIdenticalAuthentication, boolean expectChildrenToShareAuthenticationWithParent) {
+        Thread[] threads = new Thread[createThreads];
+        errors = 0;
+
+        if (topLevelThread) {
+            // PARENT (TOP-LEVEL) THREAD CREATION
+            if (expectChildrenToShareAuthenticationWithParent) {
+                // An InheritableThreadLocal
+                for (int i = 0; i < threads.length; i++) {
+                    if ((i % 2) == 0) {
+                        // Don't inject auth into current thread; neither current thread or child will have authentication
+                        threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, false, true, null);
+                    } else {
+                        // Inject auth into current thread, but not child; current thread will have auth, child will also have auth
+                        threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, false, true,
+                                prefix + "Auth_Parent_" + i);
+                    }
+                }
+            } else if (expectAllThreadsToUseIdenticalAuthentication) {
+                // A global
+                SecurityContextHolder.getContext()
+                                     .setAuthentication(new UsernamePasswordAuthenticationToken("GLOBAL_USERNAME",
+                        "pass"));
+
+                for (int i = 0; i < threads.length; i++) {
+                    if ((i % 2) == 0) {
+                        // Don't inject auth into current thread;both current thread and child will have same authentication
+                        threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, true, true,
+                                "GLOBAL_USERNAME");
+                    } else {
+                        // Inject auth into current thread; current thread will have auth, child will also have auth
+                        threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, true, true, "GLOBAL_USERNAME");
+                    }
+                }
+            } else {
+                // A standard ThreadLocal
+                for (int i = 0; i < threads.length; i++) {
+                    if ((i % 2) == 0) {
+                        // Don't inject auth into current thread; neither current thread or child will have authentication
+                        threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, false, false, null);
+                    } else {
+                        // Inject auth into current thread, but not child; current thread will have auth, child will not have auth
+                        threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, false, false,
+                                prefix + "Auth_Parent_" + i);
+                    }
+                }
+            }
+        } else {
+            // CHILD THREAD CREATION
+            if (expectChildrenToShareAuthenticationWithParent || expectAllThreadsToUseIdenticalAuthentication) {
+                // The children being created are all expected to have security (ie an InheritableThreadLocal/global AND auth was injected into parent)
+                for (int i = 0; i < threads.length; i++) {
+                    String expectedUsername = prefix;
+
+                    if (expectAllThreadsToUseIdenticalAuthentication) {
+                        expectedUsername = "GLOBAL_USERNAME";
+                    }
+
+                    // Don't inject auth into current thread; the current thread will obtain auth from its parent
+                    // NB: As topLevelThread = true, no further child threads will be created
+                    threads[i] = makeThread(prefix + "->child->Inherited_Auth_Child_" + i, false, false,
+                            expectAllThreadsToUseIdenticalAuthentication, false, expectedUsername);
+                }
+            } else {
+                // The children being created are NOT expected to have security (ie not an InheritableThreadLocal OR auth was not injected into parent)
+                for (int i = 0; i < threads.length; i++) {
+                    // Don't inject auth into current thread; neither current thread or child will have authentication
+                    // NB: As topLevelThread = true, no further child threads will be created
+                    threads[i] = makeThread(prefix + "->child->Unauth_Child_" + i, false, false, false, false, null);
+                }
+            }
+        }
+
+        // Start and execute the threads
+        startAndRun(threads);
+    }
+
+    private Thread makeThread(final String threadIdentifier, final boolean topLevelThread,
+        final boolean injectAuthIntoCurrentThread, final boolean expectAllThreadsToUseIdenticalAuthentication,
+        final boolean expectChildrenToShareAuthenticationWithParent, final String expectedUsername) {
+        final Random rnd = new Random();
+
+        Thread t = new Thread(new Runnable() {
+               public void run() {
+                    if (injectAuthIntoCurrentThread) {
+                        // Set authentication in this thread
+                        SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(
+                                expectedUsername, "pass"));
+
+                        //System.out.println(threadIdentifier + " - set to " + SecurityContextHolder.getContext().getAuthentication());
+                    } else {
+                        //System.out.println(threadIdentifier + " - not set (currently " + SecurityContextHolder.getContext().getAuthentication() + ")");
+                    }
+
+                    // Do some operations in current thread, checking authentication is as expected in the current thread (ie another thread doesn't change it)
+                    for (int i = 0; i < NUM_OPS; i++) {
+                        String currentUsername = (SecurityContextHolder.getContext().getAuthentication() == null)
+                            ? null : SecurityContextHolder.getContext().getAuthentication().getName();
+
+                        if ((i % 7) == 0) {
+                            System.out.println(threadIdentifier + " at " + i + " username " + currentUsername);
+                        }
+
+                        try {
+                            assertEquals("Failed on iteration " + i + "; Authentication was '"
+                                + currentUsername + "' but principal was expected to contain username '"
+                                + expectedUsername + "'", expectedUsername, currentUsername);
+                        } catch (ComparisonFailure err) {
+                            errors++;
+                            throw err;
+                        }
+
+                        try {
+                            Thread.sleep(rnd.nextInt(250));
+                        } catch (InterruptedException ignore) {}
+                    }
+
+                    // Load some children threads, checking the authentication is as expected in the children (ie another thread doesn't change it)
+                    if (topLevelThread) {
+                        // Make four children, but we don't want the children to have any more children (so anti-nature, huh?)
+                        if (injectAuthIntoCurrentThread && expectChildrenToShareAuthenticationWithParent) {
+                            loadStartAndWaitForThreads(false, threadIdentifier, 4,
+                                expectAllThreadsToUseIdenticalAuthentication, true);
+                        } else {
+                            loadStartAndWaitForThreads(false, threadIdentifier, 4,
+                                expectAllThreadsToUseIdenticalAuthentication, false);
+                        }
+                    }
+                }
+            }, threadIdentifier);
+
+        return t;
+    }
+}

+ 2 - 2
sandbox/itest/pom.xml

@@ -15,7 +15,7 @@
     <modules>
         <module>web</module>
         <!-- module>webflow</module-->
-        <!--module>context</module-->
+        <module>misc</module>
     </modules>
     <dependencies>
         <dependency>
@@ -36,7 +36,7 @@
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring</artifactId>
-            <version>2.5.4</version>
+            <version>2.5.5</version>
             <exclusions>
                 <exclusion>
                     <groupId>commons-logging</groupId>