/** * Copyright (c) 2009-2011 VMware, Inc. All Rights Reserved. * * Licensed 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 com.springsource.insight.plugin.grails; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.Random; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * */ public class GrailsControllerStateKeeperTest extends Assert { protected final Logger logger = LoggerFactory.getLogger(getClass()); public GrailsControllerStateKeeperTest() { super(); } @Test public void testThreadLocalStateAccess() throws InterruptedException { final Semaphore sigsem = new Semaphore(0, true); final Collection<Exception> excList = Collections.synchronizedCollection(new LinkedList<Exception>()); Collection<Thread> threadsList = new LinkedList<Thread>(); final int NUM_ITERATIONS = Short.SIZE; for (int index = 0; index < Byte.SIZE; index++) { Thread testThread = new Thread("tRunner" + index) { @Override public void run() { Thread t = Thread.currentThread(); try { sigsem.acquire(); GrailsControllerStateKeeper.State stateValue = null; Random randomizer = new Random(System.nanoTime()); logger.info(t.getName() + " start"); for (int tryIndex = 0; tryIndex < NUM_ITERATIONS; tryIndex++) { GrailsControllerStateKeeper.State currentState = GrailsControllerStateKeeper.getState(); assertNotNull(t.getName() + " Null state value at iteration #" + tryIndex, currentState); if (stateValue == null) { assertEquals(t.getName() + " Null initial value at iteration #" + tryIndex, 0, tryIndex); stateValue = currentState; } else { assertSame(t.getName() + " Mismatched state instance at iteration #" + tryIndex, stateValue, currentState); } Thread.sleep(randomizer.nextInt(Byte.MAX_VALUE) + 1L); } GrailsControllerStateKeeper.State remState = GrailsControllerStateKeeper.getAndDestroyThreadLocalState(); assertSame(t.getName() + " Mismatched removed state instance", stateValue, remState); logger.info(t.getName() + " end"); } catch (Exception e) { logger.error(t.getName() + " [" + e.getClass().getSimpleName() + "}: " + e.getMessage()); excList.add(e); } } }; threadsList.add(testThread); testThread.start(); } int numPending = threadsList.size(); sigsem.release(numPending); // release all threads at once for (Thread t : threadsList) { t.join(numPending * TimeUnit.SECONDS.toMillis(2L) + NUM_ITERATIONS * Byte.MAX_VALUE); assertFalse(t.getName() + " still alive", t.isAlive()); numPending--; logger.info(t.getName() + " done - pending=" + numPending); } if (!excList.isEmpty()) { for (Exception e : excList) { logger.error(e.getMessage()); } fail("Thread exceptions captured"); } } @Test public void testGetAndDestroyThreadLocalState() { assertNull("Unexpected pre-removal initial value", GrailsControllerStateKeeper.getAndDestroyThreadLocalState()); Object state = GrailsControllerStateKeeper.getState(); assertNotNull("No new state created", state); assertSame("Mismatched removed instance", state, GrailsControllerStateKeeper.getAndDestroyThreadLocalState()); assertNull("Unexpected new value after removal", GrailsControllerStateKeeper.getAndDestroyThreadLocalState()); } }