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;
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;
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;
27 public class SnapshotTrackerTest {
29 Logger logger = LoggerFactory.getLogger(getClass());
31 Map<String, String> data;
32 ByteString byteString;
39 data = new HashMap<>();
40 data.put("key1", "value1");
41 data.put("key2", "value2");
42 data.put("key3", "value3");
44 byteString = toByteString(data);
45 chunk1 = getNextChunk(byteString, 0, 10);
46 chunk2 = getNextChunk(byteString, 10, 10);
47 chunk3 = getNextChunk(byteString, 20, byteString.size());
51 public void testAddChunk() throws SnapshotTracker.InvalidChunkException {
52 SnapshotTracker tracker1 = new SnapshotTracker(logger, 5, "leader");
54 tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
55 tracker1.addChunk(2, chunk2, Optional.<Integer>absent());
56 tracker1.addChunk(3, chunk3, Optional.<Integer>absent());
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");
61 tracker2.addChunk(1, chunk1, Optional.<Integer>absent());
62 tracker2.addChunk(2, chunk2, Optional.<Integer>absent());
65 tracker2.addChunk(3, chunk3, Optional.<Integer>absent());
67 } catch (SnapshotTracker.InvalidChunkException e) {
68 e.getMessage().startsWith("Invalid chunk");
71 // The first chunk's index must at least be FIRST_CHUNK_INDEX
72 SnapshotTracker tracker3 = new SnapshotTracker(logger, 2, "leader");
75 tracker3.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX - 1, chunk1, Optional.<Integer>absent());
77 } catch (SnapshotTracker.InvalidChunkException e) {
81 // Out of sequence chunk indexes won't work
82 SnapshotTracker tracker4 = new SnapshotTracker(logger, 2, "leader");
84 tracker4.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX, chunk1, Optional.<Integer>absent());
87 tracker4.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX + 2, chunk2, Optional.<Integer>absent());
89 } catch (SnapshotTracker.InvalidChunkException e) {
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");
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());
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");
105 tracker6.addChunk(LeaderInstallSnapshotState.FIRST_CHUNK_INDEX, chunk1, Optional.of(-1));
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));
111 } catch (SnapshotTracker.InvalidChunkException e) {
118 public void testGetSnapShot() throws SnapshotTracker.InvalidChunkException {
120 // Trying to get a snapshot before all chunks have been received will throw an exception
121 SnapshotTracker tracker1 = new SnapshotTracker(logger, 5, "leader");
123 tracker1.addChunk(1, chunk1, Optional.<Integer>absent());
125 tracker1.getSnapshot();
127 } catch (IllegalStateException e) {
131 SnapshotTracker tracker2 = new SnapshotTracker(logger, 3, "leader");
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)));
137 byte[] snapshot = tracker2.getSnapshot();
139 assertEquals(byteString, ByteString.copyFrom(snapshot));
143 public void testGetCollectedChunks() throws SnapshotTracker.InvalidChunkException {
144 SnapshotTracker tracker1 = new SnapshotTracker(logger, 5, "leader");
146 ByteString chunks = ByteString.copyFrom(chunk1).concat(ByteString.copyFrom(chunk2));
148 tracker1.addChunk(1, chunk1, Optional.of(LeaderInstallSnapshotState.INITIAL_LAST_CHUNK_HASH_CODE));
149 tracker1.addChunk(2, chunk2, Optional.of(Arrays.hashCode(chunk1)));
151 assertEquals(chunks, tracker1.getCollectedChunks());
154 public byte[] getNextChunk(ByteString bs, int offset, int size) {
155 int snapshotLength = bs.size();
157 if (size > snapshotLength) {
158 size = snapshotLength;
160 if (start + size > snapshotLength) {
161 size = snapshotLength - start;
165 byte[] nextChunk = new byte[size];
166 bs.copyTo(nextChunk, start, 0, size);
170 private static ByteString toByteString(Map<String, String> state) {
171 ByteArrayOutputStream bos = null;
172 ObjectOutputStream os = null;
175 bos = new ByteArrayOutputStream();
176 os = new ObjectOutputStream(bos);
177 os.writeObject(state);
178 byte[] snapshotBytes = bos.toByteArray();
179 return ByteString.copyFrom(snapshotBytes);
189 } catch (IOException e) {
190 org.junit.Assert.fail("IOException in converting Hashmap to Bytestring:" + e);