diff --git a/core/java/src/net/i2p/I2PAppContext.java b/core/java/src/net/i2p/I2PAppContext.java index 12379505b2..ae0138effc 100644 --- a/core/java/src/net/i2p/I2PAppContext.java +++ b/core/java/src/net/i2p/I2PAppContext.java @@ -43,7 +43,7 @@ import net.i2p.util.I2PProperties.I2PPropertyCallback; * using the traditional singleton, where any component can access the component * in question directly, all of those I2P related singletons are exposed through * a particular I2PAppContext. This helps not only with understanding their use - * and the components I2P exposes, but it also allows multiple isolated + * and the components I2P exposes, but it also allows multiple isolated * environments to operate concurrently within the same JVM - particularly useful * for stubbing out implementations of the rooted components and simulating the * software's interaction between multiple instances.

@@ -52,13 +52,13 @@ import net.i2p.util.I2PProperties.I2PPropertyCallback; * access to one of the singletons but doesn't have its own context from which * to root itself, it binds to the I2PAppContext's globalAppContext(), which is * the first context that was created within the JVM, or a new one if no context - * existed already. This functionality is often used within the I2P core for + * existed already. This functionality is often used within the I2P core for * logging - e.g.
  *     private static final Log _log = new Log(someClass.class);
  * 
