diff --git a/router/java/test/junit/net/i2p/router/tunnel/GatewayTestBase.java b/router/java/test/junit/net/i2p/router/tunnel/GatewayTestBase.java
new file mode 100644
index 0000000000000000000000000000000000000000..0b1f64fd1fb52b569430a48a1eaf6c7d974fb9d7
--- /dev/null
+++ b/router/java/test/junit/net/i2p/router/tunnel/GatewayTestBase.java
@@ -0,0 +1,147 @@
+package net.i2p.router.tunnel;
+
+import static junit.framework.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.i2p.data.Hash;
+import net.i2p.data.RouterIdentity;
+import net.i2p.data.RouterInfo;
+import net.i2p.data.TunnelId;
+import net.i2p.data.i2np.DataMessage;
+import net.i2p.data.i2np.I2NPMessage;
+import net.i2p.router.Router;
+import net.i2p.router.RouterContext;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+
+public abstract class GatewayTestBase {
+
+    protected static RouterContext _context;
+    protected static TunnelGatewayPumper _pumper;
+    protected static TunnelCreatorConfig _config;
+    
+    protected TunnelGateway.QueuePreprocessor _preprocessor;
+    protected TunnelGateway.Sender _sender;
+    protected TestReceiver _receiver;
+    protected TunnelGateway _gw;
+    
+    @BeforeClass
+    public static void globalSetUp() {
+        // order of these matters
+        Router r = new Router();
+        _context = new RouterContext(r);
+        _context.initAll();
+        r.runRouter();
+        RouterIdentity rIdentity = new TestRouterIdentity();
+        RouterInfo rInfo = new RouterInfo();
+        rInfo.setIdentity(rIdentity);
+        r.setRouterInfo(rInfo);
+        _pumper = new TunnelGatewayPumper(_context);
+        _config = prepareConfig(8);
+    }
+    
+    @Before
+    public void baseSetUp() {
+        _preprocessor = new BatchedPreprocessor(_context,"test pre-processor");
+        setupSenderAndReceiver();
+        _gw = new PumpedTunnelGateway(_context, _preprocessor, _sender, _receiver, _pumper);
+    }
+    
+    protected abstract void setupSenderAndReceiver();
+    
+    private static class TestRouterIdentity extends RouterIdentity {
+        @Override
+        public Hash getHash() {
+            return Hash.FAKE_HASH;
+        }
+    }
+    
+    protected static DataMessage getTestMessage(int size) {
+        DataMessage m = new DataMessage(_context);
+        m.setData(new byte[size]);
+        java.util.Arrays.fill(m.getData(), (byte)0xFF);
+        m.setMessageExpiration(_context.clock().now() + 60*1000);
+        m.setUniqueId(_context.random().nextLong(I2NPMessage.MAX_ID_VALUE));
+        
+        byte [] data = m.toByteArray(); // not sure why, maybe side-effect? --zab
+        return m;
+    }
+    
+    protected class TestReceiver implements TunnelGateway.Receiver, FragmentHandler.DefragmentedReceiver {
+        private TunnelCreatorConfig _config;
+        private FragmentHandler _handler;
+        private volatile List _received;
+        public TestReceiver(TunnelCreatorConfig config) {
+            _config = config;
+            _handler = new FragmentHandler(_context, TestReceiver.this);
+            _received = new ArrayList(1000);
+        }
+        public long receiveEncrypted(byte[] encrypted) {
+            // fake all the hops...
+            
+            for (int i = 1; i <= _config.getLength() - 2; i++) {
+                HopProcessor hop = new HopProcessor(_context, _config.getConfig(i));
+                assertTrue(hop.process(encrypted, 0, encrypted.length, _config.getConfig(i).getReceiveFrom()));
+            }
+            
+            handleAtEndpoint(encrypted);
+            
+            _handler.receiveTunnelMessage(encrypted, 0, encrypted.length);
+            return -1; // or do we need to return the real message ID?
+        }        
+        
+        protected void handleAtEndpoint(byte [] encrypted) {
+        }
+        
+        public void receiveComplete(I2NPMessage msg, Hash toRouter, TunnelId toTunnel) {
+            _received.add(msg);
+        }
+        public List clearReceived() { 
+            List rv = _received; 
+            _received = new ArrayList();
+            return rv;
+        }
+        @Override
+        public Hash getSendTo() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+    }
+    
+    
+    private static TunnelCreatorConfig prepareConfig(int numHops) {
+        Hash peers[] = new Hash[numHops];
+        byte tunnelIds[][] = new byte[numHops][4];
+        for (int i = 0; i < numHops; i++) {
+            peers[i] = new Hash();
+            peers[i].setData(new byte[Hash.HASH_LENGTH]);
+            _context.random().nextBytes(peers[i].getData());
+            _context.random().nextBytes(tunnelIds[i]);
+        }
+        
+        TunnelCreatorConfig config = new TunnelCreatorConfig(_context, numHops, false);
+        for (int i = 0; i < numHops; i++) {
+            config.setPeer(i, peers[i]);
+            HopConfig cfg = config.getConfig(i);
+            cfg.setExpiration(_context.clock().now() + 60000);
+            cfg.setIVKey(_context.keyGenerator().generateSessionKey());
+            cfg.setLayerKey(_context.keyGenerator().generateSessionKey());
+            if (i > 0)
+                cfg.setReceiveFrom(peers[i-1]);
+            else
+                cfg.setReceiveFrom(null);
+            cfg.setReceiveTunnelId(tunnelIds[i]);
+            if (i < numHops - 1) {
+                cfg.setSendTo(peers[i+1]);
+                cfg.setSendTunnelId(tunnelIds[i+1]);
+            } else {
+                cfg.setSendTo(null);
+                cfg.setSendTunnelId(null);
+            }
+        }
+        return config;
+    }
+}
diff --git a/router/java/test/junit/net/i2p/router/tunnel/InboundGatewayTest.java b/router/java/test/junit/net/i2p/router/tunnel/InboundGatewayTest.java
index 8c2bdaabe42960113e501819e4ca41818e259143..dd2a0a44c70fd150da43d147ec7edb75d6db0d70 100644
--- a/router/java/test/junit/net/i2p/router/tunnel/InboundGatewayTest.java
+++ b/router/java/test/junit/net/i2p/router/tunnel/InboundGatewayTest.java
@@ -11,54 +11,25 @@ package net.i2p.router.tunnel;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 
 import static junit.framework.TestCase.*;
 import net.i2p.data.Hash;
