/* * 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 java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import org.ccnx.ccn.CCNHandle; import org.ccnx.ccn.impl.CCNFlowControl.SaveType; import org.ccnx.ccn.impl.repo.BasicPolicy; import org.ccnx.ccn.impl.repo.PolicyXML; import org.ccnx.ccn.impl.repo.PolicyXML.PolicyObject; import org.ccnx.ccn.impl.support.Log; import org.ccnx.ccn.io.CCNInputStream; import org.ccnx.ccn.io.CCNOutputStream; import org.ccnx.ccn.io.CCNVersionedInputStream; import org.ccnx.ccn.io.CCNVersionedOutputStream; import org.ccnx.ccn.io.RepositoryOutputStream; import org.ccnx.ccn.io.RepositoryVersionedOutputStream; import org.ccnx.ccn.io.content.CCNStringObject; import org.ccnx.ccn.io.content.Link; import org.ccnx.ccn.io.content.Link.LinkObject; import org.ccnx.ccn.profiles.SegmentationProfile; import org.ccnx.ccn.profiles.ccnd.CCNDCacheManager; import org.ccnx.ccn.profiles.repo.RepositoryControl; import org.ccnx.ccn.protocol.ContentName; import org.ccnx.ccn.protocol.KeyLocator; import org.ccnx.ccn.protocol.MalformedContentNameStringException; import org.ccnx.ccn.test.CCNTestHelper; import org.ccnx.ccn.test.Flosser; import org.ccnx.ccn.utils.CreateUserData; import org.junit.AfterClass; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; /** * Part of repository test infrastructure. Requires at least repository to be running, * and RFSTest to have been run. */ public class RepoIOTest extends RepoTestBase { protected static final int CACHE_CLEAR_TIMEOUT = 10000; protected static CCNTestHelper testHelper = new CCNTestHelper(RepoIOTest.class); protected static String _repoTestDir = "repotest"; protected static byte [] data = new byte[4000]; // Test stream and net object names for content written into repo before all test cases // Note these have random numbers added in initialization protected static ContentName _testPrefix; protected static String _testStream = "stream"; protected static String _testObj = "obj"; // Test stream and net object names for content not in repo before test cases protected static String _testNonRepo = "stream-nr"; protected static String _testNonRepoObj = "obj-nr"; protected static String _testLink = "link"; protected static CCNDCacheManager _cacheManager = new CCNDCacheManager(); protected static ContentName _keyNameForStream; protected static ContentName _keyNameForObj; static String USER_NAMESPACE = "TestRepoUser"; @BeforeClass public static void setUpBeforeClass() throws Exception { RepoTestBase.setUpBeforeClass(); _testPrefix = testHelper.getTestNamespace("testRepoIO"); _testStream += "-" + rand.nextInt(10000); _testObj += "-" + rand.nextInt(10000); byte value = 1; for (int i = 0; i < data.length; i++) data[i] = value++; RepositoryOutputStream ros = new RepositoryOutputStream(new ContentName(_testPrefix, _testStream), putHandle); ros.setBlockSize(100); ros.setTimeout(4000); ros.write(data, 0, data.length); ros.close(); CCNStringObject so = new CCNStringObject(new ContentName(_testPrefix, _testObj), "Initial string value", SaveType.REPOSITORY, putHandle); so.save(); // Floss content into ccnd for tests involving content not already in repo when we start Flosser floss = new Flosser(); // Floss user based keys from CreateUserData floss.handleNamespace(testHelper.getClassChildName(USER_NAMESPACE) + "/" + CreateUserData.USER_NAMES[0]); floss.handleNamespace(testHelper.getClassChildName(USER_NAMESPACE) + "/" + CreateUserData.USER_NAMES[1]); // So we can test saving keys in the sync tests we build our first sync object (a stream) with // an alternate key and the second one (a CCNNetworkObject) with an alternate key locater that is // accessed through a link. CreateUserData testUsers = new CreateUserData(testHelper.getClassChildName(USER_NAMESPACE), 2, false, null); String [] userNames = testUsers.friendlyNames().toArray(new String[2]); CCNHandle userHandle = testUsers.getHandleForUser(userNames[0]); // Build the link and the key it links to. Floss these into ccnd. _testNonRepo += "-" + rand.nextInt(10000); _testNonRepoObj += "-" + rand.nextInt(10000); _testLink += "-" + rand.nextInt(10000); ContentName name = new ContentName(_testPrefix, _testNonRepo); floss.handleNamespace(name); CCNOutputStream cos = new CCNOutputStream(name, userHandle); cos.setBlockSize(100); cos.setTimeout(4000); cos.write(data, 0, data.length); _keyNameForStream = cos.getFirstSegment().signedInfo().getKeyLocator().name().name(); cos.close(); CCNHandle userHandle2 = testUsers.getHandleForUser(userNames[1]); KeyLocator userLocator = userHandle2.keyManager().getKeyLocator(userHandle2.keyManager().getDefaultKeyID()); Link link = new Link(userLocator.name().name()); ContentName linkName = new ContentName(_testPrefix, _testLink); LinkObject lo = new LinkObject(linkName, link, SaveType.RAW, putHandle); floss.handleNamespace(lo.getBaseName()); lo.save(); KeyLocator linkLocator = new KeyLocator(linkName); userHandle2.keyManager().setKeyLocator(null, linkLocator); name = new ContentName(_testPrefix, _testNonRepoObj); floss.handleNamespace(name); so = new CCNStringObject(name, "String value for non-repo obj", SaveType.RAW, userHandle2); so.save(); _keyNameForObj = so.getFirstSegment().signedInfo().getKeyLocator().name().name(); lo.close(); so.close(); floss.stop(); } @AfterClass public static void cleanup() throws Exception { } @Before public void setUp() throws Exception { } @Test public void testPolicyViaCCN() throws Exception { Log.info(Log.FAC_TEST, "Starting testPolicyViaCCN"); checkNameSpace("/repoTest/data2", true); changePolicy("/org/ccnx/ccn/test/repo/policyTest.xml"); checkNameSpace("/repoTest/data3", false); checkNameSpace("/testNameSpace/data1", true); changePolicy("/org/ccnx/ccn/test/repo/origPolicy.xml"); checkNameSpace("/repoTest/data4", true); Log.info(Log.FAC_TEST, "Completed testPolicyViaCCN"); } @Test public void testReadFromRepo() throws Exception { Log.info(Log.FAC_TEST, "Starting testReadFromRepo"); ContentName name = new ContentName(_testPrefix, _testStream); _cacheManager.clearCache(name, getHandle, CACHE_CLEAR_TIMEOUT); Thread.sleep(5000); CCNInputStream input = new CCNInputStream(name, getHandle); byte[] testBytes = new byte[data.length]; input.read(testBytes); Assert.assertArrayEquals(data, testBytes); Log.info(Log.FAC_TEST, "Completed testReadFromRepo"); } @Test // The purpose of this test is to do versioned reads from repo // of data not already in the ccnd cache, thus testing // what happens if we pull latest version and try to read // content in order public void testVersionedRead() throws InterruptedException, IOException, MalformedContentNameStringException { Log.info(Log.FAC_TEST, "Starting testVersionedRead"); ContentName versionedNameNormal = new ContentName(_testPrefix, "testVersionNormal"); CCNVersionedOutputStream ostream = new RepositoryVersionedOutputStream(versionedNameNormal, putHandle); ostream.setBlockSize("segment".length() + new Long(5).toString().length()); for (long i=SegmentationProfile.baseSegment(); i<5; i++) { String segmentContent = "segment"+ new Long(i).toString(); ostream.write(segmentContent.getBytes(), 0, 8); } ostream.close(); _cacheManager.clearCache(versionedNameNormal, getHandle, CACHE_CLEAR_TIMEOUT); CCNVersionedInputStream vstream = new CCNVersionedInputStream(versionedNameNormal); InputStreamReader reader = new InputStreamReader(vstream); for (long i=SegmentationProfile.baseSegment(); i<5; i++) { String segmentContent = "segment"+ new Long(i).toString(); char[] cbuf = new char[8]; int count = reader.read(cbuf, 0, 8); System.out.println("for " + i + " got " + count + " (eof " + vstream.eof() + "): " + new String(cbuf)); Assert.assertEquals(segmentContent, new String(cbuf)); } Assert.assertEquals(-1, reader.read()); vstream.close(); Log.info(Log.FAC_TEST, "Completed testVersionedRead"); } @Test public void testLocalSyncInputStream() throws Exception { Log.info(Log.FAC_TEST, "Starting testLocalSyncInputStream"); // This test should run all on single handle, just as client would do CCNInputStream input = new CCNInputStream(new ContentName(_testPrefix, _testStream), getHandle); // Ignore data in this case, just trigger repo confirmation // Setup of this test writes the stream into repo, so we know it is already there -- // should get immediate confirmation from repo, which means no new repo read starts boolean confirm = RepositoryControl.localRepoSync(getHandle, input); Assert.assertTrue(confirm); input.close(); // Test case of content not already in repo Log.info("About to do first sync for stream"); ContentName name = new ContentName(_testPrefix, _testNonRepo); input = new CCNInputStream(name, getHandle); Assert.assertFalse(RepositoryControl.localRepoSync(getHandle, input)); Thread.sleep(2000); // Give repo time to fetch TODO: replace with confirmation protocol Log.info("About to do second sync for stream"); Assert.assertTrue(RepositoryControl.localRepoSync(getHandle, input)); input.close(); _cacheManager.clearCache(name, getHandle, CACHE_CLEAR_TIMEOUT); _cacheManager.clearCache(_keyNameForStream, getHandle, CACHE_CLEAR_TIMEOUT); byte[] testBytes = new byte[data.length]; input = new CCNInputStream(name, getHandle); input.read(testBytes); Assert.assertArrayEquals(data, testBytes); input.close(); Log.info(Log.FAC_TEST, "Completed testLocalSyncInputStream"); } @Test public void testLocalSyncNetObj() throws Exception { Log.info(Log.FAC_TEST, "Starting testLocalSyncNetObj"); // This test should run all on single handle, just as client would do System.out.println("Testing local repo sync request for network object"); CCNStringObject so = new CCNStringObject(new ContentName(_testPrefix, _testObj), getHandle); // Ignore data in this case, just trigger repo confirmation // Setup of this test writes the object into repo, so we know it is already there -- // should get immediate confirmation from repo, which means no new repo read starts boolean confirm = RepositoryControl.localRepoSync(getHandle, so); Assert.assertTrue(confirm); so.close(); // Test case of content not already in repo ContentName name = new ContentName(_testPrefix, _testNonRepoObj); so = new CCNStringObject(name, getHandle); Log.info("About to do first sync for object {0}", so.getBaseName()); Assert.assertFalse(RepositoryControl.localRepoSync(getHandle, so)); Thread.sleep(2000); // Give repo time to fetch TODO: replace with confirmation protocol Log.info("About to do second sync for object {0}", so.getBaseName()); Assert.assertTrue(RepositoryControl.localRepoSync(getHandle, so)); so.close(); _cacheManager.clearCache(name, getHandle, CACHE_CLEAR_TIMEOUT); _cacheManager.clearCache(_keyNameForStream, getHandle, CACHE_CLEAR_TIMEOUT); _cacheManager.clearCache(new ContentName(_testPrefix, _testLink), getHandle, CACHE_CLEAR_TIMEOUT); so = new CCNStringObject(name, getHandle); assert(so.string().equals("String value for non-repo obj")); Log.info(Log.FAC_TEST, "Completed testLocalSyncNetObj"); } private void changePolicy(String policyFile) throws Exception { FileInputStream fis = new FileInputStream(_topdir + policyFile); PolicyXML pxml = BasicPolicy.createPolicyXML(fis); fis.close(); ContentName policyName = BasicPolicy.getPolicyName(ContentName.fromNative(_globalPrefix)); PolicyObject po = new PolicyObject(policyName, pxml, SaveType.REPOSITORY, putHandle); po.save(); Thread.sleep(4000); } }