/* * A CCNx library test. * * Copyright (C) 2008-2013 Palo Alto Research Center, Inc. * * This work is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. * This work is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ package org.ccnx.ccn.test.impl; import java.io.IOException; import java.util.ArrayList; import java.util.TreeSet; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import org.ccnx.ccn.CCNContentHandler; import org.ccnx.ccn.CCNInterestHandler; import org.ccnx.ccn.config.SystemConfiguration; import org.ccnx.ccn.impl.CCNNetworkManager.NetworkProtocol; import org.ccnx.ccn.impl.support.Log; import org.ccnx.ccn.io.CCNWriter; import org.ccnx.ccn.protocol.ContentName; import org.ccnx.ccn.protocol.ContentObject; import org.ccnx.ccn.protocol.Interest; import org.ccnx.ccn.test.CCNTestBase; import org.ccnx.ccn.test.CCNTestHelper; import org.junit.AfterClass; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; /** * Test CCNNetworkManager. * * Note - this test requires ccnd to be running * */ public class NetworkTest extends CCNTestBase { protected static final int WAIT_MILLIS = 8000; protected static final int FLOOD_ITERATIONS = 1000; protected static final int TEST_TIMEOUT = SystemConfiguration.MEDIUM_TIMEOUT; protected static final int CANCEL_TEST_TIMEOUT = 100; private final Semaphore sema = new Semaphore(0); private final Semaphore filterSema = new Semaphore(0); private final Semaphore cancelSema = new Semaphore(1); private boolean gotData = false; private boolean gotInterest = false; private boolean cancelWait = false; private final Object cancelLock = new Object(); Interest testInterest = null; // Fix test so it doesn't use static names. static CCNTestHelper testHelper = new CCNTestHelper(NetworkTest.class); static ContentName testPrefix = testHelper.getClassChildName("networkTest"); @BeforeClass public static void setUpBeforeClass() throws Exception { CCNTestBase.setUpBeforeClass(); } @AfterClass public static void tearDownAfterClass() throws Exception { CCNTestBase.tearDownAfterClass(); } @Before public void setUp() throws Exception { } /** * Partially test prefix registration/deregistration * @throws Exception */ @Test public void testRegisteredPrefix() throws Exception { Log.info(Log.FAC_TEST, "Starting testRegisteredPrefix"); TestInterestHandler tfl = new TestInterestHandler(); TestContentHandler tl = new TestContentHandler(); ContentName testName1 = new ContentName(testPrefix, "foo"); Interest interest1 = new Interest(testName1); ContentName testName2 = new ContentName(testName1, "bar"); // /foo/bar Interest interest2 = new Interest(testName2); ContentName testName3 = new ContentName(testName2, "blaz"); // /foo/bar/blaz ContentName testName4 = new ContentName(testName2, "xxx"); // /foo/bar/xxx Interest interest4 = new Interest(testName4); ContentName testName5 = new ContentName(testPrefix, "zoo"); // /zoo ContentName testName6 = new ContentName(testName1, "zoo"); // /foo/zoo ContentName testName7 = new ContentName(testName2, "spaz"); // /foo/bar/spaz Interest interest6 = new Interest(testName6); // Test that we don't receive interests above what we registered gotInterest = false; putHandle.registerFilter(testName2, tfl); getHandle.expressInterest(interest1, tl); Assert.assertFalse(gotInterest); getHandle.cancelInterest(interest1, tl); getHandle.expressInterest(interest2, tl); Assert.assertTrue("Couldn't get semaphore", filterSema.tryAcquire(WAIT_MILLIS, TimeUnit.MILLISECONDS)); getHandle.checkError(TEST_TIMEOUT); Assert.assertTrue(gotInterest); getHandle.cancelInterest(interest2, tl); // Test that an "in-between" prefix gets registered properly gotInterest = false; putHandle.getNetworkManager().cancelInterestFilter(this, testName2, tfl); putHandle.registerFilter(testName3, tfl); putHandle.registerFilter(testName4, tfl); putHandle.registerFilter(testName5, tfl); putHandle.registerFilter(testName2, tfl); putHandle.registerFilter(testName1, tfl); gotInterest = false; filterSema.drainPermits(); getHandle.expressInterest(interest6, tl); Assert.assertTrue("Couldn't acquire semaphore", filterSema.tryAcquire(WAIT_MILLIS, TimeUnit.MILLISECONDS)); getHandle.checkError(TEST_TIMEOUT); Assert.assertTrue(gotInterest); getHandle.cancelInterest(interest6, tl); // Make sure that a filter that is a prefix of a registered filter // doesn't get registered separately. gotInterest = false; filterSema.drainPermits(); putHandle.registerFilter(testName7, tfl); ArrayList<ContentName> prefixes = putHandle.getNetworkManager().getRegisteredPrefixes(); Assert.assertFalse(prefixes.contains(testName7)); getHandle.expressInterest(interest4, tl); Assert.assertTrue("Couldn't acquire semaphore", filterSema.tryAcquire(WAIT_MILLIS, TimeUnit.MILLISECONDS)); getHandle.checkError(TEST_TIMEOUT); Assert.assertTrue(gotInterest); getHandle.cancelInterest(interest4, tl); gotInterest = false; filterSema.drainPermits(); getHandle.expressInterest(interest6, tl); Assert.assertTrue("Couldn't acquire semaphore", filterSema.tryAcquire(WAIT_MILLIS, TimeUnit.MILLISECONDS)); getHandle.checkError(TEST_TIMEOUT); Assert.assertTrue(gotInterest); getHandle.cancelInterest(interest6, tl); putHandle.unregisterFilter(testName1, tfl); putHandle.unregisterFilter(testName2, tfl); putHandle.unregisterFilter(testName3, tfl); putHandle.unregisterFilter(testName5, tfl); putHandle.unregisterFilter(testName7, tfl); // Make sure nothing is registered after a / ContentName slashName = ContentName.fromNative("/"); putHandle.registerFilter(testName1, tfl); putHandle.registerFilter(slashName, tfl); putHandle.registerFilter(testName5, tfl); prefixes = putHandle.getNetworkManager().getRegisteredPrefixes(); Assert.assertFalse(prefixes.contains(testName5)); putHandle.unregisterFilter(testName1, tfl); putHandle.unregisterFilter(slashName, tfl); putHandle.unregisterFilter(testName5, tfl); Log.info(Log.FAC_TEST, "Completed testRegisteredPrefix"); } @Test public void testNetworkManager() throws Exception { Log.info(Log.FAC_TEST, "Starting testNetworkManager"); /* * Test re-expression of interest */ CCNWriter writer = new CCNWriter(testPrefix, putHandle); ContentName testName = new ContentName(testPrefix, "aaa"); testInterest = new Interest(testName); TestContentHandler tl = new TestContentHandler(); getHandle.expressInterest(testInterest, tl); writer.put(testName, "aaa"); Assert.assertTrue("Couldn't acquire semaphore", sema.tryAcquire(WAIT_MILLIS, TimeUnit.MILLISECONDS)); getHandle.checkError(0); Assert.assertTrue(gotData); writer.close(); Log.info(Log.FAC_TEST, "Completed testNetworkManager"); } @Test public void testNetworkManagerFixedPrefix() throws Exception { Log.info(Log.FAC_TEST, "Starting testNetworkManagerFixedPrefix"); CCNWriter writer = new CCNWriter(putHandle); ContentName testName = new ContentName(testPrefix, "ddd"); testInterest = new Interest(testName); TestContentHandler tl = new TestContentHandler(); getHandle.expressInterest(testInterest, tl); writer.put(testName, "ddd"); Assert.assertTrue("Couldn't acquire semaphore", sema.tryAcquire(WAIT_MILLIS, TimeUnit.MILLISECONDS)); Assert.assertTrue(gotData); writer.close(); Log.info(Log.FAC_TEST, "Completed testNetworkManagerFixedPrefix"); } @Test public void testNetworkManagerBackwards() throws Exception { Log.info(Log.FAC_TEST, "Starting testNetworkManagerBackwards"); CCNWriter writer = new CCNWriter(testPrefix, putHandle); // Shouldn't have to do this -- need to refactor test. Had to add it after // fixing CCNWriter to do proper flow control. writer.disableFlowControl(); ContentName testName = new ContentName(testPrefix, "bbb"); testInterest = new Interest(testName); TestContentHandler tl = new TestContentHandler(); writer.put(testName, "bbb"); getHandle.expressInterest(testInterest, tl); Assert.assertTrue("Couldn't acquire semaphore", sema.tryAcquire(WAIT_MILLIS, TimeUnit.MILLISECONDS)); getHandle.checkError(0); Assert.assertTrue(gotData); writer.close(); Log.info(Log.FAC_TEST, "Completed testNetworkManagerBackwards"); } @Test public void testFreshnessSeconds() throws Exception { Log.info(Log.FAC_TEST, "Starting testFreshnessSeconds"); CCNWriter writer = new CCNWriter(testPrefix, putHandle); writer.disableFlowControl(); ContentName testName = new ContentName(testPrefix, "freshnessTest"); writer.put(testName, "freshnessTest", 3); Thread.sleep(80); ContentObject co = getHandle.get(testName, 1000); Assert.assertFalse(co == null); Thread.sleep(WAIT_MILLIS); co = getHandle.get(testName, 1000); Assert.assertTrue(co == null); writer.close(); Log.info(Log.FAC_TEST, "Completed testFreshnessSeconds"); } @Test public void testInterestReexpression() throws Exception { Log.info(Log.FAC_TEST, "Starting testInterestReexpression"); /* * Test re-expression of interest */ CCNWriter writer = new CCNWriter(testPrefix, putHandle); ContentName testName = new ContentName(testPrefix, "ccc"); testInterest = new Interest(testName); TestContentHandler tl = new TestContentHandler(); getHandle.expressInterest(testInterest, tl); // Sleep long enough that the interest must be re-expressed Thread.sleep(WAIT_MILLIS); writer.put(testName, "ccc"); Assert.assertTrue("Couldn't acquire semaphore", sema.tryAcquire(WAIT_MILLIS, TimeUnit.MILLISECONDS)); getHandle.checkError(0); Assert.assertTrue(gotData); writer.close(); Log.info(Log.FAC_TEST, "Completed testInterestReexpression"); } /** * Test flooding the system with a bunch of content. Only works for TCP * @throws Exception */ @Test public void testFlood() throws Exception { Log.info(Log.FAC_TEST, "Starting testFlood"); if (getHandle.getNetworkManager().getProtocol() == NetworkProtocol.TCP) { TreeSet<ContentObject> cos = new TreeSet<ContentObject>(); for (int i = 0; i < FLOOD_ITERATIONS; i++) { ContentName name = new ContentName(testPrefix, (new Integer(i)).toString()); cos.add(ContentObject.buildContentObject(name, new byte[]{(byte)i})); } for (ContentObject co : cos) putHandle.put(co); for (int i = 0; i < FLOOD_ITERATIONS; i++) { ContentObject co = getHandle.get(new ContentName(testPrefix, new Integer(i).toString()), 2000); Assert.assertNotNull("Failed in flood after " + i + " iterations", co); } } Log.info(Log.FAC_TEST, "Completed testFlood"); } /** * Test that when we cancel an interest and the interest is satisfied during the cancel, side affects * from handling the interest are not allowed to keep the interest alive. * * @throws Exception */ @Test public void testCancelAtomicity() throws Exception { CancelTestInterestHandler ctih = new CancelTestInterestHandler(); CancelTestContentHandler ctch = new CancelTestContentHandler(); cancelSema.acquire(); putHandle.registerFilter(testPrefix, ctih); Interest interest = new Interest(testPrefix); getHandle.expressInterest(interest, ctch); putHandle.checkError(CANCEL_TEST_TIMEOUT); getHandle.checkError(CANCEL_TEST_TIMEOUT); Assert.assertTrue(cancelSema.tryAcquire(TEST_TIMEOUT, TimeUnit.MILLISECONDS)); synchronized (cancelLock) { cancelWait = true; } gotData = false; getHandle.cancelInterest(interest, ctch); cancelSema.release(); putHandle.checkError(CANCEL_TEST_TIMEOUT); Assert.assertFalse("Interest was totally cancelled", gotData); } class TestInterestHandler implements CCNInterestHandler { public boolean handleInterest(Interest interest) { gotInterest = true; filterSema.release(); return true; } } class TestContentHandler implements CCNContentHandler { public Interest handleContent(ContentObject co, Interest interest) { Assert.assertFalse(co == null); gotData = true; sema.release(); /* * Test call of cancel in handler doesn't hang */ getHandle.cancelInterest(interest, this); return null; } } class CancelTestInterestHandler implements CCNInterestHandler { CCNWriter writer = null; ContentName testName = new ContentName(testPrefix, "cancelTest"); private CancelTestInterestHandler() throws IOException { writer = new CCNWriter(testName, putHandle); writer.disableFlowControl(); } public boolean handleInterest(Interest interest) { gotInterest = true; try { writer.put(testName, "Cancel Atomicity Test"); } catch (Exception e) { Assert.fail(e.getMessage()); } return false; } } class CancelTestContentHandler implements CCNContentHandler { public Interest handleContent(ContentObject data, Interest interest) { gotData = true; cancelSema.release(); int timeToWait = TEST_TIMEOUT; while (!cancelWait && timeToWait > 0) { try { Thread.sleep(50); timeToWait -=50; } catch (InterruptedException e) { break; } } try { Assert.assertTrue(cancelSema.tryAcquire(TEST_TIMEOUT, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { Assert.fail(e.getMessage()); } return interest; } } }