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