2 * Copyright (c) 2016, 2017 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.mdsal.dom.broker;
10 import static org.hamcrest.CoreMatchers.instanceOf;
11 import static org.hamcrest.MatcherAssert.assertThat;
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertNotEquals;
14 import static org.junit.Assert.assertNotNull;
15 import static org.junit.Assert.assertThrows;
16 import static org.mockito.ArgumentMatchers.any;
17 import static org.mockito.Mockito.doCallRealMethod;
18 import static org.mockito.Mockito.doNothing;
19 import static org.mockito.Mockito.doReturn;
20 import static org.mockito.Mockito.mock;
21 import static org.mockito.Mockito.timeout;
22 import static org.mockito.Mockito.verify;
23 import static org.opendaylight.mdsal.dom.broker.TestUtils.getTestRpcImplementation;
25 import com.google.common.util.concurrent.Futures;
26 import com.google.common.util.concurrent.ListenableFuture;
27 import java.util.List;
30 import java.util.concurrent.ExecutionException;
31 import java.util.concurrent.RejectedExecutionException;
32 import org.junit.Test;
33 import org.junit.runner.RunWith;
34 import org.mockito.junit.MockitoJUnitRunner;
35 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
36 import org.opendaylight.mdsal.dom.api.DOMActionAvailabilityExtension;
37 import org.opendaylight.mdsal.dom.api.DOMActionAvailabilityExtension.AvailabilityListener;
38 import org.opendaylight.mdsal.dom.api.DOMActionImplementation;
39 import org.opendaylight.mdsal.dom.api.DOMActionInstance;
40 import org.opendaylight.mdsal.dom.api.DOMActionNotAvailableException;
41 import org.opendaylight.mdsal.dom.api.DOMActionResult;
42 import org.opendaylight.mdsal.dom.api.DOMActionService;
43 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
44 import org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener;
45 import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier;
46 import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException;
47 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
48 import org.opendaylight.mdsal.dom.spi.SimpleDOMActionResult;
49 import org.opendaylight.yangtools.concepts.Registration;
50 import org.opendaylight.yangtools.yang.common.QName;
51 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
52 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
53 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
54 import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
56 @RunWith(MockitoJUnitRunner.StrictStubs.class)
57 public class DOMRpcRouterTest {
58 private static final YangInstanceIdentifier BAZ_PATH_BAD = YangInstanceIdentifier.of(
59 new NodeIdentifier(Actions.FOO), NodeIdentifierWithPredicates.of(Actions.FOO, Actions.BAR, "bad"));
60 private static final YangInstanceIdentifier BAZ_PATH_GOOD = YangInstanceIdentifier.of(
61 new NodeIdentifier(Actions.FOO), NodeIdentifierWithPredicates.of(Actions.FOO, Actions.BAR, "good"));
63 private static final DOMActionImplementation IMPL =
64 (type, path, input) -> Futures.immediateFuture(new SimpleDOMActionResult(
65 ImmutableNodes.newContainerBuilder().withNodeIdentifier(new NodeIdentifier(Actions.OUTPUT)).build()));
68 public void registerRpcImplementation() {
69 try (DOMRpcRouter rpcRouter = rpcsRouter()) {
70 assertOperationKeys(rpcRouter);
72 final Registration fooReg = rpcRouter.rpcProviderService().registerRpcImplementation(
73 getTestRpcImplementation(), DOMRpcIdentifier.create(Rpcs.FOO, null));
74 assertOperationKeys(rpcRouter, Rpcs.FOO);
76 final Registration barReg = rpcRouter.rpcProviderService().registerRpcImplementation(
77 getTestRpcImplementation(), DOMRpcIdentifier.create(Rpcs.BAR, null));
78 assertOperationKeys(rpcRouter, Rpcs.FOO, Rpcs.BAR);
81 assertOperationKeys(rpcRouter, Rpcs.BAR);
83 assertOperationKeys(rpcRouter);
88 public void registerRpcImplementations() {
89 try (DOMRpcRouter rpcRouter = rpcsRouter()) {
90 assertOperationKeys(rpcRouter);
92 final Registration fooReg = rpcRouter.rpcProviderService().registerRpcImplementations(
93 Map.of(DOMRpcIdentifier.create(Rpcs.FOO, null), getTestRpcImplementation()));
94 assertOperationKeys(rpcRouter, Rpcs.FOO);
96 final Registration barReg = rpcRouter.rpcProviderService().registerRpcImplementations(
98 DOMRpcIdentifier.create(Rpcs.BAR, null), getTestRpcImplementation(),
99 DOMRpcIdentifier.create(Rpcs.BAZ, null), getTestRpcImplementation()));
100 assertOperationKeys(rpcRouter, Rpcs.FOO, Rpcs.BAR, Rpcs.BAZ);
103 assertOperationKeys(rpcRouter, Rpcs.BAR, Rpcs.BAZ);
105 assertOperationKeys(rpcRouter);
110 private static void assertOperationKeys(final DOMRpcRouter router, final QName... keys) {
111 assertEquals(Set.of(keys), router.routingTable().getOperations().keySet());
115 public void testFailedInvokeRpc() {
116 try (var rpcRouter = rpcsRouter()) {
117 final ListenableFuture<?> future = rpcRouter.rpcService().invokeRpc(Rpcs.FOO, null);
118 final Throwable cause = assertThrows(ExecutionException.class, () -> Futures.getDone(future)).getCause();
119 assertThat(cause, instanceOf(DOMRpcImplementationNotAvailableException.class));
120 assertEquals("No implementation of RPC (rpcs)foo available", cause.getMessage());
125 public void testRpcListener() {
126 try (var rpcRouter = new DOMRpcRouter()) {
127 assertEquals(List.of(), rpcRouter.listeners());
129 final var listener = mock(DOMRpcAvailabilityListener.class);
130 doCallRealMethod().when(listener).acceptsImplementation(any());
131 doNothing().when(listener).onRpcAvailable(any());
132 doNothing().when(listener).onRpcUnavailable(any());
134 final var reg = rpcRouter.rpcService().registerRpcListener(listener);
136 assertEquals(List.of(reg), rpcRouter.listeners());
138 final var implReg = rpcRouter.rpcProviderService().registerRpcImplementation(
139 getTestRpcImplementation(), DOMRpcIdentifier.create(Rpcs.FOO, null));
140 verify(listener, timeout(1000)).onRpcAvailable(any());
143 verify(listener, timeout(1000)).onRpcUnavailable(any());
146 assertEquals(List.of(), rpcRouter.listeners());
151 public void testActionListener() {
152 try (var rpcRouter = new DOMRpcRouter()) {
153 assertEquals(List.of(), rpcRouter.actionListeners());
155 final var listener = mock(AvailabilityListener.class);
156 final var availability = rpcRouter.actionService().extension(DOMActionAvailabilityExtension.class);
157 assertNotNull(availability);
158 final var reg = availability.registerAvailabilityListener(listener);
160 assertEquals(List.of(reg), rpcRouter.actionListeners());
162 // FIXME: register implementation and verify notification
165 assertEquals(List.of(), rpcRouter.actionListeners());
170 public void onGlobalContextUpdated() {
171 try (DOMRpcRouter rpcRouter = new DOMRpcRouter()) {
172 final DOMRpcRoutingTable routingTableOriginal = rpcRouter.routingTable();
173 rpcRouter.onModelContextUpdated(TestModel.createTestContext());
174 assertNotEquals(routingTableOriginal, rpcRouter.routingTable());
179 public void testClose() {
180 final var reg = mock(Registration.class);
181 doNothing().when(reg).close();
182 final DOMSchemaService schema = mock(DOMSchemaService.class);
183 doReturn(reg).when(schema).registerSchemaContextListener(any());
185 final var rpcRouter = new DOMRpcRouter(schema);
188 final var svc = rpcRouter.rpcProviderService();
189 assertThrows(RejectedExecutionException.class, () -> svc.registerRpcImplementation(getTestRpcImplementation(),
190 DOMRpcIdentifier.create(Rpcs.FOO, null)));
194 public void testActionInstanceRouting() throws ExecutionException {
195 try (var rpcRouter = actionsRouter()) {
196 final var actionProvider = rpcRouter.actionProviderService();
197 assertNotNull(actionProvider);
198 final var actionConsumer = rpcRouter.actionService();
199 assertNotNull(actionConsumer);
201 try (var reg = actionProvider.registerActionImplementation(IMPL,
202 DOMActionInstance.of(Actions.BAZ_TYPE, LogicalDatastoreType.OPERATIONAL, BAZ_PATH_GOOD))) {
204 assertAvailable(actionConsumer, BAZ_PATH_GOOD);
205 assertUnavailable(actionConsumer, BAZ_PATH_BAD);
208 assertUnavailable(actionConsumer, BAZ_PATH_BAD);
209 assertUnavailable(actionConsumer, BAZ_PATH_GOOD);
214 public void testActionDatastoreRouting() throws ExecutionException {
215 try (var rpcRouter = actionsRouter()) {
216 final var actionProvider = rpcRouter.actionProviderService();
217 assertNotNull(actionProvider);
218 final var actionConsumer = rpcRouter.actionService();
219 assertNotNull(actionConsumer);
221 try (var reg = actionProvider.registerActionImplementation(IMPL,
222 DOMActionInstance.of(Actions.BAZ_TYPE, LogicalDatastoreType.OPERATIONAL,
223 YangInstanceIdentifier.of()))) {
225 assertAvailable(actionConsumer, BAZ_PATH_GOOD);
226 assertAvailable(actionConsumer, BAZ_PATH_BAD);
229 assertUnavailable(actionConsumer, BAZ_PATH_BAD);
230 assertUnavailable(actionConsumer, BAZ_PATH_GOOD);
234 private static DOMRpcRouter actionsRouter() {
235 final DOMRpcRouter router = new DOMRpcRouter();
236 router.onModelContextUpdated(Actions.CONTEXT);
240 private static DOMRpcRouter rpcsRouter() {
241 final DOMRpcRouter router = new DOMRpcRouter();
242 router.onModelContextUpdated(Rpcs.CONTEXT);
246 private static void assertAvailable(final DOMActionService actionService, final YangInstanceIdentifier path)
247 throws ExecutionException {
248 final DOMActionResult result = Futures.getDone(invokeBaz(actionService, path));
249 assertEquals(List.of(), result.getErrors());
252 private static void assertUnavailable(final DOMActionService actionService, final YangInstanceIdentifier path) {
253 final ListenableFuture<? extends DOMActionResult> future = invokeBaz(actionService, path);
254 final ExecutionException ex = assertThrows(ExecutionException.class, () -> Futures.getDone(future));
255 assertThat(ex.getCause(), instanceOf(DOMActionNotAvailableException.class));
258 private static ListenableFuture<? extends DOMActionResult> invokeBaz(final DOMActionService actionService,
259 final YangInstanceIdentifier path) {
260 return actionService.invokeAction(Actions.BAZ_TYPE,
261 DOMDataTreeIdentifier.of(LogicalDatastoreType.OPERATIONAL, path),
262 ImmutableNodes.newContainerBuilder().withNodeIdentifier(new NodeIdentifier(Actions.INPUT)).build());