Fix FindBugs warnings in sal-akk-raft
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / test / java / org / opendaylight / controller / cluster / raft / behaviors / SnapshotTrackerTest.java
1 /*
2  * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.cluster.raft.behaviors;
10
11 import static org.junit.Assert.assertEquals;
12
13 import com.google.common.base.Optional;
14 import com.google.protobuf.ByteString;
15 import java.io.ByteArrayOutputStream;
16 import java.io.IOException;
17 import java.io.ObjectOutputStream;
18 import java.util.Arrays;
19 import java.util.HashMap;
20 import java.util.Map;
21 import org.junit.Assert;
22 import org.junit.Before;
23 import org.junit.Test;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 public class SnapshotTrackerTest {
28
29     Logger logger = LoggerFactory.getLogger(getClass());
30
31     Map<String, String> data;
32     ByteString byteString;
33     byte[] chunk1;
34     byte[] chunk2;
35     byte[] chunk3;
36
37     @Before
38     public void setup() {
39         data = new HashMap<>();
40         data.put("key1", "value1");
41         data.put("key2", "value2");
42         data.put("key3", "value3");
43
44         byteString = toByteString(data);
45         chunk1 = getNextChunk(byteString, 0, 10);
46         chunk2 = getNextChunk(byteString, 10, 10);
47         chunk3 = getNextChunk(byteString, 20, byteString.size());
48     }
49
50     @Test
51     public void testAddChunk() throws SnapshotTracker.InvalidChunkException {
52         SnapshotTracker tracker1 = new SnapshotTracker(logger, 5, "leader");
53
54         tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
55         tracker1.addChunk(2, chunk2, Optional.<Integer>absent());
56         tracker1.addChunk(3, chunk3, Optional.<Integer>absent());
57
58         // Verify that an InvalidChunkException is thrown when we try to add a chunk to a sealed tracker
59         SnapshotTracker tracker2 = new SnapshotTracker(logger, 2, "leader");
60
61         tracker2.addChunk(1, chunk1, Optional.<Integer>absent());
62         tracker2.addChunk(2, chunk2, Optional.<Integer>absent());
63
64         try {
65             tracker2.addChunk(3, chunk3, Optional.<Integer>absent());
66             Assert.fail();
67         } catch (SnapshotTracker.InvalidChunkException e) {
68             // expected
69         }
70
71         // The first chunk's index must at least be FIRST_CHUNK_INDEX
72         SnapshotTracker tracker3 = new SnapshotTracker(logger, 2, "leader");
73
74         try {
75             tracker3.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX - 1, chunk1, Optional.<Integer>absent());
76             Assert.fail();
77         } catch (SnapshotTracker.InvalidChunkException e) {
78             // expected
79         }
80
81         // Out of sequence chunk indexes won't work
82         SnapshotTracker tracker4 = new SnapshotTracker(logger, 2, "leader");
83
84         tracker4.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX, chunk1, Optional.<Integer>absent());
85
86         try {
87             tracker4.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX + 2, chunk2, Optional.<Integer>absent());
88             Assert.fail();
89         } catch (SnapshotTracker.InvalidChunkException e) {
90             // expected
91         }
92
93         // No exceptions will be thrown when invalid chunk is added with the right sequence
94         // If the lastChunkHashCode is missing
95         SnapshotTracker tracker5 = new SnapshotTracker(logger, 2, "leader");
96
97         tracker5.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX, chunk1, Optional.<Integer>absent());
98         // Look I can add the same chunk again
99         tracker5.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX + 1, chunk1, Optional.<Integer>absent());
100
101         // An exception will be thrown when an invalid chunk is addedd with the right sequence
102         // when the lastChunkHashCode is present
103         SnapshotTracker tracker6 = new SnapshotTracker(logger, 2, "leader");
104
105         tracker6.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX, chunk1, Optional.of(-1));
106
107         try {
108             // Here we add a second chunk and tell addChunk that the previous chunk had a hash code 777
109             tracker6.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX + 1, chunk2, Optional.of(777));
110             Assert.fail();
111         } catch (SnapshotTracker.InvalidChunkException e) {
112             // expected
113         }
114
115     }
116
117     @Test
118     public void testGetSnapShot() throws SnapshotTracker.InvalidChunkException {
119
120         // Trying to get a snapshot before all chunks have been received will throw an exception
121         SnapshotTracker tracker1 = new SnapshotTracker(logger, 5, "leader");
122
123         tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
124         try {
125             tracker1.getSnapshot();
126             Assert.fail();
127         } catch (IllegalStateException e) {
128             // expected
129         }
130
131         SnapshotTracker tracker2 = new SnapshotTracker(logger, 3, "leader");
132
133         tracker2.addChunk(1, chunk1, Optional.of(LeaderInstallSnapshotState.INITIAL_LAST_CHUNK_HASH_CODE));
134         tracker2.addChunk(2, chunk2, Optional.of(Arrays.hashCode(chunk1)));
135         tracker2.addChunk(3, chunk3, Optional.of(Arrays.hashCode(chunk2)));
136
137         byte[] snapshot = tracker2.getSnapshot();
138
139         assertEquals(byteString, ByteString.copyFrom(snapshot));
140     }
141
142     @Test
143     public void testGetCollectedChunks() throws SnapshotTracker.InvalidChunkException {
144         SnapshotTracker tracker1 = new SnapshotTracker(logger, 5, "leader");
145
146         ByteString chunks = ByteString.copyFrom(chunk1).concat(ByteString.copyFrom(chunk2));
147
148         tracker1.addChunk(1, chunk1, Optional.of(LeaderInstallSnapshotState.INITIAL_LAST_CHUNK_HASH_CODE));
149         tracker1.addChunk(2, chunk2, Optional.of(Arrays.hashCode(chunk1)));
150
151         assertEquals(chunks, tracker1.getCollectedChunks());
152     }
153
154     public byte[] getNextChunk(ByteString bs, int offset, int size) {
155         int snapshotLength = bs.size();
156         int start = offset;
157         if (size > snapshotLength) {
158             size = snapshotLength;
159         } else {
160             if (start + size > snapshotLength) {
161                 size = snapshotLength - start;
162             }
163         }
164
165         byte[] nextChunk = new byte[size];
166         bs.copyTo(nextChunk, start, 0, size);
167         return nextChunk;
168     }
169
170     private static ByteString toByteString(Map<String, String> state) {
171         ByteArrayOutputStream bos = null;
172         ObjectOutputStream os = null;
173         try {
174             try {
175                 bos = new ByteArrayOutputStream();
176                 os = new ObjectOutputStream(bos);
177                 os.writeObject(state);
178                 byte[] snapshotBytes = bos.toByteArray();
179                 return ByteString.copyFrom(snapshotBytes);
180             } finally {
181                 if (os != null) {
182                     os.flush();
183                     os.close();
184                 }
185                 if (bos != null) {
186                     bos.close();
187                 }
188             }
189         } catch (IOException e) {
190             org.junit.Assert.fail("IOException in converting Hashmap to Bytestring:" + e);
191         }
192         return null;
193     }
194
195
196 }