f103abcf8409d7d69abd51baee8bbb29198e943c
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / test / java / org / opendaylight / controller / cluster / raft / behaviors / SnapshotTrackerTest.java
1 package org.opendaylight.controller.cluster.raft.behaviors;
2
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;
10 import java.util.Map;
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;
16
17 public class SnapshotTrackerTest {
18
19     Logger logger = LoggerFactory.getLogger(getClass());
20
21     Map<String, String> data;
22     ByteString byteString;
23     ByteString chunk1;
24     ByteString chunk2;
25     ByteString chunk3;
26
27     @Before
28     public void setup(){
29         data = new HashMap<>();
30         data.put("key1", "value1");
31         data.put("key2", "value2");
32         data.put("key3", "value3");
33
34         byteString = toByteString(data);
35         chunk1 = getNextChunk(byteString, 0, 10);
36         chunk2 = getNextChunk(byteString, 10, 10);
37         chunk3 = getNextChunk(byteString, 20, byteString.size());
38     }
39
40     @Test
41     public void testAddChunk() throws SnapshotTracker.InvalidChunkException {
42         SnapshotTracker tracker1 = new SnapshotTracker(logger, 5);
43
44         tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
45         tracker1.addChunk(2, chunk2, Optional.<Integer>absent());
46         tracker1.addChunk(3, chunk3, Optional.<Integer>absent());
47
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);
50
51         tracker2.addChunk(1, chunk1, Optional.<Integer>absent());
52         tracker2.addChunk(2, chunk2, Optional.<Integer>absent());
53
54         try {
55             tracker2.addChunk(3, chunk3, Optional.<Integer>absent());
56             Assert.fail();
57         } catch(SnapshotTracker.InvalidChunkException e){
58             e.getMessage().startsWith("Invalid chunk");
59         }
60
61         // The first chunk's index must at least be FIRST_CHUNK_INDEX
62         SnapshotTracker tracker3 = new SnapshotTracker(logger, 2);
63
64         try {
65             tracker3.addChunk(AbstractLeader.FIRST_CHUNK_INDEX - 1, chunk1, Optional.<Integer>absent());
66             Assert.fail();
67         } catch(SnapshotTracker.InvalidChunkException e){
68
69         }
70
71         // Out of sequence chunk indexes won't work
72         SnapshotTracker tracker4 = new SnapshotTracker(logger, 2);
73
74         tracker4.addChunk(AbstractLeader.FIRST_CHUNK_INDEX, chunk1, Optional.<Integer>absent());
75
76         try {
77             tracker4.addChunk(AbstractLeader.FIRST_CHUNK_INDEX+2, chunk2, Optional.<Integer>absent());
78             Assert.fail();
79         } catch(SnapshotTracker.InvalidChunkException e){
80
81         }
82
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);
86
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());
90
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);
94
95         tracker6.addChunk(AbstractLeader.FIRST_CHUNK_INDEX, chunk1, Optional.of(-1));
96
97         try {
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));
100             Assert.fail();
101         }catch(SnapshotTracker.InvalidChunkException e){
102
103         }
104
105     }
106
107     @Test
108     public void testGetSnapShot() throws SnapshotTracker.InvalidChunkException {
109
110         // Trying to get a snapshot before all chunks have been received will throw an exception
111         SnapshotTracker tracker1 = new SnapshotTracker(logger, 5);
112
113         tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
114         try {
115             tracker1.getSnapshot();
116             Assert.fail();
117         } catch(IllegalStateException e){
118
119         }
120
121         SnapshotTracker tracker2 = new SnapshotTracker(logger, 3);
122
123         tracker2.addChunk(1, chunk1, Optional.<Integer>absent());
124         tracker2.addChunk(2, chunk2, Optional.<Integer>absent());
125         tracker2.addChunk(3, chunk3, Optional.<Integer>absent());
126
127         byte[] snapshot = tracker2.getSnapshot();
128
129         assertEquals(byteString, ByteString.copyFrom(snapshot));
130     }
131
132     @Test
133     public void testGetCollectedChunks() throws SnapshotTracker.InvalidChunkException {
134         SnapshotTracker tracker1 = new SnapshotTracker(logger, 5);
135
136         ByteString chunks = chunk1.concat(chunk2);
137
138         tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
139         tracker1.addChunk(2, chunk2, Optional.<Integer>absent());
140
141         assertEquals(chunks, tracker1.getCollectedChunks());
142     }
143
144     public ByteString getNextChunk (ByteString bs, int offset, int size){
145         int snapshotLength = bs.size();
146         int start = offset;
147         if (size > snapshotLength) {
148             size = snapshotLength;
149         } else {
150             if ((start + size) > snapshotLength) {
151                 size = snapshotLength - start;
152             }
153         }
154         return bs.substring(start, start + size);
155     }
156
157     private ByteString toByteString(Map<String, String> state) {
158         ByteArrayOutputStream b = null;
159         ObjectOutputStream o = null;
160         try {
161             try {
162                 b = new ByteArrayOutputStream();
163                 o = new ObjectOutputStream(b);
164                 o.writeObject(state);
165                 byte[] snapshotBytes = b.toByteArray();
166                 return ByteString.copyFrom(snapshotBytes);
167             } finally {
168                 if (o != null) {
169                     o.flush();
170                     o.close();
171                 }
172                 if (b != null) {
173                     b.close();
174                 }
175             }
176         } catch (IOException e) {
177             org.junit.Assert.fail("IOException in converting Hashmap to Bytestring:" + e);
178         }
179         return null;
180     }
181
182
183 }