/*
* A CCNx library test.
*
* Copyright (C) 2008, 2009, 2011-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.io;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.DigestInputStream;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import org.ccnx.ccn.impl.security.crypto.CCNDigestHelper;
import org.ccnx.ccn.impl.support.DataUtils;
import org.ccnx.ccn.impl.support.Log;
import org.ccnx.ccn.io.CCNFileInputStream;
import org.ccnx.ccn.io.RepositoryFileOutputStream;
import org.ccnx.ccn.protocol.ContentName;
import org.ccnx.ccn.test.CCNTestBase;
import org.ccnx.ccn.test.CCNTestHelper;
import org.ccnx.ccn.test.TestUtils;
import org.junit.Assert;
import org.junit.Test;
/**
* Test class for CCNFileStream; tests writing file streams to a repository.
*/
public class CCNFileStreamTestRepo extends CCNTestBase {
static Random random = new Random();
/**
* Handle naming for the test
*/
static CCNTestHelper testHelper = new CCNTestHelper(CCNFileStreamTestRepo.class);
static final int BUF_SIZE = 1024;
public static class CountAndDigest {
int _count;
byte [] _digest;
public CountAndDigest(int count, byte [] digest) {
_count = count;
_digest = digest;
}
public int count() { return _count; }
public byte [] digest() { return _digest; }
}
@Test
public void testRepoFileOutputStream() throws Exception {
Log.info(Log.FAC_TEST, "Started testRepoFileOutputStream");
int fileSize = random.nextInt(50000);
ContentName fileName = new ContentName(testHelper.getTestNamespace("testRepoFileOutputStream"), "outputFile.bin");
// Write to a repo. Read it back in. See if repo gets the header.
RepositoryFileOutputStream rfos = new RepositoryFileOutputStream(fileName, putHandle);
byte [] digest = writeRandomFile(fileSize, rfos);
Log.info(Log.FAC_TEST, "Wrote file to repository: " + rfos.getBaseName());
CCNFileInputStream fis = new CCNFileInputStream(fileName, getHandle);
TestUtils.checkFile(getHandle, fis);
CountAndDigest readDigest = readRandomFile(fis);
Log.info(Log.FAC_TEST, "Read file from repository: " + fis.getBaseName() + " has header? " +
fis.hasHeader());
if (!fis.hasHeader()) {
Log.info(Log.FAC_TEST, "No header yet, waiting..");
fis.waitForHeader();
}
Assert.assertTrue(fis.hasHeader());
Log.info(Log.FAC_TEST, "Read file size: " + readDigest.count() + " written size: " + fileSize + " header file size " + fis.header().length());
Assert.assertEquals(readDigest.count(), fileSize);
Assert.assertEquals(fileSize, fis.header().length());
Log.info(Log.FAC_TEST, "Read digest: " + DataUtils.printBytes(readDigest.digest()) + " wrote digest: " + DataUtils.printBytes(digest));
Assert.assertArrayEquals(digest, readDigest.digest());
CCNFileInputStream fis2 = new CCNFileInputStream(rfos.getBaseName(), getHandle);
CountAndDigest readDigest2 = readRandomFile(fis2);
Log.info(Log.FAC_TEST, "Read file from repository again: " + fis2.getBaseName() + " has header? " +
fis2.hasHeader());
if (!fis2.hasHeader()) {
Log.info(Log.FAC_TEST, "No header yet, waiting..");
fis2.waitForHeader();
}
Assert.assertTrue(fis2.hasHeader());
Log.info(Log.FAC_TEST, "Read file size: " + readDigest2.count() + " written size: " + fileSize + " header file size " + fis.header().length());
Assert.assertEquals(readDigest2.count(), fileSize);
Assert.assertEquals(fileSize, fis2.header().length());
Log.info(Log.FAC_TEST, "Read digest: " + DataUtils.printBytes(readDigest2.digest()) + " wrote digest: " + DataUtils.printBytes(digest));
Assert.assertArrayEquals(digest, readDigest2.digest());
Log.info(Log.FAC_TEST, "Completed testRepoFileOutputStream");
}
public static byte [] writeRandomFile(int bytes, OutputStream out) throws IOException {
try {
DigestOutputStream dos = new DigestOutputStream(out, MessageDigest.getInstance(CCNDigestHelper.DEFAULT_DIGEST_ALGORITHM));
byte [] buf = new byte[BUF_SIZE];
int count = 0;
int towrite = 0;
while (count < bytes) {
random.nextBytes(buf);
towrite = ((bytes - count) > buf.length) ? buf.length : (bytes - count);
dos.write(buf, 0, towrite);
count += towrite;
}
dos.flush();
dos.close();
return dos.getMessageDigest().digest();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Cannot find digest algorithm: " + CCNDigestHelper.DEFAULT_DIGEST_ALGORITHM);
}
}
public static CountAndDigest readRandomFile(InputStream in) throws IOException {
try {
DigestInputStream dis = new DigestInputStream(in, MessageDigest.getInstance(CCNDigestHelper.DEFAULT_DIGEST_ALGORITHM));
byte [] buf = new byte[BUF_SIZE];
int count = 0;
int read = 0;
while (read >= 0) {
read = dis.read(buf);
if (read > 0)
count += read;
}
return new CountAndDigest(count, dis.getMessageDigest().digest());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Cannot find digest algorithm: " + CCNDigestHelper.DEFAULT_DIGEST_ALGORITHM);
}
}
}