/**
* VMware Continuent Tungsten Replicator
* Copyright (C) 2015 VMware, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Initial developer(s): Robert Hodges
* Contributor(s):
*/
package com.continuent.tungsten.common.io;
import java.io.File;
import junit.framework.TestCase;
import org.apache.log4j.Logger;
import org.junit.After;
import org.junit.Before;
import com.continuent.tungsten.common.io.BufferedFileDataInput;
import com.continuent.tungsten.common.io.BufferedFileDataOutput;
/**
* Test capabilities for buffered writes to files.
*
* @author <a href="mailto:robert.hodges@continuent.com">Robert Hodges</a>
* @version 1.0
*/
public class BufferedFileDataOutputTest extends TestCase
{
private static Logger logger = Logger
.getLogger(BufferedFileDataOutputTest.class);
/**
* Setup.
*
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception
{
logger.info("Test starting");
}
/**
* Teardown.
*
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception
{
}
/**
* Confirm that we can open non-existing and existing files.
*/
public void testOpen() throws Exception
{
File f = initFile("testOpen");
assertFalse("File does not exist", f.exists());
BufferedFileDataOutput bfdo = new BufferedFileDataOutput(f);
bfdo.close();
assertTrue("File does exist", f.exists());
BufferedFileDataOutput bfdo2 = new BufferedFileDataOutput(f);
bfdo2.close();
}
/**
* Confirm that we can write to new and existing files.
*/
public void testBasicWrite() throws Exception
{
File f = initFile("testBasicWrite");
// Write int to new file.
BufferedFileDataOutput bfdo = new BufferedFileDataOutput(f);
bfdo.writeInt(1);
assertEquals("Offset after 1 int", 4, bfdo.getOffset());
bfdo.fsync();
assertEquals("File size matches offset after fsync", 4, f.length());
bfdo.close();
// Write a second int.
BufferedFileDataOutput bfdo2 = new BufferedFileDataOutput(f);
bfdo2.writeInt(2);
assertEquals("Offset after 2 ints", 8, bfdo2.getOffset());
bfdo2.fsync();
assertEquals("File size matches offset after fsync", 8, f.length());
bfdo2.close();
// Confirm both values made it to the file.
assertEquals("File length after writing", 8, f.length());
BufferedFileDataInput bfdi = new BufferedFileDataInput(f);
assertEquals("int 1", 1, bfdi.readInt());
assertEquals("int 2", 2, bfdi.readInt());
bfdi.close();
}
/**
* Confirm that we can open a file for writing and correctly writes standard
* byte, short, int, long, and byte array values. This is a very boring test
* but very helpful.
*/
public void testWrite() throws Exception
{
File f = this.initFile("testWrite");
BufferedFileDataOutput bfdo = new BufferedFileDataOutput(f);
// Bytes.
bfdo.writeByte((byte) 1);
bfdo.writeByte(Byte.MAX_VALUE);
bfdo.writeByte(Byte.MIN_VALUE);
assertEquals("Size after bytes", 3, bfdo.getOffset());
// Shorts.
bfdo.writeShort((short) 2);
bfdo.writeShort(Short.MAX_VALUE);
bfdo.writeShort(Short.MIN_VALUE);
assertEquals("Size after shorts", 9, bfdo.getOffset());
// Ints.
bfdo.writeInt(3);
bfdo.writeInt(Integer.MAX_VALUE);
bfdo.writeInt(Integer.MIN_VALUE);
assertEquals("Size after ints", 21, bfdo.getOffset());
// Longs.
bfdo.writeLong(4);
bfdo.writeLong(Long.MAX_VALUE);
bfdo.writeLong(Long.MIN_VALUE);
assertEquals("Size after longs", 45, bfdo.getOffset());
// Byte arrays.
byte[] byteArray = new byte[10];
for (int i = 0; i < byteArray.length; i++)
byteArray[i] = (byte) i;
bfdo.write(byteArray);
assertEquals("Size after byte array", 55, bfdo.getOffset());
bfdo.fsync();
bfdo.close();
// Fire up a reader instance.
BufferedFileDataInput bfdi = new BufferedFileDataInput(f);
// Read bytes;
assertEquals("byte 1", 1, bfdi.readByte());
assertEquals("byte 2", Byte.MAX_VALUE, bfdi.readByte());
assertEquals("byte 3", Byte.MIN_VALUE, bfdi.readByte());
assertEquals("Should be at offset 3", 3, bfdi.getOffset());
// Read shorts.
assertEquals("short 1", 2, bfdi.readShort());
assertEquals("short 2", Short.MAX_VALUE, bfdi.readShort());
assertEquals("short 3", Short.MIN_VALUE, bfdi.readShort());
assertEquals("Should be at offset 9", 9, bfdi.getOffset());
// Read ints.
assertEquals("int 1", 3, bfdi.readInt());
assertEquals("int 2", Integer.MAX_VALUE, bfdi.readInt());
assertEquals("int 3", Integer.MIN_VALUE, bfdi.readInt());
assertEquals("Should be at offset 21", 21, bfdi.getOffset());
// Read longs.
assertEquals("long 1", 4, bfdi.readLong());
assertEquals("long 2", Long.MAX_VALUE, bfdi.readLong());
assertEquals("long 3", Long.MIN_VALUE, bfdi.readLong());
assertEquals("Should be at offset 45", 45, bfdi.getOffset());
// Read bytes.
byte[] myBytes = new byte[10];
bfdi.readFully(myBytes);
for (int i = 0; i < byteArray.length; i++)
{
assertEquals("byte: " + i, byteArray[i], myBytes[i]);
}
assertEquals("Should be at offset 55", 55, bfdi.getOffset());
// Clean up.
bfdi.close();
}
/**
* Confirm that we can truncate and then rewrite part of a file.
*/
public void testTruncate() throws Exception
{
// Write a test file with 100 values.
File f = this.initFile("testTruncate");
BufferedFileDataOutput bfdo = new BufferedFileDataOutput(f);
for (int i = 0; i < 100; i++)
{
bfdo.writeInt(i);
}
bfdo.fsync();
// Truncate off the last 50 ints one by one.
for (int i = 99; i >= 50; i--)
{
int length = i * 4;
bfdo.setLength(length);
assertEquals("truncated file length", length, f.length());
}
// Write missing 50 ints.
for (int i = 50; i < 100; i++)
{
bfdo.writeInt(i);
}
bfdo.fsync();
// Read and confirm the contents of the file.
BufferedFileDataInput bfdi = new BufferedFileDataInput(f);
for (int i = 0; i < 100; i++)
{
assertEquals("i: " + i, i, bfdi.readInt());
}
// Clean up.
bfdi.close();
bfdo.close();
}
/**
* Confirm that we can truncate and then rewrite part of a file.
*/
public void testLargeScaleWrite() throws Exception
{
// Write a 20Mb file with period fsync operations.
File f = this.initFile("testLargeScaleWrite");
BufferedFileDataOutput bfdo = new BufferedFileDataOutput(f, 65536);
for (int i = 0; i < 5000000; i++)
{
bfdo.writeInt(i);
if (i % 20000 == 0)
bfdo.fsync();
int bytesWritten = (i + 1) * 4;
if (bytesWritten % 1000000 == 0)
logger.info("Bytes written: " + bytesWritten);
}
bfdo.writeByte((byte) -1);
bfdo.fsync();
bfdo.close();
assertEquals("File size", (5000000 * 4) + 1, f.length());
// Read and confirm the contents of the file.
BufferedFileDataInput bfdi = new BufferedFileDataInput(f, 65536);
for (int i = 0; i < 5000000; i++)
{
assertEquals("i: " + i, i, bfdi.readInt());
}
assertEquals("Last byte", (byte) -1, bfdi.readByte());
// Clean up.
bfdi.close();
}
// Initialize a test file by clearing and return the File instance.
private File initFile(String name)
{
File f = new File(name);
if (f.exists())
f.delete();
return f;
}
}