2 * Copyright (c) 2018 Inocybe Technologies 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.controller.md.sal.dom.broker.impl;
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.Matchers.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;
26 import com.google.common.collect.ImmutableList;
27 import com.google.common.util.concurrent.CheckedFuture;
28 import com.google.common.util.concurrent.Futures;
29 import com.google.common.util.concurrent.ListenableFuture;
30 import java.util.AbstractMap.SimpleEntry;
31 import java.util.Collections;
32 import java.util.Map.Entry;
33 import java.util.concurrent.ExecutionException;
34 import org.junit.Before;
35 import org.junit.Test;
36 import org.opendaylight.controller.md.sal.dom.api.DOMRpcAvailabilityListener;
37 import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
38 import org.opendaylight.controller.md.sal.dom.api.DOMRpcIdentifier;
39 import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementation;
40 import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationNotAvailableException;
41 import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationRegistration;
42 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
43 import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
44 import org.opendaylight.controller.md.sal.dom.store.impl.TestModel;
45 import org.opendaylight.yangtools.concepts.ListenerRegistration;
46 import org.opendaylight.yangtools.yang.common.QName;
47 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
48 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
49 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
50 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
51 import org.opendaylight.yangtools.yang.model.api.Module;
52 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
53 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
54 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
57 * Unit tests for DOMRpcRouter.
59 * @author Thomas Pantelis
61 public class DOMRpcRouterTest {
63 private static final NormalizedNode<?, ?> RPC_INPUT = ImmutableNodes.leafNode(
64 QName.create(TestModel.TEST_QNAME.getModule(), "input-leaf"), "foo");
65 private static final NormalizedNode<?, ?> RPC_OUTPUT = ImmutableNodes.leafNode(
66 QName.create(TestModel.TEST_QNAME.getModule(), "output-leaf"), "bar");
67 private final TestLegacyDOMRpcImplementation testLegacyRpcImpl = new TestLegacyDOMRpcImplementation();
68 private final TestMdsalDOMRpcImplementation testMdsalRpcImpl = new TestMdsalDOMRpcImplementation();
69 private org.opendaylight.mdsal.dom.broker.DOMRpcRouter mdsalRpcRouter;
70 private DOMRpcRouter legacyRpcRouter;
71 private DOMRpcIdentifier legacyTestRpcIdentifier;
72 private DOMRpcIdentifier legacyTestRpcNoInputIdentifier;
73 private org.opendaylight.mdsal.dom.api.DOMRpcIdentifier mdsalTestRpcIdentifier;
74 private org.opendaylight.mdsal.dom.api.DOMRpcIdentifier mdsalTestRpcNoInputIdentifier;
78 mdsalRpcRouter = new org.opendaylight.mdsal.dom.broker.DOMRpcRouter();
79 final SchemaContext schemaContext = TestModel.createTestContext();
80 mdsalRpcRouter.onGlobalContextUpdated(schemaContext);
81 legacyRpcRouter = new DOMRpcRouter(mdsalRpcRouter, mdsalRpcRouter);
83 legacyTestRpcIdentifier = DOMRpcIdentifier.create(findRpc(schemaContext, "test-rpc"));
84 legacyTestRpcNoInputIdentifier = DOMRpcIdentifier.create(findRpc(schemaContext, "test-rpc-no-input"));
85 mdsalTestRpcIdentifier = org.opendaylight.mdsal.dom.api.DOMRpcIdentifier.create(
86 findRpc(schemaContext, "test-rpc"));
87 mdsalTestRpcNoInputIdentifier = org.opendaylight.mdsal.dom.api.DOMRpcIdentifier.create(
88 findRpc(schemaContext, "test-rpc-no-input"));
92 public void testLegacyRegistrationAndInvocation() throws InterruptedException, ExecutionException {
93 final DOMRpcImplementationRegistration<TestLegacyDOMRpcImplementation> reg =
94 legacyRpcRouter.registerRpcImplementation(testLegacyRpcImpl, legacyTestRpcIdentifier,
95 legacyTestRpcNoInputIdentifier);
99 DefaultDOMRpcResult result = new DefaultDOMRpcResult(RPC_OUTPUT);
100 testLegacyRpcImpl.init(Futures.immediateCheckedFuture(result));
102 ListenableFuture<DOMRpcResult> future = legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT);
104 assertSame(result, future.get());
105 testLegacyRpcImpl.verifyInput(legacyTestRpcIdentifier, RPC_INPUT);
107 // Test exception returned
109 TestLegacyDOMRpcException rpcEx = new TestLegacyDOMRpcException();
110 testLegacyRpcImpl.init(Futures.immediateFailedCheckedFuture(rpcEx));
113 legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT).get();
114 fail("Expected exception");
115 } catch (ExecutionException e) {
116 assertEquals(rpcEx, e.getCause());
119 // Test no input or output
121 testLegacyRpcImpl.init(Futures.immediateCheckedFuture(null));
123 future = legacyRpcRouter.invokeRpc(legacyTestRpcNoInputIdentifier.getType(), null);
125 assertNull(future.get());
126 testLegacyRpcImpl.verifyInput(legacyTestRpcNoInputIdentifier, null);
133 legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT).get();
134 fail("Expected exception");
135 } catch (ExecutionException e) {
136 assertTrue(e.getCause() instanceof DOMRpcImplementationNotAvailableException);
141 public void testLegacyRegistrationAndMdsalInvocation() throws InterruptedException, ExecutionException {
142 legacyRpcRouter.registerRpcImplementation(testLegacyRpcImpl, legacyTestRpcIdentifier,
143 legacyTestRpcNoInputIdentifier);
147 DefaultDOMRpcResult result = new DefaultDOMRpcResult(RPC_OUTPUT,
148 Collections.singleton(RpcResultBuilder.newError(ErrorType.RPC, "tag", "message")));
149 testLegacyRpcImpl.init(Futures.immediateCheckedFuture(result));
151 ListenableFuture<org.opendaylight.mdsal.dom.api.DOMRpcResult> future =
152 mdsalRpcRouter.invokeRpc(mdsalTestRpcIdentifier.getType(), RPC_INPUT);
154 assertEquals(RPC_OUTPUT, future.get().getResult());
155 assertEquals(1, future.get().getErrors().size());
156 assertEquals(ErrorType.RPC, future.get().getErrors().iterator().next().getErrorType());
157 assertEquals("tag", future.get().getErrors().iterator().next().getTag());
158 assertEquals("message", future.get().getErrors().iterator().next().getMessage());
159 testLegacyRpcImpl.verifyInput(legacyTestRpcIdentifier, RPC_INPUT);
161 // Test exception returned
163 TestLegacyDOMRpcException rpcEx = new TestLegacyDOMRpcException();
164 testLegacyRpcImpl.init(Futures.immediateFailedCheckedFuture(rpcEx));
167 mdsalRpcRouter.invokeRpc(mdsalTestRpcIdentifier.getType(), RPC_INPUT).get();
168 fail("Expected exception");
169 } catch (ExecutionException e) {
170 assertEquals(rpcEx, e.getCause());
173 // Test no input or output
175 testLegacyRpcImpl.init(Futures.immediateCheckedFuture(null));
177 future = mdsalRpcRouter.invokeRpc(mdsalTestRpcNoInputIdentifier.getType(), null);
179 assertNull(future.get());
180 testLegacyRpcImpl.verifyInput(legacyTestRpcNoInputIdentifier, null);
184 public void testMdsalRegistrationAndLegacyInvocation() throws InterruptedException, ExecutionException {
185 mdsalRpcRouter.registerRpcImplementation(testMdsalRpcImpl, mdsalTestRpcIdentifier,
186 mdsalTestRpcNoInputIdentifier);
190 org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult result =
191 new org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult(RPC_OUTPUT,
192 Collections.singleton(RpcResultBuilder.newError(ErrorType.RPC, "tag", "message")));
193 testMdsalRpcImpl.init(Futures.immediateCheckedFuture(result));
195 ListenableFuture<DOMRpcResult> future = legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT);
197 assertEquals(RPC_OUTPUT, future.get().getResult());
198 assertEquals(1, future.get().getErrors().size());
199 assertEquals(ErrorType.RPC, future.get().getErrors().iterator().next().getErrorType());
200 assertEquals("tag", future.get().getErrors().iterator().next().getTag());
201 assertEquals("message", future.get().getErrors().iterator().next().getMessage());
202 testMdsalRpcImpl.verifyInput(mdsalTestRpcIdentifier, RPC_INPUT);
204 // Test exception returned
206 TestMdsalDOMRpcException rpcEx = new TestMdsalDOMRpcException();
207 testMdsalRpcImpl.init(Futures.immediateFailedCheckedFuture(rpcEx));
210 legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT).get();
211 fail("Expected exception");
212 } catch (ExecutionException e) {
213 assertTrue("Unexpected exception " + e.getCause(), e.getCause() instanceof DOMRpcException);
214 assertEquals(rpcEx, e.getCause().getCause());
217 // Test no input or output
219 testMdsalRpcImpl.init(Futures.immediateCheckedFuture(null));
221 future = legacyRpcRouter.invokeRpc(legacyTestRpcNoInputIdentifier.getType(), null);
223 assertNull(future.get());
224 testMdsalRpcImpl.verifyInput(mdsalTestRpcNoInputIdentifier, null);
228 public void testRegisterRpcListener() {
229 final TestLegacyDOMRpcImplementation2 testRpcImpl2 = new TestLegacyDOMRpcImplementation2();
231 DOMRpcAvailabilityListener listener = mock(DOMRpcAvailabilityListener.class);
232 doNothing().when(listener).onRpcAvailable(any());
233 doNothing().when(listener).onRpcUnavailable(any());
234 doReturn(true).when(listener).acceptsImplementation(any());
235 final ListenerRegistration<?> listenerReg = legacyRpcRouter.registerRpcListener(listener);
237 DOMRpcAvailabilityListener filteredListener = mock(DOMRpcAvailabilityListener.class);
238 doNothing().when(filteredListener).onRpcAvailable(any());
239 doNothing().when(filteredListener).onRpcUnavailable(any());
240 doReturn(true).when(filteredListener).acceptsImplementation(testLegacyRpcImpl);
241 doReturn(false).when(filteredListener).acceptsImplementation(testRpcImpl2);
242 final ListenerRegistration<?> filteredListenerReg = legacyRpcRouter.registerRpcListener(filteredListener);
244 final DOMRpcImplementationRegistration<?> testRpcReg =
245 legacyRpcRouter.registerRpcImplementation(testLegacyRpcImpl, legacyTestRpcIdentifier);
247 verify(listener, timeout(5000)).onRpcAvailable(ImmutableList.of(legacyTestRpcIdentifier));
248 verify(filteredListener, timeout(5000)).onRpcAvailable(ImmutableList.of(legacyTestRpcIdentifier));
250 final DOMRpcImplementationRegistration<?> testRpcNoInputReg =
251 legacyRpcRouter.registerRpcImplementation(testRpcImpl2, legacyTestRpcNoInputIdentifier);
253 verify(listener, timeout(5000)).onRpcAvailable(ImmutableList.of(legacyTestRpcNoInputIdentifier));
254 verify(filteredListener, after(200).never()).onRpcAvailable(ImmutableList.of(legacyTestRpcNoInputIdentifier));
258 verify(listener, timeout(5000)).onRpcUnavailable(ImmutableList.of(legacyTestRpcIdentifier));
259 verify(filteredListener, timeout(5000)).onRpcUnavailable(ImmutableList.of(legacyTestRpcIdentifier));
261 testRpcNoInputReg.close();
263 verify(listener, timeout(5000)).onRpcUnavailable(ImmutableList.of(legacyTestRpcNoInputIdentifier));
264 verify(filteredListener, after(200).never()).onRpcUnavailable(ImmutableList.of(legacyTestRpcNoInputIdentifier));
266 reset(listener, filteredListener);
269 filteredListenerReg.close();
271 legacyRpcRouter.registerRpcImplementation(testLegacyRpcImpl, legacyTestRpcIdentifier);
273 verify(listener, after(200).never()).onRpcAvailable(ImmutableList.of(legacyTestRpcIdentifier));
274 verify(filteredListener, never()).onRpcAvailable(ImmutableList.of(legacyTestRpcIdentifier));
277 private static SchemaPath findRpc(SchemaContext schemaContext, String name) {
278 Module testModule = schemaContext.findModule("odl-datastore-test", TestModel.TEST_QNAME.getRevision()).get();
279 RpcDefinition rpcDefinition = null;
280 for (RpcDefinition def: testModule.getRpcs()) {
281 if (def.getQName().getLocalName().equals(name)) {
287 assertNotNull(name + " rpc not found in " + testModule.getRpcs(), rpcDefinition);
288 return rpcDefinition.getPath();
291 private abstract static class AbstractDOMRpcImplementation<T> {
292 Entry<T, NormalizedNode<?, ?>> rpcInput;
294 void verifyInput(T expRpc, NormalizedNode<?, ?> expInput) {
295 assertNotNull(rpcInput);
296 assertEquals(expRpc, rpcInput.getKey());
297 assertEquals(expInput, rpcInput.getValue());
301 private static class TestLegacyDOMRpcImplementation extends AbstractDOMRpcImplementation<DOMRpcIdentifier>
302 implements DOMRpcImplementation {
303 CheckedFuture<DOMRpcResult, DOMRpcException> returnFuture;
306 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(
307 final DOMRpcIdentifier rpc, final NormalizedNode<?, ?> input) {
308 rpcInput = new SimpleEntry<>(rpc, input);
312 void init(CheckedFuture<DOMRpcResult, DOMRpcException> retFuture) {
313 this.returnFuture = retFuture;
318 private static class TestMdsalDOMRpcImplementation
319 extends AbstractDOMRpcImplementation<org.opendaylight.mdsal.dom.api.DOMRpcIdentifier>
320 implements org.opendaylight.mdsal.dom.api.DOMRpcImplementation {
321 CheckedFuture<org.opendaylight.mdsal.dom.api.DOMRpcResult,
322 org.opendaylight.mdsal.dom.api.DOMRpcException> returnFuture;
325 public CheckedFuture<org.opendaylight.mdsal.dom.api.DOMRpcResult,
326 org.opendaylight.mdsal.dom.api.DOMRpcException> invokeRpc(
327 final org.opendaylight.mdsal.dom.api.DOMRpcIdentifier rpc, final NormalizedNode<?, ?> input) {
328 rpcInput = new SimpleEntry<>(rpc, input);
332 void init(CheckedFuture<org.opendaylight.mdsal.dom.api.DOMRpcResult,
333 org.opendaylight.mdsal.dom.api.DOMRpcException> retFuture) {
334 this.returnFuture = retFuture;
339 private static class TestLegacyDOMRpcImplementation2 implements DOMRpcImplementation {
341 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(
342 final DOMRpcIdentifier rpc, final NormalizedNode<?, ?> input) {
347 private static class TestLegacyDOMRpcException extends DOMRpcException {
348 private static final long serialVersionUID = 1L;
350 TestLegacyDOMRpcException() {
355 private static class TestMdsalDOMRpcException extends org.opendaylight.mdsal.dom.api.DOMRpcException {
356 private static final long serialVersionUID = 1L;
358 TestMdsalDOMRpcException() {