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.JavaTestKit;
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.mockito.MockitoAnnotations;
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 public class LocalSnapshotStoreTest {
55 private static final String PERSISTENCE_ID = "member-1-shard-default-config";
56 private static final String PREFIX_BASED_SHARD_PERSISTENCE_ID = "member-1-shard-id-ints!-config";
58 private static ActorSystem system;
59 private static ActorRef snapshotStore;
62 public static void staticSetup() {
65 system = ActorSystem.create("test", ConfigFactory.load("LocalSnapshotStoreTest.conf"));
66 snapshotStore = system.registerExtension(Persistence.lookup()).snapshotStoreFor(null);
70 public static void staticCleanup() {
71 FileUtils.deleteQuietly(SNAPSHOT_DIR);
72 JavaTestKit.shutdownActorSystem(system);
77 MockitoAnnotations.initMocks(this);
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 JavaTestKit probe = new JavaTestKit(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() throws IOException {
127 JavaTestKit probe = new JavaTestKit(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 JavaTestKit probe = new JavaTestKit(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 JavaTestKit probe = new JavaTestKit(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 JavaTestKit probe = new JavaTestKit(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 throws UnsupportedEncodingException {
200 final String encodedPersistenceId = URLEncoder.encode(persistenceId, StandardCharsets.UTF_8.name());
201 return "snapshot-" + encodedPersistenceId + "-" + seqNr + "-" + timestamp;