/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can * obtain a copy of the License at * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html * or packager/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at packager/legal/LICENSE.txt. * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [year] [name of copyright owner]" * * Contributor(s): * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */ package org.glassfish.contextpropagation.internal; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import java.util.EnumSet; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import org.glassfish.contextpropagation.ContextLifecycle; import org.glassfish.contextpropagation.PropagationMode; import org.glassfish.contextpropagation.ViewCapable; import org.glassfish.contextpropagation.adaptors.BootstrapUtils; import org.glassfish.contextpropagation.adaptors.MockContextAccessController; import org.glassfish.contextpropagation.adaptors.MockThreadLocalAccessor; import org.glassfish.contextpropagation.adaptors.RecordingLoggerAdapter; import org.glassfish.contextpropagation.bootstrap.ContextBootstrap; import org.glassfish.contextpropagation.bootstrap.LoggerAdapter.Level; import org.glassfish.contextpropagation.bootstrap.LoggerAdapter.MessageID; import org.glassfish.contextpropagation.internal.Entry.ContextType; import org.glassfish.contextpropagation.internal.SimpleMap.Filter; import org.glassfish.contextpropagation.wireadapters.glassfish.DefaultWireAdapter; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; public class SimpleMapTest { SimpleMap sm; static RecordingLoggerAdapter logger; public static class LifeCycleEventRecorder implements ContextLifecycle { StackTraceElement lastElement; Object lastArg; @Override public void contextChanged(Object replacementContext) { set(Thread.currentThread().getStackTrace(), replacementContext); } @Override public void contextAdded() { set(Thread.currentThread().getStackTrace(), null); } @Override public void contextRemoved() { set(Thread.currentThread().getStackTrace(), null); } @Override public ViewCapable contextToPropagate() { set(Thread.currentThread().getStackTrace(), null); return this; } void set(StackTraceElement[] trace, Object arg) { lastElement = trace[1]; lastArg = arg; } void verify(String methodName, Object arg) { assertEquals(methodName, lastElement.getMethodName()); assertEquals(arg, lastArg); lastElement = null; lastArg = null; } } private static final LifeCycleEventRecorder LIFE_CYCLE_CONTEXT = new LifeCycleEventRecorder(); static final Entry DUMMY_ENTRY = createEntry(LIFE_CYCLE_CONTEXT, PropagationMode.defaultSet(), ContextType.OPAQUE); private static Entry createEntry(Object context, EnumSet<PropagationMode> propModes, ContextType ct) { return new Entry(context, propModes, ct) { void validate() {} }; } @BeforeClass public static void setupClass() { logger = new RecordingLoggerAdapter(); BootstrapUtils.reset(); ContextBootstrap.configure(logger, new DefaultWireAdapter(), new MockThreadLocalAccessor(), new MockContextAccessController(), "guid"); } @Before public void setup() { sm = new SimpleMap(); sm.put("foo", createEntry("fooString", PropagationMode.defaultSet(), ContextType.STRING)); } @Test public void testGetEntry() { Entry entry = sm.getEntry("foo"); assertEquals("fooString", entry.getValue()); logger.verify(Level.DEBUG, null, MessageID.OPERATION, new Object[] {"getEntry", "foo", entry} ); } @Test(expected=java.lang.IllegalArgumentException.class) public void testGetEntryWithNullKey() { sm.getEntry(null); // Does not log if fails validation } @Test public void testGet() { assertEquals("fooString", sm.get("foo")); logger.verify(Level.DEBUG, null, MessageID.OPERATION, new Object[] {"get", "foo", "fooString"} ); } @Test(expected=java.lang.IllegalArgumentException.class) public void testGetWithNullKey() { sm.get(null); // Does not log if validate fails } @Test public void testPutWhereNoBefore() { Entry e = sm.put("new key", DUMMY_ENTRY); assertNull(e); logger.verify(Level.DEBUG, null, MessageID.PUT, new Object[] {"new key", DUMMY_ENTRY.value, null} ); LIFE_CYCLE_CONTEXT.verify("contextAdded", null); } @Test public void testPutReplace() { LifeCycleEventRecorder oldRecorder = new LifeCycleEventRecorder(); String fooString = sm.put("foo", createEntry(oldRecorder, PropagationMode.defaultSet(), ContextType.OPAQUE)); assertEquals("fooString", fooString); logger.verify(Level.DEBUG, null, MessageID.PUT, new Object[] {"foo", oldRecorder, "fooString"} ); LifeCycleEventRecorder oldValue = sm.put("foo", DUMMY_ENTRY); assertEquals(oldRecorder, oldValue); oldRecorder.verify("contextChanged", LIFE_CYCLE_CONTEXT); // oldRecoder finds out about the new value LIFE_CYCLE_CONTEXT.verify("contextAdded", null); } @Test(expected=java.lang.IllegalArgumentException.class) public void testPutWithNullKey() { sm.put(null, DUMMY_ENTRY); } @Test(expected=java.lang.IllegalArgumentException.class) public void testPutWithNullEntry() { sm.put("dummy key", null); } @Test(expected=java.lang.IllegalArgumentException.class) public void testPutWithNullValue() { sm.put("dummy key", createEntry(null, PropagationMode.defaultSet(), ContextType.ATOMICINTEGER)); } @Test(expected=java.lang.IllegalArgumentException.class) public void testPutWithInvalidEntry() { sm.put("dummy key", new Entry(null, PropagationMode.defaultSet(), ContextType.ATOMICINTEGER) { void validate() { throw new IllegalStateException(); } }); } @Test public void testRemove() { sm.put("removeMe", createEntry(LIFE_CYCLE_CONTEXT, PropagationMode.defaultSet(), ContextType.STRING)); Object removeMe = sm.remove("removeMe"); assertEquals(LIFE_CYCLE_CONTEXT, removeMe); logger.verify(Level.DEBUG, null, MessageID.OPERATION, new Object[] {"remove", "removeMe", LIFE_CYCLE_CONTEXT} ); LIFE_CYCLE_CONTEXT.verify("contextRemoved", null); } @Test public void testRemoveNoneExistent() { String removeMe = sm.remove("removeMe"); assertEquals(null, removeMe); } @Test public void testEmptyIterator() { SimpleMap emptyMap = new SimpleMap(); Iterator<?> iter = emptyMap.iterator(null, null); assertFalse(iter.hasNext()); } @Test public void testIteratorFiltersAll() { sm.put("dummy", DUMMY_ENTRY); Iterator<Map.Entry<String, Entry>> iter = sm.iterator(new Filter() { @Override public boolean keep(java.util.Map.Entry<String, Entry> mapEntry, PropagationMode mode) { return false; } }, PropagationMode.JMS_QUEUE); assertFalse(iter.hasNext()); } @SuppressWarnings("serial") @Test public void testIteratorFilterNone() { sm.put("dummy", DUMMY_ENTRY); Iterator<Map.Entry<String, Entry>> iter = sm.iterator(new Filter() { @Override public boolean keep(java.util.Map.Entry<String, Entry> mapEntry, PropagationMode mode) { return true; } }, PropagationMode.JMS_QUEUE); int count = 0; HashSet<String> keys = new HashSet<String>(); while (iter.hasNext()) { keys.add(iter.next().getKey()); count++; } assertEquals(2, count); assertEquals(new HashSet<String>() {{add("foo"); add("dummy");}}, keys); } @Test public void testIteratorRemove() { sm.put("dummy", DUMMY_ENTRY); Iterator<Map.Entry<String, Entry>> iter = sm.iterator(new Filter() { @Override public boolean keep(java.util.Map.Entry<String, Entry> mapEntry, PropagationMode mode) { return true; } }, PropagationMode.JMS_QUEUE); assertEquals(2, sm.map.size()); assertNotNull(iter.next()); iter.remove(); assertEquals(1, sm.map.size()); assertNotNull(iter.next()); iter.remove(); assertEquals(0, sm.map.size()); int exceptionCount = 0; try { iter.next(); } catch (NoSuchElementException nsee) {exceptionCount++;} assertEquals("Expected NoSuchElementException after the last element was retrieved", 1, exceptionCount); try { iter.remove(); } catch (IllegalStateException ise) {exceptionCount++;} assertEquals("Expected IllegalStateException on last remove call", 2, exceptionCount); } }