/* * A CCNx library test. * * Copyright (C) 2008-2012 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.repo; import static org.ccnx.ccn.profiles.CommandMarker.COMMAND_MARKER_BASIC_ENUMERATION; import java.io.IOException; import java.util.ArrayList; import java.util.Random; import org.ccnx.ccn.CCNContentHandler; import org.ccnx.ccn.CCNHandle; import org.ccnx.ccn.config.ConfigurationException; import org.ccnx.ccn.impl.support.Log; import org.ccnx.ccn.io.RepositoryOutputStream; import org.ccnx.ccn.profiles.CommandMarker; import org.ccnx.ccn.profiles.VersioningProfile; import org.ccnx.ccn.profiles.nameenum.BasicNameEnumeratorListener; import org.ccnx.ccn.profiles.nameenum.CCNNameEnumerator; import org.ccnx.ccn.protocol.ContentName; import org.ccnx.ccn.protocol.ContentObject; import org.ccnx.ccn.protocol.Exclude; import org.ccnx.ccn.protocol.Interest; import org.ccnx.ccn.protocol.MalformedContentNameStringException; import org.ccnx.ccn.test.AssertionCCNHandle; import org.junit.Assert; import org.junit.Test; /** * Part of repository test infrastructure. Test repository side of name enumeration. */ public class RepoNameEnumeratorTest implements BasicNameEnumeratorListener, CCNContentHandler { static final long WAIT_TIME = 500; CCNHandle getLibrary; CCNNameEnumerator getne; String prefix1String = RepoTestBase._globalPrefix+"/nameEnumerate"; //String prefix1String = "/repoTest/nameEnumerate"; ContentName prefix1; Random rand = new Random(); CCNHandle putLibrary; AssertionCCNHandle explicitExcludeHandle; ArrayList<ContentName> names1 = null; ArrayList<ContentName> names2 = null; ArrayList<ContentName> names3 = null; @Test public void repoNameEnumerationTest(){ Log.info(Log.FAC_TEST, "Starting repoNameEnumerationTest"); setHandles(); prefix1String += "-" + rand.nextInt(10000); Log.info(Log.FAC_TEST, "adding name1 to repo"); addContentToRepo(prefix1String+"/name1"); Log.info(Log.FAC_TEST, "test register prefix"); testRegisterPrefix(); Log.info(Log.FAC_TEST, "checking for first response"); testGetResponse(1); Log.info(Log.FAC_TEST, "adding second name to repo"); addContentToRepo(prefix1String+"/name2"); //make sure we get the new thing Log.info(Log.FAC_TEST, "checking for second name added"); testGetResponse(2); //make sure nothing new came in Log.info(Log.FAC_TEST, "check to make sure nothing new came in"); testGetResponse(3); Log.info(Log.FAC_TEST, "test a cancelPrefix"); testCancelPrefix(); Log.info(Log.FAC_TEST, "now add third thing"); addContentToRepo(prefix1String+"/name3"); //make sure we don't hear about this one Log.info(Log.FAC_TEST, "called cancel, shouldn't hear about the third item"); testGetResponse(3); Log.info(Log.FAC_TEST, "now testing with a version in the prefix"); ContentName versionedName = getVersionedName(prefix1String); addContentToRepo(new ContentName(versionedName, "versionNameTest")); registerPrefix(versionedName); testGetResponse(4); closeHandles(); Log.info(Log.FAC_TEST, "Completed repoNameEnumerationTest"); } private ContentName getVersionedName(String name){ try { return VersioningProfile.addVersion(ContentName.fromNative(name)); } catch (MalformedContentNameStringException e) { Assert.fail("could not create versioned name for prefix: "+name); } return null; } private void addContentToRepo(ContentName name){ try{ RepositoryOutputStream ros = new RepositoryOutputStream(name, putLibrary); ros.setTimeout(5000); byte [] data = "Testing 1 2 3".getBytes(); ros.write(data, 0, data.length); ros.close(); } catch (IOException ex) { Log.warningStackTrace(Log.FAC_TEST, ex); Assert.fail("could not put the content into the repo ("+name+"); " + ex.getMessage()); } } private void addContentToRepo(String contentName){ //method to load something to repo for testing ContentName name; try { name = ContentName.fromNative(contentName); addContentToRepo(name); } catch (MalformedContentNameStringException e) { Log.warningStackTrace(Log.FAC_TEST, e); Assert.fail("Could not create content name from String."); } } public int handleNameEnumerator(ContentName prefix, ArrayList<ContentName> names) { Log.info("I got a response from the name enumerator, with " + names.size() + " entries."); if (names1 == null) names1 = names; else if (names2 == null) names2 = names; else names3 = names; return 0; } /* * function to open and set the put and get libraries * also creates and sets the Name Enumerator Objects * */ public void setHandles(){ try { getLibrary = CCNHandle.open(); getne = new CCNNameEnumerator(getLibrary, this); putLibrary = CCNHandle.open(); } catch (ConfigurationException e) { e.printStackTrace(); Assert.fail("Failed to open libraries for tests"); } catch (IOException e) { Log.warningStackTrace(Log.FAC_TEST, e); Assert.fail("Failed to open libraries for tests"); } } public void closeHandles() { getLibrary.close(); putLibrary.close(); } public void testRegisterPrefix(){ //adding a second prefix... should never get a response, prefix1 = registerPrefix(prefix1String); registerPrefix(prefix1String+"/doesnotexist"); } public void registerPrefix(ContentName prefix){ try { getne.registerPrefix(prefix); } catch (IOException e) { System.err.println("error registering prefix"); Log.warningStackTrace(Log.FAC_TEST, e); Assert.fail("error registering prefix"); } } public ContentName registerPrefix(String pre){ try { ContentName p = ContentName.fromNative(pre); registerPrefix(p); return p; } catch (Exception e) { Assert.fail("Could not create ContentName from "+prefix1String); } return null; } public void testCancelPrefix(){ getne.cancelPrefix(prefix1); } public void testGetResponse(int count){ try { int i = 0; while (i < 500) { Thread.sleep(rand.nextInt(50)); i++; //break out early if possible if ( (count == 1 && names1!=null) || (count == 2 && names2!=null) || (count == 4 && names3!=null) ) break; } //the names are registered... System.out.println("done waiting for response: count is "+count+" i="+i); } catch (InterruptedException e) { Log.warning(Log.FAC_TEST, "error waiting for names to be registered by name enumeration responder"); Assert.fail(); } if (count == 1) { Assert.assertNotNull(names1); Log.info(Log.FAC_TEST, "names1 size = "+names1.size()); for (ContentName s: names1) Log.info(s.toString()); Assert.assertTrue(names1.size()==1); Assert.assertTrue(names1.get(0).toString().equals("/name1")); Assert.assertNull(names2); Assert.assertNull(names3); } else if (count == 2) { Assert.assertNotNull(names2); Log.info(Log.FAC_TEST, "names2 size = "+names2.size()); for (ContentName s: names2) Log.info(Log.FAC_TEST, s.toString()); Assert.assertTrue(names2.size()==2); Assert.assertTrue((names2.get(0).toString().equals("/name1") && names2.get(1).toString().equals("/name2")) || (names2.get(0).toString().equals("/name2") && names2.get(1).toString().equals("/name1"))); //not guaranteed to be in this order! //Assert.assertTrue(names2.get(0).toString().equals("/name1")); //Assert.assertTrue(names2.get(1).toString().equals("/name2")); Assert.assertNull(names3); } else if (count == 3) { if (names3 != null) { Assert.assertTrue(names2.size()==2); Assert.assertTrue((names2.get(0).toString().equals("/name1") && names2.get(1).toString().equals("/name2")) || (names2.get(0).toString().equals("/name2") && names2.get(1).toString().equals("/name1"))); } } else if (count==4) { Assert.assertNotNull(names3); Log.info(Log.FAC_TEST, "names3 size = "+names3.size()); for (ContentName s: names3) Log.info(Log.FAC_TEST, s.toString()); } } int contentReceived = 0; ContentName repoID = null; @Test public void explicitExcludeFastResponseTest(){ Log.info(Log.FAC_TEST, "Completed explicitExcludeFastResponseTest"); ContentName prefixMarked = new ContentName(COMMAND_MARKER_BASIC_ENUMERATION); //we have minSuffixComponents to account for sig, version, seg and digest Interest pi = Interest.constructInterest(prefixMarked, null, null, null, 4, null); try { explicitExcludeHandle = AssertionCCNHandle.open(); explicitExcludeHandle.expressInterest(pi, this); } catch (IOException e) { Assert.fail("Error expressing explicit interest: "+e.getMessage()); } catch (ConfigurationException e) { Assert.fail("could not create handle for test"); } try { int i = 0; while (i < 500) { Thread.sleep(50); i++; explicitExcludeHandle.checkError(0); //break out early if possible if ( contentReceived > 0) break; } //the names are registered... System.out.println("received a response"); } catch (InterruptedException e) { System.err.println("error waiting for explicit NE response."); Assert.fail(); } //now express interest excluding the repo //interest expressed in handleContent... try { int i = 0; while (i < 500) { Thread.sleep(rand.nextInt(50)); i++; explicitExcludeHandle.checkError(0); //break out early if possible if ( contentReceived == 2) Assert.fail("received a response from the repo!"); } //no response when I shouldn't have gotten one! } catch (InterruptedException e) { System.err.println("error waiting for explicit NE response."); Assert.fail(); } explicitExcludeHandle.close(); Log.info(Log.FAC_TEST, "Completed explicitExcludeFastResponseTest"); } boolean firstResponse = true; public Interest handleContent(ContentObject data, Interest interest) { ContentName responseName = null; ContentName name = data.name(); if (interest.exclude()!=null) { Assert.assertFalse(firstResponse); Assert.fail("responseName is null, this is not the first response and it should not be null"); } else { firstResponse = false; } //for now, this is copied from CCNNameEnumerator.getIDFromName should be refactored so it isn't manually copied. try { int index = name.containsWhere(CommandMarker.COMMAND_MARKER_BASIC_ENUMERATION.getBytes()); ContentName prefix = name.subname(index+1, name.count()); if(VersioningProfile.hasTerminalVersion(prefix)) responseName = VersioningProfile.cutLastVersion(prefix); else responseName = prefix; Log.finest(Log.FAC_TEST, "NameEnumeration response ID: {0}", responseName); } catch(Exception e) { Assert.fail("failed to get repo id from NE response: "+e.getMessage()); } Exclude excludes = interest.exclude(); if(excludes==null) excludes = new Exclude(); excludes.add(new byte[][]{responseName.component(0)}); Interest newInterest = Interest.constructInterest(interest.name(), excludes, null, null, 4, null); contentReceived++; return newInterest; } }