-import net.i2p.data.RouterIdentity;
-import net.i2p.data.RouterInfo;
 import net.i2p.data.TunnelId;
 import net.i2p.data.i2np.DataMessage;
 import net.i2p.data.i2np.I2NPMessage;
-import net.i2p.router.Router;
-import net.i2p.router.RouterContext;
 
 /**
  * Quick unit test for base functionality of inbound tunnel 
  * operation
  */
-public class InboundGatewayTest {
-    private static RouterContext _context;
-    private static TunnelGatewayPumper _pumper;
-    private TunnelCreatorConfig _config;
-    private TunnelGateway.QueuePreprocessor _preprocessor;
-    private TunnelGateway.Sender _sender;
-    private TestReceiver _receiver;
-    private TunnelGateway _gw;
+public class InboundGatewayTest extends GatewayTestBase {
     
-    @BeforeClass
-    public static void globalSetUp() {
-        // order of these matters
-        Router r = new Router();
-        _context = new RouterContext(r);
-        _context.initAll();
-        r.runRouter();
-        RouterIdentity rIdentity = new TestRouterIdentity();
-        RouterInfo rInfo = new RouterInfo();
-        rInfo.setIdentity(rIdentity);
-        r.setRouterInfo(rInfo);
-        _pumper = new TunnelGatewayPumper(_context);
-    }
     
-    @Before
-    public void setUp() {
-        _config = prepareConfig(8);
-        _preprocessor = new BatchedPreprocessor(_context,"test pre-processor");
+    @Override
+    protected void setupSenderAndReceiver() {
         _sender = new InboundSender(_context, _config.getConfig(0));
-        _receiver = new TestReceiver(_config);
-        _gw = new PumpedTunnelGateway(_context, _preprocessor, _sender, _receiver, _pumper);
+        _receiver = new InboundTestReceiver(_config);
     }
     
     @Test
@@ -69,12 +40,7 @@ public class InboundGatewayTest {
         long start = _context.clock().now();
     
         for (int i = 0; i < runCount; i++) {
-            DataMessage m = new DataMessage(_context);
-            m.setData(new byte[64]);
-            java.util.Arrays.fill(m.getData(), (byte)0xFF);
-            m.setMessageExpiration(_context.clock().now() + 60*1000);
-            m.setUniqueId(_context.random().nextLong(I2NPMessage.MAX_ID_VALUE));
-            byte data[] = m.toByteArray();
+           DataMessage m = getTestMessage(64);
             messages.add(m);
             _gw.add(m, null, null);
         }
@@ -95,14 +61,9 @@ public class InboundGatewayTest {
         long start = _context.clock().now();
     
         for (int i = 0; i < runCount; i++) {
-            DataMessage m = new DataMessage(_context);
-            m.setData(new byte[64]);
-            java.util.Arrays.fill(m.getData(), (byte)0xFF);
-            m.setMessageExpiration(_context.clock().now() + 60*1000);
-            m.setUniqueId(_context.random().nextLong(I2NPMessage.MAX_ID_VALUE));
+            DataMessage m = getTestMessage(64);
             Hash to = new Hash(new byte[Hash.HASH_LENGTH]);
             java.util.Arrays.fill(to.getData(), (byte)0xFF);
-            byte data[] = m.toByteArray();
             messages.add(m);
             _gw.add(m, to, null);
         }
@@ -123,15 +84,10 @@ public class InboundGatewayTest {
         long start = _context.clock().now();
     
         for (int i = 0; i < runCount; i++) {
-            DataMessage m = new DataMessage(_context);
-            m.setData(new byte[64]);
-            java.util.Arrays.fill(m.getData(), (byte)0xFF);
-            m.setMessageExpiration(_context.clock().now() + 60*1000);
-            m.setUniqueId(_context.random().nextLong(I2NPMessage.MAX_ID_VALUE));
+            DataMessage m = getTestMessage(64);
             Hash to = new Hash(new byte[Hash.HASH_LENGTH]);
             java.util.Arrays.fill(to.getData(), (byte)0xFF);
             TunnelId tunnel = new TunnelId(42);
-            byte data[] = m.toByteArray();
             messages.add(m);
             _gw.add(m, to, tunnel);
         }
@@ -152,12 +108,7 @@ public class InboundGatewayTest {
         long start = _context.clock().now();
     
         for (int i = 0; i < runCount; i++) {
-            DataMessage m = new DataMessage(_context);
-            m.setData(new byte[1024]);
-            java.util.Arrays.fill(m.getData(), (byte)0xFF);
-            m.setMessageExpiration(_context.clock().now() + 60*1000);
-            m.setUniqueId(_context.random().nextLong(I2NPMessage.MAX_ID_VALUE));
-            byte data[] = m.toByteArray();
+            DataMessage m = getTestMessage(1024);
             messages.add(m);
             _gw.add(m, null, null);
         }
@@ -170,84 +121,16 @@ public class InboundGatewayTest {
         }
     }
     
-    private static class TestRouterIdentity extends RouterIdentity {
-        @Override
-        public Hash getHash() {
-            return Hash.FAKE_HASH;
-        }
-    }
-    
-    private class TestReceiver implements TunnelGateway.Receiver, FragmentHandler.DefragmentedReceiver {
-        private TunnelCreatorConfig _config;
-        private FragmentHandler _handler;
-        private volatile List _received;
-        public TestReceiver(TunnelCreatorConfig config) {
-            _config = config;
-            _handler = new FragmentHandler(_context, TestReceiver.this);
-            _received = new ArrayList(1000);
+    private class InboundTestReceiver extends TestReceiver {
+        public InboundTestReceiver(TunnelCreatorConfig config) {
+            super(config);
         }
-        public long receiveEncrypted(byte[] encrypted) {
-            // fake all the hops...
-            
-            for (int i = 1; i <= _config.getLength() - 2; i++) {
-                HopProcessor hop = new HopProcessor(_context, _config.getConfig(i));
-                assertTrue(hop.process(encrypted, 0, encrypted.length, _config.getConfig(i).getReceiveFrom()));
-            }
-            
+        
+        @Override
+        protected void handleAtEndpoint(byte []encrypted) {
             // now handle it at the endpoint
             InboundEndpointProcessor end = new InboundEndpointProcessor(_context, _config);
             assertTrue(end.retrievePreprocessedData(encrypted, 0, encrypted.length, _config.getPeer(_config.getLength()-2)));
-            
-            
-            _handler.receiveTunnelMessage(encrypted, 0, encrypted.length);
-            return -1; // or do we need to return the real message ID?
-        }        
-        public void receiveComplete(I2NPMessage msg, Hash toRouter, TunnelId toTunnel) {
-            System.out.println("got something");
-            _received.add(msg);
-        }
-        public List clearReceived() { 
-            List rv = _received; 
-            _received = new ArrayList();
-            return rv;
-        }
-        @Override
-        public Hash getSendTo() {
-            // TODO Auto-generated method stub
-            return null;
-        }
-    }
-    
-    private TunnelCreatorConfig prepareConfig(int numHops) {
-        Hash peers[] = new Hash[numHops];
-        byte tunnelIds[][] = new byte[numHops][4];
-        for (int i = 0; i < numHops; i++) {
-            peers[i] = new Hash();
-            peers[i].setData(new byte[Hash.HASH_LENGTH]);
-            _context.random().nextBytes(peers[i].getData());
-            _context.random().nextBytes(tunnelIds[i]);
-        }
-        
-        TunnelCreatorConfig config = new TunnelCreatorConfig(_context, numHops, false);
-        for (int i = 0; i < numHops; i++) {
-            config.setPeer(i, peers[i]);
-            HopConfig cfg = config.getConfig(i);
-            cfg.setExpiration(_context.clock().now() + 60000);
-            cfg.setIVKey(_context.keyGenerator().generateSessionKey());
-            cfg.setLayerKey(_context.keyGenerator().generateSessionKey());
-            if (i > 0)
-                cfg.setReceiveFrom(peers[i-1]);
-            else
-                cfg.setReceiveFrom(null);
-            cfg.setReceiveTunnelId(tunnelIds[i]);
-            if (i < numHops - 1) {
-                cfg.setSendTo(peers[i+1]);
-                cfg.setSendTunnelId(tunnelIds[i+1]);
-            } else {
-                cfg.setSendTo(null);
-                cfg.setSendTunnelId(null);
-            }
         }
-        return config;
     }
 }
diff --git a/router/java/test/junit/net/i2p/router/tunnel/OutboundGatewayTest.java b/router/java/test/junit/net/i2p/router/tunnel/OutboundGatewayTest.java
index 7a4dbbc9122c6e769c7ab725e87e20e88161381f..a5bb4adc5fffc9ced34cd368ef68a93e6e5247a2 100644
--- a/router/java/test/junit/net/i2p/router/tunnel/OutboundGatewayTest.java
+++ b/router/java/test/junit/net/i2p/router/tunnel/OutboundGatewayTest.java
@@ -11,53 +11,40 @@ package net.i2p.router.tunnel;
 import java.util.ArrayList;
 import java.util.List;
 
-import junit.framework.TestCase;
-import net.i2p.I2PAppContext;
+import org.junit.Test;
+
+import static junit.framework.TestCase.*;
 import net.i2p.data.Hash;
 import net.i2p.data.TunnelId;
 import net.i2p.data.i2np.DataMessage;
 import net.i2p.data.i2np.I2NPMessage;
-import net.i2p.router.RouterContext;
 
 /**
  * Quick unit test for base functionality of outbound tunnel 
  * operation
  */
-public class OutboundGatewayTest extends TestCase{
-    private RouterContext _context;
-    private TunnelCreatorConfig _config;
-    private TunnelGateway.QueuePreprocessor _preprocessor;
-    private TunnelGateway.Sender _sender;
-    private TestReceiver _receiver;
-    private TunnelGateway _gw;
+public class OutboundGatewayTest extends GatewayTestBase {
     
-    public void setUp() {
-        _context = new RouterContext(null);
-        _config = prepareConfig(8);
-        _preprocessor = new TrivialPreprocessor(_context);
+    @Override
+    protected void setupSenderAndReceiver() {
         _sender = new OutboundSender(_context, _config);
         _receiver = new TestReceiver(_config);
-        _gw = new TunnelGateway(_context, _preprocessor, _sender, _receiver);
     }
     
-    public void testSmall() {
+    @Test
+    public void testSmall() throws Exception {
     	int runCount = 1;
     	
         List messages = new ArrayList(runCount);
         long start = _context.clock().now();
     
         for (int i = 0; i < runCount; i++) {
-            DataMessage m = new DataMessage(_context);
-            m.setData(new byte[64]);
-            java.util.Arrays.fill(m.getData(), (byte)0xFF);
-            m.setMessageExpiration(_context.clock().now() + 60*1000);
-            m.setUniqueId(_context.random().nextLong(I2NPMessage.MAX_ID_VALUE));
-            byte data[] = m.toByteArray();
+            DataMessage m = getTestMessage(64);
             messages.add(m);
             _gw.add(m, null, null);
         }
         
-        long time = _context.clock().now() - start;
+        Thread.sleep(10000);
         
         List received = _receiver.clearReceived();
         for (int i = 0; i < messages.size(); i++) {
@@ -65,6 +52,7 @@ public class OutboundGatewayTest extends TestCase{
         }
     }
     
+    @Test
     public void testRouter() {
     	int runCount = 1;
     	
@@ -72,14 +60,9 @@ public class OutboundGatewayTest extends TestCase{
         long start = _context.clock().now();
     
         for (int i = 0; i < runCount; i++) {
-            DataMessage m = new DataMessage(_context);
-            m.setData(new byte[64]);
-            java.util.Arrays.fill(m.getData(), (byte)0xFF);
-            m.setMessageExpiration(_context.clock().now() + 60*1000);
-            m.setUniqueId(_context.random().nextLong(I2NPMessage.MAX_ID_VALUE));
+            DataMessage m = getTestMessage(64);
             Hash to = new Hash(new byte[Hash.HASH_LENGTH]);
             java.util.Arrays.fill(to.getData(), (byte)0xFF);
-            byte data[] = m.toByteArray();
             messages.add(m);
             _gw.add(m, to, null);
         }
@@ -92,6 +75,7 @@ public class OutboundGatewayTest extends TestCase{
         }
     }
     
+    @Test
     public void testTunnel() {
     	int runCount = 1;
     	
@@ -99,11 +83,7 @@ public class OutboundGatewayTest extends TestCase{
         long start = _context.clock().now();
     
         for (int i = 0; i < runCount; i++) {
-            DataMessage m = new DataMessage(_context);
-            m.setData(new byte[64]);
-            java.util.Arrays.fill(m.getData(), (byte)0xFF);
-            m.setMessageExpiration(_context.clock().now() + 60*1000);
-            m.setUniqueId(_context.random().nextLong(I2NPMessage.MAX_ID_VALUE));
+            DataMessage m = getTestMessage(64);
             Hash to = new Hash(new byte[Hash.HASH_LENGTH]);
             java.util.Arrays.fill(to.getData(), (byte)0xFF);
             TunnelId tunnel = new TunnelId(42);
@@ -120,6 +100,7 @@ public class OutboundGatewayTest extends TestCase{
         }
     }
     
+    @Test
     public void testLarge() {
     	int runCount = 1;
     	
@@ -127,12 +108,7 @@ public class OutboundGatewayTest extends TestCase{
         long start = _context.clock().now();
     
         for (int i = 0; i < runCount; i++) {
-            DataMessage m = new DataMessage(_context);
-            m.setData(new byte[1024]);
-            java.util.Arrays.fill(m.getData(), (byte)0xFF);
-            m.setMessageExpiration(_context.clock().now() + 60*1000);
-            m.setUniqueId(_context.random().nextLong(I2NPMessage.MAX_ID_VALUE));
-            byte data[] = m.toByteArray();
+            DataMessage m = getTestMessage(1024);
             messages.add(m);
             _gw.add(m, null, null);
         }
@@ -146,13 +122,13 @@ public class OutboundGatewayTest extends TestCase{
         }
     }
     
-    private class TestReceiver implements TunnelGateway.Receiver, FragmentHandler.DefragmentedReceiver {
+    private class TestReceiverr implements TunnelGateway.Receiver, FragmentHandler.DefragmentedReceiver {
         private TunnelCreatorConfig _config;
         private FragmentHandler _handler;
         private List _received;
-        public TestReceiver(TunnelCreatorConfig config) {
+        public TestReceiverr(TunnelCreatorConfig config) {
             _config = config;
-            _handler = new FragmentHandler(_context, TestReceiver.this);
+            _handler = new FragmentHandler(_context, TestReceiverr.this);
             _received = new ArrayList(1000);
         }
         public long receiveEncrypted(byte[] encrypted) {
@@ -182,37 +158,4 @@ public class OutboundGatewayTest extends TestCase{
             return null;
         }
     }
-    
-    private TunnelCreatorConfig prepareConfig(int numHops) {
-        Hash peers[] = new Hash[numHops];
-        byte tunnelIds[][] = new byte[numHops][4];
-        for (int i = 0; i < numHops; i++) {
-            peers[i] = new Hash();
-            peers[i].setData(new byte[Hash.HASH_LENGTH]);
-            _context.random().nextBytes(peers[i].getData());
-            _context.random().nextBytes(tunnelIds[i]);
-        }
-        
-        TunnelCreatorConfig config = new TunnelCreatorConfig(_context, numHops, false);
-        for (int i = 0; i < numHops; i++) {
-            config.setPeer(i, peers[i]);
-            HopConfig cfg = config.getConfig(i);
-            cfg.setExpiration(_context.clock().now() + 60000);
-            cfg.setIVKey(_context.keyGenerator().generateSessionKey());
-            cfg.setLayerKey(_context.keyGenerator().generateSessionKey());
-            if (i > 0)
-                cfg.setReceiveFrom(peers[i-1]);
-            else
-                cfg.setReceiveFrom(null);
-            cfg.setReceiveTunnelId(tunnelIds[i]);
-            if (i < numHops - 1) {
-                cfg.setSendTo(peers[i+1]);
-                cfg.setSendTunnelId(tunnelIds[i+1]);
-            } else {
-                cfg.setSendTo(null);
-                cfg.setSendTunnelId(null);
-            }
-        }
-        return config;
-    }
 }