Refactor DOMNotificationSubscriptionListener(Registry)
[mdsal.git] / dom / mdsal-dom-broker / src / test / java / org / opendaylight / mdsal / dom / broker / DOMRpcRouterTest.java
1 /*
2  * Copyright (c) 2016, 2017 Cisco Systems, Inc. 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.mdsal.dom.broker;
9
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;
24
25 import com.google.common.util.concurrent.Futures;
26 import com.google.common.util.concurrent.ListenableFuture;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
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.ListenerRegistration;
50 import org.opendaylight.yangtools.concepts.Registration;
51 import org.opendaylight.yangtools.yang.common.QName;
52 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
53 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
54 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
55 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
56 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextListener;
57
58 @RunWith(MockitoJUnitRunner.StrictStubs.class)
59 public class DOMRpcRouterTest {
60     private static final YangInstanceIdentifier BAZ_PATH_BAD = YangInstanceIdentifier.of(
61         new NodeIdentifier(Actions.FOO), NodeIdentifierWithPredicates.of(Actions.FOO, Actions.BAR, "bad"));
62     private static final YangInstanceIdentifier BAZ_PATH_GOOD = YangInstanceIdentifier.of(
63         new NodeIdentifier(Actions.FOO), NodeIdentifierWithPredicates.of(Actions.FOO, Actions.BAR, "good"));
64
65     private static final DOMActionImplementation IMPL =
66         (type, path, input) -> Futures.immediateFuture(new SimpleDOMActionResult(
67             Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(Actions.OUTPUT)).build()));
68
69     @Test
70     public void registerRpcImplementation() {
71         try (DOMRpcRouter rpcRouter = rpcsRouter()) {
72             assertOperationKeys(rpcRouter);
73
74             final Registration fooReg = rpcRouter.rpcProviderService().registerRpcImplementation(
75                 getTestRpcImplementation(), DOMRpcIdentifier.create(Rpcs.FOO, null));
76             assertOperationKeys(rpcRouter, Rpcs.FOO);
77
78             final Registration barReg = rpcRouter.rpcProviderService().registerRpcImplementation(
79                 getTestRpcImplementation(), DOMRpcIdentifier.create(Rpcs.BAR, null));
80             assertOperationKeys(rpcRouter, Rpcs.FOO, Rpcs.BAR);
81
82             fooReg.close();
83             assertOperationKeys(rpcRouter, Rpcs.BAR);
84             barReg.close();
85             assertOperationKeys(rpcRouter);
86         }
87     }
88
89     @Test
90     public void registerRpcImplementations() {
91         try (DOMRpcRouter rpcRouter = rpcsRouter()) {
92             assertOperationKeys(rpcRouter);
93
94             final Registration fooReg = rpcRouter.rpcProviderService().registerRpcImplementations(
95                 Map.of(DOMRpcIdentifier.create(Rpcs.FOO, null), getTestRpcImplementation()));
96             assertOperationKeys(rpcRouter, Rpcs.FOO);
97
98             final Registration barReg = rpcRouter.rpcProviderService().registerRpcImplementations(
99                 Map.of(
100                     DOMRpcIdentifier.create(Rpcs.BAR, null), getTestRpcImplementation(),
101                     DOMRpcIdentifier.create(Rpcs.BAZ, null), getTestRpcImplementation()));
102             assertOperationKeys(rpcRouter, Rpcs.FOO, Rpcs.BAR, Rpcs.BAZ);
103
104             fooReg.close();
105             assertOperationKeys(rpcRouter, Rpcs.BAR, Rpcs.BAZ);
106             barReg.close();
107             assertOperationKeys(rpcRouter);
108         }
109     }
110
111
112     private static void assertOperationKeys(final DOMRpcRouter router, final QName... keys) {
113         assertEquals(Set.of(keys), router.routingTable().getOperations().keySet());
114     }
115
116     @Test
117     public void testFailedInvokeRpc() {
118         try (var rpcRouter = rpcsRouter()) {
119             final ListenableFuture<?> future = rpcRouter.rpcService().invokeRpc(Rpcs.FOO, null);
120             final Throwable cause = assertThrows(ExecutionException.class, () -> Futures.getDone(future)).getCause();
121             assertThat(cause, instanceOf(DOMRpcImplementationNotAvailableException.class));
122             assertEquals("No implementation of RPC (rpcs)foo available", cause.getMessage());
123         }
124     }
125
126     @Test
127     public void testRpcListener() {
128         try (var rpcRouter = new DOMRpcRouter()) {
129             assertEquals(List.of(), rpcRouter.listeners());
130
131             final var listener = mock(DOMRpcAvailabilityListener.class);
132             doCallRealMethod().when(listener).acceptsImplementation(any());
133             doNothing().when(listener).onRpcAvailable(any());
134             doNothing().when(listener).onRpcUnavailable(any());
135
136             final var reg = rpcRouter.rpcService().registerRpcListener(listener);
137             assertNotNull(reg);
138             assertEquals(List.of(reg), rpcRouter.listeners());
139
140             final var implReg = rpcRouter.rpcProviderService().registerRpcImplementation(
141                 getTestRpcImplementation(), DOMRpcIdentifier.create(Rpcs.FOO, null));
142             verify(listener, timeout(1000)).onRpcAvailable(any());
143
144             implReg.close();
145             verify(listener, timeout(1000)).onRpcUnavailable(any());
146
147             reg.close();
148             assertEquals(List.of(), rpcRouter.listeners());
149         }
150     }
151
152     @Test
153     public void testActionListener() {
154         try (var rpcRouter = new DOMRpcRouter()) {
155             assertEquals(List.of(), rpcRouter.actionListeners());
156
157             final var listener = mock(AvailabilityListener.class);
158             final var availability = rpcRouter.actionService().extension(DOMActionAvailabilityExtension.class);
159             assertNotNull(availability);
160             final var reg = availability.registerAvailabilityListener(listener);
161             assertNotNull(reg);
162             assertEquals(List.of(reg), rpcRouter.actionListeners());
163
164             // FIXME: register implementation and verify notification
165
166             reg.close();
167             assertEquals(List.of(), rpcRouter.actionListeners());
168         }
169     }
170
171     @Test
172     public void onGlobalContextUpdated() {
173         try (DOMRpcRouter rpcRouter = new DOMRpcRouter()) {
174             final DOMRpcRoutingTable routingTableOriginal = rpcRouter.routingTable();
175             rpcRouter.onModelContextUpdated(TestModel.createTestContext());
176             assertNotEquals(routingTableOriginal, rpcRouter.routingTable());
177         }
178     }
179
180     @Test
181     public void testClose() {
182         final ListenerRegistration<EffectiveModelContextListener> reg = mock(ListenerRegistration.class);
183         doNothing().when(reg).close();
184         final DOMSchemaService schema = mock(DOMSchemaService.class);
185         doReturn(reg).when(schema).registerSchemaContextListener(any());
186
187         final var rpcRouter = new DOMRpcRouter(schema);
188         rpcRouter.close();
189
190         final var svc = rpcRouter.rpcProviderService();
191         assertThrows(RejectedExecutionException.class, () -> svc.registerRpcImplementation(getTestRpcImplementation(),
192             DOMRpcIdentifier.create(Rpcs.FOO, null)));
193     }
194
195     @Test
196     public void testActionInstanceRouting() throws ExecutionException {
197         try (var rpcRouter = actionsRouter()) {
198             final var actionProvider = rpcRouter.actionProviderService();
199             assertNotNull(actionProvider);
200             final var actionConsumer = rpcRouter.actionService();
201             assertNotNull(actionConsumer);
202
203             try (var reg = actionProvider.registerActionImplementation(IMPL,
204                 DOMActionInstance.of(Actions.BAZ_TYPE, LogicalDatastoreType.OPERATIONAL, BAZ_PATH_GOOD))) {
205
206                 assertAvailable(actionConsumer, BAZ_PATH_GOOD);
207                 assertUnavailable(actionConsumer, BAZ_PATH_BAD);
208             }
209
210             assertUnavailable(actionConsumer, BAZ_PATH_BAD);
211             assertUnavailable(actionConsumer, BAZ_PATH_GOOD);
212         }
213     }
214
215     @Test
216     public void testActionDatastoreRouting() throws ExecutionException {
217         try (var rpcRouter = actionsRouter()) {
218             final var actionProvider = rpcRouter.actionProviderService();
219             assertNotNull(actionProvider);
220             final var actionConsumer = rpcRouter.actionService();
221             assertNotNull(actionConsumer);
222
223             try (var reg = actionProvider.registerActionImplementation(IMPL,
224                 DOMActionInstance.of(Actions.BAZ_TYPE, LogicalDatastoreType.OPERATIONAL,
225                     YangInstanceIdentifier.of()))) {
226
227                 assertAvailable(actionConsumer, BAZ_PATH_GOOD);
228                 assertAvailable(actionConsumer, BAZ_PATH_BAD);
229             }
230
231             assertUnavailable(actionConsumer, BAZ_PATH_BAD);
232             assertUnavailable(actionConsumer, BAZ_PATH_GOOD);
233         }
234     }
235
236     private static DOMRpcRouter actionsRouter() {
237         final DOMRpcRouter router = new DOMRpcRouter();
238         router.onModelContextUpdated(Actions.CONTEXT);
239         return router;
240     }
241
242     private static DOMRpcRouter rpcsRouter() {
243         final DOMRpcRouter router = new DOMRpcRouter();
244         router.onModelContextUpdated(Rpcs.CONTEXT);
245         return router;
246     }
247
248     private static void assertAvailable(final DOMActionService actionService, final YangInstanceIdentifier path)
249             throws ExecutionException {
250         final DOMActionResult result = Futures.getDone(invokeBaz(actionService, path));
251         assertEquals(List.of(), result.getErrors());
252     }
253
254     private static void assertUnavailable(final DOMActionService actionService, final YangInstanceIdentifier path) {
255         final ListenableFuture<? extends DOMActionResult> future = invokeBaz(actionService, path);
256         final ExecutionException ex = assertThrows(ExecutionException.class, () -> Futures.getDone(future));
257         assertThat(ex.getCause(), instanceOf(DOMActionNotAvailableException.class));
258     }
259
260     private static ListenableFuture<? extends DOMActionResult> invokeBaz(final DOMActionService actionService,
261             final YangInstanceIdentifier path) {
262         return actionService.invokeAction(Actions.BAZ_TYPE,
263             new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, path),
264             Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(Actions.INPUT)).build());
265     }
266 }