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.net.URLEncoder;
36 import java.nio.charset.StandardCharsets;
37 import org.apache.commons.io.FileUtils;
38 import org.apache.commons.lang3.SerializationUtils;
39 import org.junit.After;
40 import org.junit.AfterClass;
41 import org.junit.Before;
42 import org.junit.BeforeClass;
43 import org.junit.Test;
44 import org.junit.runner.RunWith;
45 import org.mockito.junit.MockitoJUnitRunner;
49 * Unit tests for LocalSnapshotStore. These are in addition to LocalSnapshotStoreSpecTest to cover a few cases
50 * that SnapshotStoreSpec doesn't.
52 * @author Thomas Pantelis
54 @RunWith(MockitoJUnitRunner.StrictStubs.class)
55 public class LocalSnapshotStoreTest {
56 private static final String PERSISTENCE_ID = "member-1-shard-default-config";
57 private static final String PREFIX_BASED_SHARD_PERSISTENCE_ID = "member-1-shard-id-ints!-config";
59 private static ActorSystem system;
60 private static ActorRef snapshotStore;
63 public static void staticSetup() {
66 system = ActorSystem.create("test", ConfigFactory.load("LocalSnapshotStoreTest.conf"));
67 snapshotStore = system.registerExtension(Persistence.lookup()).snapshotStoreFor(null, ConfigFactory.empty());
71 public static void staticCleanup() {
72 FileUtils.deleteQuietly(SNAPSHOT_DIR);
73 TestKit.shutdownActorSystem(system);
82 public void cleanup() {
87 public void testDoLoadAsync() throws IOException {
88 createSnapshotFile(PERSISTENCE_ID, "one", 0, 1000);
89 createSnapshotFile(PERSISTENCE_ID, "two", 1, 2000);
90 createSnapshotFile(PERSISTENCE_ID, "three", 1, 3000);
92 createSnapshotFile(PREFIX_BASED_SHARD_PERSISTENCE_ID, "foo", 0, 1000);
93 createSnapshotFile(PREFIX_BASED_SHARD_PERSISTENCE_ID, "bar", 1, 2000);
94 createSnapshotFile(PREFIX_BASED_SHARD_PERSISTENCE_ID, "foobar", 1, 3000);
96 createSnapshotFile("member-1-shard-default-oper", "foo", 0, 1000);
97 createSnapshotFile("member-1-shard-toaster-oper", "foo", 0, 1000);
98 new File(SNAPSHOT_DIR, "other").createNewFile();
99 new File(SNAPSHOT_DIR, "other-1485349217290").createNewFile();
101 SnapshotMetadata metadata3 = new SnapshotMetadata(PERSISTENCE_ID, 1, 3000);
103 TestKit probe = new TestKit(system);
104 snapshotStore.tell(new LoadSnapshot(PERSISTENCE_ID,
105 SnapshotSelectionCriteria.latest(), Long.MAX_VALUE), probe.getRef());
106 LoadSnapshotResult result = probe.expectMsgClass(LoadSnapshotResult.class);
107 Option<SelectedSnapshot> possibleSnapshot = result.snapshot();
109 assertEquals("SelectedSnapshot present", TRUE, possibleSnapshot.nonEmpty());
110 assertEquals("SelectedSnapshot metadata", metadata3, possibleSnapshot.get().metadata());
111 assertEquals("SelectedSnapshot snapshot", "three", possibleSnapshot.get().snapshot());
113 snapshotStore.tell(new LoadSnapshot(PREFIX_BASED_SHARD_PERSISTENCE_ID,
114 SnapshotSelectionCriteria.latest(), Long.MAX_VALUE), probe.getRef());
115 result = probe.expectMsgClass(LoadSnapshotResult.class);
116 possibleSnapshot = result.snapshot();
118 SnapshotMetadata prefixBasedShardMetada3 = new SnapshotMetadata(PREFIX_BASED_SHARD_PERSISTENCE_ID, 1, 3000);
120 assertEquals("SelectedSnapshot present", TRUE, possibleSnapshot.nonEmpty());
121 assertEquals("SelectedSnapshot metadata", prefixBasedShardMetada3, possibleSnapshot.get().metadata());
122 assertEquals("SelectedSnapshot snapshot", "foobar", possibleSnapshot.get().snapshot());
126 public void testDoLoadAsyncWithNoSnapshots() {
127 TestKit probe = new TestKit(system);
128 snapshotStore.tell(new LoadSnapshot(PERSISTENCE_ID,
129 SnapshotSelectionCriteria.latest(), Long.MAX_VALUE), probe.getRef());
130 LoadSnapshotResult result = probe.expectMsgClass(LoadSnapshotResult.class);
131 Option<SelectedSnapshot> possibleSnapshot = result.snapshot();
133 assertEquals("SelectedSnapshot present", FALSE, possibleSnapshot.nonEmpty());
137 public void testDoLoadAsyncWithRetry() throws IOException {
138 createSnapshotFile(PERSISTENCE_ID, "one", 0, 1000);
139 createSnapshotFile(PERSISTENCE_ID, null, 1, 2000);
141 SnapshotMetadata metadata = new SnapshotMetadata(PERSISTENCE_ID, 0, 1000);
143 TestKit probe = new TestKit(system);
144 snapshotStore.tell(new LoadSnapshot(PERSISTENCE_ID,
145 SnapshotSelectionCriteria.latest(), Long.MAX_VALUE), probe.getRef());
146 LoadSnapshotResult result = probe.expectMsgClass(LoadSnapshotResult.class);
147 Option<SelectedSnapshot> possibleSnapshot = result.snapshot();
149 assertEquals("SelectedSnapshot present", TRUE, possibleSnapshot.nonEmpty());
150 assertEquals("SelectedSnapshot metadata", metadata, possibleSnapshot.get().metadata());
151 assertEquals("SelectedSnapshot snapshot", "one", possibleSnapshot.get().snapshot());
154 @SuppressWarnings("checkstyle:illegalThrows")
155 @Test(expected = IOException.class)
156 public void testDoLoadAsyncWithFailure() throws Throwable {
157 createSnapshotFile(PERSISTENCE_ID, null, 1, 2000);
159 TestKit probe = new TestKit(system);
160 snapshotStore.tell(new SnapshotProtocol.LoadSnapshot(PERSISTENCE_ID,
161 SnapshotSelectionCriteria.latest(), Long.MAX_VALUE), probe.getRef());
162 LoadSnapshotFailed failed = probe.expectMsgClass(LoadSnapshotFailed.class);
163 throw failed.cause();
167 public void testDoLoadAsyncWithAkkaSerializedSnapshot() throws IOException {
168 SnapshotSerializer snapshotSerializer = new SnapshotSerializer((ExtendedActorSystem) system);
170 String name = toSnapshotName(PERSISTENCE_ID, 1, 1000);
171 try (FileOutputStream fos = new FileOutputStream(new File(SNAPSHOT_DIR, name))) {
172 fos.write(snapshotSerializer.toBinary(new Snapshot("one")));
175 SnapshotMetadata metadata = new SnapshotMetadata(PERSISTENCE_ID, 1, 1000);
177 TestKit probe = new TestKit(system);
178 snapshotStore.tell(new LoadSnapshot(PERSISTENCE_ID,
179 SnapshotSelectionCriteria.latest(), Long.MAX_VALUE), probe.getRef());
180 LoadSnapshotResult result = probe.expectMsgClass(LoadSnapshotResult.class);
181 Option<SelectedSnapshot> possibleSnapshot = result.snapshot();
183 assertEquals("SelectedSnapshot present", TRUE, possibleSnapshot.nonEmpty());
184 assertEquals("SelectedSnapshot metadata", metadata, possibleSnapshot.get().metadata());
185 assertEquals("SelectedSnapshot snapshot", "one", possibleSnapshot.get().snapshot());
188 private static void createSnapshotFile(final String persistenceId, final String payload, final int seqNr,
189 final int timestamp) throws IOException {
190 String name = toSnapshotName(persistenceId, seqNr, timestamp);
191 try (FileOutputStream fos = new FileOutputStream(new File(SNAPSHOT_DIR, name))) {
192 if (payload != null) {
193 fos.write(SerializationUtils.serialize(payload));
198 private static String toSnapshotName(final String persistenceId, final int seqNr, final int timestamp) {
199 return "snapshot-" + URLEncoder.encode(persistenceId, StandardCharsets.UTF_8) + "-" + seqNr + "-" + timestamp;