Revert "build: Downgrade to Java 1.7"

This reverts commit bc30e65ea2d14d71fabca92c96aef089f4b77d43.

Change-Id: If6bcd1218c6d0e3753af7ad351fba4784b5ac6ad
diff --git a/src/test/java/com/intel/jndn/utils/TestHelper.java b/src/test/java/com/intel/jndn/utils/TestHelper.java
index fbf931e..a73aba4 100644
--- a/src/test/java/com/intel/jndn/utils/TestHelper.java
+++ b/src/test/java/com/intel/jndn/utils/TestHelper.java
@@ -24,6 +24,8 @@
 import java.util.concurrent.TimeUnit;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 import net.named_data.jndn.Data;
 import net.named_data.jndn.Face;
 import net.named_data.jndn.Name;
@@ -49,19 +51,15 @@
   }
 
   public static List<CompletableFuture<Data>> buildFutureSegments(Name name, int from, int to) {
-    List<CompletableFuture<Data>> list = new ArrayList<>();
-    for (Data d : buildSegments(name, from, to)) {
-      list.add(CompletableFuture.completedFuture(d));
-    }
-    return list;
+    return buildSegments(name, from, to).stream()
+            .map((d) -> CompletableFuture.completedFuture(d))
+            .collect(Collectors.toList());
   }
 
   public static List<Data> buildSegments(Name name, int from, int to) {
-    List<Data> list = new ArrayList<>();
-    for (Integer i = from; i < to; i++) {
-      list.add(buildData(new Name(name).appendSegment(i), i.toString(), to - 1));
-    }
-    return list;
+    return IntStream.range(from, to).boxed()
+            .map((i) -> buildData(new Name(name).appendSegment(i), i.toString(), to - 1))
+            .collect(Collectors.toList());
   }
 
   public static Data buildData(Name name, String content) {
diff --git a/src/test/java/com/intel/jndn/utils/client/impl/AdvancedClientFileTestIT.java b/src/test/java/com/intel/jndn/utils/client/impl/AdvancedClientFileTestIT.java
new file mode 100644
index 0000000..45572a7
--- /dev/null
+++ b/src/test/java/com/intel/jndn/utils/client/impl/AdvancedClientFileTestIT.java
@@ -0,0 +1,118 @@
+/*
+ * jndn-utils
+ * 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.utils.client.impl;
+
+import com.intel.jndn.utils.Client;
+import com.intel.jndn.utils.TestHelper;
+import com.intel.jndn.utils.server.impl.SegmentedServerHelper;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.CompletableFuture;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+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.OnInterestCallback;
+import net.named_data.jndn.security.SecurityException;
+import org.junit.Test;
+
+/**
+ * Test AdvancedClient.java; requires a hostname to an NFD accepting a generated
+ * key to register prefixes, e.g. mvn test -Dnfd.ip=10.10.10.1
+ *
+ * @author Andrew Brown <andrew.brown@intel.com>
+ */
+public class AdvancedClientFileTestIT {
+
+  private static final Logger logger = Logger.getLogger(AdvancedClientFileTestIT.class.getName());
+  private static final Name PREFIX = new Name("/test/advanced-client").append(TestHelper.buildRandomString(10));
+  private static final int NUM_MESSAGES = 100;
+  private static final int MESSAGE_SIZE_BYTES = 10000;
+  private static final int SEGMENT_SIZE_BYTES = 5000;
+  private final TestHelper.NdnEnvironment environment;
+
+  public AdvancedClientFileTestIT() throws SecurityException {
+    String ip = System.getProperty("nfd.ip");
+    logger.info("Testing on NFD at: " + ip);
+    environment = TestHelper.buildTestEnvironment(ip, 2);
+  }
+
+  @Test
+  public void stressTest() throws Exception {
+    Face producer = environment.faces.get(0);
+    Face consumer = environment.faces.get(1);
+
+    producer.registerPrefix(PREFIX, new AdvancedDataServer(MESSAGE_SIZE_BYTES, SEGMENT_SIZE_BYTES), null);
+
+    // TODO this must be here until the prefix registration callback is complete
+    Thread.sleep(500);
+
+    long startTime = System.currentTimeMillis();
+    AdvancedClient client = new AdvancedClient();
+    List<CompletableFuture<Data>> requests = expressInterests(client, consumer, PREFIX, NUM_MESSAGES);
+    List<Data> datas = requests.stream().map((f) -> TestHelper.retrieve(f)).collect(Collectors.toList());
+    long endTime = System.currentTimeMillis();
+
+    logger.info(String.format("Transfered %d bytes in %d ms", MESSAGE_SIZE_BYTES * NUM_MESSAGES, endTime - startTime));
+  }
+
+  private List<CompletableFuture<Data>> expressInterests(Client client, Face face, Name name, int count) {
+    return IntStream.range(0, count).boxed().map((i) -> client.getAsync(face, name)).collect(Collectors.toList());
+  }
+
+  private class AdvancedDataServer implements OnInterestCallback {
+
+    private final int contentSize;
+    private final int segmentSize;
+
+    public AdvancedDataServer(int contentSize, int segmentSize) {
+      this.contentSize = contentSize;
+      this.segmentSize = segmentSize;
+    }
+
+    @Override
+    public void onInterest(Name prefix, Interest interest, Face face, long interestFilterId, InterestFilter filter) {
+      // ignore segmented requests, the data has already been put below
+      if (SegmentationHelper.isSegmented(interest.getName(), (byte) 0x00)) {
+        return;
+      }
+      
+      // randomly ignore 10% of requests
+      if (new Random().nextInt(10) < 2){
+        logger.info("Skipping an interest: " + interest.toUri());
+        return;
+      }
+
+      ByteArrayInputStream bytes = new ByteArrayInputStream(TestHelper.buildRandomString(contentSize).getBytes());
+      Data data = TestHelper.buildData(interest.getName(), "");
+      data.getMetaInfo().setFreshnessPeriod(0);
+
+      try {
+        for (Data segment : SegmentedServerHelper.segment(data, bytes, segmentSize)) {
+          logger.log(Level.INFO, "Put data: " + segment.getName().toUri());
+          face.putData(segment);
+        }
+      } catch (IOException ex) {
+        logger.log(Level.SEVERE, "Failed to put data.", ex);
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/intel/jndn/utils/client/impl/AdvancedClientStressTestIT.java b/src/test/java/com/intel/jndn/utils/client/impl/AdvancedClientStressTestIT.java
new file mode 100644
index 0000000..6a99599
--- /dev/null
+++ b/src/test/java/com/intel/jndn/utils/client/impl/AdvancedClientStressTestIT.java
@@ -0,0 +1,118 @@
+/*
+ * jndn-utils
+ * 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.utils.client.impl;
+
+import com.intel.jndn.utils.Client;
+import com.intel.jndn.utils.TestHelper;
+import com.intel.jndn.utils.server.impl.SegmentedServerHelper;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.CompletableFuture;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+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.OnInterestCallback;
+import net.named_data.jndn.security.SecurityException;
+import org.junit.Test;
+
+/**
+ * Test AdvancedClient.java; requires a hostname to an NFD accepting a generated
+ * key to register prefixes, e.g. mvn test -Dnfd.ip=10.10.10.1
+ *
+ * @author Andrew Brown <andrew.brown@intel.com>
+ */
+public class AdvancedClientStressTestIT {
+
+  private static final Logger logger = Logger.getLogger(AdvancedClientStressTestIT.class.getName());
+  private static final Name PREFIX = new Name("/test/advanced-client").append(TestHelper.buildRandomString(10));
+  private static final int NUM_MESSAGES = 100;
+  private static final int MESSAGE_SIZE_BYTES = 10000;
+  private static final int SEGMENT_SIZE_BYTES = 5000;
+  private final TestHelper.NdnEnvironment environment;
+
+  public AdvancedClientStressTestIT() throws SecurityException {
+    String ip = System.getProperty("nfd.ip");
+    logger.info("Testing on NFD at: " + ip);
+    environment = TestHelper.buildTestEnvironment(ip, 2);
+  }
+
+  @Test
+  public void stressTest() throws Exception {
+    Face producer = environment.faces.get(0);
+    Face consumer = environment.faces.get(1);
+
+    producer.registerPrefix(PREFIX, new RandomDataServer(MESSAGE_SIZE_BYTES, SEGMENT_SIZE_BYTES), null);
+
+    // TODO this must be here until the prefix registration callback is complete
+    Thread.sleep(500);
+
+    long startTime = System.currentTimeMillis();
+    AdvancedClient client = new AdvancedClient();
+    List<CompletableFuture<Data>> requests = expressInterests(client, consumer, PREFIX, NUM_MESSAGES);
+    List<Data> datas = requests.stream().map((f) -> TestHelper.retrieve(f)).collect(Collectors.toList());
+    long endTime = System.currentTimeMillis();
+
+    logger.info(String.format("Transfered %d bytes in %d ms", MESSAGE_SIZE_BYTES * NUM_MESSAGES, endTime - startTime));
+  }
+
+  private List<CompletableFuture<Data>> expressInterests(Client client, Face face, Name name, int count) {
+    return IntStream.range(0, count).boxed().map((i) -> client.getAsync(face, name)).collect(Collectors.toList());
+  }
+
+  private class RandomDataServer implements OnInterestCallback {
+
+    private final int contentSize;
+    private final int segmentSize;
+
+    public RandomDataServer(int contentSize, int segmentSize) {
+      this.contentSize = contentSize;
+      this.segmentSize = segmentSize;
+    }
+
+    @Override
+    public void onInterest(Name prefix, Interest interest, Face face, long interestFilterId, InterestFilter filter) {
+      // ignore segmented requests, the data has already been put below
+      if (SegmentationHelper.isSegmented(interest.getName(), (byte) 0x00)) {
+        return;
+      }
+      
+      // randomly ignore 10% of requests
+      if (new Random().nextInt(10) < 2){
+        logger.info("Skipping an interest: " + interest.toUri());
+        return;
+      }
+
+      ByteArrayInputStream bytes = new ByteArrayInputStream(TestHelper.buildRandomString(contentSize).getBytes());
+      Data data = TestHelper.buildData(interest.getName(), "");
+      data.getMetaInfo().setFreshnessPeriod(0);
+
+      try {
+        for (Data segment : SegmentedServerHelper.segment(data, bytes, segmentSize)) {
+          logger.log(Level.INFO, "Put data: " + segment.getName().toUri());
+          face.putData(segment);
+        }
+      } catch (IOException ex) {
+        logger.log(Level.SEVERE, "Failed to put data.", ex);
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/intel/jndn/utils/client/impl/DefaultSegmentedClientTest.java b/src/test/java/com/intel/jndn/utils/client/impl/DefaultSegmentedClientTest.java
index 7ed72d4..2d65724 100644
--- a/src/test/java/com/intel/jndn/utils/client/impl/DefaultSegmentedClientTest.java
+++ b/src/test/java/com/intel/jndn/utils/client/impl/DefaultSegmentedClientTest.java
@@ -22,8 +22,6 @@
 import net.named_data.jndn.Interest;
 import net.named_data.jndn.Name;
 import static org.junit.Assert.assertEquals;
-
-import net.named_data.jndn.OnData;
 import org.junit.Test;
 
 /**
@@ -42,12 +40,9 @@
     Interest interest = new Interest(name);
     DataStream stream = instance.getSegmentsAsync(face, interest);
 
-    final TestCounter counter = new TestCounter();
-    stream.observe(new OnData() {
-      @Override
-      public void onData(Interest interest, Data data) {
-        counter.count++;
-      }
+    TestCounter counter = new TestCounter();
+    stream.observe((i, d) -> {
+      counter.count++;
     });
 
     for (Data segment : TestHelper.buildSegments(name, 0, 5)) {
@@ -82,12 +77,9 @@
     Interest interest = new Interest(name);
     DataStream stream = instance.getSegmentsAsync(face, interest);
 
-    final TestCounter counter = new TestCounter();
-    stream.observe(new OnData() {
-      @Override
-      public void onData(Interest interest, Data data) {
-        counter.count++;
-      }
+    TestCounter counter = new TestCounter();
+    stream.observe((i, d) -> {
+      counter.count++;
     });
 
     for (Data segment : TestHelper.buildSegments(name, 0, 5)) {
diff --git a/src/test/java/com/intel/jndn/utils/client/impl/SegmentedDataStreamTest.java b/src/test/java/com/intel/jndn/utils/client/impl/SegmentedDataStreamTest.java
index 9407cfc..2f165b9 100644
--- a/src/test/java/com/intel/jndn/utils/client/impl/SegmentedDataStreamTest.java
+++ b/src/test/java/com/intel/jndn/utils/client/impl/SegmentedDataStreamTest.java
@@ -20,7 +20,6 @@
 import net.named_data.jndn.Interest;
 import net.named_data.jndn.Name;
 import net.named_data.jndn.Name.Component;
-import net.named_data.jndn.OnData;
 import net.named_data.jndn.encoding.EncodingException;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
@@ -51,16 +50,13 @@
   public void testAddingUnorderedData() throws StreamException {
     Name name = new Name("/test/segmented/data/stream");
     Interest interest = new Interest(name);
-    final ArrayList<Long> segments = new ArrayList<>();
+    ArrayList<Long> segments = new ArrayList<>();
 
-    instance.observe(new OnData() {
-      @Override
-      public void onData(Interest i, Data d) {
-        try {
-          segments.add(d.getName().get(-1).toSegment());
-        } catch (EncodingException ex) {
-          throw new RuntimeException(ex);
-        }
+    instance.observe((i, d) -> {
+      try {
+        segments.add(d.getName().get(-1).toSegment());
+      } catch (EncodingException ex) {
+        throw new RuntimeException(ex);
       }
     });
 
@@ -103,10 +99,10 @@
   @Test
   public void testOrderedPackets() {
     int end = 10;
-    for (int i = 0; i < end; i++) {
+    IntStream.range(0, end).forEach((i) -> {
       addPacketToInstance(i);
       assertEquals(i, instance.current());
-    };
+    });
 
     assertEquals(end, instance.list().length);
   }
diff --git a/src/test/java/com/intel/jndn/utils/client/impl/SimpleClientTestIT.java b/src/test/java/com/intel/jndn/utils/client/impl/SimpleClientTestIT.java
new file mode 100644
index 0000000..f49525b
--- /dev/null
+++ b/src/test/java/com/intel/jndn/utils/client/impl/SimpleClientTestIT.java
@@ -0,0 +1,135 @@
+/*
+ * jndn-utils
+ * 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.utils.client.impl;
+
+import com.intel.jndn.utils.client.impl.SimpleClient;
+import com.intel.jndn.utils.TestHelper;
+import java.io.IOException;
+import java.util.concurrent.CompletableFuture;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+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.OnInterestCallback;
+import net.named_data.jndn.security.SecurityException;
+import net.named_data.jndn.util.Blob;
+import org.junit.Assert;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import org.junit.Test;
+
+/**
+ * Test SimpleClient.java; requires a hostname to an NFD accepting a generated
+ * key to register prefixes, e.g. mvn test -Dnfd.ip=10.10.10.1
+ *
+ * @author Andrew Brown <andrew.brown@intel.com>
+ */
+public class SimpleClientTestIT {
+
+  private static final Logger logger = Logger.getLogger(SimpleClientTestIT.class.getName());
+  private static final Name PREFIX_RETRIEVE = new Name("/test/simple-client/retrieve-one").append(TestHelper.buildRandomString(10));
+  private static final Name PREFIX_RETRIEVE_MULTIPLE = new Name("/test/simple-client/retrieve-multiple").append(TestHelper.buildRandomString(10));
+
+  SimpleClient instance;
+  private final TestHelper.NdnEnvironment environment;
+
+  public SimpleClientTestIT() throws SecurityException {
+    String ip = System.getProperty("nfd.ip");
+    environment = TestHelper.buildTestEnvironment(ip, 2);
+    instance = SimpleClient.getDefault();
+  }
+
+  @Test
+  public void testRetrieval() throws Exception {
+    // setup faces
+    Face producerFace = environment.faces.get(0);
+    Face consumerFace = environment.faces.get(1);
+
+    // setup server
+    Data servedData = new Data();
+    servedData.setContent(new Blob("....."));
+    servedData.getMetaInfo().setFreshnessPeriod(0);
+    producerFace.registerPrefix(PREFIX_RETRIEVE, new DataServer(servedData), null);
+
+    // TODO this must be here until the prefix registration callback is complete
+    Thread.sleep(500);
+
+    // send interest
+    CompletableFuture<Data> future = instance.getAsync(consumerFace, PREFIX_RETRIEVE);
+    Data retrievedData = future.get();
+
+    // verify
+    Assert.assertEquals(servedData.getContent().toString(), retrievedData.getContent().toString());
+  }
+
+  @Test
+  public void testSyncRetrieval() throws Exception {
+    String ip = System.getProperty("nfd.ip");
+    Face face = new Face(ip);
+    Interest interest = new Interest(new Name("/localhop/nfd/rib")); // this query should return some data if NFD is running locally
+    interest.setInterestLifetimeMilliseconds(2000);
+    Data data = SimpleClient.getDefault().getSync(face, interest);
+    assertNotNull(data);
+  }
+
+  @Test
+  public void testMultipleRetrieval() throws Exception {
+    int numInterests = 100;
+
+    // setup faces
+    Face producerFace = environment.faces.get(0);
+    Face consumerFace = environment.faces.get(1);
+
+    // setup server
+    Data servedData = new Data();
+    servedData.setContent(new Blob("0123456789"));
+    servedData.getMetaInfo().setFreshnessPeriod(0);
+    producerFace.registerPrefix(PREFIX_RETRIEVE_MULTIPLE, new DataServer(servedData), null);
+
+    // this must be here until the prefix registration callback is complete
+    Thread.sleep(500);
+
+    // request all packets
+    Stream<CompletableFuture<Data>> futures = IntStream.range(0, numInterests)
+            .boxed().map((i) -> instance.getAsync(consumerFace, PREFIX_RETRIEVE_MULTIPLE));
+
+    // check all returned packets
+    futures.map((f) -> TestHelper.retrieve(f))
+            .forEach((d) -> assertEquals(servedData.getContent().toString(), d.getContent().toString()));
+  }
+
+  private class DataServer implements OnInterestCallback {
+
+    private Data data;
+
+    public DataServer(Data data) {
+      this.data = data;
+    }
+
+    @Override
+    public void onInterest(Name prefix, Interest interest, Face face, long interestFilterId, InterestFilter filter) {
+      data.setName(interest.getName());
+      try {
+        face.putData(data);
+      } catch (IOException ex) {
+        logger.log(Level.SEVERE, "Failed to put data.", ex);
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/intel/jndn/utils/server/impl/SegmentedServerTestIT.java b/src/test/java/com/intel/jndn/utils/server/impl/SegmentedServerTestIT.java
new file mode 100644
index 0000000..a3409a3
--- /dev/null
+++ b/src/test/java/com/intel/jndn/utils/server/impl/SegmentedServerTestIT.java
@@ -0,0 +1,104 @@
+/*
+ * jndn-utils
+ * 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.utils.server.impl;
+
+import com.intel.jndn.mock.MockKeyChain;
+import com.intel.jndn.utils.TestHelper;
+import com.intel.jndn.utils.client.impl.AdvancedClient;
+import java.io.IOException;
+import java.util.logging.Logger;
+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.security.KeyChain;
+import net.named_data.jndn.security.SecurityException;
+import net.named_data.jndn.util.Blob;
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+/**
+ * Test the {@link SegmentedServer} on an actual NFD; to run this, pass the NFD
+ * IP/host name as a parameter like <code>-Dnfd.ip=10.1.1.1</code>.
+ *
+ * @author Andrew Brown <andrew.brown@intel.com>
+ */
+public class SegmentedServerTestIT {
+
+  private static final Logger logger = Logger.getLogger(SegmentedServerTestIT.class.getName());
+  private static final Name PREFIX = new Name("/test/for/segmented-server");
+  protected static final int DATA_SIZE_BYTES = 10000;
+  Face face;
+  SegmentedServer instance;
+  private String ip;
+
+  public SegmentedServerTestIT() throws SecurityException {
+    this.ip = System.getProperty("nfd.ip");
+    this.face = new Face(ip);
+    this.instance = new SegmentedServer(face, PREFIX);
+    KeyChain mockKeyChain = MockKeyChain.configure(new Name("/test/server"));
+    face.setCommandSigningInfo(mockKeyChain, mockKeyChain.getDefaultCertificateName());
+  }
+
+  @Test
+  public void testRegisterAndRetrieval() throws Exception {
+    final Name dataName = new Name(PREFIX).append("1");
+
+    // why a new thread? The server will only operate if someone turns the crank,
+    // i.e. someone calls face.processEvents() every so often. 
+    new Thread(new Runnable() {
+      @Override
+      public void run() {
+        try {
+          instance.serve(buildDataPacket(dataName));
+        } catch (IOException ex) {
+          logger.info("Failed to serve data.");
+        }
+
+        while (true) {
+          try {
+            face.processEvents();
+          } catch (IOException | EncodingException ex) {
+            logger.info("Failed while processing events.");
+          }
+        }
+      }
+    }).start();
+
+    // TODO why wait? we want to make sure the thread is running and that the prefix
+    // registration has succeeded on the NFD before we send interests
+    Thread.sleep(1000);
+
+    // why a different face? because we don't want the abover face.processEvents()
+    // to interfere with the SimpleClient's processEvents().
+    logger.info("Retrieving data: " + dataName.toUri());
+    Interest interest = new Interest(dataName);
+    interest.setInterestLifetimeMilliseconds(2000);
+    interest.setMustBeFresh(true);
+    interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
+
+    Data retrieved = AdvancedClient.getDefault().getSync(new Face(ip), interest);
+    assertNotNull(retrieved);
+    assertEquals(DATA_SIZE_BYTES, retrieved.getContent().size());
+    logger.info("Retrieved data: " + retrieved.getName().toUri());
+  }
+
+  Data buildDataPacket(Name name) {
+    Data data = new Data(new Name(name).appendSegment(0));
+    data.setContent(new Blob(TestHelper.buildRandomBytes(DATA_SIZE_BYTES)));
+    data.getMetaInfo().setFreshnessPeriod(30000);
+    return data;
+  }
+}