/*
* A CCNx library test.
*
* Copyright (C) 2008, 2009, 2010, 2011 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.util.TreeSet;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import org.ccnx.ccn.CCNFilterListener;
import org.ccnx.ccn.CCNInterestListener;
import org.ccnx.ccn.impl.CCNNetworkManager.NetworkProtocol;
import org.ccnx.ccn.impl.support.Log;
import org.ccnx.ccn.io.CCNWriter;
import org.ccnx.ccn.profiles.SegmentationProfile;
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.
*
* This should eventually have more tests
*
* 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;
private Semaphore sema = new Semaphore(0);
private Semaphore filterSema = new Semaphore(0);
private boolean gotData = false;
private boolean gotInterest = false;
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.setLevel(Log.FAC_NETMANAGER, Level.FINEST);
TestFilterListener tfl = new TestFilterListener();
TestListener tl = new TestListener();
ContentName testName1 = ContentName.fromNative(testPrefix, "foo");
Interest interest1 = new Interest(testName1);
ContentName testName2 = ContentName.fromNative(testName1, "bar"); // /foo/bar
Interest interest2 = new Interest(testName2);
ContentName testName3 = ContentName.fromNative(testName2, "blaz"); // /foo/bar/blaz
ContentName testName4 = ContentName.fromNative(testName2, "xxx"); // /foo/bar/xxx
Interest interest4 = new Interest(testName4);
ContentName testName5 = ContentName.fromNative(testPrefix, "zoo"); // /zoo
ContentName testName6 = ContentName.fromNative(testName1, "zoo"); // /foo/zoo
ContentName testName7 = ContentName.fromNative(testName2, "spaz"); // /foo/bar/spaz
Interest interest6 = new Interest(testName6);
// Test that we don't receive interests above what we registered
gotInterest = false;
putHandle.getNetworkManager().setInterestFilter(this, testName2, tfl);
Thread.sleep(1000);
Assert.assertFalse(gotInterest);
getHandle.cancelInterest(interest1, tl);
getHandle.expressInterest(interest2, tl);
filterSema.tryAcquire(WAIT_MILLIS, TimeUnit.MILLISECONDS);
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.getNetworkManager().setInterestFilter(this, testName3, tfl);
putHandle.getNetworkManager().setInterestFilter(this, testName4, tfl);
putHandle.getNetworkManager().setInterestFilter(this, testName5, tfl);
putHandle.getNetworkManager().setInterestFilter(this, testName2, tfl);
putHandle.getNetworkManager().setInterestFilter(this, testName1, tfl);
// The following is to make sure that a filter that is a prefix of a registered filter
// doesn't get registered separately. There's no good way to test this directly (I don't think)
// currently but we can see that it is done by checking out the log
putHandle.getNetworkManager().setInterestFilter(this, testName7, tfl);
getHandle.expressInterest(interest4, tl);
filterSema.tryAcquire(WAIT_MILLIS, TimeUnit.MILLISECONDS);
Assert.assertTrue(gotInterest);
getHandle.cancelInterest(interest4, tl);
gotInterest = false;
filterSema.drainPermits();
getHandle.expressInterest(interest6, tl);
filterSema.tryAcquire(WAIT_MILLIS, TimeUnit.MILLISECONDS);
Assert.assertTrue(gotInterest);
getHandle.cancelInterest(interest6, tl);
putHandle.getNetworkManager().cancelInterestFilter(this, testName1, tfl);
putHandle.getNetworkManager().cancelInterestFilter(this, testName2, tfl);
putHandle.getNetworkManager().cancelInterestFilter(this, testName3, tfl);
putHandle.getNetworkManager().cancelInterestFilter(this, testName5, tfl);
// Test that nothing after / is registered. Need to examine logs to ensure this is
// done correctly.
ContentName slashName = ContentName.fromNative("/");
putHandle.getNetworkManager().setInterestFilter(this, testName1, tfl);
putHandle.getNetworkManager().setInterestFilter(this, slashName, tfl);
putHandle.getNetworkManager().setInterestFilter(this, testName5, tfl);
putHandle.getNetworkManager().cancelInterestFilter(this, testName1, tfl);
putHandle.getNetworkManager().cancelInterestFilter(this, slashName, tfl);
putHandle.getNetworkManager().cancelInterestFilter(this, testName5, tfl);
}
@Test
public void testNetworkManager() throws Exception {
/*
* Test re-expression of interest
*/
CCNWriter writer = new CCNWriter(testPrefix, putHandle);
ContentName testName = ContentName.fromNative(testPrefix, "aaa");
testInterest = new Interest(testName);
TestListener tl = new TestListener();
getHandle.expressInterest(testInterest, tl);
Thread.sleep(80);
writer.put(testName, "aaa");
sema.tryAcquire(WAIT_MILLIS, TimeUnit.MILLISECONDS);
Assert.assertTrue(gotData);
}
@Test
public void testNetworkManagerFixedPrefix() throws Exception {
CCNWriter writer = new CCNWriter(putHandle);
ContentName testName = ContentName.fromNative(testPrefix, "ddd");
testInterest = new Interest(testName);
TestListener tl = new TestListener();
getHandle.expressInterest(testInterest, tl);
Thread.sleep(80);
writer.put(testName, "ddd");
sema.tryAcquire(WAIT_MILLIS, TimeUnit.MILLISECONDS);
Assert.assertTrue(gotData);
}
@Test
public void testNetworkManagerBackwards() throws Exception {
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 = ContentName.fromNative(testPrefix, "bbb");
testInterest = new Interest(testName);
TestListener tl = new TestListener();
writer.put(testName, "bbb");
Thread.sleep(80);
getHandle.expressInterest(testInterest, tl);
sema.tryAcquire(WAIT_MILLIS, TimeUnit.MILLISECONDS);
Assert.assertTrue(gotData);
}
@Test
public void testFreshnessSeconds() throws Exception {
CCNWriter writer = new CCNWriter(testPrefix, putHandle);
writer.disableFlowControl();
ContentName testName = ContentName.fromNative(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);
}
@Test
public void testInterestReexpression() throws Exception {
/*
* Test re-expression of interest
*/
CCNWriter writer = new CCNWriter(testPrefix, putHandle);
ContentName testName = ContentName.fromNative(testPrefix, "ccc");
testInterest = new Interest(testName);
TestListener tl = new TestListener();
getHandle.expressInterest(testInterest, tl);
// Sleep long enough that the interest must be re-expressed
Thread.sleep(WAIT_MILLIS);
writer.put(testName, "ccc");
sema.tryAcquire(WAIT_MILLIS, TimeUnit.MILLISECONDS);
Assert.assertTrue(gotData);
}
/**
* Test flooding the system with a bunch of content. Only works for TCP
* @throws Exception
*/
@Test
public void testFlood() throws Exception {
if (getHandle.getNetworkManager().getProtocol() == NetworkProtocol.TCP) {
System.out.println("Testing TCP flooding");
TreeSet<ContentObject> cos = new TreeSet<ContentObject>();
for (int i = 0; i < FLOOD_ITERATIONS; i++) {
ContentName name = ContentName.fromNative(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(ContentName.fromNative(testPrefix, new Integer(i).toString()), 2000);
Assert.assertNotNull(co);
}
}
}
class TestFilterListener implements CCNFilterListener {
public boolean handleInterest(Interest interest) {
gotInterest = true;
filterSema.release();
return true;
}
}
class TestListener implements CCNInterestListener {
public Interest handleContent(ContentObject co,
Interest interest) {
Assert.assertFalse(co == null);
ContentName nameBase = SegmentationProfile.segmentRoot(co.name());
Assert.assertEquals(nameBase.stringComponent(nameBase.count()-1), new String(co.content()));
gotData = true;
sema.release();
/*
* Test call of cancel in handler doesn't hang
*/
getHandle.cancelInterest(testInterest, this);
return null;
}
}
}