/*
 * A CCNx library test.
 *
 * Copyright (C) 2008, 2009 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.IOException;
import java.util.ArrayList;

import org.ccnx.ccn.impl.repo.RepositoryException;
import org.ccnx.ccn.impl.support.DataUtils;
import org.ccnx.ccn.impl.support.Log;
import org.ccnx.ccn.io.CCNReader;
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.PublisherID;
import org.ccnx.ccn.protocol.PublisherPublicKeyDigest;
import org.junit.Assert;
import org.junit.Test;

/**
 * Part of repository test infrastructure.
 */
public class RepoInitialReadTest extends RepoTestBase {
	
	public static final long TIMEOUT = 5000;
	
	@Test
	public void testReadViaRepo() throws Throwable {
		System.out.println("Testing reading objects from repo");
		ContentName name = ContentName.fromNative("/repoTest/data1");
		
		// Since we have 2 pieces of data with the name /repoTest/data1 we need to compute both
		// digests to make sure we get the right data.
		ContentName name1 = findFullName(name, "Here's my data!");
		ContentName digestName = findFullName(name, "Testing2");
		String tooLongName = "0123456789";
		for (int i = 0; i < 30; i++)
			tooLongName += "0123456789";
		
		// Have 2 pieces of data with the same name here too.
		ContentName longName = findFullName(ContentName.fromNative("/repoTest/" + tooLongName),
				"Long name!");
		ContentName badCharName = ContentName.fromNative("/repoTest/" + "*x?y<z>u");
		ContentName badCharLongName = ContentName.fromNative("/repoTest/" + tooLongName + "*x?y<z>u");
			
		checkDataWithDigest(name1, "Here's my data!");
		checkDataWithDigest(digestName, "Testing2");
		checkDataWithDigest(longName, "Long name!");
		checkData(badCharName, "Funny characters!");
		checkData(badCharLongName, "Long and funny");
		
		CCNReader reader = new CCNReader(getHandle);
		ArrayList<ContentObject>keys = reader.enumerate(new Interest(keyprefix), 4000);
		for (ContentObject keyObject : keys) {
			checkDataAndPublisher(name, "Testing2", new PublisherPublicKeyDigest(keyObject.content()));
		}
	}
	
	/**
	 * Find a content object by name (without digest) and content, and return the full name (with digest)
	 * @param name ContentName without digest component
	 * @param str The content
	 * @return ContentName with implicit digest
	 * @throws IOException 
	 */
	private ContentName findFullName(ContentName name, String str) throws IOException {
		byte[] content = str.getBytes();
		Exclude e = null;
		for(;;) {
			Interest i = Interest.constructInterest(name, e, Interest.CHILD_SELECTOR_LEFT, null, null, null);
			Log.info("searching for {0} content {1}, exclude {2}", name, str, e);
			ContentObject co = getHandle.get(i, TIMEOUT);
			Assert.assertTrue(null != co);
			Log.info("got result {0} digest={1}", co, DataUtils.printHexBytes(co.digest()));
			if (DataUtils.arrayEquals(co.content(), content))
				return co.fullName();
			byte [][]omissions = { co.digest() };
			if (e == null)
				e = new Exclude(omissions);
			else
				e.add(omissions);
		}
	}
	
	private void checkDataWithDigest(ContentName name, String data) throws RepositoryException, IOException, InterruptedException {
		// When generating an Interest for the exact name with content digest, need to set maxSuffixComponents
		// to 0, signifying that name ends with explicit digest
		Interest interest = new Interest(name);
		interest.maxSuffixComponents(0);
		checkData(interest, data.getBytes());
	}
	
	private void checkDataAndPublisher(ContentName name, String data, PublisherPublicKeyDigest publisher) 
				throws IOException, InterruptedException {
		Interest interest = new Interest(name, new PublisherID(publisher));
		ContentObject testContent = getHandle.get(interest, 10000);
		Assert.assertFalse(testContent == null);
		Assert.assertEquals(data, new String(testContent.content()));
		Assert.assertTrue(testContent.signedInfo().getPublisherKeyID().equals(publisher));
	}

}

@@ -50,16 +50,22 @@
 08, 2009
+, 2011
  Palo Al
@@ -1350,16 +1350,968 @@
 ructure.
+  This test must be run after RFSTest and can be%0A * run only once correctly after running RFSTest.%0A * %0A * This test tests reading of unusual objects which can't be written to a running repo%0A * via the current repo writing algorithms. The data needed for this test can only be created%0A * by something like RFSTest which creates and saves a repo file structure without a running%0A * repo by calling saveContent methods directly with different kinds of data.  %0A * %0A * It is normally desirable that tests such as this can be run repeatedly and achieve the same %0A * results. But since we can't write the data to be tested via the repo, and once we have read the %0A * data once, it may be cached by ccnd, a correct running of the test after the first time can't be %0A * guaranteed and is in fact unlikely with this test. Possibly this test should just be eliminated but %0A * since it is part of the historic repo test suite I am leaving it in for the time being.
 %0A */%0Apub

Document reasoning for RepoInitialReadTest refs #100367