Major refactoring and improvements

This commit removes dependency on jndn-utils (it requires Java 8, while
jndn-management needs to be compatible with Java 7 to support Android)

Some changes include interface unification with structures in ndn-cxx library

Change-Id: I944ea41e225edc1848657ed574b625c7ec18df5d
diff --git a/src/test/java/com/intel/jndn/management/FaceStatusTest.java b/src/test/java/com/intel/jndn/management/FaceStatusTest.java
deleted file mode 100644
index 742743e..0000000
--- a/src/test/java/com/intel/jndn/management/FaceStatusTest.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * jndn-management
- * Copyright (c) 2015, 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.management;
-
-import com.intel.jndn.management.types.StatusDataset;
-import com.intel.jndn.management.types.FaceStatus;
-import com.intel.jndn.utils.client.impl.SimpleClient;
-import java.io.IOException;
-import java.util.List;
-import java.util.logging.Logger;
-import junit.framework.Assert;
-import net.named_data.jndn.Data;
-import net.named_data.jndn.Face;
-import net.named_data.jndn.Interest;
-import net.named_data.jndn.Name;
-import net.named_data.jndn.encoding.EncodingException;
-import net.named_data.jndn.util.Blob;
-import org.junit.Test;
-import static org.junit.Assert.*;
-
-/**
- * Test whether the decoding for the face management service is working
- * correctly
- *
- * @author Andrew Brown <andrew.brown@intel.com>
- */
-public class FaceStatusTest {
-
-  private static final Logger logger = Logger.getLogger(FaceStatusTest.class.getName());
-
-  /**
-   * Test encoding/decoding
-   *
-   * @throws java.lang.Exception
-   */
-  @Test
-  public void testEncodeDecode() throws Exception {
-    FaceStatus status = new FaceStatus();
-    status.setFaceId(42);
-    status.setUri("...");
-    status.setLocalUri("...");
-
-    // encode
-    Blob encoded = status.wireEncode();
-
-    // decode
-    FaceStatus decoded = new FaceStatus();
-    decoded.wireDecode(encoded.buf());
-
-    // test
-    Assert.assertEquals(status.getFaceId(), decoded.getFaceId());
-    Assert.assertEquals(status.getUri(), decoded.getUri());
-    Assert.assertEquals(status.getLocalUri(), decoded.getLocalUri());
-    Assert.assertEquals(status.getExpirationPeriod(), decoded.getExpirationPeriod());
-    Assert.assertEquals(status.getFaceScope(), decoded.getFaceScope());
-    Assert.assertEquals(status.getFacePersistency(), decoded.getFacePersistency());
-    Assert.assertEquals(status.getLinkType(), decoded.getLinkType());
-    Assert.assertEquals(status.getInBytes(), decoded.getInBytes());
-    Assert.assertEquals(status.getOutBytes(), decoded.getOutBytes());
-  }
-
-  /**
-   * Test of decode method, of class FaceStatus.
-   *
-   * @throws java.lang.Exception
-   */
-  @Test
-  public void testDecodeFakeData() throws Exception {
-    Data data = getFaceData(true);
-    List<FaceStatus> results = StatusDataset.wireDecode(data.getContent(), FaceStatus.class);
-    assertTrue(results.size() > 4);
-    for (FaceStatus f : results) {
-      // the first face (face 1) should always be the internal face
-      if (f.getFaceId() == 1) {
-        assertEquals("internal://", f.getUri());
-        assertEquals("internal://", f.getLocalUri());
-      }
-    }
-  }
-
-  /**
-   * Integration test to run on actual system
-   *
-   * @param args
-   * @throws EncodingException
-   */
-  public static void main(String[] args) throws Exception {
-    Data data = getFaceData(false);
-    List<FaceStatus> results = StatusDataset.wireDecode(data.getContent(), FaceStatus.class);
-    assertTrue(results.size() > 4);
-    for (FaceStatus f : results) {
-      // the first face (face 1) should always be the internal face
-      if (f.getFaceId() == 1) {
-        assertEquals("internal://", f.getUri());
-        assertEquals("internal://", f.getLocalUri());
-      }
-    }
-  }
-
-  /**
-   * Retrieve a TLV encoded representation of the face list data
-   *
-   * @param usePreComputedData to avoid errors when local NFD is not present
-   * @return
-   */
-  private static Data getFaceData(boolean usePreComputedData) throws IOException {
-    // use pre-computed data to avoid errors when local NFD is not present
-    if (usePreComputedData) {
-      Data data = new Data();
-      data.setContent(new Blob(hexStringToByteArray(DATA)));
-      return data;
-    } // alternately, query the actual localhost for current data
-    else {
-      Face forwarder = new Face("localhost");
-
-      // build management Interest packet; see <a href="http://redmine.named-data.net/projects/nfd/wiki/StatusDataset">http://redmine.named-data.net/projects/nfd/wiki/StatusDataset</a>
-      Interest interest = new Interest(new Name("/localhost/nfd/faces/list"));
-      interest.setMustBeFresh(true);
-      interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
-      interest.setInterestLifetimeMilliseconds(2000.0);
-
-      // send packet
-      Data data = SimpleClient.getDefault().getSync(forwarder, interest);
-      String hex = data.getContent().toHex();
-      logger.info("Hex dump of face list: " + hex);
-      return data;
-    }
-  }
-
-  /**
-   * Pre-computed face list from a vanilla NFD running on Ubuntu 14.04
-   */
-  private static final String DATA = "803a690101720b696e7465726e616c3a2f2f810b696e7465726e616c3a2f2f840101850100860100900100910201429202063993010094010095010080406901fe720f636f6e74656e7473746f72653a2f2f810f636f6e74656e7473746f72653a2f2f84010185010086010090010091010092010093010094010095010080306901ff72076e756c6c3a2f2f81076e756c6c3a2f2f8401018501008601009001009101009201009301009401009501008053690201007219756470343a2f2f3232342e302e32332e3137303a35363336338117756470343a2f2f31302e35342e31322e373a35363336338401008501008601009001009101009201009301009401009501008056690201017219756470343a2f2f3232342e302e32332e3137303a3536333633811a756470343a2f2f3139322e3136382e35302e35373a3536333633840100850100860100900100910100920100930100940100950100804869020102721b65746865723a2f2f5b30313a30303a35653a30303a31373a61615d810a6465763a2f2f65746830840100850100860100900100910100920100930100940100950100804969020103721b65746865723a2f2f5b30313a30303a35653a30303a31373a61615d810b6465763a2f2f776c616e30840100850100860100900100910100920100930100940100950100804669020104720766643a2f2f32328114756e69783a2f2f2f72756e2f6e66642e736f636b840101850101860100900206349101019201019302012e940400014079950400041903804e690201197216746370343a2f2f3132372e302e302e313a35363336358115746370343a2f2f3132372e302e302e313a36333633840101850101860100900101910100920100930100940132950100";
-
-  /**
-   * Convert hex string to bytes; special thanks to
-   * <a href="http://stackoverflow.com/questions/140131">http://stackoverflow.com/questions/140131</a>
-   *
-   * @param s
-   * @return
-   */
-  private static byte[] hexStringToByteArray(String s) {
-    int len = s.length();
-    byte[] data = new byte[len / 2];
-    for (int i = 0; i < len; i += 2) {
-      data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
-              + Character.digit(s.charAt(i + 1), 16));
-    }
-    return data;
-  }
-
-}
diff --git a/src/test/java/com/intel/jndn/management/FibEntryTest.java b/src/test/java/com/intel/jndn/management/FibEntryTest.java
deleted file mode 100644
index e966a97..0000000
--- a/src/test/java/com/intel/jndn/management/FibEntryTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * jndn-management
- * Copyright (c) 2015, 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.management;
-
-import com.intel.jndn.management.types.StatusDataset;
-import com.intel.jndn.management.types.NextHopRecord;
-import com.intel.jndn.management.types.FibEntry;
-import com.intel.jndn.utils.client.impl.SimpleClient;
-import java.util.List;
-import junit.framework.Assert;
-import net.named_data.jndn.Data;
-import net.named_data.jndn.Face;
-import net.named_data.jndn.Interest;
-import net.named_data.jndn.Name;
-import net.named_data.jndn.encoding.EncodingException;
-import net.named_data.jndn.util.Blob;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import org.junit.Test;
-
-/**
- * Test encode/decode of FibEntry and NextHopRecord
- *
- * @author Andrew Brown <andrew.brown@intel.com>
- */
-public class FibEntryTest {
-
-  /**
-   * Test encoding/decoding
-   *
-   * @throws java.lang.Exception
-   */
-  @Test
-  public void testEncodeDecode() throws Exception {
-    NextHopRecord nextHopRecord = new NextHopRecord();
-    nextHopRecord.setFaceId(42);
-    nextHopRecord.setCost(100);
-    FibEntry entry = new FibEntry();
-    entry.setName(new Name("/fib/entry/test"));
-    entry.getRecords().add(nextHopRecord);
-
-    // encode
-    Blob encoded = entry.wireEncode();
-
-    // decode
-    FibEntry decoded = new FibEntry();
-    decoded.wireDecode(encoded.buf());
-
-    // test
-    Assert.assertEquals(entry.getName().toUri(), decoded.getName().toUri());
-    Assert.assertEquals(entry.getRecords().get(0).getFaceId(), decoded.getRecords().get(0).getFaceId());
-    Assert.assertEquals(entry.getRecords().get(0).getCost(), decoded.getRecords().get(0).getCost());
-  }
-
-  /**
-   * Integration test to run on actual system
-   *
-   * @param args
-   * @throws EncodingException
-   */
-  public static void main(String[] args) throws Exception {
-    Face forwarder = new Face("localhost");
-
-    // build management Interest packet; see <a href="http://redmine.named-data.net/projects/nfd/wiki/StatusDataset">http://redmine.named-data.net/projects/nfd/wiki/StatusDataset</a>
-    Interest interest = new Interest(new Name("/localhost/nfd/fib/list"));
-    interest.setMustBeFresh(true);
-    interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
-    interest.setInterestLifetimeMilliseconds(2000.0);
-
-    // send packet
-    Data data = SimpleClient.getDefault().getSync(forwarder, interest);
-
-    // decode results
-    List<FibEntry> results = StatusDataset.wireDecode(data.getContent(), FibEntry.class);
-    assertTrue(results.size() > 0);
-    assertEquals("/localhost/nfd", results.get(0).getName().toUri());
-  }
-}
diff --git a/src/test/java/com/intel/jndn/management/ForwarderStatusTest.java b/src/test/java/com/intel/jndn/management/ForwarderStatusTest.java
deleted file mode 100644
index bf6b727..0000000
--- a/src/test/java/com/intel/jndn/management/ForwarderStatusTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * jndn-management
- * Copyright (c) 2015, 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.management;
-
-import com.intel.jndn.management.types.ForwarderStatus;
-import junit.framework.Assert;
-import net.named_data.jndn.util.Blob;
-import org.junit.Test;
-
-/**
- * Test encoding/decoding of ForwarderStatus.
- *
- * @author Andrew Brown <andrew.brown@intel.com>
- */
-public class ForwarderStatusTest {
-
-  /**
-   * Test encoding/decoding
-   *
-   * @throws java.lang.Exception
-   */
-  @Test
-  public void testEncodeDecode() throws Exception {
-    ForwarderStatus status = new ForwarderStatus();
-    status.setNfdVersion("1.0");
-    status.setCurrentTimestamp(System.currentTimeMillis());
-    status.setNumInDatas(42);
-
-    // encode
-    Blob encoded = status.wireEncode();
-
-    // decode
-    ForwarderStatus decoded = new ForwarderStatus();
-    decoded.wireDecode(encoded.buf());
-
-    // test
-    Assert.assertEquals(status.getNfdVersion(), decoded.getNfdVersion());
-    Assert.assertEquals(status.getCurrentTimestamp(), decoded.getCurrentTimestamp());
-    Assert.assertEquals(status.getStartTimestamp(), decoded.getStartTimestamp());
-    Assert.assertEquals(status.getNumInDatas(), decoded.getNumInDatas());
-  }
-}
diff --git a/src/test/java/com/intel/jndn/management/IntegrationSuite.java b/src/test/java/com/intel/jndn/management/IntegrationSuite.java
deleted file mode 100644
index 2758e98..0000000
--- a/src/test/java/com/intel/jndn/management/IntegrationSuite.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * jndn-management
- * Copyright (c) 2015, 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.management;
-
-import com.intel.jndn.management.types.RibEntry;
-import java.util.logging.Logger;
-import junit.framework.Assert;
-import net.named_data.jndn.Face;
-import net.named_data.jndn.KeyLocator;
-import net.named_data.jndn.Name;
-import net.named_data.jndn.security.KeyChain;
-
-/**
- * Tests to run with a local NFD as part of integration testing; will not run in
- * the maven test phase, must be run manually.
- *
- * @author Andrew Brown <andrew.brown@intel.com>
- */
-public class IntegrationSuite {
-
-  private static final Logger logger = Logger.getLogger(IntegrationSuite.class.getName());
-
-  /**
-   * Test NFD methods
-   *
-   * @param args
-   * @throws Exception
-   */
-  public static void main(String[] args) throws Exception {
-    Face face = new Face("localhost");
-    KeyChain keyChain = buildTestKeyChain();
-    face.setCommandSigningInfo(keyChain, keyChain.getDefaultCertificateName());
-
-    Assert.assertTrue(NFD.pingLocal(face));
-    
-    // grab key locator
-    KeyLocator keyLocator = NFD.getKeyLocator(face);
-    Assert.assertNotNull(keyLocator);
-    logger.info("Connected to NFD with key locator: " + keyLocator.getKeyName().toUri());
-
-    // grab datasets
-    Assert.assertTrue(NFD.getForwarderStatus(face).getStartTimestamp() > 0);
-    Assert.assertFalse(NFD.getFaceList(face).isEmpty());
-    Assert.assertFalse(NFD.getFibList(face).isEmpty());
-    Assert.assertFalse(NFD.getRouteList(face).isEmpty());
-
-    // create a new route
-    NFD.register(face, "udp4://127.0.0.1:56363", new Name("/my/test/route"), 999);
-
-    // check that route is created
-    Thread.sleep(1000); // NFD registers the route asynchronously
-    boolean found = false;
-    for (RibEntry route : NFD.getRouteList(face)) {
-      logger.info("Found route: " + route.getName().toUri());
-      if (route.getName().equals(new Name("/my/test/route"))) {
-        found = true;
-      }
-    }
-    Assert.assertTrue(found);
-
-    // remove the route
-    NFD.unregister(face, new Name("/my/test/route"), "udp4://127.0.0.1:56363");
-  }
-
-  /**
-   * Setup the KeyChain with a default identity; TODO move this to
-   * MemoryIdentityStorage once it can handle getting/setting defaults
-   *
-   * @return
-   * @throws net.named_data.jndn.security.SecurityException
-   */
-  public static KeyChain buildTestKeyChain() throws net.named_data.jndn.security.SecurityException {
-    KeyChain keyChain = new KeyChain();
-    try {
-      keyChain.getDefaultCertificateName();
-    } catch (net.named_data.jndn.security.SecurityException e) {
-      keyChain.createIdentity(new Name("/test/identity"));
-      keyChain.getIdentityManager().setDefaultIdentity(new Name("/test/identity"));
-    }
-    return keyChain;
-  }
-}
diff --git a/src/test/java/com/intel/jndn/management/LocalControlHeaderTest.java b/src/test/java/com/intel/jndn/management/LocalControlHeaderTest.java
deleted file mode 100644
index 709c8a1..0000000
--- a/src/test/java/com/intel/jndn/management/LocalControlHeaderTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * jndn-management
- * Copyright (c) 2015, 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.management;
-
-import com.intel.jndn.management.types.LocalControlHeader;
-import com.intel.jndn.utils.client.impl.SimpleClient;
-import java.util.logging.Logger;
-import junit.framework.Assert;
-import net.named_data.jndn.Data;
-import net.named_data.jndn.Face;
-import net.named_data.jndn.Name;
-import net.named_data.jndn.encoding.EncodingException;
-import net.named_data.jndn.security.KeyChain;
-
-/**
- * Test functionality for LocalControlHeader
- *
- * @author Andrew Brown <andrew.brown@intel.com>
- */
-public class LocalControlHeaderTest {
-
-  private static final Logger logger = Logger.getLogger(IntegrationSuite.class.getName());
-
-  /**
-   * Integration test to run on actual system
-   *
-   * @param args
-   * @throws EncodingException
-   */
-  public static void main(String[] args) throws Exception {
-    // setup forwarder face
-    Face forwarder = new Face("localhost");
-    KeyChain keyChain = IntegrationSuite.buildTestKeyChain();
-    forwarder.setCommandSigningInfo(keyChain, keyChain.getDefaultCertificateName());
-
-    // enable incoming face ID header
-    NFD.enableLocalControlHeader(forwarder, LocalControlHeader.INCOMING_FACE_ID);
-
-    // use and verify
-    Data data = SimpleClient.getDefault().getSync(forwarder, new Name("/localhost/nfd"));
-    long faceId = data.getIncomingFaceId();
-    Assert.assertTrue(faceId != -1); // this verifies that the headers are working correctly
-    logger.info("Face ID for this client on the forwarder: " + faceId);
-  }
-}
diff --git a/src/test/java/com/intel/jndn/management/NdnPingClientIT.java b/src/test/java/com/intel/jndn/management/NdnPingClientIT.java
new file mode 100644
index 0000000..b561b6e
--- /dev/null
+++ b/src/test/java/com/intel/jndn/management/NdnPingClientIT.java
@@ -0,0 +1,55 @@
+/*
+ * jndn-management
+ * Copyright (c) 2015, 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.management;
+
+import com.intel.jndn.management.enums.Strategies;
+import com.intel.jndn.management.types.RibEntry;
+import com.intel.jndn.management.types.StrategyChoice;
+import com.intel.jndn.mock.MockKeyChain;
+import net.named_data.jndn.Face;
+import net.named_data.jndn.KeyLocator;
+import net.named_data.jndn.Name;
+import net.named_data.jndn.encoding.EncodingException;
+import net.named_data.jndn.security.KeyChain;
+import net.named_data.jndn.security.SecurityException;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Random;
+import java.util.logging.Logger;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+/**
+ * Testing basic pining using real NFD instance (NFD must be run locally while executing the test)
+ *
+ * @author Andrew Brown <andrew.brown@intel.com>
+ */
+public class NdnPingClientIT {
+  private Face face;
+
+  @Before
+  public void setUp() throws SecurityException {
+    face = new Face("localhost");
+  }
+
+  @Test
+  public void testPingLocal() throws IOException, ManagementException {
+    boolean hasSucceeded = NdnPingClient.pingLocal(face);
+    assertTrue(hasSucceeded);
+  }
+}
diff --git a/src/test/java/com/intel/jndn/management/NfdcIT.java b/src/test/java/com/intel/jndn/management/NfdcIT.java
new file mode 100644
index 0000000..8a8a0c3
--- /dev/null
+++ b/src/test/java/com/intel/jndn/management/NfdcIT.java
@@ -0,0 +1,126 @@
+/*
+ * jndn-management
+ * Copyright (c) 2015, 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.management;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Random;
+import java.util.logging.Logger;
+
+import com.intel.jndn.management.enums.LocalControlHeader;
+import com.intel.jndn.management.enums.Strategies;
+import com.intel.jndn.management.types.RibEntry;
+import com.intel.jndn.management.types.StrategyChoice;
+import com.intel.jndn.mock.MockKeyChain;
+import net.named_data.jndn.Face;
+import net.named_data.jndn.KeyLocator;
+import net.named_data.jndn.Name;
+import net.named_data.jndn.encoding.EncodingException;
+import net.named_data.jndn.security.KeyChain;
+import net.named_data.jndn.security.SecurityException;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
+
+/**
+ * Testing Nfdc with real NFD instance (NFD must be run locally while executing the test)
+ *
+ * @author Andrew Brown <andrew.brown@intel.com>
+ */
+public class NfdcIT {
+  private static final Logger LOG = Logger.getLogger(NfdcIT.class.getName());
+  private Face face;
+
+  @Before
+  public void setUp() throws SecurityException {
+    face = new Face("localhost");
+    KeyChain keyChain = MockKeyChain.configure(new Name("/tmp/identity"));
+    face.setCommandSigningInfo(keyChain, keyChain.getDefaultCertificateName());
+  }
+
+  @Test
+  public void testConnectivity() throws IOException, ManagementException {
+    KeyLocator keyLocator = Nfdc.getKeyLocator(face);
+    assertNotNull(keyLocator);
+    LOG.info("Connected to NFD with key locator: " + keyLocator.getKeyName().toUri());
+  }
+
+  @Test
+  public void testStatusDatasets() throws Exception {
+    assertTrue(Nfdc.getForwarderStatus(face).getStartTimestamp() > 0);
+    assertFalse(Nfdc.getFaceList(face).isEmpty());
+    assertFalse(Nfdc.getFibList(face).isEmpty());
+    assertFalse(Nfdc.getRouteList(face).isEmpty());
+  }
+
+  @Test
+  public void testRoutes() throws EncodingException, IOException, ManagementException, InterruptedException {
+    Nfdc.register(face, new Name("/my/route/to/app/face"), 333);
+    int faceId = Nfdc.createFace(face, "udp4://127.0.0.1:56363");
+    Nfdc.register(face, "udp4://127.0.0.1:56363", new Name("/my/test/route"), 999);
+    Nfdc.register(face, faceId, new Name("/"), 555);
+
+    // check that route is created
+    Thread.sleep(1000); // NFD registers the route asynchronously
+
+    boolean found = false;
+    for (RibEntry route : Nfdc.getRouteList(face)) {
+      LOG.info("Found route: " + route.getName().toUri());
+      if (route.getName().equals(new Name("/my/test/route"))) {
+        found = true;
+      }
+    }
+    assertTrue(found);
+
+    Nfdc.unregister(face, new Name("/my/route/to/app/face"));
+
+    // remove the route
+    Nfdc.unregister(face, new Name("/my/test/route"), "udp4://127.0.0.1:56363");
+
+    // remove face
+    Nfdc.destroyFace(face, faceId);
+  }
+
+  @Test
+  public void testStrategies() throws Exception {
+    Name prefix = new Name("/test/strategy").append("random:" + new Random().nextInt());
+
+    List<StrategyChoice> choices = Nfdc.getStrategyList(face);
+    int oldSize = choices.size();
+
+    Nfdc.setStrategy(face, prefix, Strategies.CLIENT_CONTROL);
+    Thread.sleep(1000); // strategy takes a while to register
+
+    choices = Nfdc.getStrategyList(face);
+    assertEquals(oldSize + 1, choices.size());
+
+    Nfdc.unsetStrategy(face, prefix);
+  }
+
+  /**
+   * LocalControlHeader would work only with NFD < 0.3.4, broken otherwise
+   */
+  @Test(expected = ManagementException.class)
+  public void testLocalControlHeader() throws Exception {
+    Nfdc.enableLocalControlHeader(face, LocalControlHeader.INCOMING_FACE_ID);
+    Thread.sleep(1000); // strategy takes a while to register
+
+    // TODO: add asserts
+
+    Nfdc.disableLocalControlHeader(face, LocalControlHeader.INCOMING_FACE_ID);
+  }
+}
diff --git a/src/test/java/com/intel/jndn/management/RibEntryTest.java b/src/test/java/com/intel/jndn/management/RibEntryTest.java
deleted file mode 100644
index 9494239..0000000
--- a/src/test/java/com/intel/jndn/management/RibEntryTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * jndn-management
- * Copyright (c) 2015, 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.management;
-
-import com.intel.jndn.management.types.StatusDataset;
-import com.intel.jndn.management.types.RibEntry;
-import com.intel.jndn.management.types.Route;
-import com.intel.jndn.utils.client.impl.SimpleClient;
-import java.util.List;
-import junit.framework.Assert;
-import net.named_data.jndn.Data;
-import net.named_data.jndn.Face;
-import net.named_data.jndn.Interest;
-import net.named_data.jndn.Name;
-import net.named_data.jndn.encoding.EncodingException;
-import net.named_data.jndn.util.Blob;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import org.junit.Test;
-
-/**
- * Test encoding/decoding for RibEntry.
- *
- * @author Andrew Brown <andrew.brown@intel.com>
- */
-public class RibEntryTest {
-
-  /**
-   * Test encoding/decoding
-   *
-   * @throws java.lang.Exception
-   */
-  @Test
-  public void testEncodeDecode() throws Exception {
-    Route route = new Route();
-    route.setFaceId(42);
-    route.setCost(100);
-    route.setOrigin(0);
-    RibEntry entry = new RibEntry();
-    entry.setName(new Name("/rib/entry/test"));
-    entry.getRoutes().add(route);
-
-    // encode
-    Blob encoded = entry.wireEncode();
-
-    // decode
-    RibEntry decoded = new RibEntry();
-    decoded.wireDecode(encoded.buf());
-
-    // test
-    Assert.assertEquals(entry.getName().toUri(), decoded.getName().toUri());
-    Assert.assertEquals(entry.getRoutes().get(0).getFaceId(), decoded.getRoutes().get(0).getFaceId());
-    Assert.assertEquals(entry.getRoutes().get(0).getCost(), decoded.getRoutes().get(0).getCost());
-    Assert.assertEquals(entry.getRoutes().get(0).getOrigin(), decoded.getRoutes().get(0).getOrigin());
-  }
-
-  /**
-   * Integration test to run on actual system
-   *
-   * @param args
-   * @throws EncodingException
-   */
-  public static void main(String[] args) throws Exception {
-    Face forwarder = new Face("localhost");
-
-    // build management Interest packet; see <a href="http://redmine.named-data.net/projects/nfd/wiki/StatusDataset">http://redmine.named-data.net/projects/nfd/wiki/StatusDataset</a>
-    Interest interest = new Interest(new Name("/localhost/nfd/rib/list"));
-    interest.setMustBeFresh(true);
-    interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
-    interest.setInterestLifetimeMilliseconds(2000.0);
-
-    // send packet
-    Data data = SimpleClient.getDefault().getSync(forwarder, interest);
-
-    // decode results
-    List<RibEntry> results = StatusDataset.wireDecode(data.getContent(), RibEntry.class);
-    assertTrue(results.size() > 0);
-    assertEquals("/localhost/nfd/rib", results.get(0).getName().toUri());
-  }
-}
diff --git a/src/test/java/com/intel/jndn/management/StrategyTestIT.java b/src/test/java/com/intel/jndn/management/StrategyTestIT.java
deleted file mode 100644
index c0abd14..0000000
--- a/src/test/java/com/intel/jndn/management/StrategyTestIT.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * jndn-management
- * Copyright (c) 2015, 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.management;
-
-import com.intel.jndn.management.types.StrategyChoice;
-import com.intel.jndn.mock.MockKeyChain;
-import java.util.List;
-import java.util.Random;
-import java.util.logging.Logger;
-import static junit.framework.Assert.assertEquals;
-import net.named_data.jndn.Face;
-import net.named_data.jndn.Name;
-import net.named_data.jndn.security.KeyChain;
-import org.junit.Test;
-
-/**
- * Test strategy management on a real, local NFD
- *
- * @author Andrew Brown <andrew.brown@intel.com>
- */
-public class StrategyTestIT {
-
-  private static final Logger logger = Logger.getLogger(StrategyTestIT.class.getName());
-  Name prefix;
-  Face face;
-
-  public StrategyTestIT() throws net.named_data.jndn.security.SecurityException {
-    this.prefix = new Name("/test/strategy").append("random:" + new Random().nextInt());
-    this.face = new Face("localhost"); // strategy commands only available on localhost
-    KeyChain mockKeyChain = MockKeyChain.configure(new Name("/test/server"));
-    face.setCommandSigningInfo(mockKeyChain, mockKeyChain.getDefaultCertificateName());
-  }
-
-  @Test
-  public void testStrategySetUnset() throws Exception {
-    List<StrategyChoice> choices = NFD.getStrategyList(face);
-    int oldSize = choices.size();
-
-    NFD.setStrategy(face, prefix, Strategies.CLIENT_CONTROL);
-    Thread.sleep(1000); // strategy takes a while to register
-
-    choices = NFD.getStrategyList(face);
-    assertEquals(oldSize + 1, choices.size());
-
-    NFD.unsetStrategy(face, prefix);
-  }
-}
diff --git a/src/test/java/com/intel/jndn/management/TestHelper.java b/src/test/java/com/intel/jndn/management/TestHelper.java
new file mode 100644
index 0000000..09ea326
--- /dev/null
+++ b/src/test/java/com/intel/jndn/management/TestHelper.java
@@ -0,0 +1,42 @@
+/*
+ * jndn-management
+ * Copyright (c) 2016, Regents of the University of California
+ *
+ * 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.management;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Helper methods for unit tests
+ */
+public class TestHelper {
+  /**
+   * Prevent instances of TestHelper
+   */
+  private TestHelper() {
+  }
+
+  /**
+   * Construct ByteBuffer from int[]
+   */
+  public static ByteBuffer
+  bufferFromIntArray(int[] array)
+  {
+    ByteBuffer result = ByteBuffer.allocate(array.length);
+    for (int value : array) {
+      result.put((byte) (value & 0xFF));
+    }
+
+    result.flip();
+    return result;
+  }
+}
diff --git a/src/test/java/com/intel/jndn/management/types/FaceStatusTest.java b/src/test/java/com/intel/jndn/management/types/FaceStatusTest.java
new file mode 100644
index 0000000..b6b959b
--- /dev/null
+++ b/src/test/java/com/intel/jndn/management/types/FaceStatusTest.java
@@ -0,0 +1,103 @@
+/*
+ * jndn-management
+ * Copyright (c) 2015, 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.management.types;
+
+import com.intel.jndn.management.TestHelper;
+import com.intel.jndn.management.enums.FacePersistency;
+import com.intel.jndn.management.enums.FaceScope;
+import com.intel.jndn.management.enums.LinkType;
+
+import java.nio.ByteBuffer;
+import net.named_data.jndn.util.Blob;
+import static org.junit.Assert.*;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test whether the decoding for the face management service is working
+ * correctly
+ *
+ * @author Andrew Brown <andrew.brown@intel.com>
+ */
+public class FaceStatusTest {
+  ByteBuffer TestFaceStatus;
+
+  @Before
+  public void setUp() throws Exception {
+    TestFaceStatus = TestHelper.bufferFromIntArray(new int[] {
+      0x80, 0x5e, 0x69, 0x01, 0x64, 0x72, 0x15, 0x74, 0x63, 0x70,
+      0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e,
+      0x32, 0x2e, 0x31, 0x3a, 0x36, 0x33, 0x36, 0x33, 0x81, 0x16,
+      0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32,
+      0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x32, 0x3a, 0x35, 0x35, 0x35,
+      0x35, 0x35, 0x6d, 0x02, 0x27, 0x10, 0x84, 0x01, 0x01, 0x85,
+      0x01, 0x01, 0x86, 0x01, 0x01, 0x90, 0x01, 0x0a, 0x91, 0x01,
+      0xc8, 0x97, 0x01, 0x01, 0x92, 0x02, 0x0b, 0xb8, 0x93, 0x01,
+      0x04, 0x98, 0x01, 0x02, 0x94, 0x04, 0x4f, 0x41, 0xe7, 0x7b,
+      0x95, 0x04, 0x3b, 0x8d, 0x37, 0x30,
+    });
+  }
+
+  /**
+   * Test encoding
+   */
+  @Test
+  public void testEncode() throws Exception {
+    FaceStatus status = new FaceStatus();
+    status.setFaceId(100)
+      .setRemoteUri("tcp4://192.0.2.1:6363")
+      .setLocalUri("tcp4://192.0.2.2:55555")
+      .setFaceScope(FaceScope.LOCAL)
+      .setFacePersistency(FacePersistency.ON_DEMAND)
+      .setLinkType(LinkType.MULTI_ACCESS)
+      .setExpirationPeriod(10000)
+      .setNInInterests(10)
+      .setNInDatas(200)
+      .setNInNacks(1)
+      .setNOutInterests(3000)
+      .setNOutDatas(4)
+      .setNOutNacks(2)
+      .setNInBytes(1329719163)
+      .setNOutBytes(999110448);
+
+    // encode
+    Blob encoded = status.wireEncode();
+    assertEquals(TestFaceStatus, encoded.buf());
+  }
+
+  /**
+   * Test decoding
+   */
+  @Test
+  public void testDecode() throws Exception {
+    FaceStatus status = new FaceStatus(TestFaceStatus);
+
+    assertEquals(100, status.getFaceId());
+    assertEquals("tcp4://192.0.2.1:6363", status.getRemoteUri());
+    assertEquals("tcp4://192.0.2.2:55555", status.getLocalUri());
+    assertEquals(FaceScope.LOCAL, status.getFaceScope());
+    assertEquals(FacePersistency.ON_DEMAND, status.getFacePersistency());
+    assertEquals(LinkType.MULTI_ACCESS, status.getLinkType());
+    assertEquals(10000, status.getExpirationPeriod());
+    assertEquals(10, status.getNInInterests());
+    assertEquals(200, status.getNInDatas());
+    assertEquals(1, status.getNInNacks());
+    assertEquals(3000, status.getNOutInterests());
+    assertEquals(4, status.getNOutDatas());
+    assertEquals(2, status.getNOutNacks());
+    assertEquals(1329719163, status.getNInBytes());
+    assertEquals(999110448, status.getNOutBytes());
+  }
+}
diff --git a/src/test/java/com/intel/jndn/management/types/FibEntryTest.java b/src/test/java/com/intel/jndn/management/types/FibEntryTest.java
new file mode 100644
index 0000000..d8c19f4
--- /dev/null
+++ b/src/test/java/com/intel/jndn/management/types/FibEntryTest.java
@@ -0,0 +1,138 @@
+/*
+ * jndn-management
+ * Copyright (c) 2015, 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.management.types;
+
+import com.intel.jndn.management.TestHelper;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import net.named_data.jndn.Name;
+import net.named_data.jndn.encoding.EncodingException;
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test encode/decode of FibEntry and NextHopRecord
+ *
+ * @author Andrew Brown <andrew.brown@intel.com>
+ */
+public class FibEntryTest {
+  ByteBuffer TestNextHopRecord;
+  ByteBuffer TestFibEntryNoNextHops;
+  ByteBuffer TestFibEntry;
+
+  @Before
+  public void setUp() {
+    TestNextHopRecord = TestHelper.bufferFromIntArray(new int[] {
+      0x81, 0x06, 0x69, 0x01, 0x0a, 0x6a, 0x01, 0xc8
+    });
+
+    TestFibEntryNoNextHops = TestHelper.bufferFromIntArray(new int[] {
+      0x80, 0x15, 0x07, 0x13, 0x08, 0x04, 0x74, 0x68, 0x69, 0x73,
+      0x08, 0x02, 0x69, 0x73, 0x08, 0x01, 0x61, 0x08, 0x04, 0x74,
+      0x65, 0x73, 0x74
+    });
+    TestFibEntry = TestHelper.bufferFromIntArray(new int[] {
+      0x80, 0x38, 0x07, 0x13, 0x08, 0x04, 0x74, 0x68, 0x69, 0x73, 0x08, 0x02, 0x69, 0x73, 0x08, 0x01,
+      0x61, 0x08, 0x04, 0x74, 0x65, 0x73, 0x74, 0x81, 0x06, 0x69, 0x01, 0x0a, 0x6a, 0x01, 0xc8, 0x81,
+      0x07, 0x69, 0x01, 0x14, 0x6a, 0x02, 0x01, 0x2c, 0x81, 0x07, 0x69, 0x01, 0x1e, 0x6a, 0x02, 0x01,
+      0x90, 0x81, 0x07, 0x69, 0x01, 0x28, 0x6a, 0x02, 0x01, 0xf4
+    });
+  }
+
+  @Test
+  public void testNextHopRecordEncode()
+  {
+    NextHopRecord record = new NextHopRecord();
+    record.setFaceId(10);
+    record.setCost(200);
+
+    ByteBuffer wire = record.wireEncode().buf();
+    assertEquals(TestNextHopRecord, wire);
+  }
+
+  @Test
+  public void testNextHopRecordDecode() throws EncodingException {
+    NextHopRecord record = new NextHopRecord(TestNextHopRecord);
+
+    assertEquals(10, record.getFaceId());
+    assertEquals(200, record.getCost());
+  }
+
+  @Test
+  public void testFibEntryNoNextHopEncode()
+  {
+    FibEntry entry = new FibEntry();
+    entry.setPrefix(new Name("/this/is/a/test"));
+
+    ByteBuffer wire = entry.wireEncode().buf();
+    assertEquals(TestFibEntryNoNextHops, wire);
+  }
+
+  @Test
+  public void testFibEntryNoNextHopsDecode() throws EncodingException {
+    FibEntry entry = new FibEntry(TestFibEntryNoNextHops);
+
+    assertEquals("/this/is/a/test", entry.getPrefix().toString());
+    assertEquals(0, entry.getNextHopRecords().size());
+  }
+
+  @Test
+  public void testFibEntryEncode()
+  {
+    FibEntry entry = new FibEntry();
+    entry.setPrefix(new Name("/this/is/a/test"));
+
+    List<NextHopRecord> records = new ArrayList<>();
+    for (int i = 1; i < 4; i++)
+    {
+      NextHopRecord record = new NextHopRecord();
+      record.setFaceId(i * 10);
+      record.setCost((i * 100) + 100);
+      records.add(record);
+    }
+
+    entry.setNextHopRecords(records);
+
+    NextHopRecord oneMore = new NextHopRecord();
+    oneMore.setFaceId(40);
+    oneMore.setCost(500);
+
+    entry.addNextHopRecord(oneMore);
+
+    ByteBuffer wire = entry.wireEncode().buf();
+    assertEquals(TestFibEntry, wire);
+  }
+
+  @Test
+  public void testFibEntryDecode() throws EncodingException {
+    FibEntry entry = new FibEntry(TestFibEntry);
+
+    List<NextHopRecord> records = entry.getNextHopRecords();
+
+    assertEquals("/this/is/a/test", entry.getPrefix().toUri());
+    assertEquals(4, entry.getNextHopRecords().size());
+
+    int value = 1;
+
+    for (NextHopRecord record : records) {
+      assertEquals(value * 10, record.getFaceId());
+      assertEquals((value * 100) + 100, record.getCost());
+      ++value;
+    }
+  }
+}
diff --git a/src/test/java/com/intel/jndn/management/types/ForwarderStatusTest.java b/src/test/java/com/intel/jndn/management/types/ForwarderStatusTest.java
new file mode 100644
index 0000000..5ff5157
--- /dev/null
+++ b/src/test/java/com/intel/jndn/management/types/ForwarderStatusTest.java
@@ -0,0 +1,88 @@
+/*
+ * jndn-management
+ * Copyright (c) 2015, 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.management.types;
+
+import java.nio.ByteBuffer;
+
+import com.intel.jndn.management.TestHelper;
+import net.named_data.jndn.encoding.EncodingException;
+import static org.junit.Assert.assertEquals;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test encoding/decoding of ForwarderStatus.
+ *
+ * @author Andrew Brown <andrew.brown@intel.com>
+ */
+public class ForwarderStatusTest {
+  ByteBuffer TestForwarderStatus;
+
+  @Before
+  public void setUp() throws Exception {
+    TestForwarderStatus = TestHelper.bufferFromIntArray(new int[] {
+      0x80, 0x11, 0x30, 0x2e, 0x32, 0x2e, 0x30, 0x2d, 0x36, 0x35,
+      0x2d, 0x67, 0x37, 0x35, 0x61, 0x62, 0x36, 0x62, 0x37, 0x81, 0x08, 0x00,
+      0x00, 0x00, 0x57, 0x5b, 0x42, 0xa6, 0x2d, 0x82, 0x08, 0x00, 0x00, 0x00,
+      0xce, 0x50, 0x36, 0xd7, 0x20, 0x83, 0x04, 0x6e, 0x43, 0xe4, 0x78, 0x84,
+      0x04, 0x25, 0x0e, 0xfe, 0xe4, 0x85, 0x04, 0x1c, 0xbc, 0xb7, 0x4d, 0x86,
+      0x04, 0x69, 0x9a, 0x61, 0xf2, 0x87, 0x04, 0x4b, 0x65, 0xe3, 0xf0, 0x90,
+      0x04, 0x24, 0x86, 0xc3, 0x5f, 0x91, 0x04, 0x6d, 0xe2, 0xbc, 0xf2, 0x97,
+      0x02, 0x04, 0xd2, 0x92, 0x04, 0x38, 0xc0, 0x92, 0x3d, 0x93, 0x04, 0x08,
+      0x3c, 0xbf, 0x2a, 0x98, 0x02, 0x10, 0xe1,
+    });
+  }
+
+  @Test
+  public void testEncode() {
+    ForwarderStatus status = new ForwarderStatus();
+    status.setNfdVersion("0.2.0-65-g75ab6b7");
+    status.setStartTimestamp(375193249325L);
+    status.setCurrentTimestamp(886109034272L);
+    status.setNNameTreeEntries(1849943160);
+    status.setNFibEntries(621739748);
+    status.setNPitEntries(482129741);
+    status.setNMeasurementsEntries(1771725298);
+    status.setNCsEntries(1264968688);
+    status.setNInInterests(612811615);
+    status.setNInDatas(1843576050);
+    status.setNInNacks(1234);
+    status.setNOutInterests(952144445);
+    status.setNOutDatas(138198826);
+    status.setNOutNacks(4321);
+
+    ByteBuffer wire = status.wireEncode().buf();
+    assertEquals(TestForwarderStatus, wire);
+  }
+
+  @Test
+  public void testDecode() throws EncodingException {
+    ForwarderStatus status = new ForwarderStatus(TestForwarderStatus);
+
+    assertEquals("0.2.0-65-g75ab6b7", status.getNfdVersion());
+    assertEquals(375193249325L,       status.getStartTimestamp());
+    assertEquals(886109034272L,       status.getCurrentTimestamp());
+    assertEquals(1849943160,          status.getNNameTreeEntries());
+    assertEquals(621739748,           status.getNFibEntries());
+    assertEquals(482129741,           status.getNPitEntries());
+    assertEquals(1771725298,          status.getNMeasurementsEntries());
+    assertEquals(1264968688,          status.getNCsEntries());
+    assertEquals(612811615,           status.getNInInterests());
+    assertEquals(1843576050,          status.getNInDatas());
+    assertEquals(1234,                status.getNInNacks());
+    assertEquals(952144445,           status.getNOutInterests());
+    assertEquals(138198826,           status.getNOutDatas());
+    assertEquals(4321,                status.getNOutNacks());
+  }
+}
diff --git a/src/test/java/com/intel/jndn/management/types/RibEntryTest.java b/src/test/java/com/intel/jndn/management/types/RibEntryTest.java
new file mode 100644
index 0000000..82b4d22
--- /dev/null
+++ b/src/test/java/com/intel/jndn/management/types/RibEntryTest.java
@@ -0,0 +1,288 @@
+/*
+ * jndn-management
+ * Copyright (c) 2015, 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.management.types;
+
+import java.nio.ByteBuffer;
+
+import com.intel.jndn.management.TestHelper;
+import com.intel.jndn.management.enums.RouteFlags;
+
+import java.util.List;
+import java.util.ListIterator;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import net.named_data.jndn.Name;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RibEntryTest {
+  ByteBuffer RouteData;
+  ByteBuffer RouteInfiniteExpirationPeriod;
+  ByteBuffer RibEntryData;
+  ByteBuffer RibEntryInfiniteExpirationPeriod;
+  ByteBuffer RibEntryForRootData;
+
+  @Before
+  public void setUp() throws Exception {
+    RouteData = TestHelper.bufferFromIntArray(new int[] {
+        0x81, 0x10, 0x69, 0x01, 0x01, 0x6f, 0x01, 0x80, 0x6a, 0x01, 0x64, 0x6c, 0x01, 0x02,
+        0x6d, 0x02, 0x27, 0x10
+      });
+    RouteInfiniteExpirationPeriod = TestHelper.bufferFromIntArray(new int[] {
+        0x81, 0x0C, 0x69, 0x01, 0x01, 0x6f, 0x01, 0x80, 0x6a, 0x01, 0x64, 0x6c, 0x01, 0x02
+      });
+    RibEntryData = TestHelper.bufferFromIntArray(new int[] {
+        // Header + Name (ndn:/hello/world)
+        0x80, 0x34, 0x07, 0x0e, 0x08, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
+        0x08, 0x05, 0x77, 0x6f, 0x72, 0x6c, 0x64,
+        // Route
+        0x81, 0x10, 0x69, 0x01, 0x01, 0x6f, 0x01, 0x80, 0x6a, 0x01, 0x64, 0x6c, 0x01, 0x02,
+        0x6d, 0x02, 0x27, 0x10,
+        // Route
+        0x81, 0x10, 0x69, 0x01, 0x02, 0x6f, 0x01, 0x00, 0x6a, 0x01, 0x20, 0x6c, 0x01, 0x01,
+        0x6d, 0x02, 0x13, 0x88
+      });
+    RibEntryInfiniteExpirationPeriod = TestHelper.bufferFromIntArray(new int[] {
+        // Header + Name (ndn:/hello/world)
+        0x80, 0x30, 0x07, 0x0e, 0x08, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
+        0x08, 0x05, 0x77, 0x6f, 0x72, 0x6c, 0x64,
+        // Route
+        0x81, 0x10, 0x69, 0x01, 0x01, 0x6f, 0x01, 0x80, 0x6a, 0x01, 0x64, 0x6c, 0x01, 0x02,
+        0x6d, 0x02, 0x27, 0x10,
+        // Route with no ExpirationPeriod
+        0x81, 0x0C, 0x69, 0x01, 0x02, 0x6f, 0x01, 0x00, 0x6a, 0x01, 0x20, 0x6c, 0x01, 0x01,
+      });
+    RibEntryForRootData = TestHelper.bufferFromIntArray(new int[] {
+        // Header + Name (ndn:/)
+        0x80, 0x26, 0x07, 0x00,
+        // Route
+        0x81, 0x10, 0x69, 0x01, 0x01, 0x6f, 0x01, 0x80, 0x6a, 0x01, 0x64, 0x6c, 0x01, 0x02,
+        0x6d, 0x02, 0x27, 0x10,
+        // Route
+        0x81, 0x10, 0x69, 0x01, 0x02, 0x6f, 0x01, 0x00, 0x6a, 0x01, 0x20, 0x6c, 0x01, 0x01,
+        0x6d, 0x02, 0x13, 0x88
+      });
+  }
+
+  @Test
+  public void testRouteEncode() throws Exception {
+    Route route = new Route();
+    route.setFaceId(1);
+    route.setOrigin(128);
+    route.setCost(100);
+    route.setFlags(RouteFlags.CAPTURE.toInteger());
+    route.setExpirationPeriod(10000);
+
+    assertEquals(RouteData, route.wireEncode().buf());
+  }
+
+  @Test
+  public void testRouteDecode() throws Exception {
+    Route route = new Route(RouteData);
+
+    assertEquals(route.getFaceId(), 1);
+    assertEquals(route.getOrigin(), 128);
+    assertEquals(route.getCost(), 100);
+    assertEquals(RouteFlags.CAPTURE.toInteger(), route.getFlags());
+    assertEquals(route.getExpirationPeriod(), 10000);
+    assertEquals(route.hasInfiniteExpirationPeriod(), false);
+  }
+
+  @Test
+  public void testRouteInfiniteExpirationPeriodEncode() throws Exception {
+    Route route = new Route();
+    route.setFaceId(1);
+    route.setOrigin(128);
+    route.setCost(100);
+    route.setFlags(RouteFlags.CAPTURE.toInteger());
+    route.setExpirationPeriod(Route.INFINITE_EXPIRATION_PERIOD);
+
+    assertEquals(RouteInfiniteExpirationPeriod, route.wireEncode().buf());
+  }
+
+  @Test
+  public void testRouteInfiniteExpirationPeriodDecode() throws Exception {
+    Route route = new Route(RouteInfiniteExpirationPeriod);
+
+    assertEquals(route.getFaceId(), 1);
+    assertEquals(route.getOrigin(), 128);
+    assertEquals(route.getCost(), 100);
+    assertEquals(RouteFlags.CAPTURE.toInteger(), route.getFlags());
+    assertEquals(route.getExpirationPeriod(), Route.INFINITE_EXPIRATION_PERIOD);
+    assertEquals(route.hasInfiniteExpirationPeriod(), true);
+  }
+
+  @Test
+  public void testRouteOutputStream() throws Exception {
+    Route route = new Route();
+    route.setFaceId(1);
+    route.setOrigin(128);
+    route.setCost(100);
+    route.setFlags(RouteFlags.CAPTURE.toInteger());
+    route.setExpirationPeriod(10000);
+
+    assertEquals(route.toString(), "Route(FaceId: 1, Origin: 128, Cost: 100, " +
+                                   "Flags: 2, ExpirationPeriod: 10000 milliseconds)");
+  }
+
+  @Test
+  public void testRibEntryEncode() throws Exception {
+    RibEntry entry = newRibEntry("/hello/world", 2, false);
+
+    assertEquals(RibEntryData, entry.wireEncode().buf());
+  }
+
+  @Test
+  public void testRibEntryDecode() throws Exception {
+    RibEntry entry = new RibEntry(RibEntryData);
+
+    assertRibEntry(entry, "/hello/world", 2, false);
+  }
+
+  @Test
+  public void testRibEntryForRootEncode() throws Exception {
+    RibEntry entry = newRibEntry("/", 2, false);
+
+    assertEquals(RibEntryForRootData, entry.wireEncode().buf());
+  }
+
+  @Test
+  public void testRibEntryForRootDecode() throws Exception {
+    RibEntry entry = new RibEntry(RibEntryForRootData);
+
+    assertRibEntry(entry, "/", 2, false);
+  }
+
+  @Test
+  public void testRibEntryInfiniteExpirationPeriodEncode() throws Exception {
+    RibEntry entry = newRibEntry("/hello/world", 2, true);
+    assertEquals(RibEntryInfiniteExpirationPeriod, entry.wireEncode().buf());
+  }
+
+  @Test
+  public void testRibEntryInfiniteExpirationPeriodDecode() throws Exception {
+    RibEntry entry = new RibEntry();
+
+    entry.wireDecode(RibEntryInfiniteExpirationPeriod);
+    assertRibEntry(entry, "/hello/world", 2, true);
+  }
+
+  @Test
+  public void testRibEntryClear() throws Exception {
+    RibEntry entry = newRibEntry("/hello/world", 2, true);
+    assertEquals(entry.getRoutes().size(), 2);
+    assertRibEntry(entry, "/hello/world", 2, true);
+
+    entry.clearRoutes();
+    assertEquals(entry.getRoutes().size(), 0);
+  }
+
+  @Test
+  public void testRibEntryOutputStream() throws Exception {
+    RibEntry entry = newRibEntry("/hello/world", 2, true);
+
+    assertEquals("RibEntry{\n" +
+                 "  Name: /hello/world\n" +
+                 "  Route(FaceId: 1, Origin: 128, Cost: 100, Flags: 2, ExpirationPeriod: 10000 milliseconds)\n" +
+                 "  Route(FaceId: 2, Origin: 0, Cost: 32, Flags: 1, ExpirationPeriod: Infinity)\n" +
+                 "}",
+                 entry.toString());
+  }
+
+  @Test
+  public void testRibEntryAddRoutes() {
+    RibEntry a = newRibEntry("/hello/world", 2, true);
+
+    RibEntry b = new RibEntry();
+    b.setName(new Name("/another/prefix"));
+    b.setRoutes(a.getRoutes());
+
+    assertEquals("RibEntry{\n" +
+                 "  Name: /another/prefix\n" +
+                 "  Route(FaceId: 1, Origin: 128, Cost: 100, Flags: 2, ExpirationPeriod: 10000 milliseconds)\n" +
+                 "  Route(FaceId: 2, Origin: 0, Cost: 32, Flags: 1, ExpirationPeriod: Infinity)\n" +
+                 "}",
+                 b.toString());
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  //////////////////////////////////////////////////////////////////////////////
+
+  private RibEntry newRibEntry(String name, int nRoutes, boolean isInfiniteSecond) {
+    RibEntry entry = new RibEntry();
+    entry.setName(new Name(name));
+
+    Route route1 = new Route();
+    route1.setFaceId(1);
+    route1.setOrigin(128);
+    route1.setCost(100);
+    route1.setFlags(RouteFlags.CAPTURE.toInteger());
+    route1.setExpirationPeriod(10000);
+    entry.addRoute(route1);
+
+    if (nRoutes > 1) {
+      Route route2 = new Route();
+      route2.setFaceId(2);
+      route2.setOrigin(0);
+      route2.setCost(32);
+      route2.setFlags(RouteFlags.CHILD_INHERIT.toInteger());
+      if (isInfiniteSecond) {
+        route2.setExpirationPeriod(Route.INFINITE_EXPIRATION_PERIOD);
+      }
+      else {
+        route2.setExpirationPeriod(5000);
+      }
+      entry.addRoute(route2);
+    }
+
+    return entry;
+  }
+
+  private void assertRibEntry(RibEntry entry, String name, int nRoutes, boolean isInfiniteSecond) throws Exception {
+    assertEquals(entry.getName().toUri(), name);
+    assertEquals(entry.getRoutes().size(), nRoutes);
+
+    List<Route> routes = entry.getRoutes();
+
+    ListIterator<Route> it = routes.listIterator();
+    assertTrue(it.hasNext());
+    Route item = it.next();
+    assertEquals(item.getFaceId(), 1);
+    assertEquals(item.getOrigin(), 128);
+    assertEquals(item.getCost(), 100);
+    assertEquals(RouteFlags.CAPTURE.toInteger(), item.getFlags());
+    assertEquals(item.getExpirationPeriod(), 10000);
+    assertEquals(item.hasInfiniteExpirationPeriod(), false);
+
+    if (nRoutes > 1) {
+      assertTrue(it.hasNext());
+      item = it.next();
+      assertEquals(item.getFaceId(), 2);
+      assertEquals(item.getOrigin(), 0);
+      assertEquals(item.getCost(), 32);
+      assertEquals(RouteFlags.CHILD_INHERIT.toInteger(), item.getFlags());
+
+      if (isInfiniteSecond) {
+        assertEquals(item.getExpirationPeriod(), Route.INFINITE_EXPIRATION_PERIOD);
+        assertEquals(item.hasInfiniteExpirationPeriod(), true);
+      }
+      else {
+        assertEquals(item.getExpirationPeriod(), 5000);
+        assertEquals(item.hasInfiniteExpirationPeriod(), false);
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/intel/jndn/management/types/StrategyChoiceTest.java b/src/test/java/com/intel/jndn/management/types/StrategyChoiceTest.java
index 1b2ab64..077d91c 100644
--- a/src/test/java/com/intel/jndn/management/types/StrategyChoiceTest.java
+++ b/src/test/java/com/intel/jndn/management/types/StrategyChoiceTest.java
@@ -11,41 +11,53 @@
  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
  * more details.
  */
