diff --git a/apps/ministreaming/java/build.xml b/apps/ministreaming/java/build.xml
index 62254c801742c2cbbf253dede2710125250a68ab..14f729446b29c3f15be233bd9f3601002ed59292 100644
--- a/apps/ministreaming/java/build.xml
+++ b/apps/ministreaming/java/build.xml
@@ -188,8 +188,11 @@
         <cobertura-instrument todir="./build/obj_cobertura">
             <fileset dir="./build/obj">
                 <include name="**/*.class"/>
+                <!-- exclude stub classes -->
+                <exclude name="net/i2p/client/streaming/I2PSocketManagerFull.class" />
                 <!-- exclude Test classes -->
                 <exclude name="**/*Test.class" />
+                <exclude name="net/i2p/client/streaming/impl/I2PSocketManagerFull.class" />
                 <!-- exclude anything not in net.i2p.* -->
                 <exclude name="org/cybergarage/**/*.class" />
                 <exclude name="org/freenetproject/**/*.class" />
diff --git a/apps/ministreaming/java/test/junit/net/i2p/client/streaming/I2PSocketManagerFactoryTest.java b/apps/ministreaming/java/test/junit/net/i2p/client/streaming/I2PSocketManagerFactoryTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f00cf0dc145d800dbf20e33689977bbd4651e32
--- /dev/null
+++ b/apps/ministreaming/java/test/junit/net/i2p/client/streaming/I2PSocketManagerFactoryTest.java
@@ -0,0 +1,68 @@
+package net.i2p.client.streaming;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.Properties;
+
+import net.i2p.client.I2PClient;
+import net.i2p.client.I2PClientFactory;
+import net.i2p.client.streaming.impl.I2PSocketManagerFull;
+import net.i2p.data.Destination;
+
+import org.junit.Test;
+
+public class I2PSocketManagerFactoryTest {
+    @Test
+    public void testCreateDiscMgr() throws Exception {
+        I2PSocketManagerFull mgr = (I2PSocketManagerFull) I2PSocketManagerFactory.createDisconnectedManager(null, null, 0, null);
+        assertThat(mgr, is(not(nullValue())));
+        assertThat(mgr.getName(), is("manager"));
+
+        assertTrue(mgr.getOpts().containsKey(I2PClient.PROP_RELIABILITY));
+        assertThat(mgr.getOpts().getProperty(I2PClient.PROP_RELIABILITY), is(I2PClient.PROP_RELIABILITY_NONE));
+    }
+
+    @Test
+    public void testCreateDiscMgr_customDest() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Destination dest = I2PClientFactory.createClient().createDestination(baos);
+        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+
+        I2PSocketManagerFull mgr = (I2PSocketManagerFull) I2PSocketManagerFactory.createDisconnectedManager(bais, null, 0, null);
+        assertThat(mgr, is(not(nullValue())));
+        assertThat(mgr.getName(), is("manager"));
+
+        assertThat(mgr.getSession().getMyDestination(), is(equalTo(dest)));
+    }
+
+    @Test
+    public void testCreateDiscMgr_customI2CP() throws Exception {
+        I2PSocketManagerFull mgr = (I2PSocketManagerFull) I2PSocketManagerFactory.createDisconnectedManager(null, "example.com", 3333, null);
+        assertThat(mgr, is(not(nullValue())));
+        assertThat(mgr.getName(), is("manager"));
+
+        assertTrue(mgr.getOpts().containsKey(I2PClient.PROP_TCP_HOST));
+        assertThat(mgr.getOpts().getProperty(I2PClient.PROP_TCP_HOST), is("example.com"));
+        assertTrue(mgr.getOpts().containsKey(I2PClient.PROP_TCP_PORT));
+        assertThat(mgr.getOpts().getProperty(I2PClient.PROP_TCP_PORT), is("3333"));
+    }
+
+    @Test
+    public void testCreateDiscMgr_customOpts() throws Exception {
+        Properties opts = new Properties();
+        opts.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_BEST_EFFORT);
+        opts.setProperty("foo", "bar");
+
+        I2PSocketManagerFull mgr = (I2PSocketManagerFull) I2PSocketManagerFactory.createDisconnectedManager(null, null, 0, opts);
+        assertThat(mgr, is(not(nullValue())));
+        assertThat(mgr.getName(), is("manager"));
+
+        assertTrue(mgr.getOpts().containsKey(I2PClient.PROP_RELIABILITY));
+        assertThat(mgr.getOpts().getProperty(I2PClient.PROP_RELIABILITY), is(I2PClient.PROP_RELIABILITY_BEST_EFFORT));
+        assertTrue(mgr.getOpts().containsKey("foo"));
+        assertThat(mgr.getOpts().getProperty("foo"), is("bar"));
+    }
+}
diff --git a/apps/ministreaming/java/test/junit/net/i2p/client/streaming/impl/I2PSocketManagerFull.java b/apps/ministreaming/java/test/junit/net/i2p/client/streaming/impl/I2PSocketManagerFull.java
new file mode 100644
index 0000000000000000000000000000000000000000..e40c2f40f5c43139504319c59bbd63e550c1633d
--- /dev/null
+++ b/apps/ministreaming/java/test/junit/net/i2p/client/streaming/impl/I2PSocketManagerFull.java
@@ -0,0 +1,196 @@
+package net.i2p.client.streaming.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.net.ConnectException;
+import java.net.NoRouteToHostException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import net.i2p.I2PAppContext;
+import net.i2p.I2PException;
+import net.i2p.client.I2PSession;
+import net.i2p.client.I2PSessionException;
+import net.i2p.client.streaming.I2PServerSocket;
+import net.i2p.client.streaming.I2PSocket;
+import net.i2p.client.streaming.I2PSocketManager;
+import net.i2p.client.streaming.I2PSocketOptions;
+import net.i2p.data.Destination;
+
+/**
+ * Stub for testing I2PSocketManagerFactory.
+ *
+ * @author str4d
+ */
+public class I2PSocketManagerFull implements I2PSocketManager {
+    private I2PSession _session;
+    private Properties _opts;
+    private String _name;
+
+    /**
+     * This is what I2PSocketManagerFactory.createManager() returns.
+     * Direct instantiation by others is deprecated.
+     * 
+     * @param context non-null
+     * @param session non-null
+     * @param opts may be null
+     * @param name non-null
+     */
+    public I2PSocketManagerFull(I2PAppContext context, I2PSession session, Properties opts, String name) {
+        _session = session;
+        _opts = opts;
+        _name = name;
+    }
+
+    @Override
+    public I2PSession getSession() {
+        return _session;
+    }
+
+    public Properties getOpts() {
+        return _opts;
+    }
+
+    @Override
+    public String getName() {
+        return _name;
+    }
+
+    @Override
+    public I2PSession addSubsession(InputStream privateKeyStream,
+            Properties opts) throws I2PSessionException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void removeSubsession(I2PSession session) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<I2PSession> getSubsessions() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setAcceptTimeout(long ms) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public long getAcceptTimeout() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setDefaultOptions(I2PSocketOptions options) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public I2PSocketOptions getDefaultOptions() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public I2PServerSocket getServerSocket() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public I2PSocketOptions buildOptions() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public I2PSocketOptions buildOptions(Properties opts) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public I2PSocket connect(Destination peer, I2PSocketOptions options)
+            throws I2PException, ConnectException, NoRouteToHostException,
+            InterruptedIOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public I2PSocket connect(Destination peer) throws I2PException,
+            ConnectException, NoRouteToHostException, InterruptedIOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void destroySocketManager() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isDestroyed() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Set<I2PSocket> listSockets() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean ping(Destination peer, long timeoutMs) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean ping(Destination peer, int localPort, int remotePort,
+            long timeoutMs) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public byte[] ping(Destination peer, int localPort, int remotePort,
+            long timeoutMs, byte[] payload) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setName(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void init(I2PAppContext context, I2PSession session,
+            Properties opts, String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addDisconnectListener(DisconnectListener lsnr) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void removeDisconnectListener(DisconnectListener lsnr) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ServerSocket getStandardServerSocket() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Socket connectToSocket(Destination peer) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Socket connectToSocket(Destination peer, int timeout)
+            throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+}