2 * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.controller.cluster.raft.behaviors;
11 import static org.junit.Assert.assertEquals;
12 import com.google.common.base.Optional;
13 import com.google.protobuf.ByteString;
14 import java.io.ByteArrayOutputStream;
15 import java.io.IOException;
16 import java.io.ObjectOutputStream;
17 import java.util.HashMap;
19 import org.junit.Assert;
20 import org.junit.Before;
21 import org.junit.Test;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
25 public class SnapshotTrackerTest {
27 Logger logger = LoggerFactory.getLogger(getClass());
29 Map<String, String> data;
30 ByteString byteString;
37 data = new HashMap<>();
38 data.put("key1", "value1");
39 data.put("key2", "value2");
40 data.put("key3", "value3");
42 byteString = toByteString(data);
43 chunk1 = getNextChunk(byteString, 0, 10);
44 chunk2 = getNextChunk(byteString, 10, 10);
45 chunk3 = getNextChunk(byteString, 20, byteString.size());
49 public void testAddChunk() throws SnapshotTracker.InvalidChunkException {
50 SnapshotTracker tracker1 = new SnapshotTracker(logger, 5);
52 tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
53 tracker1.addChunk(2, chunk2, Optional.<Integer>absent());
54 tracker1.addChunk(3, chunk3, Optional.<Integer>absent());
56 // Verify that an InvalidChunkException is thrown when we try to add a chunk to a sealed tracker
57 SnapshotTracker tracker2 = new SnapshotTracker(logger, 2);
59 tracker2.addChunk(1, chunk1, Optional.<Integer>absent());
60 tracker2.addChunk(2, chunk2, Optional.<Integer>absent());
63 tracker2.addChunk(3, chunk3, Optional.<Integer>absent());
65 } catch(SnapshotTracker.InvalidChunkException e){
66 e.getMessage().startsWith("Invalid chunk");
69 // The first chunk's index must at least be FIRST_CHUNK_INDEX
70 SnapshotTracker tracker3 = new SnapshotTracker(logger, 2);
73 tracker3.addChunk(AbstractLeader.FIRST_CHUNK_INDEX - 1, chunk1, Optional.<Integer>absent());
75 } catch(SnapshotTracker.InvalidChunkException e){
79 // Out of sequence chunk indexes won't work
80 SnapshotTracker tracker4 = new SnapshotTracker(logger, 2);
82 tracker4.addChunk(AbstractLeader.FIRST_CHUNK_INDEX, chunk1, Optional.<Integer>absent());
85 tracker4.addChunk(AbstractLeader.FIRST_CHUNK_INDEX+2, chunk2, Optional.<Integer>absent());
87 } catch(SnapshotTracker.InvalidChunkException e){
91 // No exceptions will be thrown when invalid chunk is added with the right sequence
92 // If the lastChunkHashCode is missing
93 SnapshotTracker tracker5 = new SnapshotTracker(logger, 2);
95 tracker5.addChunk(AbstractLeader.FIRST_CHUNK_INDEX, chunk1, Optional.<Integer>absent());
96 // Look I can add the same chunk again
97 tracker5.addChunk(AbstractLeader.FIRST_CHUNK_INDEX + 1, chunk1, Optional.<Integer>absent());
99 // An exception will be thrown when an invalid chunk is addedd with the right sequence
100 // when the lastChunkHashCode is present
101 SnapshotTracker tracker6 = new SnapshotTracker(logger, 2);
103 tracker6.addChunk(AbstractLeader.FIRST_CHUNK_INDEX, chunk1, Optional.of(-1));
106 // Here we add a second chunk and tell addChunk that the previous chunk had a hash code 777
107 tracker6.addChunk(AbstractLeader.FIRST_CHUNK_INDEX + 1, chunk2, Optional.of(777));
109 }catch(SnapshotTracker.InvalidChunkException e){
116 public void testGetSnapShot() throws SnapshotTracker.InvalidChunkException {
118 // Trying to get a snapshot before all chunks have been received will throw an exception
119 SnapshotTracker tracker1 = new SnapshotTracker(logger, 5);
121 tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
123 tracker1.getSnapshot();
125 } catch(IllegalStateException e){
129 SnapshotTracker tracker2 = new SnapshotTracker(logger, 3);
131 tracker2.addChunk(1, chunk1, Optional.<Integer>absent());
132 tracker2.addChunk(2, chunk2, Optional.<Integer>absent());
133 tracker2.addChunk(3, chunk3, Optional.<Integer>absent());
135 byte[] snapshot = tracker2.getSnapshot();
137 assertEquals(byteString, ByteString.copyFrom(snapshot));
141 public void testGetCollectedChunks() throws SnapshotTracker.InvalidChunkException {
142 SnapshotTracker tracker1 = new SnapshotTracker(logger, 5);
144 ByteString chunks = chunk1.concat(chunk2);
146 tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
147 tracker1.addChunk(2, chunk2, Optional.<Integer>absent());
149 assertEquals(chunks, tracker1.getCollectedChunks());
152 public ByteString getNextChunk (ByteString bs, int offset, int size){
153 int snapshotLength = bs.size();
155 if (size > snapshotLength) {
156 size = snapshotLength;
158 if ((start + size) > snapshotLength) {
159 size = snapshotLength - start;
162 return bs.substring(start, start + size);
165 private static ByteString toByteString(Map<String, String> state) {
166 ByteArrayOutputStream b = null;
167 ObjectOutputStream o = null;
170 b = new ByteArrayOutputStream();
171 o = new ObjectOutputStream(b);
172 o.writeObject(state);
173 byte[] snapshotBytes = b.toByteArray();
174 return ByteString.copyFrom(snapshotBytes);
184 } catch (IOException e) {
185 org.junit.Assert.fail("IOException in converting Hashmap to Bytestring:" + e);