/** * Copyright (c) 2002-2011 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j. * * Neo4j is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.neo4j.ha; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; import java.util.Arrays; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.junit.Test; import org.neo4j.kernel.ha.BlockLogBuffer; import org.neo4j.kernel.ha.BlockLogReader; public class TestBlockLogBuffer { @Test public void onlyOneNonFullBlock() throws IOException { byte[] bytes = new byte[255]; ChannelBuffer wrappedBuffer = ChannelBuffers.wrappedBuffer( bytes ); wrappedBuffer.resetWriterIndex(); BlockLogBuffer buffer = new BlockLogBuffer( wrappedBuffer ); byte byteValue = 5; int intValue = 1234; long longValue = 574853; float floatValue = 304985.5f; double doubleValue = 48493.22d; final byte[] bytesValue = new byte[] { 1, 5, 2, 6, 3 }; final char[] charsValue = "This is chars".toCharArray(); buffer.put( byteValue ); buffer.putInt( intValue ); buffer.putLong( longValue ); buffer.putFloat( floatValue ); buffer.putDouble( doubleValue ); buffer.put( bytesValue ); buffer.put( charsValue ); buffer.done(); ByteBuffer verificationBuffer = ByteBuffer.wrap( bytes ); assertEquals( 56, verificationBuffer.get() ); assertEquals( byteValue, verificationBuffer.get() ); assertEquals( intValue, verificationBuffer.getInt() ); assertEquals( longValue, verificationBuffer.getLong() ); assertEquals( floatValue, verificationBuffer.getFloat(), 0.0 ); assertEquals( doubleValue, verificationBuffer.getDouble(), 0.0 ); byte[] actualBytes = new byte[bytesValue.length]; verificationBuffer.get( actualBytes ); assertThat( actualBytes, new ArrayMatches<byte[]>( bytesValue ) ); char[] actualChars = new char[charsValue.length]; verificationBuffer.asCharBuffer().get( actualChars ); assertThat( actualChars, new ArrayMatches<char[]>( charsValue ) ); } @Test public void readSmallPortions() throws IOException { byte[] bytes = new byte[255]; ChannelBuffer wrappedBuffer = ChannelBuffers.wrappedBuffer( bytes ); wrappedBuffer.resetWriterIndex(); BlockLogBuffer buffer = new BlockLogBuffer( wrappedBuffer ); byte byteValue = 5; int intValue = 1234; long longValue = 574853; buffer.put( byteValue ); buffer.putInt( intValue ); buffer.putLong( longValue ); buffer.done(); ReadableByteChannel reader = new BlockLogReader( wrappedBuffer ); ByteBuffer verificationBuffer = ByteBuffer.wrap( new byte[1] ); reader.read( verificationBuffer ); verificationBuffer.flip(); assertEquals( byteValue, verificationBuffer.get() ); verificationBuffer = ByteBuffer.wrap( new byte[4] ); reader.read( verificationBuffer ); verificationBuffer.flip(); assertEquals( intValue, verificationBuffer.getInt() ); verificationBuffer = ByteBuffer.wrap( new byte[8] ); reader.read( verificationBuffer ); verificationBuffer.flip(); assertEquals( longValue, verificationBuffer.getLong() ); } @Test public void readOnlyOneNonFullBlock() throws IOException { byte[] bytes = new byte[255]; ChannelBuffer wrappedBuffer = ChannelBuffers.wrappedBuffer( bytes ); wrappedBuffer.resetWriterIndex(); BlockLogBuffer buffer = new BlockLogBuffer( wrappedBuffer ); byte byteValue = 5; int intValue = 1234; long longValue = 574853; float floatValue = 304985.5f; double doubleValue = 48493.22d; final byte[] bytesValue = new byte[] { 1, 5, 2, 6, 3 }; final char[] charsValue = "This is chars".toCharArray(); buffer.put( byteValue ); buffer.putInt( intValue ); buffer.putLong( longValue ); buffer.putFloat( floatValue ); buffer.putDouble( doubleValue ); buffer.put( bytesValue ); buffer.put( charsValue ); buffer.done(); ReadableByteChannel reader = new BlockLogReader( wrappedBuffer ); ByteBuffer verificationBuffer = ByteBuffer.wrap( new byte[1000] ); reader.read( verificationBuffer ); verificationBuffer.flip(); assertEquals( byteValue, verificationBuffer.get() ); assertEquals( intValue, verificationBuffer.getInt() ); assertEquals( longValue, verificationBuffer.getLong() ); assertEquals( floatValue, verificationBuffer.getFloat(), 0.0 ); assertEquals( doubleValue, verificationBuffer.getDouble(), 0.0 ); byte[] actualBytes = new byte[bytesValue.length]; verificationBuffer.get( actualBytes ); assertThat( actualBytes, new ArrayMatches<byte[]>( bytesValue ) ); char[] actualChars = new char[charsValue.length]; verificationBuffer.asCharBuffer().get( actualChars ); assertThat( actualChars, new ArrayMatches<char[]>( charsValue ) ); } @Test public void onlyOneFullBlock() throws Exception { byte[] bytes = new byte[256]; ChannelBuffer wrappedBuffer = ChannelBuffers.wrappedBuffer( bytes ); wrappedBuffer.resetWriterIndex(); BlockLogBuffer buffer = new BlockLogBuffer( wrappedBuffer ); byte[] bytesValue = new byte[255]; bytesValue[0] = 1; bytesValue[254] = -1; buffer.put( bytesValue ); buffer.done(); ByteBuffer verificationBuffer = ByteBuffer.wrap( bytes ); assertEquals( (byte) 255, verificationBuffer.get() ); byte[] actualBytes = new byte[bytesValue.length]; verificationBuffer.get( actualBytes ); assertThat( actualBytes, new ArrayMatches<byte[]>( bytesValue ) ); } @Test public void readOnlyOneFullBlock() throws Exception { byte[] bytes = new byte[256]; ChannelBuffer wrappedBuffer = ChannelBuffers.wrappedBuffer( bytes ); wrappedBuffer.resetWriterIndex(); BlockLogBuffer buffer = new BlockLogBuffer( wrappedBuffer ); byte[] bytesValue = new byte[255]; bytesValue[0] = 1; bytesValue[254] = -1; buffer.put( bytesValue ); buffer.done(); ReadableByteChannel reader = new BlockLogReader( wrappedBuffer ); ByteBuffer verificationBuffer = ByteBuffer.wrap( new byte[1000] ); reader.read( verificationBuffer ); verificationBuffer.flip(); byte[] actualBytes = new byte[bytesValue.length]; verificationBuffer.get( actualBytes ); assertThat( actualBytes, new ArrayMatches<byte[]>( bytesValue ) ); } @Test public void canWriteLargestAtomAfterFillingBuffer() throws Exception { byte[] bytes = new byte[300]; ChannelBuffer wrappedBuffer = ChannelBuffers.wrappedBuffer( bytes ); wrappedBuffer.resetWriterIndex(); BlockLogBuffer buffer = new BlockLogBuffer( wrappedBuffer ); byte[] bytesValue = new byte[255]; bytesValue[0] = 1; bytesValue[254] = -1; long longValue = 123456; buffer.put( bytesValue ); buffer.putLong( longValue ); buffer.done(); ByteBuffer verificationBuffer = ByteBuffer.wrap( bytes ); assertEquals( (byte) 0, verificationBuffer.get() ); byte[] actualBytes = new byte[bytesValue.length]; verificationBuffer.get( actualBytes ); assertThat( actualBytes, new ArrayMatches<byte[]>( bytesValue ) ); assertEquals( (byte) 8, verificationBuffer.get() ); assertEquals( longValue, verificationBuffer.getLong() ); } @Test public void canWriteReallyLargeByteArray() throws Exception { byte[] bytes = new byte[650]; ChannelBuffer wrappedBuffer = ChannelBuffers.wrappedBuffer( bytes ); wrappedBuffer.resetWriterIndex(); BlockLogBuffer buffer = new BlockLogBuffer( wrappedBuffer ); byte[] bytesValue = new byte[600]; bytesValue[1] = 1; bytesValue[99] = 2; bytesValue[199] = 3; bytesValue[299] = 4; bytesValue[399] = 5; bytesValue[499] = 6; bytesValue[599] = 7; buffer.put( bytesValue ); buffer.done(); byte[] actual; ByteBuffer verificationBuffer = ByteBuffer.wrap( bytes ); assertEquals( (byte) 0, verificationBuffer.get() ); actual = new byte[255]; verificationBuffer.get( actual ); assertThat( actual, new ArrayMatches<byte[]>( Arrays.copyOfRange( bytesValue, 0, 255 ) ) ); assertEquals( (byte) 0, verificationBuffer.get() ); actual = new byte[255]; verificationBuffer.get( actual ); assertThat( actual, new ArrayMatches<byte[]>( Arrays.copyOfRange( bytesValue, 255, 510 ) ) ); assertEquals( (byte) 90, verificationBuffer.get() ); actual = new byte[90]; verificationBuffer.get( actual ); assertThat( actual, new ArrayMatches<byte[]>( Arrays.copyOfRange( bytesValue, 510, 600 ) ) ); } @Test public void canReaderReallyLargeByteArray() throws Exception { byte[] bytes = new byte[650]; ChannelBuffer wrappedBuffer = ChannelBuffers.wrappedBuffer( bytes ); wrappedBuffer.resetWriterIndex(); BlockLogBuffer buffer = new BlockLogBuffer( wrappedBuffer ); byte[] bytesValue = new byte[600]; bytesValue[1] = 1; bytesValue[99] = 2; bytesValue[199] = 3; bytesValue[299] = 4; bytesValue[399] = 5; bytesValue[499] = 6; bytesValue[599] = 7; buffer.put( bytesValue ); buffer.done(); byte[] actual; BlockLogReader reader = new BlockLogReader( wrappedBuffer ); ByteBuffer verificationBuffer = ByteBuffer.wrap( new byte[1000] ); reader.read( verificationBuffer ); verificationBuffer.flip(); actual = new byte[255]; verificationBuffer.get( actual ); assertThat( actual, new ArrayMatches<byte[]>( Arrays.copyOfRange( bytesValue, 0, 255 ) ) ); actual = new byte[255]; verificationBuffer.get( actual ); assertThat( actual, new ArrayMatches<byte[]>( Arrays.copyOfRange( bytesValue, 255, 510 ) ) ); actual = new byte[90]; verificationBuffer.get( actual ); assertThat( actual, new ArrayMatches<byte[]>( Arrays.copyOfRange( bytesValue, 510, 600 ) ) ); } private class ArrayMatches<T> extends BaseMatcher<T> { private final T expected; private Object actual; public ArrayMatches( T expected ) { this.expected = expected; } public boolean matches( Object actual ) { this.actual = actual; if ( expected instanceof byte[] && actual instanceof byte[] ) { return Arrays.equals( (byte[]) actual, (byte[]) expected ); } else if ( expected instanceof char[] && actual instanceof char[] ) { return Arrays.equals( (char[]) actual, (char[]) expected ); } return false; } public void describeTo( Description descr ) { descr.appendText( String.format( "expected %s, got %s", toString( expected ), toString( actual ) ) ); } private String toString( Object value ) { if ( value instanceof byte[] ) { return Arrays.toString( (byte[]) value ) + "; len=" + ( (byte[]) value ).length; } if ( value instanceof char[] ) { return Arrays.toString( (char[]) value ) + "; len=" + ( (char[]) value ).length; } return "" + value; } } }