2 * Copyright (c) 2016 Cisco 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.netconf.topology.singleton.impl;
10 import static java.nio.charset.StandardCharsets.UTF_8;
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNull;
13 import static org.junit.Assert.assertTrue;
14 import static org.mockito.ArgumentMatchers.any;
15 import static org.mockito.ArgumentMatchers.anyCollection;
16 import static org.mockito.ArgumentMatchers.argThat;
17 import static org.mockito.ArgumentMatchers.eq;
18 import static org.mockito.Mockito.after;
19 import static org.mockito.Mockito.doAnswer;
20 import static org.mockito.Mockito.doNothing;
21 import static org.mockito.Mockito.doReturn;
22 import static org.mockito.Mockito.mock;
23 import static org.mockito.Mockito.reset;
24 import static org.mockito.Mockito.timeout;
25 import static org.mockito.Mockito.times;
26 import static org.mockito.Mockito.verify;
27 import static org.mockito.Mockito.verifyNoMoreInteractions;
28 import static org.mockito.MockitoAnnotations.initMocks;
29 import static org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils.DEFAULT_SCHEMA_REPOSITORY;
31 import akka.actor.ActorRef;
32 import akka.actor.ActorSystem;
33 import akka.actor.Props;
34 import akka.actor.Status.Failure;
35 import akka.actor.Status.Success;
36 import akka.pattern.AskTimeoutException;
37 import akka.pattern.Patterns;
38 import akka.testkit.TestActorRef;
39 import akka.testkit.javadsl.TestKit;
40 import akka.util.Timeout;
41 import com.google.common.collect.ImmutableList;
42 import com.google.common.collect.Lists;
43 import com.google.common.io.ByteSource;
44 import com.google.common.net.InetAddresses;
45 import com.google.common.util.concurrent.Futures;
46 import com.google.common.util.concurrent.SettableFuture;
47 import java.io.InputStream;
48 import java.net.InetSocketAddress;
49 import java.util.ArrayList;
50 import java.util.Collections;
51 import java.util.List;
52 import java.util.Scanner;
53 import java.util.concurrent.ExecutionException;
54 import java.util.concurrent.TimeUnit;
55 import org.junit.After;
56 import org.junit.Before;
57 import org.junit.Rule;
58 import org.junit.Test;
59 import org.junit.rules.ExpectedException;
60 import org.mockito.ArgumentCaptor;
61 import org.mockito.Mock;
62 import org.opendaylight.controller.cluster.schema.provider.impl.YangTextSchemaSourceSerializationProxy;
63 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
64 import org.opendaylight.mdsal.dom.api.DOMActionException;
65 import org.opendaylight.mdsal.dom.api.DOMActionResult;
66 import org.opendaylight.mdsal.dom.api.DOMActionService;
67 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
68 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
69 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
70 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
71 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
72 import org.opendaylight.mdsal.dom.api.DOMMountPoint;
73 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
74 import org.opendaylight.mdsal.dom.api.DOMNotificationService;
75 import org.opendaylight.mdsal.dom.api.DOMRpcException;
76 import org.opendaylight.mdsal.dom.api.DOMRpcResult;
77 import org.opendaylight.mdsal.dom.api.DOMRpcService;
78 import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
79 import org.opendaylight.mdsal.dom.spi.SimpleDOMActionResult;
80 import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice.SchemaResourcesDTO;
81 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
82 import org.opendaylight.netconf.topology.singleton.impl.actors.NetconfNodeActor;
83 import org.opendaylight.netconf.topology.singleton.impl.utils.ClusteringActionException;
84 import org.opendaylight.netconf.topology.singleton.impl.utils.ClusteringRpcException;
85 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
86 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup.NetconfTopologySetupBuilder;
87 import org.opendaylight.netconf.topology.singleton.messages.AskForMasterMountPoint;
88 import org.opendaylight.netconf.topology.singleton.messages.CreateInitialMasterActorData;
89 import org.opendaylight.netconf.topology.singleton.messages.MasterActorDataInitialized;
90 import org.opendaylight.netconf.topology.singleton.messages.NotMasterException;
91 import org.opendaylight.netconf.topology.singleton.messages.RefreshSetupMasterActorData;
92 import org.opendaylight.netconf.topology.singleton.messages.RegisterMountPoint;
93 import org.opendaylight.netconf.topology.singleton.messages.UnregisterSlaveMountPoint;
94 import org.opendaylight.yangtools.concepts.ObjectRegistration;
95 import org.opendaylight.yangtools.util.concurrent.FluentFutures;
96 import org.opendaylight.yangtools.yang.common.QName;
97 import org.opendaylight.yangtools.yang.common.RpcError;
98 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
99 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
100 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
101 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
102 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
103 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
104 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
105 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
106 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
107 import org.opendaylight.yangtools.yang.model.repo.api.EffectiveModelContextFactory;
108 import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
109 import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
110 import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
111 import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
112 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
113 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
114 import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
115 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
116 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
117 import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository;
118 import org.opendaylight.yangtools.yang.parser.rfc7950.repo.TextToASTTransformer;
119 import scala.concurrent.Await;
120 import scala.concurrent.Future;
121 import scala.concurrent.duration.Duration;
123 public class NetconfNodeActorTest {
125 private static final Timeout TIMEOUT = new Timeout(Duration.create(5, "seconds"));
126 private static final RevisionSourceIdentifier SOURCE_IDENTIFIER1 = RevisionSourceIdentifier.create("yang1");
127 private static final RevisionSourceIdentifier SOURCE_IDENTIFIER2 = RevisionSourceIdentifier.create("yang2");
129 private ActorSystem system = ActorSystem.create();
130 private final TestKit testKit = new TestKit(system);
133 public final ExpectedException exception = ExpectedException.none();
135 private ActorRef masterRef;
136 private RemoteDeviceId remoteDeviceId;
137 private final SharedSchemaRepository masterSchemaRepository = new SharedSchemaRepository("master");
140 private DOMRpcService mockDOMRpcService;
143 private DOMActionService mockDOMActionService;
146 private DOMMountPointService mockMountPointService;
149 private DOMMountPointService.DOMMountPointBuilder mockMountPointBuilder;
152 private ObjectRegistration<DOMMountPoint> mockMountPointReg;
155 private DOMDataBroker mockDOMDataBroker;
158 private SchemaSourceRegistration<?> mockSchemaSourceReg1;
161 private SchemaSourceRegistration<?> mockSchemaSourceReg2;
164 private SchemaSourceRegistry mockRegistry;
167 private EffectiveModelContextFactory mockSchemaContextFactory;
170 private SchemaRepository mockSchemaRepository;
173 private EffectiveModelContext mockSchemaContext;
176 private SchemaResourcesDTO schemaResourceDTO;
179 public void setup() {
182 remoteDeviceId = new RemoteDeviceId("netconf-topology",
183 new InetSocketAddress(InetAddresses.forString("127.0.0.1"), 9999));
185 masterSchemaRepository.registerSchemaSourceListener(
186 TextToASTTransformer.create(masterSchemaRepository, masterSchemaRepository));
188 doReturn(masterSchemaRepository).when(schemaResourceDTO).getSchemaRepository();
189 doReturn(mockRegistry).when(schemaResourceDTO).getSchemaRegistry();
190 final NetconfTopologySetup setup = NetconfTopologySetupBuilder.create().setActorSystem(system)
191 .setIdleTimeout(Duration.apply(1, TimeUnit.SECONDS)).setSchemaResourceDTO(schemaResourceDTO).build();
193 final Props props = NetconfNodeActor.props(setup, remoteDeviceId, TIMEOUT, mockMountPointService);
195 masterRef = TestActorRef.create(system, props, "master_messages");
197 resetMountPointMocks();
199 doReturn(mockMountPointBuilder).when(mockMountPointService).createMountPoint(any());
201 doReturn(mockSchemaSourceReg1).when(mockRegistry).registerSchemaSource(any(), withSourceId(SOURCE_IDENTIFIER1));
202 doReturn(mockSchemaSourceReg2).when(mockRegistry).registerSchemaSource(any(), withSourceId(SOURCE_IDENTIFIER2));
204 doReturn(mockSchemaContextFactory).when(mockSchemaRepository)
205 .createEffectiveModelContextFactory();
209 public void teardown() {
210 TestKit.shutdownActorSystem(system, true);
215 public void testInitializeAndRefreshMasterData() {
217 // Test CreateInitialMasterActorData.
219 initializeMaster(new ArrayList<>());
221 // Test RefreshSetupMasterActorData.
223 final RemoteDeviceId newRemoteDeviceId = new RemoteDeviceId("netconf-topology2",
224 new InetSocketAddress(InetAddresses.forString("127.0.0.2"), 9999));
226 final NetconfTopologySetup newSetup = NetconfTopologySetupBuilder.create()
227 .setSchemaResourceDTO(schemaResourceDTO).setActorSystem(system).build();
229 masterRef.tell(new RefreshSetupMasterActorData(newSetup, newRemoteDeviceId), testKit.getRef());
231 testKit.expectMsgClass(MasterActorDataInitialized.class);
235 public void tesAskForMasterMountPoint() {
237 // Test with master not setup yet.
239 final TestKit kit = new TestKit(system);
241 masterRef.tell(new AskForMasterMountPoint(kit.getRef()), kit.getRef());
243 final Failure failure = kit.expectMsgClass(Failure.class);
244 assertTrue(failure.cause() instanceof NotMasterException);
246 // Now initialize - master should send the RegisterMountPoint message.
248 List<SourceIdentifier> sourceIdentifiers = Lists.newArrayList(RevisionSourceIdentifier.create("testID"));
249 initializeMaster(sourceIdentifiers);
251 masterRef.tell(new AskForMasterMountPoint(kit.getRef()), kit.getRef());
253 final RegisterMountPoint registerMountPoint = kit.expectMsgClass(RegisterMountPoint.class);
255 assertEquals(sourceIdentifiers, registerMountPoint.getSourceIndentifiers());
259 public void testRegisterAndUnregisterMountPoint() throws Exception {
261 ActorRef slaveRef = registerSlaveMountPoint();
265 slaveRef.tell(new UnregisterSlaveMountPoint(), testKit.getRef());
267 verify(mockMountPointReg, timeout(5000)).close();
268 verify(mockSchemaSourceReg1, timeout(1000)).close();
269 verify(mockSchemaSourceReg2, timeout(1000)).close();
271 // Test registration with another interleaved registration that completes while the first registration
272 // is resolving the schema context.
274 reset(mockSchemaSourceReg1, mockRegistry, mockSchemaRepository);
275 resetMountPointMocks();
277 doReturn(mockSchemaSourceReg1).when(mockRegistry).registerSchemaSource(any(), withSourceId(SOURCE_IDENTIFIER1));
279 doReturn(mockSchemaContextFactory).when(mockSchemaRepository)
280 .createEffectiveModelContextFactory();
282 final SchemaSourceRegistration<?> newMockSchemaSourceReg = mock(SchemaSourceRegistration.class);
284 final EffectiveModelContextFactory newMockSchemaContextFactory = mock(EffectiveModelContextFactory.class);
285 doReturn(Futures.immediateFuture(mockSchemaContext))
286 .when(newMockSchemaContextFactory).createEffectiveModelContext(anyCollection());
289 SettableFuture<SchemaContext> future = SettableFuture.create();
291 doReturn(newMockSchemaSourceReg).when(mockRegistry).registerSchemaSource(any(),
292 withSourceId(SOURCE_IDENTIFIER1));
294 doReturn(newMockSchemaContextFactory).when(mockSchemaRepository)
295 .createEffectiveModelContextFactory();
297 slaveRef.tell(new RegisterMountPoint(ImmutableList.of(SOURCE_IDENTIFIER1), masterRef),
300 future.set(mockSchemaContext);
303 }).when(mockSchemaContextFactory).createEffectiveModelContext(anyCollection());
305 doReturn(mockSchemaContextFactory).when(mockSchemaRepository)
306 .createEffectiveModelContextFactory();
308 slaveRef.tell(new RegisterMountPoint(ImmutableList.of(SOURCE_IDENTIFIER1), masterRef), testKit.getRef());
310 verify(mockMountPointBuilder, timeout(5000)).register();
311 verify(mockMountPointBuilder, after(500)).addInitialSchemaContext(mockSchemaContext);
312 verify(mockMountPointBuilder).addService(eq(DOMDataBroker.class), any());
313 verify(mockMountPointBuilder).addService(eq(DOMRpcService.class), any());
314 verify(mockMountPointBuilder).addService(eq(DOMActionService.class), any());
315 verify(mockMountPointBuilder).addService(eq(DOMNotificationService.class), any());
316 verify(mockSchemaSourceReg1).close();
317 verify(mockRegistry, times(2)).registerSchemaSource(any(), withSourceId(SOURCE_IDENTIFIER1));
318 verify(mockSchemaRepository, times(2)).createEffectiveModelContextFactory();
319 verifyNoMoreInteractions(mockMountPointBuilder, newMockSchemaSourceReg);
321 // Stop the slave actor and verify schema source registrations are closed.
323 final Future<Boolean> stopFuture = Patterns.gracefulStop(slaveRef, TIMEOUT.duration());
324 Await.result(stopFuture, TIMEOUT.duration());
326 verify(mockMountPointReg).close();
327 verify(newMockSchemaSourceReg).close();
330 @SuppressWarnings("unchecked")
332 public void testRegisterMountPointWithSchemaFailures() throws Exception {
333 SchemaResourcesDTO schemaResourceDTO2 = mock(SchemaResourcesDTO.class);
334 doReturn(mockRegistry).when(schemaResourceDTO2).getSchemaRegistry();
335 doReturn(mockSchemaRepository).when(schemaResourceDTO2).getSchemaRepository();
336 final NetconfTopologySetup setup = NetconfTopologySetupBuilder.create().setSchemaResourceDTO(schemaResourceDTO2)
337 .setActorSystem(system).build();
339 final ActorRef slaveRef = system.actorOf(NetconfNodeActor.props(setup, remoteDeviceId, TIMEOUT,
340 mockMountPointService));
342 // Test unrecoverable failure.
344 doReturn(Futures.immediateFailedFuture(new SchemaResolutionException("mock")))
345 .when(mockSchemaContextFactory).createEffectiveModelContext(anyCollection());
347 slaveRef.tell(new RegisterMountPoint(ImmutableList.of(SOURCE_IDENTIFIER1, SOURCE_IDENTIFIER2),
348 masterRef), testKit.getRef());
350 testKit.expectMsgClass(Success.class);
352 verify(mockRegistry, timeout(5000)).registerSchemaSource(any(), withSourceId(SOURCE_IDENTIFIER1));
353 verify(mockRegistry, timeout(5000)).registerSchemaSource(any(), withSourceId(SOURCE_IDENTIFIER2));
355 verify(mockMountPointBuilder, after(1000).never()).register();
356 verify(mockSchemaSourceReg1, timeout(1000)).close();
357 verify(mockSchemaSourceReg2, timeout(1000)).close();
359 // Test recoverable AskTimeoutException - schema context resolution should be retried.
361 reset(mockSchemaSourceReg1, mockSchemaSourceReg2);
363 doReturn(Futures.immediateFailedFuture(new SchemaResolutionException("mock",
364 new AskTimeoutException("timeout"))))
365 .doReturn(Futures.immediateFuture(mockSchemaContext))
366 .when(mockSchemaContextFactory).createEffectiveModelContext(anyCollection());
368 slaveRef.tell(new RegisterMountPoint(ImmutableList.of(SOURCE_IDENTIFIER1, SOURCE_IDENTIFIER2),
369 masterRef), testKit.getRef());
371 testKit.expectMsgClass(Success.class);
373 verify(mockMountPointBuilder, timeout(5000)).register();
374 verifyNoMoreInteractions(mockSchemaSourceReg1, mockSchemaSourceReg2);
376 // Test AskTimeoutException with an interleaved successful registration. The first schema context resolution
377 // attempt should not be retried.
379 reset(mockSchemaSourceReg1, mockSchemaSourceReg2, mockSchemaRepository, mockSchemaContextFactory);
380 resetMountPointMocks();
382 final EffectiveModelContextFactory mockSchemaContextFactorySuccess = mock(EffectiveModelContextFactory.class);
383 doReturn(Futures.immediateFuture(mockSchemaContext))
384 .when(mockSchemaContextFactorySuccess).createEffectiveModelContext(anyCollection());
387 SettableFuture<SchemaContext> future = SettableFuture.create();
389 doReturn(mockSchemaContextFactorySuccess).when(mockSchemaRepository)
390 .createEffectiveModelContextFactory();
392 slaveRef.tell(new RegisterMountPoint(ImmutableList.of(SOURCE_IDENTIFIER1, SOURCE_IDENTIFIER2),
393 masterRef), testKit.getRef());
395 future.setException(new SchemaResolutionException("mock", new AskTimeoutException("timeout")));
398 }).when(mockSchemaContextFactory).createEffectiveModelContext(anyCollection());
400 doReturn(mockSchemaContextFactory).when(mockSchemaRepository).createEffectiveModelContextFactory();
402 slaveRef.tell(new RegisterMountPoint(ImmutableList.of(SOURCE_IDENTIFIER1, SOURCE_IDENTIFIER2),
403 masterRef), testKit.getRef());
405 verify(mockMountPointBuilder, timeout(5000)).register();
406 verify(mockSchemaRepository, times(2)).createEffectiveModelContextFactory();
409 @Test(expected = MissingSchemaSourceException.class)
410 public void testMissingSchemaSourceOnMissingProvider() throws Exception {
411 SchemaResourcesDTO schemaResourceDTO2 = mock(SchemaResourcesDTO.class);
412 doReturn(DEFAULT_SCHEMA_REPOSITORY).when(schemaResourceDTO2).getSchemaRegistry();
413 doReturn(DEFAULT_SCHEMA_REPOSITORY).when(schemaResourceDTO2).getSchemaRepository();
414 final NetconfTopologySetup setup = NetconfTopologySetupBuilder.create().setActorSystem(system)
415 .setSchemaResourceDTO(schemaResourceDTO2).setIdleTimeout(Duration.apply(1, TimeUnit.SECONDS)).build();
416 final Props props = NetconfNodeActor.props(setup, remoteDeviceId, TIMEOUT, mockMountPointService);
417 ActorRef actor = TestActorRef.create(system, props, "master_messages_2");
419 final SourceIdentifier sourceIdentifier = RevisionSourceIdentifier.create("testID");
421 final ProxyYangTextSourceProvider proxyYangProvider =
422 new ProxyYangTextSourceProvider(actor, system.dispatcher(), TIMEOUT);
424 final Future<YangTextSchemaSourceSerializationProxy> resolvedSchemaFuture =
425 proxyYangProvider.getYangTextSchemaSource(sourceIdentifier);
426 Await.result(resolvedSchemaFuture, TIMEOUT.duration());
430 public void testYangTextSchemaSourceRequest() throws Exception {
431 final SourceIdentifier sourceIdentifier = RevisionSourceIdentifier.create("testID");
433 final ProxyYangTextSourceProvider proxyYangProvider =
434 new ProxyYangTextSourceProvider(masterRef, system.dispatcher(), TIMEOUT);
436 final YangTextSchemaSource yangTextSchemaSource = YangTextSchemaSource.delegateForByteSource(sourceIdentifier,
437 ByteSource.wrap("YANG".getBytes(UTF_8)));
441 final SchemaSourceRegistration<YangTextSchemaSource> schemaSourceReg = masterSchemaRepository
442 .registerSchemaSource(id -> Futures.immediateFuture(yangTextSchemaSource),
443 PotentialSchemaSource.create(sourceIdentifier, YangTextSchemaSource.class, 1));
445 final Future<YangTextSchemaSourceSerializationProxy> resolvedSchemaFuture =
446 proxyYangProvider.getYangTextSchemaSource(sourceIdentifier);
448 final YangTextSchemaSourceSerializationProxy success = Await.result(resolvedSchemaFuture, TIMEOUT.duration());
450 assertEquals(sourceIdentifier, success.getRepresentation().getIdentifier());
451 assertEquals("YANG", convertStreamToString(success.getRepresentation().openStream()));
453 // Test missing source failure.
455 exception.expect(MissingSchemaSourceException.class);
457 schemaSourceReg.close();
459 final Future<YangTextSchemaSourceSerializationProxy> failedSchemaFuture =
460 proxyYangProvider.getYangTextSchemaSource(sourceIdentifier);
462 Await.result(failedSchemaFuture, TIMEOUT.duration());
466 @SuppressWarnings({"checkstyle:AvoidHidingCauseException", "checkstyle:IllegalThrows"})
467 public void testSlaveInvokeRpc() throws Throwable {
469 final List<SourceIdentifier> sourceIdentifiers =
470 Lists.newArrayList(RevisionSourceIdentifier.create("testID"));
472 initializeMaster(sourceIdentifiers);
473 registerSlaveMountPoint();
475 ArgumentCaptor<DOMRpcService> domRPCServiceCaptor = ArgumentCaptor.forClass(DOMRpcService.class);
476 verify(mockMountPointBuilder).addService(eq(DOMRpcService.class), domRPCServiceCaptor.capture());
478 final DOMRpcService slaveDomRPCService = domRPCServiceCaptor.getValue();
479 assertTrue(slaveDomRPCService instanceof ProxyDOMRpcService);
481 final QName testQName = QName.create("", "TestQname");
482 final SchemaPath schemaPath = SchemaPath.create(true, testQName);
483 final NormalizedNode<?, ?> outputNode = ImmutableContainerNodeBuilder.create()
484 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(testQName))
485 .withChild(ImmutableNodes.leafNode(testQName, "foo")).build();
486 final RpcError rpcError = RpcResultBuilder.newError(RpcError.ErrorType.RPC, null, "Rpc invocation failed.");
488 // RPC with no response output.
490 doReturn(FluentFutures.immediateNullFluentFuture()).when(mockDOMRpcService).invokeRpc(any(), any());
492 DOMRpcResult result = slaveDomRPCService.invokeRpc(schemaPath, outputNode).get(2, TimeUnit.SECONDS);
494 assertEquals(null, result);
496 // RPC with response output.
498 doReturn(FluentFutures.immediateFluentFuture(new DefaultDOMRpcResult(outputNode)))
499 .when(mockDOMRpcService).invokeRpc(any(), any());
501 result = slaveDomRPCService.invokeRpc(schemaPath, outputNode).get(2, TimeUnit.SECONDS);
503 assertEquals(outputNode, result.getResult());
504 assertTrue(result.getErrors().isEmpty());
506 // RPC with response error.
508 doReturn(FluentFutures.immediateFluentFuture(new DefaultDOMRpcResult(rpcError)))
509 .when(mockDOMRpcService).invokeRpc(any(), any());
511 result = slaveDomRPCService.invokeRpc(schemaPath, outputNode).get(2, TimeUnit.SECONDS);
513 assertNull(result.getResult());
514 assertEquals(rpcError, result.getErrors().iterator().next());
516 // RPC with response output and error.
518 doReturn(FluentFutures.immediateFluentFuture(new DefaultDOMRpcResult(outputNode, rpcError)))
519 .when(mockDOMRpcService).invokeRpc(any(), any());
521 final DOMRpcResult resultOutputError =
522 slaveDomRPCService.invokeRpc(schemaPath, outputNode).get(2, TimeUnit.SECONDS);
524 assertEquals(outputNode, resultOutputError.getResult());
525 assertEquals(rpcError, resultOutputError.getErrors().iterator().next());
529 exception.expect(DOMRpcException.class);
531 doReturn(FluentFutures.immediateFailedFluentFuture(new ClusteringRpcException("mock")))
532 .when(mockDOMRpcService).invokeRpc(any(), any());
535 slaveDomRPCService.invokeRpc(schemaPath, outputNode).get(2, TimeUnit.SECONDS);
536 } catch (ExecutionException e) {
542 @SuppressWarnings({"checkstyle:AvoidHidingCauseException", "checkstyle:IllegalThrows"})
543 public void testSlaveInvokeAction() throws Throwable {
544 final List<SourceIdentifier> sourceIdentifiers = Lists
545 .newArrayList(RevisionSourceIdentifier.create("testActionID"));
546 initializeMaster(sourceIdentifiers);
547 registerSlaveMountPoint();
549 ArgumentCaptor<DOMActionService> domActionServiceCaptor = ArgumentCaptor.forClass(DOMActionService.class);
550 verify(mockMountPointBuilder).addService(eq(DOMActionService.class), domActionServiceCaptor.capture());
552 final DOMActionService slaveDomActionService = domActionServiceCaptor.getValue();
553 assertTrue(slaveDomActionService instanceof ProxyDOMActionService);
555 final QName testQName = QName.create("test", "2019-08-16", "TestActionQname");
556 final SchemaPath schemaPath = SchemaPath.create(true, testQName);
558 final YangInstanceIdentifier yangIIdPath = YangInstanceIdentifier
559 .create(new YangInstanceIdentifier.NodeIdentifier(testQName));
561 final DOMDataTreeIdentifier domDataTreeIdentifier = new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL,
564 final ContainerNode outputNode = ImmutableContainerNodeBuilder.create()
565 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(testQName))
566 .withChild(ImmutableNodes.leafNode(testQName, "foo")).build();
568 // Action with no response output.
569 doReturn(FluentFutures.immediateNullFluentFuture()).when(mockDOMActionService)
570 .invokeAction(any(), any(), any());
571 DOMActionResult result = slaveDomActionService.invokeAction(schemaPath, domDataTreeIdentifier, outputNode)
572 .get(2, TimeUnit.SECONDS);
573 assertEquals(null, result);
575 // Action with response output.
576 doReturn(FluentFutures.immediateFluentFuture(new SimpleDOMActionResult(outputNode))).when(mockDOMActionService)
577 .invokeAction(any(), any(), any());
578 result = slaveDomActionService.invokeAction(schemaPath, domDataTreeIdentifier, outputNode)
579 .get(2, TimeUnit.SECONDS);
581 assertEquals(outputNode, result.getOutput().get());
582 assertTrue(result.getErrors().isEmpty());
585 exception.expect(DOMActionException.class);
586 doReturn(FluentFutures.immediateFailedFluentFuture(new ClusteringActionException("mock")))
587 .when(mockDOMActionService).invokeAction(any(), any(), any());
589 slaveDomActionService.invokeAction(schemaPath, domDataTreeIdentifier, outputNode).get(2, TimeUnit.SECONDS);
590 } catch (ExecutionException e) {
596 public void testSlaveNewTransactionRequests() {
598 doReturn(mock(DOMDataTreeReadTransaction.class)).when(mockDOMDataBroker).newReadOnlyTransaction();
599 doReturn(mock(DOMDataTreeReadWriteTransaction.class)).when(mockDOMDataBroker).newReadWriteTransaction();
600 doReturn(mock(DOMDataTreeWriteTransaction.class)).when(mockDOMDataBroker).newWriteOnlyTransaction();
602 initializeMaster(Collections.emptyList());
603 registerSlaveMountPoint();
605 ArgumentCaptor<DOMDataBroker> domDataBrokerCaptor = ArgumentCaptor.forClass(DOMDataBroker.class);
606 verify(mockMountPointBuilder).addService(eq(DOMDataBroker.class), domDataBrokerCaptor.capture());
608 final DOMDataBroker slaveDOMDataBroker = domDataBrokerCaptor.getValue();
609 assertTrue(slaveDOMDataBroker instanceof ProxyDOMDataBroker);
611 slaveDOMDataBroker.newReadOnlyTransaction();
612 verify(mockDOMDataBroker).newReadOnlyTransaction();
614 slaveDOMDataBroker.newReadWriteTransaction();
615 verify(mockDOMDataBroker).newReadWriteTransaction();
617 slaveDOMDataBroker.newWriteOnlyTransaction();
618 verify(mockDOMDataBroker).newWriteOnlyTransaction();
621 private ActorRef registerSlaveMountPoint() {
622 SchemaResourcesDTO schemaResourceDTO2 = mock(SchemaResourcesDTO.class);
623 doReturn(mockRegistry).when(schemaResourceDTO2).getSchemaRegistry();
624 doReturn(mockSchemaRepository).when(schemaResourceDTO2).getSchemaRepository();
625 final ActorRef slaveRef = system.actorOf(NetconfNodeActor.props(
626 NetconfTopologySetupBuilder.create().setSchemaResourceDTO(schemaResourceDTO2).setActorSystem(system)
627 .build(), remoteDeviceId, TIMEOUT, mockMountPointService));
629 doReturn(Futures.immediateFuture(mockSchemaContext))
630 .when(mockSchemaContextFactory).createEffectiveModelContext(anyCollection());
632 slaveRef.tell(new RegisterMountPoint(ImmutableList.of(SOURCE_IDENTIFIER1, SOURCE_IDENTIFIER2),
633 masterRef), testKit.getRef());
635 verify(mockMountPointBuilder, timeout(5000)).register();
636 verify(mockMountPointBuilder).addInitialSchemaContext(mockSchemaContext);
637 verify(mockMountPointBuilder).addService(eq(DOMDataBroker.class), any());
638 verify(mockMountPointBuilder).addService(eq(DOMRpcService.class), any());
639 verify(mockMountPointBuilder).addService(eq(DOMNotificationService.class), any());
641 testKit.expectMsgClass(Success.class);
646 private void initializeMaster(final List<SourceIdentifier> sourceIdentifiers) {
647 masterRef.tell(new CreateInitialMasterActorData(mockDOMDataBroker, sourceIdentifiers,
648 mockDOMRpcService, mockDOMActionService), testKit.getRef());
650 testKit.expectMsgClass(MasterActorDataInitialized.class);
653 private void resetMountPointMocks() {
654 reset(mockMountPointReg, mockMountPointBuilder);
656 doNothing().when(mockMountPointReg).close();
658 doReturn(mockMountPointBuilder).when(mockMountPointBuilder).addInitialSchemaContext(any());
659 doReturn(mockMountPointBuilder).when(mockMountPointBuilder).addService(any(), any());
660 doReturn(mockMountPointReg).when(mockMountPointBuilder).register();
663 private static PotentialSchemaSource<?> withSourceId(final SourceIdentifier identifier) {
664 return argThat(argument -> identifier.equals(argument.getSourceIdentifier()));
667 private static String convertStreamToString(final InputStream is) {
668 try (Scanner scanner = new Scanner(is)) {
669 return scanner.useDelimiter("\\A").hasNext() ? scanner.next() : "";