2 * Copyright (c) 2017 Brocade Communications 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
8 package org.opendaylight.controller.cluster.persistence;
10 import static java.lang.Boolean.FALSE;
11 import static java.lang.Boolean.TRUE;
12 import static org.junit.Assert.assertEquals;
13 import static org.opendaylight.controller.cluster.persistence.LocalSnapshotStoreSpecTest.SNAPSHOT_DIR;
14 import static org.opendaylight.controller.cluster.persistence.LocalSnapshotStoreSpecTest.cleanSnapshotDir;
15 import static org.opendaylight.controller.cluster.persistence.LocalSnapshotStoreSpecTest.createSnapshotDir;
17 import akka.actor.ActorRef;
18 import akka.actor.ActorSystem;
19 import akka.actor.ExtendedActorSystem;
20 import akka.persistence.Persistence;
21 import akka.persistence.SelectedSnapshot;
22 import akka.persistence.SnapshotMetadata;
23 import akka.persistence.SnapshotProtocol;
24 import akka.persistence.SnapshotProtocol.LoadSnapshot;
25 import akka.persistence.SnapshotProtocol.LoadSnapshotFailed;
26 import akka.persistence.SnapshotProtocol.LoadSnapshotResult;
27 import akka.persistence.SnapshotSelectionCriteria;
28 import akka.persistence.serialization.Snapshot;
29 import akka.persistence.serialization.SnapshotSerializer;
30 import akka.testkit.javadsl.TestKit;
31 import com.typesafe.config.ConfigFactory;
33 import java.io.FileOutputStream;
34 import java.io.IOException;
35 import java.io.UnsupportedEncodingException;
36 import java.net.URLEncoder;
37 import java.nio.charset.StandardCharsets;
38 import org.apache.commons.io.FileUtils;
39 import org.apache.commons.lang.SerializationUtils;
40 import org.junit.After;
41 import org.junit.AfterClass;
42 import org.junit.Before;
43 import org.junit.BeforeClass;
44 import org.junit.Test;
45 import org.junit.runner.RunWith;
46 import org.mockito.junit.MockitoJUnitRunner;
50 * Unit tests for LocalSnapshotStore. These are in addition to LocalSnapshotStoreSpecTest to cover a few cases
51 * that SnapshotStoreSpec doesn't.
53 * @author Thomas Pantelis
55 @RunWith(MockitoJUnitRunner.StrictStubs.class)
56 public class LocalSnapshotStoreTest {
57 private static final String PERSISTENCE_ID = "member-1-shard-default-config";
58 private static final String PREFIX_BASED_SHARD_PERSISTENCE_ID = "member-1-shard-id-ints!-config";
60 private static ActorSystem system;
61 private static ActorRef snapshotStore;
64 public static void staticSetup() {
67 system = ActorSystem.create("test", ConfigFactory.load("LocalSnapshotStoreTest.conf"));
68 snapshotStore = system.registerExtension(Persistence.lookup()).snapshotStoreFor(null, ConfigFactory.empty());
72 public static void staticCleanup() {
73 FileUtils.deleteQuietly(SNAPSHOT_DIR);
74 TestKit.shutdownActorSystem(system);
83 public void cleanup() {
88 public void testDoLoadAsync() throws IOException {
89 createSnapshotFile(PERSISTENCE_ID, "one", 0, 1000);
90 createSnapshotFile(PERSISTENCE_ID, "two", 1, 2000);
91 createSnapshotFile(PERSISTENCE_ID, "three", 1, 3000);
93 createSnapshotFile(PREFIX_BASED_SHARD_PERSISTENCE_ID, "foo", 0, 1000);
94 createSnapshotFile(PREFIX_BASED_SHARD_PERSISTENCE_ID, "bar", 1, 2000);
95 createSnapshotFile(PREFIX_BASED_SHARD_PERSISTENCE_ID, "foobar", 1, 3000);
97 createSnapshotFile("member-1-shard-default-oper", "foo", 0, 1000);
98 createSnapshotFile("member-1-shard-toaster-oper", "foo", 0, 1000);
99 new File(SNAPSHOT_DIR, "other").createNewFile();
100 new File(SNAPSHOT_DIR, "other-1485349217290").createNewFile();
102 SnapshotMetadata metadata3 = new SnapshotMetadata(PERSISTENCE_ID, 1, 3000);
104 TestKit probe = new TestKit(system);
105 snapshotStore.tell(new LoadSnapshot(PERSISTENCE_ID,
106 SnapshotSelectionCriteria.latest(), Long.MAX_VALUE), probe.getRef());
107 LoadSnapshotResult result = probe.expectMsgClass(LoadSnapshotResult.class);
108 Option<SelectedSnapshot> possibleSnapshot = result.snapshot();
110 assertEquals("SelectedSnapshot present", TRUE, possibleSnapshot.nonEmpty());
111 assertEquals("SelectedSnapshot metadata", metadata3, possibleSnapshot.get().metadata());
112 assertEquals("SelectedSnapshot snapshot", "three", possibleSnapshot.get().snapshot());
114 snapshotStore.tell(new LoadSnapshot(PREFIX_BASED_SHARD_PERSISTENCE_ID,
115 SnapshotSelectionCriteria.latest(), Long.MAX_VALUE), probe.getRef());
116 result = probe.expectMsgClass(LoadSnapshotResult.class);
117 possibleSnapshot = result.snapshot();
119 SnapshotMetadata prefixBasedShardMetada3 = new SnapshotMetadata(PREFIX_BASED_SHARD_PERSISTENCE_ID, 1, 3000);
121 assertEquals("SelectedSnapshot present", TRUE, possibleSnapshot.nonEmpty());
122 assertEquals("SelectedSnapshot metadata", prefixBasedShardMetada3, possibleSnapshot.get().metadata());
123 assertEquals("SelectedSnapshot snapshot", "foobar", possibleSnapshot.get().snapshot());
127 public void testDoLoadAsyncWithNoSnapshots() {
128 TestKit probe = new TestKit(system);
129 snapshotStore.tell(new LoadSnapshot(PERSISTENCE_ID,
130 SnapshotSelectionCriteria.latest(), Long.MAX_VALUE), probe.getRef());
131 LoadSnapshotResult result = probe.expectMsgClass(LoadSnapshotResult.class);
132 Option<SelectedSnapshot> possibleSnapshot = result.snapshot();
134 assertEquals("SelectedSnapshot present", FALSE, possibleSnapshot.nonEmpty());
138 public void testDoLoadAsyncWithRetry() throws IOException {
139 createSnapshotFile(PERSISTENCE_ID, "one", 0, 1000);
140 createSnapshotFile(PERSISTENCE_ID, null, 1, 2000);
142 SnapshotMetadata metadata = new SnapshotMetadata(PERSISTENCE_ID, 0, 1000);
144 TestKit probe = new TestKit(system);
145 snapshotStore.tell(new LoadSnapshot(PERSISTENCE_ID,
146 SnapshotSelectionCriteria.latest(), Long.MAX_VALUE), probe.getRef());
147 LoadSnapshotResult result = probe.expectMsgClass(LoadSnapshotResult.class);
148 Option<SelectedSnapshot> possibleSnapshot = result.snapshot();
150 assertEquals("SelectedSnapshot present", TRUE, possibleSnapshot.nonEmpty());
151 assertEquals("SelectedSnapshot metadata", metadata, possibleSnapshot.get().metadata());
152 assertEquals("SelectedSnapshot snapshot", "one", possibleSnapshot.get().snapshot());
155 @SuppressWarnings("checkstyle:illegalThrows")
156 @Test(expected = IOException.class)
157 public void testDoLoadAsyncWithFailure() throws Throwable {
158 createSnapshotFile(PERSISTENCE_ID, null, 1, 2000);
160 TestKit probe = new TestKit(system);
161 snapshotStore.tell(new SnapshotProtocol.LoadSnapshot(PERSISTENCE_ID,
162 SnapshotSelectionCriteria.latest(), Long.MAX_VALUE), probe.getRef());
163 LoadSnapshotFailed failed = probe.expectMsgClass(LoadSnapshotFailed.class);
164 throw failed.cause();
168 public void testDoLoadAsyncWithAkkaSerializedSnapshot() throws IOException {
169 SnapshotSerializer snapshotSerializer = new SnapshotSerializer((ExtendedActorSystem) system);
171 String name = toSnapshotName(PERSISTENCE_ID, 1, 1000);
172 try (FileOutputStream fos = new FileOutputStream(new File(SNAPSHOT_DIR, name))) {
173 fos.write(snapshotSerializer.toBinary(new Snapshot("one")));
176 SnapshotMetadata metadata = new SnapshotMetadata(PERSISTENCE_ID, 1, 1000);
178 TestKit probe = new TestKit(system);
179 snapshotStore.tell(new LoadSnapshot(PERSISTENCE_ID,
180 SnapshotSelectionCriteria.latest(), Long.MAX_VALUE), probe.getRef());
181 LoadSnapshotResult result = probe.expectMsgClass(LoadSnapshotResult.class);
182 Option<SelectedSnapshot> possibleSnapshot = result.snapshot();
184 assertEquals("SelectedSnapshot present", TRUE, possibleSnapshot.nonEmpty());
185 assertEquals("SelectedSnapshot metadata", metadata, possibleSnapshot.get().metadata());
186 assertEquals("SelectedSnapshot snapshot", "one", possibleSnapshot.get().snapshot());
189 private static void createSnapshotFile(final String persistenceId, final String payload, final int seqNr,
190 final int timestamp) throws IOException {
191 String name = toSnapshotName(persistenceId, seqNr, timestamp);
192 try (FileOutputStream fos = new FileOutputStream(new File(SNAPSHOT_DIR, name))) {
193 if (payload != null) {
194 fos.write(SerializationUtils.serialize(payload));
199 private static String toSnapshotName(final String persistenceId, final int seqNr, final int timestamp)
200 throws UnsupportedEncodingException {
201 final String encodedPersistenceId = URLEncoder.encode(persistenceId, StandardCharsets.UTF_8.name());
202 return "snapshot-" + encodedPersistenceId + "-" + seqNr + "-" + timestamp;