Fix checkstyle reported by odlparent-3.0.0
[controller.git] / opendaylight / md-sal / cds-access-client / src / test / java / org / opendaylight / controller / cluster / access / client / ActorBehaviorTest.java
1 /*
2  * Copyright (c) 2017 Pantheon Technologies s.r.o. 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 package org.opendaylight.controller.cluster.access.client;
9
10 import static org.mockito.Matchers.any;
11 import static org.mockito.Mockito.mock;
12 import static org.mockito.Mockito.timeout;
13 import static org.mockito.Mockito.verify;
14 import static org.mockito.Mockito.when;
15
16 import akka.actor.ActorRef;
17 import akka.actor.ActorSystem;
18 import akka.actor.Props;
19 import akka.persistence.Persistence;
20 import akka.persistence.SelectedSnapshot;
21 import akka.persistence.SnapshotMetadata;
22 import akka.testkit.JavaTestKit;
23 import akka.testkit.TestProbe;
24 import java.lang.reflect.Field;
25 import java.util.Optional;
26 import java.util.concurrent.TimeUnit;
27 import org.junit.After;
28 import org.junit.Assert;
29 import org.junit.Before;
30 import org.junit.Test;
31 import org.opendaylight.controller.cluster.access.concepts.ClientIdentifier;
32 import org.opendaylight.controller.cluster.access.concepts.FrontendIdentifier;
33 import org.opendaylight.controller.cluster.access.concepts.FrontendType;
34 import org.opendaylight.controller.cluster.access.concepts.MemberName;
35 import scala.concurrent.duration.Duration;
36 import scala.concurrent.duration.FiniteDuration;
37
38 public class ActorBehaviorTest {
39
40     private static final String MEMBER_1_FRONTEND_TYPE_1 = "member-1-frontend-type-1";
41     private static final FiniteDuration TIMEOUT = Duration.apply(5, TimeUnit.SECONDS);
42
43     private ActorSystem system;
44     private TestProbe probe;
45     private ClientActorBehavior<BackendInfo> initialBehavior;
46     private MockedSnapshotStore.SaveRequest saveRequest;
47     private FrontendIdentifier id;
48     private ActorRef mockedActor;
49
50     @Before
51     public void setUp() throws Exception {
52         initialBehavior = createInitialBehaviorMock();
53         system = ActorSystem.apply("system1");
54         final ActorRef storeRef = system.registerExtension(Persistence.lookup()).snapshotStoreFor(null);
55         probe = new TestProbe(system);
56         storeRef.tell(probe.ref(), ActorRef.noSender());
57         final MemberName name = MemberName.forName("member-1");
58         id = FrontendIdentifier.create(name, FrontendType.forName("type-1"));
59         mockedActor = system.actorOf(MockedActor.props(id, initialBehavior));
60         //handle initial actor recovery
61         saveRequest = handleRecovery(null);
62     }
63
64     @After
65     public void tearDown() throws Exception {
66         JavaTestKit.shutdownActorSystem(system);
67     }
68
69     @Test
70     public void testInitialBehavior() throws Exception {
71         final InternalCommand<BackendInfo> cmd = mock(InternalCommand.class);
72         when(cmd.execute(any())).thenReturn(initialBehavior);
73         mockedActor.tell(cmd, ActorRef.noSender());
74         verify(cmd, timeout(1000)).execute(initialBehavior);
75     }
76
77     @Test
78     public void testCommandStashing() throws Exception {
79         system.stop(mockedActor);
80         mockedActor = system.actorOf(MockedActor.props(id, initialBehavior));
81         final InternalCommand<BackendInfo> cmd = mock(InternalCommand.class);
82         when(cmd.execute(any())).thenReturn(initialBehavior);
83         //send messages before recovery is completed
84         mockedActor.tell(cmd, ActorRef.noSender());
85         mockedActor.tell(cmd, ActorRef.noSender());
86         mockedActor.tell(cmd, ActorRef.noSender());
87         //complete recovery
88         handleRecovery(null);
89         verify(cmd, timeout(1000).times(3)).execute(initialBehavior);
90     }
91
92     @Test
93     public void testRecoveryAfterRestart() throws Exception {
94         system.stop(mockedActor);
95         mockedActor = system.actorOf(MockedActor.props(id, initialBehavior));
96         final MockedSnapshotStore.SaveRequest newSaveRequest =
97                 handleRecovery(new SelectedSnapshot(saveRequest.getMetadata(), saveRequest.getSnapshot()));
98         Assert.assertEquals(MEMBER_1_FRONTEND_TYPE_1, newSaveRequest.getMetadata().persistenceId());
99     }
100
101     @Test
102     public void testRecoveryAfterRestartFrontendIdMismatch() throws Exception {
103         system.stop(mockedActor);
104         //start actor again
105         mockedActor = system.actorOf(MockedActor.props(id, initialBehavior));
106         probe.expectMsgClass(MockedSnapshotStore.LoadRequest.class);
107         //offer snapshot with incorrect client id
108         final SnapshotMetadata metadata = saveRequest.getMetadata();
109         final FrontendIdentifier anotherFrontend = FrontendIdentifier.create(MemberName.forName("another"),
110                 FrontendType.forName("type-2"));
111         final ClientIdentifier incorrectClientId = ClientIdentifier.create(anotherFrontend, 0);
112         probe.watch(mockedActor);
113         probe.reply(Optional.of(new SelectedSnapshot(metadata, incorrectClientId)));
114         //actor should be stopped
115         probe.expectTerminated(mockedActor, TIMEOUT);
116     }
117
118     @Test
119     public void testRecoveryAfterRestartSaveSnapshotFail() throws Exception {
120         system.stop(mockedActor);
121         mockedActor = system.actorOf(MockedActor.props(id, initialBehavior));
122         probe.watch(mockedActor);
123         probe.expectMsgClass(MockedSnapshotStore.LoadRequest.class);
124         probe.reply(Optional.empty());
125         probe.expectMsgClass(MockedSnapshotStore.SaveRequest.class);
126         probe.reply(new RuntimeException("save failed"));
127         probe.expectMsgClass(MockedSnapshotStore.DeleteByMetadataRequest.class);
128         probe.expectTerminated(mockedActor, TIMEOUT);
129     }
130
131     @Test
132     public void testRecoveryAfterRestartDeleteSnapshotsFail() throws Exception {
133         system.stop(mockedActor);
134         mockedActor = system.actorOf(MockedActor.props(id, initialBehavior));
135         probe.watch(mockedActor);
136         probe.expectMsgClass(MockedSnapshotStore.LoadRequest.class);
137         probe.reply(Optional.empty());
138         probe.expectMsgClass(MockedSnapshotStore.SaveRequest.class);
139         probe.reply(Void.TYPE);
140         probe.expectMsgClass(MockedSnapshotStore.DeleteByCriteriaRequest.class);
141         probe.reply(new RuntimeException("delete failed"));
142         //actor shouldn't terminate
143         probe.expectNoMsg();
144     }
145
146     @SuppressWarnings("unchecked")
147     private static ClientActorBehavior<BackendInfo> createInitialBehaviorMock() throws Exception {
148         final ClientActorBehavior<BackendInfo> initialBehavior = mock(ClientActorBehavior.class);
149         //persistenceId() in AbstractClientActorBehavior is final and can't be mocked
150         //use reflection to work around this
151         final Field context = AbstractClientActorBehavior.class.getDeclaredField("context");
152         context.setAccessible(true);
153         final AbstractClientActorContext ctx = mock(AbstractClientActorContext.class);
154         context.set(initialBehavior, ctx);
155         final Field persistenceId = AbstractClientActorContext.class.getDeclaredField("persistenceId");
156         persistenceId.setAccessible(true);
157         persistenceId.set(ctx, MEMBER_1_FRONTEND_TYPE_1);
158         return initialBehavior;
159     }
160
161     private MockedSnapshotStore.SaveRequest handleRecovery(final SelectedSnapshot savedState) {
162         probe.expectMsgClass(MockedSnapshotStore.LoadRequest.class);
163         //offer snapshot
164         probe.reply(Optional.ofNullable(savedState));
165         final MockedSnapshotStore.SaveRequest nextSaveRequest =
166                 probe.expectMsgClass(MockedSnapshotStore.SaveRequest.class);
167         probe.reply(Void.TYPE);
168         //check old snapshots deleted
169         probe.expectMsgClass(MockedSnapshotStore.DeleteByCriteriaRequest.class);
170         probe.reply(Void.TYPE);
171         return nextSaveRequest;
172     }
173
174     private static class MockedActor extends AbstractClientActor {
175
176         private final ClientActorBehavior<?> initialBehavior;
177         private final ClientActorConfig mockConfig = AccessClientUtil.newMockClientActorConfig();
178
179         private static Props props(final FrontendIdentifier frontendId, final ClientActorBehavior<?> initialBehavior) {
180             return Props.create(MockedActor.class, () -> new MockedActor(frontendId, initialBehavior));
181         }
182
183         MockedActor(final FrontendIdentifier frontendId, final ClientActorBehavior<?> initialBehavior) {
184             super(frontendId);
185             this.initialBehavior = initialBehavior;
186         }
187
188         @Override
189         protected ClientActorBehavior<?> initialBehavior(final ClientActorContext context) {
190             return initialBehavior;
191         }
192
193         @Override
194         protected ClientActorConfig getClientActorConfig() {
195             return mockConfig;
196         }
197     }
198
199 }