Deprecate all MD-SAL APIs
[controller.git] / opendaylight / md-sal / sal-dom-broker / src / test / java / org / opendaylight / controller / md / sal / dom / broker / impl / DOMRpcRouterTest.java
1 /*
2  * Copyright (c) 2018 Inocybe Technologies 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.md.sal.dom.broker.impl;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertNull;
13 import static org.junit.Assert.assertSame;
14 import static org.junit.Assert.assertTrue;
15 import static org.junit.Assert.fail;
16 import static org.mockito.ArgumentMatchers.any;
17 import static org.mockito.Mockito.after;
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.never;
22 import static org.mockito.Mockito.reset;
23 import static org.mockito.Mockito.timeout;
24 import static org.mockito.Mockito.verify;
25
26 import com.google.common.collect.ImmutableList;
27 import com.google.common.util.concurrent.CheckedFuture;
28 import com.google.common.util.concurrent.FluentFuture;
29 import com.google.common.util.concurrent.Futures;
30 import com.google.common.util.concurrent.ListenableFuture;
31 import java.util.AbstractMap.SimpleEntry;
32 import java.util.Collections;
33 import java.util.Map.Entry;
34 import java.util.concurrent.ExecutionException;
35 import org.junit.Before;
36 import org.junit.Test;
37 import org.opendaylight.controller.md.sal.dom.api.DOMRpcAvailabilityListener;
38 import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
39 import org.opendaylight.controller.md.sal.dom.api.DOMRpcIdentifier;
40 import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementation;
41 import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationNotAvailableException;
42 import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationRegistration;
43 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
44 import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
45 import org.opendaylight.controller.md.sal.dom.store.impl.TestModel;
46 import org.opendaylight.yangtools.concepts.ListenerRegistration;
47 import org.opendaylight.yangtools.util.concurrent.FluentFutures;
48 import org.opendaylight.yangtools.yang.common.QName;
49 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
50 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
51 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
52 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
53 import org.opendaylight.yangtools.yang.model.api.Module;
54 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
55 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
56 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
57
58 /**
59  * Unit tests for DOMRpcRouter.
60  *
61  * @author Thomas Pantelis
62  */
63 @Deprecated
64 public class DOMRpcRouterTest {
65
66     private static final NormalizedNode<?, ?> RPC_INPUT = ImmutableNodes.leafNode(
67             QName.create(TestModel.TEST_QNAME.getModule(), "input-leaf"), "foo");
68     private static final NormalizedNode<?, ?> RPC_OUTPUT = ImmutableNodes.leafNode(
69             QName.create(TestModel.TEST_QNAME.getModule(), "output-leaf"), "bar");
70     private final TestLegacyDOMRpcImplementation testLegacyRpcImpl = new TestLegacyDOMRpcImplementation();
71     private final TestMdsalDOMRpcImplementation testMdsalRpcImpl = new TestMdsalDOMRpcImplementation();
72     private org.opendaylight.mdsal.dom.broker.DOMRpcRouter mdsalRpcRouter;
73     private DOMRpcRouter legacyRpcRouter;
74     private DOMRpcIdentifier legacyTestRpcIdentifier;
75     private DOMRpcIdentifier legacyTestRpcNoInputIdentifier;
76     private org.opendaylight.mdsal.dom.api.DOMRpcIdentifier mdsalTestRpcIdentifier;
77     private org.opendaylight.mdsal.dom.api.DOMRpcIdentifier mdsalTestRpcNoInputIdentifier;
78
79     @Before
80     public void setup() {
81         mdsalRpcRouter = new org.opendaylight.mdsal.dom.broker.DOMRpcRouter();
82         final SchemaContext schemaContext = TestModel.createTestContext();
83         mdsalRpcRouter.onGlobalContextUpdated(schemaContext);
84         legacyRpcRouter = new DOMRpcRouter(mdsalRpcRouter.getRpcService(), mdsalRpcRouter.getRpcProviderService());
85
86         legacyTestRpcIdentifier = DOMRpcIdentifier.create(findRpc(schemaContext, "test-rpc"));
87         legacyTestRpcNoInputIdentifier = DOMRpcIdentifier.create(findRpc(schemaContext, "test-rpc-no-input"));
88         mdsalTestRpcIdentifier = org.opendaylight.mdsal.dom.api.DOMRpcIdentifier.create(
89                 findRpc(schemaContext, "test-rpc"));
90         mdsalTestRpcNoInputIdentifier = org.opendaylight.mdsal.dom.api.DOMRpcIdentifier.create(
91                 findRpc(schemaContext, "test-rpc-no-input"));
92     }
93
94     @Test
95     public void testLegacyRegistrationAndInvocation() throws InterruptedException, ExecutionException {
96         final DOMRpcImplementationRegistration<TestLegacyDOMRpcImplementation> reg =
97             legacyRpcRouter.registerRpcImplementation(testLegacyRpcImpl, legacyTestRpcIdentifier,
98                     legacyTestRpcNoInputIdentifier);
99
100         // Test success
101
102         DefaultDOMRpcResult result = new DefaultDOMRpcResult(RPC_OUTPUT);
103         testLegacyRpcImpl.init(Futures.immediateCheckedFuture(result));
104
105         ListenableFuture<DOMRpcResult> future = legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT);
106
107         assertSame(result, future.get());
108         testLegacyRpcImpl.verifyInput(legacyTestRpcIdentifier, RPC_INPUT);
109
110         // Test exception returned
111
112         TestLegacyDOMRpcException rpcEx = new TestLegacyDOMRpcException();
113         testLegacyRpcImpl.init(Futures.immediateFailedCheckedFuture(rpcEx));
114
115         try {
116             legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT).get();
117             fail("Expected exception");
118         } catch (ExecutionException e) {
119             assertEquals(rpcEx, e.getCause());
120         }
121
122         // Test no input or output
123
124         testLegacyRpcImpl.init(Futures.immediateCheckedFuture(null));
125
126         future = legacyRpcRouter.invokeRpc(legacyTestRpcNoInputIdentifier.getType(), null);
127
128         assertNull(future.get());
129         testLegacyRpcImpl.verifyInput(legacyTestRpcNoInputIdentifier, null);
130
131         // Test close
132
133         reg.close();
134
135         try {
136             legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT).get();
137             fail("Expected exception");
138         } catch (ExecutionException e) {
139             assertTrue(e.getCause() instanceof DOMRpcImplementationNotAvailableException);
140         }
141     }
142
143     @Test
144     public void testLegacyRegistrationAndMdsalInvocation() throws InterruptedException, ExecutionException {
145         legacyRpcRouter.registerRpcImplementation(testLegacyRpcImpl, legacyTestRpcIdentifier,
146                 legacyTestRpcNoInputIdentifier);
147
148         // Test success
149
150         DefaultDOMRpcResult result = new DefaultDOMRpcResult(RPC_OUTPUT,
151                 Collections.singleton(RpcResultBuilder.newError(ErrorType.RPC, "tag", "message")));
152         testLegacyRpcImpl.init(Futures.immediateCheckedFuture(result));
153
154         ListenableFuture<org.opendaylight.mdsal.dom.api.DOMRpcResult> future =
155                 mdsalRpcRouter.getRpcService().invokeRpc(mdsalTestRpcIdentifier.getType(), RPC_INPUT);
156
157         assertEquals(RPC_OUTPUT, future.get().getResult());
158         assertEquals(1, future.get().getErrors().size());
159         assertEquals(ErrorType.RPC, future.get().getErrors().iterator().next().getErrorType());
160         assertEquals("tag", future.get().getErrors().iterator().next().getTag());
161         assertEquals("message", future.get().getErrors().iterator().next().getMessage());
162         testLegacyRpcImpl.verifyInput(legacyTestRpcIdentifier, RPC_INPUT);
163
164         // Test exception returned
165
166         TestLegacyDOMRpcException rpcEx = new TestLegacyDOMRpcException();
167         testLegacyRpcImpl.init(Futures.immediateFailedCheckedFuture(rpcEx));
168
169         try {
170             mdsalRpcRouter.getRpcService().invokeRpc(mdsalTestRpcIdentifier.getType(), RPC_INPUT).get();
171             fail("Expected exception");
172         } catch (ExecutionException e) {
173             assertEquals(rpcEx, e.getCause());
174         }
175
176         // Test no input or output
177
178         testLegacyRpcImpl.init(Futures.immediateCheckedFuture(null));
179
180         future = mdsalRpcRouter.getRpcService().invokeRpc(mdsalTestRpcNoInputIdentifier.getType(), null);
181
182         assertNull(future.get());
183         testLegacyRpcImpl.verifyInput(legacyTestRpcNoInputIdentifier, null);
184     }
185
186     @Test
187     public void testMdsalRegistrationAndLegacyInvocation() throws InterruptedException, ExecutionException {
188         mdsalRpcRouter.getRpcProviderService().registerRpcImplementation(testMdsalRpcImpl, mdsalTestRpcIdentifier,
189                 mdsalTestRpcNoInputIdentifier);
190
191         // Test success
192
193         org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult result =
194             new org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult(RPC_OUTPUT,
195                 Collections.singleton(RpcResultBuilder.newError(ErrorType.RPC, "tag", "message")));
196         testMdsalRpcImpl.init(FluentFutures.immediateFluentFuture(result));
197
198         ListenableFuture<DOMRpcResult> future = legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT);
199
200         assertEquals(RPC_OUTPUT, future.get().getResult());
201         assertEquals(1, future.get().getErrors().size());
202         assertEquals(ErrorType.RPC, future.get().getErrors().iterator().next().getErrorType());
203         assertEquals("tag", future.get().getErrors().iterator().next().getTag());
204         assertEquals("message", future.get().getErrors().iterator().next().getMessage());
205         testMdsalRpcImpl.verifyInput(mdsalTestRpcIdentifier, RPC_INPUT);
206
207         // Test exception returned
208
209         TestMdsalDOMRpcException rpcEx = new TestMdsalDOMRpcException();
210         testMdsalRpcImpl.init(FluentFutures.immediateFailedFluentFuture(rpcEx));
211
212         try {
213             legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT).get();
214             fail("Expected exception");
215         } catch (ExecutionException e) {
216             assertTrue("Unexpected exception " + e.getCause(), e.getCause() instanceof DOMRpcException);
217             assertEquals(rpcEx, e.getCause().getCause());
218         }
219
220         // Test no input or output
221
222         testMdsalRpcImpl.init(FluentFutures.immediateNullFluentFuture());
223
224         future = legacyRpcRouter.invokeRpc(legacyTestRpcNoInputIdentifier.getType(), null);
225
226         assertNull(future.get());
227         testMdsalRpcImpl.verifyInput(mdsalTestRpcNoInputIdentifier, null);
228     }
229
230     @Test
231     public void testRegisterRpcListener() {
232         final TestLegacyDOMRpcImplementation2 testRpcImpl2 = new TestLegacyDOMRpcImplementation2();
233
234         DOMRpcAvailabilityListener listener = mock(DOMRpcAvailabilityListener.class);
235         doNothing().when(listener).onRpcAvailable(any());
236         doNothing().when(listener).onRpcUnavailable(any());
237         doReturn(true).when(listener).acceptsImplementation(any());
238         final ListenerRegistration<?> listenerReg = legacyRpcRouter.registerRpcListener(listener);
239
240         DOMRpcAvailabilityListener filteredListener = mock(DOMRpcAvailabilityListener.class);
241         doNothing().when(filteredListener).onRpcAvailable(any());
242         doNothing().when(filteredListener).onRpcUnavailable(any());
243         doReturn(true).when(filteredListener).acceptsImplementation(testLegacyRpcImpl);
244         doReturn(false).when(filteredListener).acceptsImplementation(testRpcImpl2);
245         final ListenerRegistration<?> filteredListenerReg = legacyRpcRouter.registerRpcListener(filteredListener);
246
247         final DOMRpcImplementationRegistration<?> testRpcReg =
248                 legacyRpcRouter.registerRpcImplementation(testLegacyRpcImpl, legacyTestRpcIdentifier);
249
250         verify(listener, timeout(5000)).onRpcAvailable(ImmutableList.of(legacyTestRpcIdentifier));
251         verify(filteredListener, timeout(5000)).onRpcAvailable(ImmutableList.of(legacyTestRpcIdentifier));
252
253         final DOMRpcImplementationRegistration<?> testRpcNoInputReg =
254                 legacyRpcRouter.registerRpcImplementation(testRpcImpl2, legacyTestRpcNoInputIdentifier);
255
256         verify(listener, timeout(5000)).onRpcAvailable(ImmutableList.of(legacyTestRpcNoInputIdentifier));
257         verify(filteredListener, after(200).never()).onRpcAvailable(ImmutableList.of(legacyTestRpcNoInputIdentifier));
258
259         testRpcReg.close();
260
261         verify(listener, timeout(5000)).onRpcUnavailable(ImmutableList.of(legacyTestRpcIdentifier));
262         verify(filteredListener, timeout(5000)).onRpcUnavailable(ImmutableList.of(legacyTestRpcIdentifier));
263
264         testRpcNoInputReg.close();
265
266         verify(listener, timeout(5000)).onRpcUnavailable(ImmutableList.of(legacyTestRpcNoInputIdentifier));
267         verify(filteredListener, after(200).never()).onRpcUnavailable(ImmutableList.of(legacyTestRpcNoInputIdentifier));
268
269         reset(listener, filteredListener);
270
271         listenerReg.close();
272         filteredListenerReg.close();
273
274         legacyRpcRouter.registerRpcImplementation(testLegacyRpcImpl, legacyTestRpcIdentifier);
275
276         verify(listener, after(200).never()).onRpcAvailable(ImmutableList.of(legacyTestRpcIdentifier));
277         verify(filteredListener, never()).onRpcAvailable(ImmutableList.of(legacyTestRpcIdentifier));
278     }
279
280     private static SchemaPath findRpc(SchemaContext schemaContext, String name) {
281         Module testModule = schemaContext.findModule("odl-datastore-test", TestModel.TEST_QNAME.getRevision()).get();
282         RpcDefinition rpcDefinition = null;
283         for (RpcDefinition def: testModule.getRpcs()) {
284             if (def.getQName().getLocalName().equals(name)) {
285                 rpcDefinition = def;
286                 break;
287             }
288         }
289
290         assertNotNull(name + " rpc not found in " + testModule.getRpcs(), rpcDefinition);
291         return rpcDefinition.getPath();
292     }
293
294     private abstract static class AbstractDOMRpcImplementation<T> {
295         Entry<T, NormalizedNode<?, ?>> rpcInput;
296
297         void verifyInput(T expRpc, NormalizedNode<?, ?> expInput) {
298             assertNotNull(rpcInput);
299             assertEquals(expRpc, rpcInput.getKey());
300             assertEquals(expInput, rpcInput.getValue());
301         }
302     }
303
304     private static class TestLegacyDOMRpcImplementation extends AbstractDOMRpcImplementation<DOMRpcIdentifier>
305             implements DOMRpcImplementation {
306         CheckedFuture<DOMRpcResult, DOMRpcException> returnFuture;
307
308         @Override
309         public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(
310                 final DOMRpcIdentifier rpc, final NormalizedNode<?, ?> input) {
311             rpcInput = new SimpleEntry<>(rpc, input);
312             return returnFuture;
313         }
314
315         void init(CheckedFuture<DOMRpcResult, DOMRpcException> retFuture) {
316             this.returnFuture = retFuture;
317             rpcInput = null;
318         }
319     }
320
321     private static class TestMdsalDOMRpcImplementation
322             extends AbstractDOMRpcImplementation<org.opendaylight.mdsal.dom.api.DOMRpcIdentifier>
323             implements org.opendaylight.mdsal.dom.api.DOMRpcImplementation {
324         FluentFuture<org.opendaylight.mdsal.dom.api.DOMRpcResult> returnFuture;
325
326         @Override
327         public FluentFuture<org.opendaylight.mdsal.dom.api.DOMRpcResult> invokeRpc(
328                     final org.opendaylight.mdsal.dom.api.DOMRpcIdentifier rpc, final NormalizedNode<?, ?> input) {
329             rpcInput = new SimpleEntry<>(rpc, input);
330             return returnFuture;
331         }
332
333         void init(FluentFuture<org.opendaylight.mdsal.dom.api.DOMRpcResult> retFuture) {
334             this.returnFuture = retFuture;
335             rpcInput = null;
336         }
337     }
338
339     private static class TestLegacyDOMRpcImplementation2 implements DOMRpcImplementation {
340         @Override
341         public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(
342                 final DOMRpcIdentifier rpc, final NormalizedNode<?, ?> input) {
343             return null;
344         }
345     }
346
347     private static class TestLegacyDOMRpcException extends DOMRpcException {
348         private static final long serialVersionUID = 1L;
349
350         TestLegacyDOMRpcException() {
351             super("test");
352         }
353     }
354
355     private static class TestMdsalDOMRpcException extends org.opendaylight.mdsal.dom.api.DOMRpcException {
356         private static final long serialVersionUID = 1L;
357
358         TestMdsalDOMRpcException() {
359             super("test");
360         }
361     }
362 }