Migrate sal-akka-raft tests
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / test / java / org / opendaylight / controller / cluster / raft / behaviors / SnapshotTrackerTest.java
index f103abcf8409d7d69abd51baee8bbb29198e943c..d8d2b4045bd9fa362cfd250927374d44bb3e88f7 100644 (file)
+/*
+ * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * 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 com.google.common.base.Optional;
-import com.google.protobuf.ByteString;
-import java.io.ByteArrayOutputStream;
+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 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<String, String> data;
-    ByteString byteString;
-    ByteString chunk1;
-    ByteString chunk2;
-    ByteString chunk3;
+    @Mock
+    private RaftActorContext mockContext;
+    private FileBackedOutputStream fbos;
+    private Map<String, String> data;
+    private ByteString byteString;
+    private byte[] chunk1;
+    private byte[] chunk2;
+    private byte[] chunk3;
 
     @Before
-    public void setup(){
+    public void setup() {
         data = new HashMap<>();
         data.put("key1", "value1");
         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);
-
-        tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
-        tracker1.addChunk(2, chunk2, Optional.<Integer>absent());
-        tracker1.addChunk(3, chunk3, Optional.<Integer>absent());
-
-        // Verify that an InvalidChunkException is thrown when we try to add a chunk to a sealed tracker
-        SnapshotTracker tracker2 = new SnapshotTracker(logger, 2);
-
-        tracker2.addChunk(1, chunk1, Optional.<Integer>absent());
-        tracker2.addChunk(2, chunk2, Optional.<Integer>absent());
-
-        try {
-            tracker2.addChunk(3, chunk3, Optional.<Integer>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);
-
-        try {
-            tracker3.addChunk(AbstractLeader.FIRST_CHUNK_INDEX - 1, chunk1, Optional.<Integer>absent());
-            Assert.fail();
-        } catch(SnapshotTracker.InvalidChunkException e){
+        verify(fbos).cleanup();
+    }
 
+    @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);
-
-        tracker4.addChunk(AbstractLeader.FIRST_CHUNK_INDEX, chunk1, Optional.<Integer>absent());
-
-        try {
-            tracker4.addChunk(AbstractLeader.FIRST_CHUNK_INDEX+2, chunk2, Optional.<Integer>absent());
-            Assert.fail();
-        } catch(SnapshotTracker.InvalidChunkException e){
-
+    @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);
-
-        tracker5.addChunk(AbstractLeader.FIRST_CHUNK_INDEX, chunk1, Optional.<Integer>absent());
-        // Look I can add the same chunk again
-        tracker5.addChunk(AbstractLeader.FIRST_CHUNK_INDEX + 1, chunk1, Optional.<Integer>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);
-
-        tracker6.addChunk(AbstractLeader.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(AbstractLeader.FIRST_CHUNK_INDEX + 1, chunk2, Optional.of(777));
-            Assert.fail();
-        }catch(SnapshotTracker.InvalidChunkException e){
-
+    @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);
-
-        tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
-        try {
-            tracker1.getSnapshot();
-            Assert.fail();
-        } catch(IllegalStateException e){
-
+    @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);
-
-        tracker2.addChunk(1, chunk1, Optional.<Integer>absent());
-        tracker2.addChunk(2, chunk2, Optional.<Integer>absent());
-        tracker2.addChunk(3, chunk3, Optional.<Integer>absent());
-
-        byte[] snapshot = tracker2.getSnapshot();
-
-        assertEquals(byteString, ByteString.copyFrom(snapshot));
     }
 
-    @Test
-    public void testGetCollectedChunks() throws SnapshotTracker.InvalidChunkException {
-        SnapshotTracker tracker1 = new SnapshotTracker(logger, 5);
-
-        ByteString chunks = chunk1.concat(chunk2);
-
-        tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
-        tracker1.addChunk(2, chunk2, Optional.<Integer>absent());
-
-        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 ByteString 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) {
             size = snapshotLength;
         } else {
-            if ((start + size) > snapshotLength) {
+            if (start + size > snapshotLength) {
                 size = snapshotLength - start;
             }
         }
-        return bs.substring(start, start + size);
-    }
 
-    private ByteString toByteString(Map<String, String> state) {
-        ByteArrayOutputStream b = null;
-        ObjectOutputStream o = null;
-        try {
-            try {
-                b = new ByteArrayOutputStream();
-                o = new ObjectOutputStream(b);
-                o.writeObject(state);
-                byte[] snapshotBytes = b.toByteArray();
-                return ByteString.copyFrom(snapshotBytes);
-            } finally {
-                if (o != null) {
-                    o.flush();
-                    o.close();
-                }
-                if (b != null) {
-                    b.close();
-                }
-            }
-        } catch (IOException e) {
-            org.junit.Assert.fail("IOException in converting Hashmap to Bytestring:" + e);
-        }
-        return null;
+        byte[] nextChunk = new byte[size];
+        bs.copyTo(nextChunk, start, 0, size);
+        return nextChunk;
     }
-
-
-}
\ No newline at end of file
+}