1 package org.opendaylight.controller.cluster.raft.behaviors;
3 import static org.junit.Assert.assertEquals;
4 import com.google.common.base.Optional;
5 import com.google.protobuf.ByteString;
6 import java.io.ByteArrayOutputStream;
7 import java.io.IOException;
8 import java.io.ObjectOutputStream;
9 import java.util.HashMap;
11 import org.junit.Assert;
12 import org.junit.Before;
13 import org.junit.Test;
14 import org.slf4j.Logger;
15 import org.slf4j.LoggerFactory;
17 public class SnapshotTrackerTest {
19 Logger logger = LoggerFactory.getLogger(getClass());
21 Map<String, String> data;
22 ByteString byteString;
29 data = new HashMap<>();
30 data.put("key1", "value1");
31 data.put("key2", "value2");
32 data.put("key3", "value3");
34 byteString = toByteString(data);
35 chunk1 = getNextChunk(byteString, 0, 10);
36 chunk2 = getNextChunk(byteString, 10, 10);
37 chunk3 = getNextChunk(byteString, 20, byteString.size());
41 public void testAddChunk() throws SnapshotTracker.InvalidChunkException {
42 SnapshotTracker tracker1 = new SnapshotTracker(logger, 5);
44 tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
45 tracker1.addChunk(2, chunk2, Optional.<Integer>absent());
46 tracker1.addChunk(3, chunk3, Optional.<Integer>absent());
48 // Verify that an InvalidChunkException is thrown when we try to add a chunk to a sealed tracker
49 SnapshotTracker tracker2 = new SnapshotTracker(logger, 2);
51 tracker2.addChunk(1, chunk1, Optional.<Integer>absent());
52 tracker2.addChunk(2, chunk2, Optional.<Integer>absent());
55 tracker2.addChunk(3, chunk3, Optional.<Integer>absent());
57 } catch(SnapshotTracker.InvalidChunkException e){
58 e.getMessage().startsWith("Invalid chunk");
61 // The first chunk's index must at least be FIRST_CHUNK_INDEX
62 SnapshotTracker tracker3 = new SnapshotTracker(logger, 2);
65 tracker3.addChunk(AbstractLeader.FIRST_CHUNK_INDEX - 1, chunk1, Optional.<Integer>absent());
67 } catch(SnapshotTracker.InvalidChunkException e){
71 // Out of sequence chunk indexes won't work
72 SnapshotTracker tracker4 = new SnapshotTracker(logger, 2);
74 tracker4.addChunk(AbstractLeader.FIRST_CHUNK_INDEX, chunk1, Optional.<Integer>absent());
77 tracker4.addChunk(AbstractLeader.FIRST_CHUNK_INDEX+2, chunk2, Optional.<Integer>absent());
79 } catch(SnapshotTracker.InvalidChunkException e){
83 // No exceptions will be thrown when invalid chunk is added with the right sequence
84 // If the lastChunkHashCode is missing
85 SnapshotTracker tracker5 = new SnapshotTracker(logger, 2);
87 tracker5.addChunk(AbstractLeader.FIRST_CHUNK_INDEX, chunk1, Optional.<Integer>absent());
88 // Look I can add the same chunk again
89 tracker5.addChunk(AbstractLeader.FIRST_CHUNK_INDEX + 1, chunk1, Optional.<Integer>absent());
91 // An exception will be thrown when an invalid chunk is addedd with the right sequence
92 // when the lastChunkHashCode is present
93 SnapshotTracker tracker6 = new SnapshotTracker(logger, 2);
95 tracker6.addChunk(AbstractLeader.FIRST_CHUNK_INDEX, chunk1, Optional.of(-1));
98 // Here we add a second chunk and tell addChunk that the previous chunk had a hash code 777
99 tracker6.addChunk(AbstractLeader.FIRST_CHUNK_INDEX + 1, chunk2, Optional.of(777));
101 }catch(SnapshotTracker.InvalidChunkException e){
108 public void testGetSnapShot() throws SnapshotTracker.InvalidChunkException {
110 // Trying to get a snapshot before all chunks have been received will throw an exception
111 SnapshotTracker tracker1 = new SnapshotTracker(logger, 5);
113 tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
115 tracker1.getSnapshot();
117 } catch(IllegalStateException e){
121 SnapshotTracker tracker2 = new SnapshotTracker(logger, 3);
123 tracker2.addChunk(1, chunk1, Optional.<Integer>absent());
124 tracker2.addChunk(2, chunk2, Optional.<Integer>absent());
125 tracker2.addChunk(3, chunk3, Optional.<Integer>absent());
127 byte[] snapshot = tracker2.getSnapshot();
129 assertEquals(byteString, ByteString.copyFrom(snapshot));
133 public void testGetCollectedChunks() throws SnapshotTracker.InvalidChunkException {
134 SnapshotTracker tracker1 = new SnapshotTracker(logger, 5);
136 ByteString chunks = chunk1.concat(chunk2);
138 tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
139 tracker1.addChunk(2, chunk2, Optional.<Integer>absent());
141 assertEquals(chunks, tracker1.getCollectedChunks());
144 public ByteString getNextChunk (ByteString bs, int offset, int size){
145 int snapshotLength = bs.size();
147 if (size > snapshotLength) {
148 size = snapshotLength;
150 if ((start + size) > snapshotLength) {
151 size = snapshotLength - start;
154 return bs.substring(start, start + size);
157 private ByteString toByteString(Map<String, String> state) {
158 ByteArrayOutputStream b = null;
159 ObjectOutputStream o = null;
162 b = new ByteArrayOutputStream();
163 o = new ObjectOutputStream(b);
164 o.writeObject(state);
165 byte[] snapshotBytes = b.toByteArray();
166 return ByteString.copyFrom(snapshotBytes);
176 } catch (IOException e) {
177 org.junit.Assert.fail("IOException in converting Hashmap to Bytestring:" + e);