Merge pull request #6 from 01org/add-mock-forwarder

Add mock forwarder
diff --git a/build.gradle b/build.gradle
index bcddbe2..ddc709a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,3 +1,17 @@
+/*
+ * jndn-mock
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 3, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ */
+
 buildscript {
   repositories {
     jcenter()
@@ -13,10 +27,10 @@
 apply plugin: 'java'
 apply plugin: 'maven'
 apply plugin: 'signing'
-apply plugin: 'checkstyle'
+//apply plugin: 'checkstyle'
 
 group = 'com.intel.jndn.mock'
-version = '1.0.3'
+version = '1.1.0'
 
 sourceCompatibility = JavaVersion.VERSION_1_7
 targetCompatibility = JavaVersion.VERSION_1_7
diff --git a/config/checkstyle/checkstyle-test.xml b/config/checkstyle/checkstyle-test.xml
index 81b48ec..503f6e0 100644
--- a/config/checkstyle/checkstyle-test.xml
+++ b/config/checkstyle/checkstyle-test.xml
@@ -1,4 +1,18 @@
 <?xml version="1.0"?>
+<!--
+  ~ jndn-mock
+  ~ Copyright (c) 2016, Intel Corporation.
+  ~
+  ~ This program is free software; you can redistribute it and/or modify it
+  ~ under the terms and conditions of the GNU Lesser General Public License,
+  ~ version 3, as published by the Free Software Foundation.
+  ~
+  ~ This program is distributed in the hope it will be useful, but WITHOUT ANY
+  ~ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+  ~ FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+  ~ more details.
+  -->
+
 <!DOCTYPE module PUBLIC
           "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
           "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
index 86eda33..9fb4286 100644
--- a/config/checkstyle/checkstyle.xml
+++ b/config/checkstyle/checkstyle.xml
@@ -1,4 +1,18 @@
 <?xml version="1.0"?>
+<!--
+  ~ jndn-mock
+  ~ Copyright (c) 2016, Intel Corporation.
+  ~
+  ~ This program is free software; you can redistribute it and/or modify it
+  ~ under the terms and conditions of the GNU Lesser General Public License,
+  ~ version 3, as published by the Free Software Foundation.
+  ~
+  ~ This program is distributed in the hope it will be useful, but WITHOUT ANY
+  ~ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+  ~ FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+  ~ more details.
+  -->
+
 <!DOCTYPE module PUBLIC
           "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
           "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index cdddf1e..bdeb380 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,3 +1,17 @@
+#
+# jndn-mock
+# Copyright (c) 2016, Intel Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU Lesser General Public License,
+# version 3, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+# more details.
+#
+
 #Sun Jan 31 16:45:16 PST 2016
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
diff --git a/nb-configuration.xml b/nb-configuration.xml
index b51151d..2f96e1e 100644
--- a/nb-configuration.xml
+++ b/nb-configuration.xml
@@ -1,4 +1,18 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ jndn-mock
+  ~ Copyright (c) 2016, Intel Corporation.
+  ~
+  ~ This program is free software; you can redistribute it and/or modify it
+  ~ under the terms and conditions of the GNU Lesser General Public License,
+  ~ version 3, as published by the Free Software Foundation.
+  ~
+  ~ This program is distributed in the hope it will be useful, but WITHOUT ANY
+  ~ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+  ~ FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+  ~ more details.
+  -->
+
 <project-shared-configuration>
     <!--
 This file contains additional configuration written by modules in the NetBeans IDE.
diff --git a/pom.xml b/pom.xml
index c92da38..2b9da0a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.intel.jndn.mock</groupId>
   <artifactId>jndn-mock</artifactId>
-  <version>1.0.3</version>
+  <version>1.1.0</version>
   <name>jndn-mock</name>
   <description>Tools for testing NDN Java code without using network IO.</description>
   <url>https://github.com/01org/jndn-utils</url>
diff --git a/src/main/java/com/intel/jndn/mock/MeasurableFace.java b/src/main/java/com/intel/jndn/mock/MeasurableFace.java
new file mode 100644
index 0000000..c862756
--- /dev/null
+++ b/src/main/java/com/intel/jndn/mock/MeasurableFace.java
@@ -0,0 +1,47 @@
+/*
+ * jndn-mock
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 3, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ */
+
+package com.intel.jndn.mock;
+
+import net.named_data.jndn.Data;
+import net.named_data.jndn.Interest;
+
+import java.util.Collection;
+
+/**
+ * Provide API for measuring packet use on a given face
+ *
+ * @author Andrew Brown, andrew.brown@intel.com
+ */
+public interface MeasurableFace {
+  /**
+   * @return all interest packets sent by the measured face
+   */
+  Collection<Interest> sentInterests();
+
+  /**
+   * @return all data packets sent by the measured face
+   */
+  Collection<Data> sentDatas();
+
+  /**
+   * @return all interest packets received by the measured face
+   */
+  Collection<Interest> receivedInterests();
+
+  /**
+   * @return all data packets received by the measured face
+   */
+  Collection<Data> receivedDatas();
+}
diff --git a/src/main/java/com/intel/jndn/mock/MockFace.java b/src/main/java/com/intel/jndn/mock/MockFace.java
index 8980fa7..dc1661a 100644
--- a/src/main/java/com/intel/jndn/mock/MockFace.java
+++ b/src/main/java/com/intel/jndn/mock/MockFace.java
@@ -1,6 +1,6 @@
 /*
  * jndn-mock
- * Copyright (c) 2013-2015 Regents of the University of California.
+ * Copyright (c) 2016, Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU Lesser General Public License,
@@ -36,8 +36,8 @@
 /**
  * A client-side face for unit testing.
  *
- * @author Alexander Afanasyev, <aa@cs.ucla.edu>
- * @author Andrew Brown <andrew.brown@intel.com>
+ * @author Alexander Afanasyev, aa@cs.ucla.edu
+ * @author Andrew Brown, andrew.brown@intel.com
  */
 public class MockFace extends Face {
   /**
@@ -77,7 +77,7 @@
   public final List<SignalOnSendData> onSendData = new ArrayList<>();
 
   private static final Logger LOGGER = Logger.getLogger(MockFace.class.getName());
-  private MockFaceTransport transport;
+  private MockTransport transport;
   private KeyChain keyChain;
 
   /////////////////////////////////////////////////////////////////////////////
@@ -163,7 +163,7 @@
    *
    * @throws SecurityException should not be thrown by this test class
    */
-  public MockFace() throws SecurityException {
+  public MockFace() {
     this(DEFAULT_OPTIONS);
   }
 
@@ -175,7 +175,7 @@
    *   new MockFace(new Options());
    *   // use onSendInterest.add(handler) and onSendData.add(handler)
    *   // to add custom logic when Interest or Data packet are sent
-   *   // from the upper level (to transport)
+   *   // from the upper level (to callback)
    * </pre>
    *
    * To create Face that just logs packets in sentInterests and sentData:
@@ -186,8 +186,8 @@
    * @param options see {@link Options}
    */
   public MockFace(final Options options) {
-    super(new MockFaceTransport(), null);
-    transport = (MockFaceTransport) node_.getTransport();
+    super(new MockTransport(), null);
+    transport = (MockTransport) node_.getTransport();
     transport.setOnSendBlock(new OnIncomingPacket());
 
     try {
@@ -222,7 +222,7 @@
   /**
    * Route incoming packets to the correct callbacks.
    */
-  private class OnIncomingPacket implements MockFaceTransport.OnSendBlockSignal {
+  private class OnIncomingPacket implements MockTransport.OnSendBlockSignal {
     /**
      * {@inheritDoc}
      */
@@ -252,7 +252,7 @@
           LOGGER.info("Received an unknown packet");
         }
       } catch (EncodingException e) {
-        LOGGER.log(Level.INFO, "Failed to decode incoming packet", e);
+        LOGGER.log(Level.INFO, "Failed to decodeParameters incoming packet", e);
       }
     }
   }
@@ -309,7 +309,7 @@
   }
 
   /**
-   * Mock reception of the Interest packet on the Face (from transport).
+   * Mock reception of the Interest packet on the Face (from callback).
    *
    * @param interest the mock-remote interest to add to the PIT
    * @throws EncodingException if packet encoding fails (it should not)
@@ -319,7 +319,7 @@
   }
 
   /**
-   * Mock reception of the Data packet on the Face (from transport).
+   * Mock reception of the Data packet on the Face (from callback).
    *
    * @param data the mock-remote data to add to the CS
    * @throws EncodingException if packet encoding fails (it should not)
@@ -329,7 +329,7 @@
   }
 
   /**
-   * @return the transport for this face
+   * @return the callback for this face
    */
   public Transport getTransport() {
     return transport;
diff --git a/src/main/java/com/intel/jndn/mock/MockForwarder.java b/src/main/java/com/intel/jndn/mock/MockForwarder.java
new file mode 100644
index 0000000..11ea73e
--- /dev/null
+++ b/src/main/java/com/intel/jndn/mock/MockForwarder.java
@@ -0,0 +1,233 @@
+/*
+ * jndn-mock
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 3, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ */
+
+package com.intel.jndn.mock;
+
+import com.intel.jndn.mock.forwarder.BufferHandler;
+import com.intel.jndn.mock.forwarder.FibImpl;
+import com.intel.jndn.mock.forwarder.LocalFibEntry;
+import com.intel.jndn.mock.forwarder.OnPrefixRegistration;
+import com.intel.jndn.mock.forwarder.PitImpl;
+import net.named_data.jndn.Data;
+import net.named_data.jndn.Face;
+import net.named_data.jndn.ForwardingFlags;
+import net.named_data.jndn.Interest;
+import net.named_data.jndn.Name;
+import net.named_data.jndn.OnData;
+import net.named_data.jndn.OnNetworkNack;
+import net.named_data.jndn.OnTimeout;
+import net.named_data.jndn.encoding.WireFormat;
+import net.named_data.jndn.security.KeyChain;
+import net.named_data.jndn.security.SecurityException;
+import net.named_data.jndn.transport.Transport;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.logging.Logger;
+
+/**
+ * A mock forwarder for use in testing applications without network IO. It does not fully implement NFD functionality
+ * but currently does allow registering prefixes (to receive sent interests) and limited forwarding flag support.
+ *
+ * @author Andrew Brown, andrew.brown@intel.com
+ */
+public class MockForwarder {
+  private static final Logger LOGGER = Logger.getLogger(MockForwarder.class.getName());
+  private final KeyChain keyChain;
+  private final Name certName;
+  private final Fib fib = new FibImpl();
+  private final Pit pit = new PitImpl();
+
+  /**
+   * Forwarding information base API; use this for recording FIB entries.
+   */
+  public interface Fib {
+    /**
+     * @param interest the incoming client interest
+     * @return all FIB entries matching the interest
+     */
+    Collection<FibEntry> find(Interest interest);
+
+    /**
+     * @param entry a new FIB entry to add; enables routing to the face (or more correctly, channel) contained in this
+     * entry
+     */
+    void add(FibEntry entry);
+  }
+
+  /**
+   * Entry in the FIB; use this for forwarding interest packets.
+   */
+  public interface FibEntry {
+    /**
+     * @param interest the interest to forward
+     * @param sourceTransport the source of the interest for use in the callback
+     */
+    void forward(Interest interest, Transport sourceTransport);
+
+    /**
+     * @return then entry prefix name
+     */
+    Name getPrefix();
+
+    /**
+     * @return the entry flags
+     */
+    ForwardingFlags getFlags();
+  }
+
+  /**
+   * Pending interest table API; use this for recording incoming interests.
+   */
+  public interface Pit {
+    /**
+     * @param entry the PIT entry to add
+     */
+    void add(PitEntry entry);
+
+    /**
+     * @param interest the incoming interest to match against
+     * @return true if the interest matches an entry already in the PIT
+     */
+    boolean has(Interest interest);
+
+    /**
+     * @param name the name to match against
+     * @return the PIT entries matching a name, removing them from the PIT
+     */
+    Collection<PitEntry> extract(Name name);
+  }
+
+  /**
+   * Entry in the PIT; use this for forwarding data packets.
+   */
+  public interface PitEntry {
+    /**
+     * @param data the packet to forward
+     */
+    void forward(Data data);
+
+    /**
+     * @return the interest that first created the entry
+     */
+    Interest getInterest();
+
+    /**
+     * @return true if the entry has been satisfied (has had a matching data forwarded through it)
+     */
+    boolean isSatisfied();
+  }
+
+  /**
+   * Mock-specific API for recording the source and destination of incoming interests
+   */
+  public interface OnInterestReceived {
+    /**
+     * Called when the mock forwarder receives incoming interests from a face; see {@link #register(Name,
+     * OnInterestReceived, ForwardingFlags)}.
+     *
+     * @param interest the incoming interest
+     * @param destinationTransport the transport that sent the interest; necessary for the forwarder to be able to
+     * register prefixes (TODO in the future this should also be a {@link Face}, perhaps rename as remoteFace).
+     * @param sourceFace the face receiving the interest; use {@link Face#putData(Data)} to reply
+     */
+    void in(Interest interest, Transport destinationTransport, Face sourceFace);
+  }
+
+  public MockForwarder() {
+    try {
+      keyChain = MockKeyChain.configure(new Name("/mock/forwarder"));
+      certName = keyChain.getDefaultCertificateName();
+    } catch (SecurityException e) {
+      throw new IllegalStateException("Failed to set up mock prefix registration", e);
+    }
+
+    OnPrefixRegistration onPrefixRegistration = new OnPrefixRegistration(keyChain, fib);
+    Name registrationPrefix = new Name("/localhost/nfd/rib/register");
+    register(registrationPrefix, onPrefixRegistration, new ForwardingFlags());
+  }
+
+  public Face connect() {
+    MockForwarderFace face = new MockForwarderFace();
+    face.setCommandSigningInfo(keyChain, certName);
+    LOGGER.info("Connected new face using transport: " + face.getTransport());
+    return face;
+  }
+
+  public void register(Name prefix, OnInterestReceived callback, ForwardingFlags flags) {
+    Face registrationFace = this.connect();
+    FibEntry registrationEntry = new LocalFibEntry(prefix, callback, registrationFace, flags);
+    fib.add(registrationEntry);
+    LOGGER.info("Registered new prefix to receive interests: " + prefix);
+  }
+
+  private class MockForwarderFace extends Face implements MeasurableFace {
+    final Collection<Interest> sentInterests = new ArrayList<>();
+    final Collection<Data> sentDatas = new ArrayList<>();
+    final Collection<Interest> receivedInterests = new ArrayList<>();
+    final Collection<Data> receivedDatas = new ArrayList<>();
+
+    MockForwarderFace() {
+      super(new MockTransport(), null);
+      MockTransport transport = (MockTransport) node_.getTransport();
+      transport.setOnSendBlock(new BufferHandler(transport, fib, pit));
+    }
+
+    Transport getTransport() {
+      return node_.getTransport();
+    }
+
+    @Override
+    public long expressInterest(Interest interest, OnData onData, OnTimeout onTimeout,
+                                OnNetworkNack onNetworkNack, WireFormat wireFormat) throws IOException {
+      sentInterests.add(interest);
+      return super.expressInterest(interest, onData, onTimeout, onNetworkNack, wireFormat);
+    }
+
+    @Override
+    public long expressInterest(Name name, Interest interestTemplate, OnData onData, OnTimeout onTimeout,
+                                OnNetworkNack onNetworkNack, WireFormat wireFormat) throws IOException {
+      sentInterests.add(getInterestCopy(name, interestTemplate));
+      return super.expressInterest(name, interestTemplate, onData, onTimeout, onNetworkNack, wireFormat);
+    }
+
+    @Override
+    public void putData(Data data, WireFormat wireFormat) throws IOException {
+      sentDatas.add(data);
+      super.putData(data, wireFormat);
+    }
+
+    @Override
+    public Collection<Interest> sentInterests() {
+      return Collections.unmodifiableCollection(sentInterests);
+    }
+
+    @Override
+    public Collection<Data> sentDatas() {
+      return Collections.unmodifiableCollection(sentDatas);
+    }
+
+    @Override
+    public Collection<Interest> receivedInterests() {
+      return Collections.unmodifiableCollection(receivedInterests);
+    }
+
+    @Override
+    public Collection<Data> receivedDatas() {
+      return Collections.unmodifiableCollection(receivedDatas);
+    }
+  }
+}
diff --git a/src/main/java/com/intel/jndn/mock/MockKeyChain.java b/src/main/java/com/intel/jndn/mock/MockKeyChain.java
index 1a0bafb..30710e1 100644
--- a/src/main/java/com/intel/jndn/mock/MockKeyChain.java
+++ b/src/main/java/com/intel/jndn/mock/MockKeyChain.java
@@ -1,6 +1,6 @@
 /*
  * jndn-mock
- * Copyright (c) 2015, Intel Corporation.
+ * Copyright (c) 2016, Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU Lesser General Public License,
@@ -26,7 +26,7 @@
 /**
  * Create an in-memory key chain for use in NDN-related tests.
  *
- * @author Andrew Brown <andrew.brown@intel.com>
+ * @author Andrew Brown, andrew.brown@intel.com
  */
 public final class MockKeyChain {
   /**
diff --git a/src/main/java/com/intel/jndn/mock/MockTransport.java b/src/main/java/com/intel/jndn/mock/MockTransport.java
index df437e0..7e788a0 100644
--- a/src/main/java/com/intel/jndn/mock/MockTransport.java
+++ b/src/main/java/com/intel/jndn/mock/MockTransport.java
@@ -1,6 +1,6 @@
 /*
  * jndn-mock
- * Copyright (c) 2015, Intel Corporation.
+ * Copyright (c) 2016, Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU Lesser General Public License,
@@ -28,12 +28,12 @@
  * Non-public class for handling data buffering in NDN unit tests; works in
  * conjunction with {@link MockFace}.
  *
- * @author Alexander Afanasyev, <aa@cs.ucla.edu>
- * @author Andrew Brown <andrew.brown@intel.com>
+ * @author Alexander Afanasyev, aa@cs.ucla.edu
+ * @author Andrew Brown, andrew.brown@intel.com
  */
-class MockFaceTransport extends Transport {
+public class MockTransport extends Transport {
   private OnSendBlockSignal onSendBlock;
-  private static final Logger LOGGER = Logger.getLogger(MockFaceTransport.class.getName());
+  private static final Logger LOGGER = Logger.getLogger(MockTransport.class.getName());
   private boolean connected;
   private ElementReader elementReader;
   private final List<ByteBuffer> receiveBuffer = new LinkedList<>();
diff --git a/src/main/java/com/intel/jndn/mock/forwarder/BufferHandler.java b/src/main/java/com/intel/jndn/mock/forwarder/BufferHandler.java
new file mode 100644
index 0000000..4572115
--- /dev/null
+++ b/src/main/java/com/intel/jndn/mock/forwarder/BufferHandler.java
@@ -0,0 +1,101 @@
+/*
+ * jndn-mock
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 3, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ */
+
+package com.intel.jndn.mock.forwarder;
+
+import com.intel.jndn.mock.MockForwarder;
+import com.intel.jndn.mock.MockTransport;
+import net.named_data.jndn.Data;
+import net.named_data.jndn.Interest;
+import net.named_data.jndn.encoding.EncodingException;
+import net.named_data.jndn.encoding.TlvWireFormat;
+import net.named_data.jndn.encoding.tlv.Tlv;
+import net.named_data.jndn.encoding.tlv.TlvDecoder;
+import net.named_data.jndn.transport.Transport;
+
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @author Andrew Brown, andrew.brown@intel.com
+ */
+public class BufferHandler implements MockTransport.OnSendBlockSignal {
+
+  private static final Logger LOGGER = Logger.getLogger(BufferHandler.class.getName());
+  private final MockTransport transport;
+  private final MockForwarder.Fib fib;
+  private final MockForwarder.Pit pit;
+
+  public BufferHandler(MockTransport transport, MockForwarder.Fib fib, MockForwarder.Pit pit) {
+    this.transport = transport;
+    this.fib = fib;
+    this.pit = pit;
+  }
+
+  @Override
+  public void emit(ByteBuffer buffer) {
+    try {
+      if (isInterest(buffer) || isData(buffer)) {
+        TlvDecoder decoder = new TlvDecoder(buffer);
+        if (decoder.peekType(Tlv.Interest, buffer.remaining())) {
+          Interest interest = new Interest();
+          interest.wireDecode(buffer, TlvWireFormat.get());
+          forward(interest, transport);
+        } else if (decoder.peekType(Tlv.Data, buffer.remaining())) {
+          Data data = new Data();
+          data.wireDecode(buffer, TlvWireFormat.get());
+          forward(data);
+        }
+      } else {
+        LOGGER.warning("Received an unknown packet");
+      }
+    } catch (EncodingException e) {
+      LOGGER.log(Level.INFO, "Failed to decodeParameters incoming packet", e);
+    }
+  }
+
+  private boolean isInterest(ByteBuffer buffer) {
+    return buffer.get(0) == Tlv.Interest;
+  }
+
+  private boolean isData(ByteBuffer buffer) {
+    return buffer.get(0) == Tlv.Data;
+  }
+
+  private void forward(Interest interest, Transport transport) {
+    if (pit.has(interest)) {
+      LOGGER.info("Already seen interest, swallowing: " + interest.toUri());
+      return;
+    }
+
+    LOGGER.info("Adding interest to PIT: " + interest.toUri());
+    pit.add(new PitEntryImpl(interest, (MockTransport) transport));
+
+    LOGGER.info("Forwarding interest: " + interest.toUri());
+    for (MockForwarder.FibEntry entry : fib.find(interest)) {
+      entry.forward(interest, transport);
+    }
+  }
+
+  private void forward(Data data) {
+    Collection<MockForwarder.PitEntry> found = pit.extract(data.getName());
+    LOGGER.log(Level.INFO, "Found {0} pending interests", found.size());
+
+    for (MockForwarder.PitEntry pendingInterest : found) {
+      pendingInterest.forward(data);
+    }
+  }
+}
diff --git a/src/main/java/com/intel/jndn/mock/forwarder/ClientFibEntry.java b/src/main/java/com/intel/jndn/mock/forwarder/ClientFibEntry.java
new file mode 100644
index 0000000..020a8fb
--- /dev/null
+++ b/src/main/java/com/intel/jndn/mock/forwarder/ClientFibEntry.java
@@ -0,0 +1,57 @@
+/*
+ * jndn-mock
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 3, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ */
+
+package com.intel.jndn.mock.forwarder;
+
+import com.intel.jndn.mock.MockForwarder;
+import com.intel.jndn.mock.MockTransport;
+import net.named_data.jndn.ForwardingFlags;
+import net.named_data.jndn.Interest;
+import net.named_data.jndn.Name;
+import net.named_data.jndn.transport.Transport;
+
+import java.util.logging.Logger;
+
+/**
+ * @author Andrew Brown, andrew.brown@intel.com
+ */
+class ClientFibEntry implements MockForwarder.FibEntry {
+
+  private static final Logger LOGGER = Logger.getLogger(ClientFibEntry.class.getName());
+  private final Name prefix;
+  private final MockTransport transport;
+  private final ForwardingFlags flags;
+
+  ClientFibEntry(Name prefix, MockTransport transport, ForwardingFlags flags) {
+    this.prefix = prefix;
+    this.transport = transport;
+    this.flags = flags;
+  }
+
+  @Override
+  public void forward(Interest interest, Transport sourceTransport) {
+    LOGGER.info("Receiving interest on: " + this.transport);
+    transport.receive(interest.wireEncode().buf());
+  }
+
+  @Override
+  public Name getPrefix() {
+    return new Name(prefix);
+  }
+
+  @Override
+  public ForwardingFlags getFlags() {
+    return flags;
+  }
+}
diff --git a/src/main/java/com/intel/jndn/mock/forwarder/FibImpl.java b/src/main/java/com/intel/jndn/mock/forwarder/FibImpl.java
new file mode 100644
index 0000000..e2473a5
--- /dev/null
+++ b/src/main/java/com/intel/jndn/mock/forwarder/FibImpl.java
@@ -0,0 +1,51 @@
+/*
+ * jndn-mock
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 3, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ */
+
+package com.intel.jndn.mock.forwarder;
+
+import com.intel.jndn.mock.MockForwarder;
+import net.named_data.jndn.Interest;
+import net.named_data.jndn.Name;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @author Andrew Brown, andrew.brown@intel.com
+ */
+public class FibImpl implements MockForwarder.Fib {
+
+  private final ConcurrentHashMap<Name, MockForwarder.FibEntry> fib = new ConcurrentHashMap<>();
+
+  @Override
+  public void add(MockForwarder.FibEntry entry) {
+    fib.put(entry.getPrefix(), entry);
+  }
+
+  public List<MockForwarder.FibEntry> find(Interest interest) {
+    ArrayList<MockForwarder.FibEntry> entries = new ArrayList<>();
+    for (int i = interest.getName().size(); i >= 0; i--) {
+      Name prefix = interest.getName().getPrefix(i);
+      MockForwarder.FibEntry entry = fib.get(prefix);
+      if (entry != null) {
+        entries.add(entry);
+        if (!entry.getFlags().getChildInherit() || entry.getFlags().getCapture()) {
+          break;
+        }
+      }
+    }
+    return entries;
+  }
+}
diff --git a/src/main/java/com/intel/jndn/mock/forwarder/LocalFibEntry.java b/src/main/java/com/intel/jndn/mock/forwarder/LocalFibEntry.java
new file mode 100644
index 0000000..c803c3e
--- /dev/null
+++ b/src/main/java/com/intel/jndn/mock/forwarder/LocalFibEntry.java
@@ -0,0 +1,58 @@
+/*
+ * jndn-mock
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 3, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ */
+
+package com.intel.jndn.mock.forwarder;
+
+import com.intel.jndn.mock.MockForwarder;
+import net.named_data.jndn.Face;
+import net.named_data.jndn.ForwardingFlags;
+import net.named_data.jndn.Interest;
+import net.named_data.jndn.Name;
+import net.named_data.jndn.transport.Transport;
+
+import java.util.logging.Logger;
+
+/**
+ * @author Andrew Brown, andrew.brown@intel.com
+ */
+public class LocalFibEntry implements MockForwarder.FibEntry {
+
+  private static final Logger LOGGER = Logger.getLogger(LocalFibEntry.class.getName());
+  private final Name prefix;
+  private final MockForwarder.OnInterestReceived callback;
+  private final Face registrationFace;
+  private final ForwardingFlags flags;
+
+  public LocalFibEntry(Name prefix, MockForwarder.OnInterestReceived callback, Face registrationFace, ForwardingFlags flags) {
+    this.prefix = prefix;
+    this.callback = callback;
+    this.registrationFace = registrationFace;
+    this.flags = flags;
+  }
+
+  public void forward(Interest interest, Transport sourceTransport) {
+    LOGGER.info("Forwarding interest on: " + this.callback);
+    callback.in(interest, sourceTransport, registrationFace);
+  }
+
+  @Override
+  public Name getPrefix() {
+    return new Name(prefix);
+  }
+
+  @Override
+  public ForwardingFlags getFlags() {
+    return flags;
+  }
+}
diff --git a/src/main/java/com/intel/jndn/mock/forwarder/OnPrefixRegistration.java b/src/main/java/com/intel/jndn/mock/forwarder/OnPrefixRegistration.java
new file mode 100644
index 0000000..3bbf56e
--- /dev/null
+++ b/src/main/java/com/intel/jndn/mock/forwarder/OnPrefixRegistration.java
@@ -0,0 +1,103 @@
+/*
+ * jndn-mock
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 3, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ */
+
+package com.intel.jndn.mock.forwarder;
+
+import com.intel.jndn.mock.MockForwarder;
+import com.intel.jndn.mock.MockTransport;
+import net.named_data.jndn.ControlParameters;
+import net.named_data.jndn.ControlResponse;
+import net.named_data.jndn.Data;
+import net.named_data.jndn.Face;
+import net.named_data.jndn.Interest;
+import net.named_data.jndn.encoding.EncodingException;
+import net.named_data.jndn.security.KeyChain;
+import net.named_data.jndn.security.SecurityException;
+import net.named_data.jndn.transport.Transport;
+
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Handle prefix registration requests from clients to a mock forwarder; must conform to specification outlined in
+ * https://redmine.named-data.net/projects/nfd/wiki/RibMgmt.
+ *
+ * @author Andrew Brown, andrew.brown@intel.com
+ */
+public class OnPrefixRegistration implements MockForwarder.OnInterestReceived {
+  private static final Logger LOGGER = Logger.getLogger(OnPrefixRegistration.class.getName());
+  private static final int STATUS_CODE_OK = 200;
+  private static final int CONTROL_PARAMETERS_NAME_OFFSET = -5;
+  private static final int CONTROL_COMMAND_NAME_OFFSET = 3;
+  private final KeyChain keyChain;
+  private final MockForwarder.Fib fib;
+
+  public OnPrefixRegistration(KeyChain keyChain, MockForwarder.Fib fib) {
+    this.keyChain = keyChain;
+    this.fib = fib;
+  }
+
+  @Override
+  public void in(Interest interest, Transport destinationTransport, Face localFace) {
+    LOGGER.info("Received registration request: " + interest.toUri());
+    ControlParameters params = decodeParameters(interest);
+
+    MockForwarder.FibEntry entry = new ClientFibEntry(params.getName(), (MockTransport) destinationTransport, params.getForwardingFlags());
+    fib.add(entry);
+    LOGGER.info("Added new route " + params.getName() + " to: " + destinationTransport);
+
+    ControlResponse response = encodeResponse(params);
+
+    Data data = new Data();
+    data.setName(interest.getName());
+    data.setContent(response.wireEncode());
+    signResponse(data);
+
+    try {
+      localFace.putData(data);
+    } catch (IOException e) {
+      LOGGER.log(Level.SEVERE, "Failed to send registration response", e);
+    }
+  }
+
+  private ControlParameters decodeParameters(Interest interest) {
+    ControlParameters params = new ControlParameters();
+    try {
+      params.wireDecode(interest.getName().get(CONTROL_PARAMETERS_NAME_OFFSET).getValue());
+      params.setFaceId(1);
+      params.setOrigin(0);
+      params.setCost(0);
+    } catch (EncodingException e) {
+      throw new IllegalArgumentException("", e);
+    }
+    return params;
+  }
+
+  private ControlResponse encodeResponse(ControlParameters params) {
+    ControlResponse response = new ControlResponse();
+    response.setStatusCode(STATUS_CODE_OK);
+    response.setStatusText("OK");
+    response.setBodyAsControlParameters(params);
+    return response;
+  }
+
+  private void signResponse(Data data) {
+    try {
+      keyChain.sign(data);
+    } catch (SecurityException e) {
+      LOGGER.log(Level.FINE, "MockKeyChain signing failed", e);
+    }
+  }
+}
diff --git a/src/main/java/com/intel/jndn/mock/forwarder/PitEntryImpl.java b/src/main/java/com/intel/jndn/mock/forwarder/PitEntryImpl.java
new file mode 100644
index 0000000..d5e3a5b
--- /dev/null
+++ b/src/main/java/com/intel/jndn/mock/forwarder/PitEntryImpl.java
@@ -0,0 +1,57 @@
+/*
+ * jndn-mock
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 3, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ */
+
+package com.intel.jndn.mock.forwarder;
+
+import com.intel.jndn.mock.MockForwarder;
+import com.intel.jndn.mock.MockTransport;
+import net.named_data.jndn.Data;
+import net.named_data.jndn.Interest;
+
+import java.util.logging.Logger;
+
+/**
+ * @author Andrew Brown, andrew.brown@intel.com
+ */
+final class PitEntryImpl implements MockForwarder.PitEntry {
+
+  private static final Logger LOGGER = Logger.getLogger(PitEntryImpl.class.getName());
+  private final Interest interest;
+  private final MockTransport transport;
+  private boolean satisfied = false;
+
+  PitEntryImpl(Interest interest, MockTransport transport) {
+    this.interest = interest;
+    this.transport = transport;
+  }
+
+  public void forward(Data data) {
+    LOGGER.info("Forwarding data on: " + this.transport);
+
+    if (satisfied) {
+      LOGGER.warning("Data already forwarded for PIT entry: " + interest.toUri());
+    }
+
+    transport.receive(data.wireEncode().buf());
+    satisfied = true;
+  }
+
+  public Interest getInterest() {
+    return new Interest(interest);
+  }
+
+  public boolean isSatisfied() {
+    return satisfied;
+  }
+}
diff --git a/src/main/java/com/intel/jndn/mock/forwarder/PitImpl.java b/src/main/java/com/intel/jndn/mock/forwarder/PitImpl.java
new file mode 100644
index 0000000..81eb15f
--- /dev/null
+++ b/src/main/java/com/intel/jndn/mock/forwarder/PitImpl.java
@@ -0,0 +1,59 @@
+/*
+ * jndn-mock
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 3, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ */
+
+package com.intel.jndn.mock.forwarder;
+
+import com.intel.jndn.mock.MockForwarder;
+import net.named_data.jndn.Interest;
+import net.named_data.jndn.Name;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Naive implementation of a pending interest table
+ *
+ * @author Andrew Brown, andrew.brown@intel.com
+ */
+public class PitImpl implements MockForwarder.Pit {
+
+  private final Map<Name, List<MockForwarder.PitEntry>> pit = new ConcurrentHashMap<>();
+
+  public List<MockForwarder.PitEntry> extract(Name name) {
+    ArrayList<MockForwarder.PitEntry> entries = new ArrayList<>();
+    for (int i = name.size(); i >= 0; i--) {
+      Name prefix = name.getPrefix(i);
+      List<MockForwarder.PitEntry> pendingInterests = pit.get(prefix);
+      if (pendingInterests != null) {
+        entries.addAll(pendingInterests);
+        pendingInterests.clear(); // TODO is this necessary
+      }
+    }
+    return entries;
+  }
+
+  public void add(MockForwarder.PitEntry entry) {
+    if (!pit.containsKey(entry.getInterest().getName())) {
+      pit.put(entry.getInterest().getName(), new ArrayList<MockForwarder.PitEntry>(1));
+    }
+    pit.get(entry.getInterest().getName()).add(entry);
+  }
+
+  public boolean has(Interest interest) {
+    List<MockForwarder.PitEntry> entries = pit.get(interest.getName());
+    return entries != null && !entries.isEmpty();
+  }
+}
diff --git a/src/main/java/com/intel/jndn/mock/package-info.java b/src/main/java/com/intel/jndn/mock/package-info.java
index 21dcda2..ae13ee4 100644
--- a/src/main/java/com/intel/jndn/mock/package-info.java
+++ b/src/main/java/com/intel/jndn/mock/package-info.java
@@ -1,3 +1,17 @@
+/*
+ * jndn-mock
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 3, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ */
+
 /**
  * NDN Face mocking classes.
  */
diff --git a/src/test/java/com/intel/jndn/mock/MockFaceTest.java b/src/test/java/com/intel/jndn/mock/MockFaceTest.java
index 7c8bbc9..015da4b 100644
--- a/src/test/java/com/intel/jndn/mock/MockFaceTest.java
+++ b/src/test/java/com/intel/jndn/mock/MockFaceTest.java
@@ -1,6 +1,6 @@
 /*
  * jndn-mock
- * Copyright (c) 2015, Intel Corporation.
+ * Copyright (c) 2016, Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU Lesser General Public License,
@@ -168,8 +168,7 @@
   @Test
   public void testThatTransportConnectsOnPrefixRegistration() throws IOException, SecurityException {
     assertFalse(face.getTransport().getIsConnected());
-    face.registerPrefix(new Name("/fake/prefix"), (OnInterestCallback) null, (OnRegisterFailed) null,
-            (OnRegisterSuccess) null);
+    face.registerPrefix(new Name("/fake/prefix"), null, null, (OnRegisterSuccess) null);
     assertTrue(face.getTransport().getIsConnected());
   }
 
@@ -181,8 +180,8 @@
     }
     final State state = new State();
 
-    // connect transport
-    face.registerPrefix(new Name("/fake/prefix"), (OnInterestCallback) null, new OnRegisterFailed() {
+    // connect callback
+    face.registerPrefix(new Name("/fake/prefix"), null, new OnRegisterFailed() {
       @Override
       public void onRegisterFailed(final Name prefix) {
         state.regFailed = true;
diff --git a/src/test/java/com/intel/jndn/mock/MockForwarderTest.java b/src/test/java/com/intel/jndn/mock/MockForwarderTest.java
new file mode 100644
index 0000000..6bf09ab
--- /dev/null
+++ b/src/test/java/com/intel/jndn/mock/MockForwarderTest.java
@@ -0,0 +1,106 @@
+/*
+ * jndn-mock
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 3, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ */
+
+package com.intel.jndn.mock;
+
+import net.named_data.jndn.Data;
+import net.named_data.jndn.Face;
+import net.named_data.jndn.Interest;
+import net.named_data.jndn.InterestFilter;
+import net.named_data.jndn.Name;
+import net.named_data.jndn.OnData;
+import net.named_data.jndn.OnInterestCallback;
+import net.named_data.jndn.OnRegisterFailed;
+import net.named_data.jndn.OnRegisterSuccess;
+import net.named_data.jndn.OnTimeout;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Logger;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author Andrew Brown, andrew.brown@intel.com
+ */
+public class MockForwarderTest {
+  private static final Logger LOGGER = Logger.getLogger(MockForwarderTest.class.getName());
+
+  @Test
+  public void usage() throws Exception {
+    Name prefix = new Name("/test");
+    MockForwarder forwarder = new MockForwarder();
+    Face a = forwarder.connect();
+    Face b = forwarder.connect();
+
+    LOGGER.info("Registering prefix: " + prefix);
+    final CountDownLatch response1 = new CountDownLatch(1);
+    a.registerPrefix(prefix, new OnInterestCallback() {
+      @Override
+      public void onInterest(Name prefix, Interest interest, Face face, long interestFilterId, InterestFilter filter) {
+        LOGGER.info("Received interest: " + interest.toUri());
+        try {
+          face.putData(new Data(interest.getName()));
+          LOGGER.info("Sent data to interest: " + interest.getName());
+        } catch (IOException e) {
+          LOGGER.info("Failed to send data for: " + interest.toUri());
+        }
+      }
+    }, new OnRegisterFailed() {
+      @Override
+      public void onRegisterFailed(Name prefix) {
+        LOGGER.severe("Failed to register prefix for: " + prefix);
+        response1.countDown();
+      }
+    }, new OnRegisterSuccess() {
+      @Override
+      public void onRegisterSuccess(Name prefix, long registeredPrefixId) {
+        LOGGER.info("Prefix registered: " + prefix);
+        response1.countDown();
+      }
+    });
+    a.processEvents();
+    response1.await(1, TimeUnit.SECONDS);
+    assertEquals(0, response1.getCount());
+
+    LOGGER.info("Sending interest to prefix: " + prefix);
+    final CountDownLatch response2 = new CountDownLatch(1);
+    final AtomicBoolean received = new AtomicBoolean(false);
+    b.expressInterest(prefix, new OnData() {
+      @Override
+      public void onData(Interest interest, Data data) {
+        LOGGER.info("Received data: " + data.getName());
+        response2.countDown();
+        received.set(true);
+      }
+    }, new OnTimeout() {
+      @Override
+      public void onTimeout(Interest interest) {
+        LOGGER.info("Failed to receive data for interest: " + interest.toUri());
+        response2.countDown();
+      }
+    });
+    b.processEvents();
+    a.processEvents();
+    b.processEvents();
+    a.processEvents();
+
+    response2.await(1, TimeUnit.SECONDS);
+    assertTrue(received.get());
+  }
+}
\ No newline at end of file
diff --git a/src/test/java/com/intel/jndn/mock/MockKeyChainTest.java b/src/test/java/com/intel/jndn/mock/MockKeyChainTest.java
index 86d3b13..1448423 100644
--- a/src/test/java/com/intel/jndn/mock/MockKeyChainTest.java
+++ b/src/test/java/com/intel/jndn/mock/MockKeyChainTest.java
@@ -1,6 +1,6 @@
 /*
  * jndn-mock
- * Copyright (c) 2015, Intel Corporation.
+ * Copyright (c) 2016, Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU Lesser General Public License,
@@ -23,7 +23,7 @@
 /**
  * Test MockKeyChain.
  *
- * @author Andrew Brown <andrew.brown@intel.com>
+ * @author Andrew Brown, andrew.brown@intel.com
  */
 public class MockKeyChainTest {
 
diff --git a/src/test/java/com/intel/jndn/mock/forwarder/MockForwarderVisibilityTest.java b/src/test/java/com/intel/jndn/mock/forwarder/MockForwarderVisibilityTest.java
new file mode 100644
index 0000000..c38fa6e
--- /dev/null
+++ b/src/test/java/com/intel/jndn/mock/forwarder/MockForwarderVisibilityTest.java
@@ -0,0 +1,45 @@
+/*
+ * jndn-mock
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 3, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ */
+
+package com.intel.jndn.mock.forwarder;
+
+import com.intel.jndn.mock.MockForwarder;
+import net.named_data.jndn.Face;
+import net.named_data.jndn.ForwardingFlags;
+import net.named_data.jndn.Interest;
+import net.named_data.jndn.Name;
+import net.named_data.jndn.transport.Transport;
+import org.junit.Test;
+
+/**
+ * Ensure MockForwarder methods are visible publicly; does not test functionality
+ *
+ * @author Andrew Brown, andrew.brown@intel.com
+ */
+public class MockForwarderVisibilityTest {
+
+  @Test
+  public void ensureVisibility() {
+    MockForwarder forwarder = new MockForwarder();
+
+    forwarder.connect();
+
+    forwarder.register(new Name("/a/b/c"), new MockForwarder.OnInterestReceived() {
+      @Override
+      public void in(Interest interest, Transport destinationTransport, Face sourceFace) {
+        // do nothing
+      }
+    }, new ForwardingFlags());
+  }
+}
\ No newline at end of file