-package com.intel.jndn.management.types;
+package com.intel.jndn.management;
 
-import com.intel.jndn.management.Strategies;
-import junit.framework.Assert;
+import com.intel.jndn.management.types.StrategyChoice;
 import net.named_data.jndn.Name;
 import net.named_data.jndn.encoding.EncodingException;
-import net.named_data.jndn.util.Blob;
+import org.junit.Before;
 import org.junit.Test;
 
+import java.nio.ByteBuffer;
+
+import static org.junit.Assert.assertEquals;
+
 /**
- * Test StrategyCHoice encoding/decoding
+ * Test StrategyChoice encoding/decoding
  *
  * @author Andrew Brown <andrew.brown@intel.com>
  */
 public class StrategyChoiceTest {
+  ByteBuffer TestStrategyChoice;
 
-  /**
-   * Test of wireEncode method, of class StrategyChoice.
-   * @throws net.named_data.jndn.encoding.EncodingException
-   */
+  @Before
+  public void setUp() throws Exception {
+    TestStrategyChoice = TestHelper.bufferFromIntArray(new int[] {
+      0x80, 0x39, 0x07, 0x0e, 0x08, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x08, 0x05, 0x77,
+      0x6f, 0x72, 0x6c, 0x64, 0x6b, 0x27, 0x07, 0x25, 0x08, 0x04, 0x73, 0x6f, 0x6d, 0x65,
+      0x08, 0x03, 0x6e, 0x6f, 0x6e, 0x08, 0x08, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e,
+      0x67, 0x08, 0x08, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x08, 0x04, 0x6e,
+      0x61, 0x6d, 0x65
+    });
+  }
+
   @Test
-  public void testEncodeDecode() throws EncodingException {
-    StrategyChoice choice = new StrategyChoice();
-    choice.setName(new Name("/a/b"));
-    choice.setStrategy(Strategies.NCC);
+  public void testEncode() {
+    StrategyChoice strategyChoice = new StrategyChoice();
+    strategyChoice
+      .setName(new Name("/hello/world"))
+      .setStrategy(new Name("/some/non/existing/strategy/name"))
+    ;
 
-    // encode
-    Blob encoded = choice.wireEncode();
+    ByteBuffer wire = strategyChoice.wireEncode().buf();
+    assertEquals(TestStrategyChoice, wire);
+  }
 
-    // decode
-    StrategyChoice decoded = new StrategyChoice();
-    decoded.wireDecode(encoded.buf());
-
-    // test
-    Assert.assertEquals(choice.getName().toUri(), decoded.getName().toUri());
-    Assert.assertEquals(choice.getStrategy().toUri(), decoded.getStrategy().toUri());
+  @Test
+  public void testDecode() throws EncodingException {
+    StrategyChoice strategyChoice = new StrategyChoice(TestStrategyChoice);
+    assertEquals("/hello/world", strategyChoice.getName().toUri());
+    assertEquals("/some/non/existing/strategy/name", strategyChoice.getStrategy().toUri());
   }
 }