X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-akka-raft%2Fsrc%2Ftest%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fcluster%2Fraft%2Fbehaviors%2FSnapshotTrackerTest.java;h=d8d2b4045bd9fa362cfd250927374d44bb3e88f7;hp=99c7b58724414c97f3c9a2e8e981e8b27dde83a6;hb=dcc9827eab4f95b8e35820e8355066ff105d2720;hpb=e1eca73a5ae2ffae8dd78c6fe5281cd2f45d5ef3 diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/SnapshotTrackerTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/SnapshotTrackerTest.java index 99c7b58724..d8d2b4045b 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/SnapshotTrackerTest.java +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/SnapshotTrackerTest.java @@ -5,34 +5,46 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ - package org.opendaylight.controller.cluster.raft.behaviors; import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; -import com.google.common.base.Optional; -import com.google.protobuf.ByteString; -import java.io.ByteArrayOutputStream; +import akka.protobuf.ByteString; +import com.google.common.io.ByteSource; import java.io.IOException; -import java.io.ObjectOutputStream; +import java.io.Serializable; import java.util.Arrays; import java.util.HashMap; import java.util.Map; -import org.junit.Assert; +import java.util.OptionalInt; +import org.apache.commons.lang3.SerializationUtils; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.opendaylight.controller.cluster.io.FileBackedOutputStream; +import org.opendaylight.controller.cluster.io.FileBackedOutputStreamFactory; +import org.opendaylight.controller.cluster.raft.RaftActorContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +@RunWith(MockitoJUnitRunner.StrictStubs.class) public class SnapshotTrackerTest { + private static final Logger LOG = LoggerFactory.getLogger(SnapshotTrackerTest.class); - Logger logger = LoggerFactory.getLogger(getClass()); - - Map data; - ByteString byteString; - byte[] chunk1; - byte[] chunk2; - byte[] chunk3; + @Mock + private RaftActorContext mockContext; + private FileBackedOutputStream fbos; + private Map data; + private ByteString byteString; + private byte[] chunk1; + private byte[] chunk2; + private byte[] chunk3; @Before public void setup() { @@ -41,117 +53,72 @@ public class SnapshotTrackerTest { data.put("key2", "value2"); data.put("key3", "value3"); - byteString = toByteString(data); + byteString = ByteString.copyFrom(SerializationUtils.serialize((Serializable) data)); chunk1 = getNextChunk(byteString, 0, 10); chunk2 = getNextChunk(byteString, 10, 10); chunk3 = getNextChunk(byteString, 20, byteString.size()); + + fbos = spy(new FileBackedOutputStream(100000000, "target")); + FileBackedOutputStreamFactory mockFactory = mock(FileBackedOutputStreamFactory.class); + doReturn(fbos).when(mockFactory).newInstance(); + doReturn(mockFactory).when(mockContext).getFileBackedOutputStreamFactory(); } @Test - public void testAddChunk() throws SnapshotTracker.InvalidChunkException { - SnapshotTracker tracker1 = new SnapshotTracker(logger, 5, "leader"); - - tracker1.addChunk(1, chunk1, Optional.absent()); - tracker1.addChunk(2, chunk2, Optional.absent()); - tracker1.addChunk(3, chunk3, Optional.absent()); - - // Verify that an InvalidChunkException is thrown when we try to add a chunk to a sealed tracker - SnapshotTracker tracker2 = new SnapshotTracker(logger, 2, "leader"); - - tracker2.addChunk(1, chunk1, Optional.absent()); - tracker2.addChunk(2, chunk2, Optional.absent()); - - try { - tracker2.addChunk(3, chunk3, Optional.absent()); - Assert.fail(); - } catch (SnapshotTracker.InvalidChunkException e) { - e.getMessage().startsWith("Invalid chunk"); + public void testAddChunks() throws IOException { + try (SnapshotTracker tracker = new SnapshotTracker(LOG, 3, "leader", mockContext)) { + tracker.addChunk(1, chunk1, OptionalInt.of(LeaderInstallSnapshotState.INITIAL_LAST_CHUNK_HASH_CODE)); + tracker.addChunk(2, chunk2, OptionalInt.of(Arrays.hashCode(chunk1))); + tracker.addChunk(3, chunk3, OptionalInt.of(Arrays.hashCode(chunk2))); + + ByteSource snapshotBytes = tracker.getSnapshotBytes(); + assertEquals("Deserialized", data, SerializationUtils.deserialize(snapshotBytes.read())); } - // The first chunk's index must at least be FIRST_CHUNK_INDEX - SnapshotTracker tracker3 = new SnapshotTracker(logger, 2, "leader"); + verify(fbos).cleanup(); + } - try { - tracker3.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX - 1, chunk1, Optional.absent()); - Assert.fail(); - } catch (SnapshotTracker.InvalidChunkException e) { - // expected + @Test(expected = SnapshotTracker.InvalidChunkException.class) + public void testAddChunkWhenAlreadySealed() throws IOException { + try (SnapshotTracker tracker = new SnapshotTracker(LOG, 2, "leader", mockContext)) { + tracker.addChunk(1, chunk1, OptionalInt.empty()); + tracker.addChunk(2, chunk2, OptionalInt.empty()); + tracker.addChunk(3, chunk3, OptionalInt.empty()); } + } - // Out of sequence chunk indexes won't work - SnapshotTracker tracker4 = new SnapshotTracker(logger, 2, "leader"); - - tracker4.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX, chunk1, Optional.absent()); - - try { - tracker4.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX + 2, chunk2, Optional.absent()); - Assert.fail(); - } catch (SnapshotTracker.InvalidChunkException e) { - // expected + @Test(expected = SnapshotTracker.InvalidChunkException.class) + public void testInvalidFirstChunkIndex() throws IOException { + try (SnapshotTracker tracker = new SnapshotTracker(LOG, 2, "leader", mockContext)) { + tracker.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX - 1, chunk1, OptionalInt.empty()); } + } - // No exceptions will be thrown when invalid chunk is added with the right sequence - // If the lastChunkHashCode is missing - SnapshotTracker tracker5 = new SnapshotTracker(logger, 2, "leader"); - - tracker5.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX, chunk1, Optional.absent()); - // Look I can add the same chunk again - tracker5.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX + 1, chunk1, Optional.absent()); - - // An exception will be thrown when an invalid chunk is addedd with the right sequence - // when the lastChunkHashCode is present - SnapshotTracker tracker6 = new SnapshotTracker(logger, 2, "leader"); - - tracker6.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX, chunk1, Optional.of(-1)); - - try { - // Here we add a second chunk and tell addChunk that the previous chunk had a hash code 777 - tracker6.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX + 1, chunk2, Optional.of(777)); - Assert.fail(); - } catch (SnapshotTracker.InvalidChunkException e) { - // expected + @Test(expected = SnapshotTracker.InvalidChunkException.class) + public void testOutOfSequenceChunk() throws IOException { + try (SnapshotTracker tracker = new SnapshotTracker(LOG, 2, "leader", mockContext)) { + tracker.addChunk(1, chunk1, OptionalInt.empty()); + tracker.addChunk(3, chunk3, OptionalInt.empty()); } - } - @Test - public void testGetSnapShot() throws SnapshotTracker.InvalidChunkException { - - // Trying to get a snapshot before all chunks have been received will throw an exception - SnapshotTracker tracker1 = new SnapshotTracker(logger, 5, "leader"); - - tracker1.addChunk(1, chunk1, Optional.absent()); - try { - tracker1.getSnapshot(); - Assert.fail(); - } catch (IllegalStateException e) { - // expected + @Test(expected = SnapshotTracker.InvalidChunkException.class) + public void testInvalidLastChunkHashCode() throws IOException { + try (SnapshotTracker tracker = new SnapshotTracker(LOG, 2, "leader", mockContext)) { + tracker.addChunk(1, chunk1, OptionalInt.of(LeaderInstallSnapshotState.INITIAL_LAST_CHUNK_HASH_CODE)); + tracker.addChunk(2, chunk2, OptionalInt.of(1)); } - - SnapshotTracker tracker2 = new SnapshotTracker(logger, 3, "leader"); - - tracker2.addChunk(1, chunk1, Optional.of(LeaderInstallSnapshotState.INITIAL_LAST_CHUNK_HASH_CODE)); - tracker2.addChunk(2, chunk2, Optional.of(Arrays.hashCode(chunk1))); - tracker2.addChunk(3, chunk3, Optional.of(Arrays.hashCode(chunk2))); - - byte[] snapshot = tracker2.getSnapshot(); - - assertEquals(byteString, ByteString.copyFrom(snapshot)); } - @Test - public void testGetCollectedChunks() throws SnapshotTracker.InvalidChunkException { - SnapshotTracker tracker1 = new SnapshotTracker(logger, 5, "leader"); - - ByteString chunks = ByteString.copyFrom(chunk1).concat(ByteString.copyFrom(chunk2)); - - tracker1.addChunk(1, chunk1, Optional.of(LeaderInstallSnapshotState.INITIAL_LAST_CHUNK_HASH_CODE)); - tracker1.addChunk(2, chunk2, Optional.of(Arrays.hashCode(chunk1))); - - assertEquals(chunks, tracker1.getCollectedChunks()); + @Test(expected = IllegalStateException.class) + public void testGetSnapshotBytesWhenNotSealed() throws IOException { + try (SnapshotTracker tracker = new SnapshotTracker(LOG, 2, "leader", mockContext)) { + tracker.addChunk(1, chunk1, OptionalInt.empty()); + tracker.getSnapshotBytes(); + } } - public byte[] getNextChunk(ByteString bs, int offset, int size) { + private static byte[] getNextChunk(final ByteString bs, final int offset, int size) { int snapshotLength = bs.size(); int start = offset; if (size > snapshotLength) { @@ -166,31 +133,4 @@ public class SnapshotTrackerTest { bs.copyTo(nextChunk, start, 0, size); return nextChunk; } - - private static ByteString toByteString(Map state) { - ByteArrayOutputStream bos = null; - ObjectOutputStream os = null; - try { - try { - bos = new ByteArrayOutputStream(); - os = new ObjectOutputStream(bos); - os.writeObject(state); - byte[] snapshotBytes = bos.toByteArray(); - return ByteString.copyFrom(snapshotBytes); - } finally { - if (os != null) { - os.flush(); - os.close(); - } - if (bos != null) { - bos.close(); - } - } - } catch (IOException e) { - org.junit.Assert.fail("IOException in converting Hashmap to Bytestring:" + e); - } - return null; - } - - }