* It is for this reason that applications that care about working with multiple * contexts should build their own context as soon as possible (within the main(..)) - * so that any referenced components will latch on to that context instead of + * so that any referenced components will latch on to that context instead of * instantiating a new one. However, there are situations in which both can be * relevant. * @@ -66,9 +66,9 @@ import net.i2p.util.I2PProperties.I2PPropertyCallback; public class I2PAppContext { /** the context that components without explicit root are bound */ protected static volatile I2PAppContext _globalAppContext; - + protected final I2PProperties _overrideProps; - + private StatManager _statManager; protected SessionKeyManager _sessionKeyManager; private NamingService _namingService; @@ -121,7 +121,7 @@ public class I2PAppContext { _lock17 = new Object(), _lock18 = new Object(), _lock19 = new Object(), _lock20 = new Object(); /** - * Pull the default context, creating a new one if necessary, else using + * Pull the default context, creating a new one if necessary, else using * the first one created. * * Warning - do not save the returned value, or the value of any methods below, @@ -129,7 +129,7 @@ public class I2PAppContext { * started in the same JVM after the first is shut down, * e.g. on Android. */ - public static I2PAppContext getGlobalContext() { + public static I2PAppContext getGlobalContext() { // skip the global lock - _gAC must be volatile // http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html I2PAppContext rv = _globalAppContext; @@ -141,12 +141,12 @@ public class I2PAppContext { _globalAppContext = new I2PAppContext(false, null); } } - return _globalAppContext; + return _globalAppContext; } - + /** * Sets the default context, unless there is one already. - * NOT a public API, for use by RouterContext only, NOT for external use. + * NOT a public API, for use by RouterContext and TestContext only, NOT for external use. * * @param ctx context constructed with doInit = false * @return success (false if previously set) @@ -172,10 +172,10 @@ public class I2PAppContext { * @return context or null * @since 0.8.2 */ - public static I2PAppContext getCurrentContext() { - return _globalAppContext; + public static I2PAppContext getCurrentContext() { + return _globalAppContext; } - + /** * Create a brand new context. * WARNING: In almost all cases, you should use getGlobalContext() instead, @@ -186,7 +186,7 @@ public class I2PAppContext { public I2PAppContext() { this(true, null); } - + /** * Create a brand new context. * WARNING: In almost all cases, you should use getGlobalContext() instead, @@ -197,7 +197,7 @@ public class I2PAppContext { public I2PAppContext(Properties envProps) { this(true, envProps); } - + /** * Create a brand new context. * WARNING: In almost all cases, you should use getGlobalContext() instead, @@ -212,14 +212,14 @@ public class I2PAppContext { * @since protected since 0.9.33, NOT for external use */ protected I2PAppContext(boolean doInit, Properties envProps) { - synchronized (I2PAppContext.class) { + synchronized (I2PAppContext.class) { _overrideProps = new I2PProperties(); if (envProps != null) _overrideProps.putAll(envProps); _shutdownTasks = new ConcurrentHashSet(32); _portMapper = new PortMapper(this); _appManager = isRouterContext() ? null : new ClientAppManagerImpl(this); - + /* * Directories. These are all set at instantiation and will not be changed by * subsequent property changes. @@ -449,8 +449,8 @@ public class I2PAppContext { } /** - * Access the configuration attributes of this context, using properties - * provided during the context construction, or falling back on + * Access the configuration attributes of this context, using properties + * provided during the context construction, or falling back on * System.getProperty if no properties were provided during construction * (or the specified prop wasn't included). * @@ -465,8 +465,8 @@ public class I2PAppContext { } /** - * Access the configuration attributes of this context, using properties - * provided during the context construction, or falling back on + * Access the configuration attributes of this context, using properties + * provided during the context construction, or falling back on * System.getProperty if no properties were provided during construction * (or the specified prop wasn't included). * @@ -545,7 +545,7 @@ public class I2PAppContext { } /** - * Access the configuration attributes of this context, listing the properties + * Access the configuration attributes of this context, listing the properties * provided during the context construction, as well as the ones included in * System.getProperties. * @@ -555,29 +555,29 @@ public class I2PAppContext { * @return set of Strings containing the names of defined system properties */ @SuppressWarnings({ "unchecked", "rawtypes" }) - public Set getPropertyNames() { + public Set getPropertyNames() { // clone to avoid ConcurrentModificationException Set names = new HashSet((Set) (Set) ((Properties) System.getProperties().clone()).keySet()); // TODO-Java6: s/keySet()/stringPropertyNames()/ if (_overrideProps != null) names.addAll((Set) (Set) _overrideProps.keySet()); // TODO-Java6: s/keySet()/stringPropertyNames()/ return names; } - + /** - * Access the configuration attributes of this context, listing the properties + * Access the configuration attributes of this context, listing the properties * provided during the context construction, as well as the ones included in * System.getProperties. * * @return new Properties with system and context properties * @since 0.8.4 */ - public Properties getProperties() { + public Properties getProperties() { // clone to avoid ConcurrentModificationException Properties rv = (Properties) System.getProperties().clone(); rv.putAll(_overrideProps); return rv; } - + /** * Add a callback, which will fire upon changes in the property * given in the specific callback. @@ -585,12 +585,12 @@ public class I2PAppContext { * @param callback The implementation of the callback. */ public void addPropertyCallback(I2PPropertyCallback callback) {} - + /** * The statistics component with which we can track various events * over time. */ - public StatManager statManager() { + public StatManager statManager() { if (!_statManagerInitialized) initializeStatManager(); return _statManager; @@ -603,10 +603,10 @@ public class I2PAppContext { _statManagerInitialized = true; } } - + /** * The session key manager which coordinates the sessionKey / sessionTag - * data. This component allows transparent operation of the + * data. This component allows transparent operation of the * ElGamal/AES+SessionTag algorithm, and contains all of the session tags * for one particular application. * @@ -620,7 +620,7 @@ public class I2PAppContext { * The dummy SKM does NOT handle session tags. * Overridden in RouterContext to return the full TransientSessionKeyManager. */ - public SessionKeyManager sessionKeyManager() { + public SessionKeyManager sessionKeyManager() { if (!_sessionKeyManagerInitialized) initializeSessionKeyManager(); return _sessionKeyManager; @@ -628,19 +628,19 @@ public class I2PAppContext { protected void initializeSessionKeyManager() { synchronized (_lock3) { - if (_sessionKeyManager == null) + if (_sessionKeyManager == null) //_sessionKeyManager = new PersistentSessionKeyManager(this); _sessionKeyManager = new SessionKeyManager(this); _sessionKeyManagerInitialized = true; } } - + /** * Pull up the naming service used in this context. The naming service itself - * works by querying the context's properties, so those props should be + * works by querying the context's properties, so those props should be * specified to customize the naming service exposed. */ - public NamingService namingService() { + public NamingService namingService() { if (!_namingServiceInitialized) initializeNamingService(); return _namingService; @@ -654,7 +654,7 @@ public class I2PAppContext { _namingServiceInitialized = true; } } - + /** * This is the ElGamal engine used within this context. While it doesn't * really have anything substantial that is context specific (the algorithm @@ -680,7 +680,7 @@ public class I2PAppContext { /** * Ok, I'll admit it. there is no good reason for having a context specific * AES engine. We dont really keep stats on it, since its just too fast to - * matter. Though for the crazy people out there, we do expose a way to + * matter. Though for the crazy people out there, we do expose a way to * disable it. */ public AESEngine aes() { @@ -697,14 +697,14 @@ public class I2PAppContext { _AESEngineInitialized = true; } } - + /** * Query the log manager for this context, which may in turn have its own - * set of configuration settings (loaded from the context's properties). + * set of configuration settings (loaded from the context's properties). * Each context's logManager keeps its own isolated set of Log instances with * their own log levels, output locations, and rotation configuration. */ - public LogManager logManager() { + public LogManager logManager() { if (!_logManagerInitialized) initializeLogManager(); return _logManager; @@ -751,12 +751,12 @@ public class I2PAppContext { _hmac256Initialized = true; } } - + /** * Our SHA256 instance (see the hmac discussion for why its context specific) * */ - public SHA256Generator sha() { + public SHA256Generator sha() { if (!_shaInitialized) initializeSHA(); return _sha; @@ -769,12 +769,12 @@ public class I2PAppContext { _shaInitialized = true; } } - + /** * Our DSA engine (see HMAC and SHA above) * */ - public DSAEngine dsa() { + public DSAEngine dsa() { if (!_dsaInitialized) initializeDSA(); return _dsa; @@ -787,7 +787,7 @@ public class I2PAppContext { _dsaInitialized = true; } } - + /** * Component to generate ElGamal, DSA, and Session keys. For why it is in * the appContext, see the DSA, HMAC, and SHA comments above. @@ -805,7 +805,7 @@ public class I2PAppContext { _keyGeneratorInitialized = true; } } - + /** * The context's synchronized clock, which is kept context specific only to * enable simulators to play with clock skew among different instances. @@ -824,11 +824,11 @@ public class I2PAppContext { _clockInitialized = true; } } - + /** - * Determine how much do we want to mess with the keys to turn them - * into something we can route. This is context specific because we - * may want to test out how things react when peers don't agree on + * Determine how much do we want to mess with the keys to turn them + * into something we can route. This is context specific because we + * may want to test out how things react when peers don't agree on * how to skew. * * As of 0.9.16, returns null in I2PAppContext. @@ -839,7 +839,7 @@ public class I2PAppContext { public RoutingKeyGenerator routingKeyGenerator() { return null; } - + /** * Basic hash map */ @@ -856,7 +856,7 @@ public class I2PAppContext { _keyRingInitialized = true; } } - + /** * [insert snarky comment here] * @@ -886,7 +886,7 @@ public class I2PAppContext { public void addShutdownTask(Runnable task) { _shutdownTasks.add(task); } - + /** * @return an unmodifiable Set * @since 0.7.1 @@ -894,7 +894,7 @@ public class I2PAppContext { public Set getShutdownTasks() { return Collections.unmodifiableSet(_shutdownTasks); } - + /** * Use this instead of context instanceof RouterContext * @since 0.7.9 @@ -1007,7 +1007,7 @@ public class I2PAppContext { return _appManager; } - /** + /** * How long this router was down before it started, or 0 if unknown. * * This may be used for a determination of whether to regenerate keys, for example. diff --git a/core/java/test/junit/net/i2p/CoreTestBase.java b/core/java/test/junit/net/i2p/CoreTestBase.java new file mode 100644 index 0000000000..4914072216 --- /dev/null +++ b/core/java/test/junit/net/i2p/CoreTestBase.java @@ -0,0 +1,18 @@ +package net.i2p; + +import org.junit.BeforeClass; + +/** + * Base class for JUnit tests that need to use + * a TestContext + */ +public class CoreTestBase { + + protected static TestContext testContext; + + @BeforeClass + public static void setupContext() { + testContext = new TestContext(); + testContext = (TestContext) I2PAppContext.getGlobalContext(); + } +} diff --git a/core/java/test/junit/net/i2p/TestContext.java b/core/java/test/junit/net/i2p/TestContext.java new file mode 100644 index 0000000000..364a8f5df2 --- /dev/null +++ b/core/java/test/junit/net/i2p/TestContext.java @@ -0,0 +1,19 @@ +package net.i2p; + +import net.i2p.client.naming.NamingService; + +public class TestContext extends I2PAppContext { + + public TestContext() { + I2PAppContext.setGlobalContext(this); + } + + // add more subsystems here + public NamingService namingService; + + // override more subsystem getters here + @Override + public NamingService namingService() { + return namingService; + } +} diff --git a/core/java/test/junit/net/i2p/util/ConvertToHashMockTest.java b/core/java/test/junit/net/i2p/util/ConvertToHashMockTest.java new file mode 100644 index 0000000000..b75a49c0a5 --- /dev/null +++ b/core/java/test/junit/net/i2p/util/ConvertToHashMockTest.java @@ -0,0 +1,38 @@ +package net.i2p.util; + +import net.i2p.CoreTestBase; +import net.i2p.client.naming.NamingService; +import net.i2p.data.Destination; +import net.i2p.data.Hash; +import org.junit.Before; + +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.mockito.Mockito.*; +import static org.junit.Assert.*; + +public class ConvertToHashMockTest extends CoreTestBase { + + @Mock private NamingService namingService; + @Mock private Destination destination; + @Mock private Hash hash; + + @Before + public void before() { + MockitoAnnotations.initMocks(this); + testContext.namingService = namingService; + } + + @Test + public void testMockedDestination() { + when(namingService.lookup("zzz.i2p")).thenReturn(destination); + when(destination.calculateHash()).thenReturn(hash); + + assertSame(hash, ConvertToHash.getHash("zzz.i2p")); + + verify(namingService).lookup("zzz.i2p"); + verify(destination).calculateHash(); + } +}