1 package org.opendaylight.controller.cluster.raft.behaviors;
3 import static org.junit.Assert.assertEquals;
4 import static org.mockito.Mockito.mock;
5 import akka.event.LoggingAdapter;
6 import com.google.common.base.Optional;
7 import com.google.protobuf.ByteString;
8 import java.io.ByteArrayOutputStream;
9 import java.io.IOException;
10 import java.io.ObjectOutputStream;
11 import java.util.HashMap;
13 import org.junit.Assert;
14 import org.junit.Before;
15 import org.junit.Test;
17 public class SnapshotTrackerTest {
19 Map<String, String> data;
20 ByteString byteString;
27 data = new HashMap<>();
28 data.put("key1", "value1");
29 data.put("key2", "value2");
30 data.put("key3", "value3");
32 byteString = toByteString(data);
33 chunk1 = getNextChunk(byteString, 0, 10);
34 chunk2 = getNextChunk(byteString, 10, 10);
35 chunk3 = getNextChunk(byteString, 20, byteString.size());
39 public void testAddChunk() throws SnapshotTracker.InvalidChunkException {
40 SnapshotTracker tracker1 = new SnapshotTracker(mock(LoggingAdapter.class), 5);
42 tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
43 tracker1.addChunk(2, chunk2, Optional.<Integer>absent());
44 tracker1.addChunk(3, chunk3, Optional.<Integer>absent());
46 // Verify that an InvalidChunkException is thrown when we try to add a chunk to a sealed tracker
47 SnapshotTracker tracker2 = new SnapshotTracker(mock(LoggingAdapter.class), 2);
49 tracker2.addChunk(1, chunk1, Optional.<Integer>absent());
50 tracker2.addChunk(2, chunk2, Optional.<Integer>absent());
53 tracker2.addChunk(3, chunk3, Optional.<Integer>absent());
55 } catch(SnapshotTracker.InvalidChunkException e){
56 e.getMessage().startsWith("Invalid chunk");
59 // The first chunk's index must at least be FIRST_CHUNK_INDEX
60 SnapshotTracker tracker3 = new SnapshotTracker(mock(LoggingAdapter.class), 2);
63 tracker3.addChunk(AbstractLeader.FIRST_CHUNK_INDEX - 1, chunk1, Optional.<Integer>absent());
65 } catch(SnapshotTracker.InvalidChunkException e){
69 // Out of sequence chunk indexes won't work
70 SnapshotTracker tracker4 = new SnapshotTracker(mock(LoggingAdapter.class), 2);
72 tracker4.addChunk(AbstractLeader.FIRST_CHUNK_INDEX, chunk1, Optional.<Integer>absent());
75 tracker4.addChunk(AbstractLeader.FIRST_CHUNK_INDEX+2, chunk2, Optional.<Integer>absent());
77 } catch(SnapshotTracker.InvalidChunkException e){
81 // No exceptions will be thrown when invalid chunk is added with the right sequence
82 // If the lastChunkHashCode is missing
83 SnapshotTracker tracker5 = new SnapshotTracker(mock(LoggingAdapter.class), 2);
85 tracker5.addChunk(AbstractLeader.FIRST_CHUNK_INDEX, chunk1, Optional.<Integer>absent());
86 // Look I can add the same chunk again
87 tracker5.addChunk(AbstractLeader.FIRST_CHUNK_INDEX + 1, chunk1, Optional.<Integer>absent());
89 // An exception will be thrown when an invalid chunk is addedd with the right sequence
90 // when the lastChunkHashCode is present
91 SnapshotTracker tracker6 = new SnapshotTracker(mock(LoggingAdapter.class), 2);
93 tracker6.addChunk(AbstractLeader.FIRST_CHUNK_INDEX, chunk1, Optional.of(-1));
96 // Here we add a second chunk and tell addChunk that the previous chunk had a hash code 777
97 tracker6.addChunk(AbstractLeader.FIRST_CHUNK_INDEX + 1, chunk2, Optional.of(777));
99 }catch(SnapshotTracker.InvalidChunkException e){
106 public void testGetSnapShot() throws SnapshotTracker.InvalidChunkException {
108 // Trying to get a snapshot before all chunks have been received will throw an exception
109 SnapshotTracker tracker1 = new SnapshotTracker(mock(LoggingAdapter.class), 5);
111 tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
113 tracker1.getSnapshot();
115 } catch(IllegalStateException e){
119 SnapshotTracker tracker2 = new SnapshotTracker(mock(LoggingAdapter.class), 3);
121 tracker2.addChunk(1, chunk1, Optional.<Integer>absent());
122 tracker2.addChunk(2, chunk2, Optional.<Integer>absent());
123 tracker2.addChunk(3, chunk3, Optional.<Integer>absent());
125 byte[] snapshot = tracker2.getSnapshot();
127 assertEquals(byteString, ByteString.copyFrom(snapshot));
131 public void testGetCollectedChunks() throws SnapshotTracker.InvalidChunkException {
132 SnapshotTracker tracker1 = new SnapshotTracker(mock(LoggingAdapter.class), 5);
134 ByteString chunks = chunk1.concat(chunk2);
136 tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
137 tracker1.addChunk(2, chunk2, Optional.<Integer>absent());
139 assertEquals(chunks, tracker1.getCollectedChunks());
142 public ByteString getNextChunk (ByteString bs, int offset, int size){
143 int snapshotLength = bs.size();
145 if (size > snapshotLength) {
146 size = snapshotLength;
148 if ((start + size) > snapshotLength) {
149 size = snapshotLength - start;
152 return bs.substring(start, start + size);
155 private ByteString toByteString(Map<String, String> state) {
156 ByteArrayOutputStream b = null;
157 ObjectOutputStream o = null;
160 b = new ByteArrayOutputStream();
161 o = new ObjectOutputStream(b);
162 o.writeObject(state);
163 byte[] snapshotBytes = b.toByteArray();
164 return ByteString.copyFrom(snapshotBytes);
174 } catch (IOException e) {
175 org.junit.Assert.fail("IOException in converting Hashmap to Bytestring:" + e);