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.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;
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;
59 * Unit tests for DOMRpcRouter.
61 * @author Thomas Pantelis
64 public class DOMRpcRouterTest {
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;
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());
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"));
95 public void testLegacyRegistrationAndInvocation() throws InterruptedException, ExecutionException {
96 final DOMRpcImplementationRegistration<TestLegacyDOMRpcImplementation> reg =
97 legacyRpcRouter.registerRpcImplementation(testLegacyRpcImpl, legacyTestRpcIdentifier,
98 legacyTestRpcNoInputIdentifier);
102 DefaultDOMRpcResult result = new DefaultDOMRpcResult(RPC_OUTPUT);
103 testLegacyRpcImpl.init(Futures.immediateCheckedFuture(result));
105 ListenableFuture<DOMRpcResult> future = legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT);
107 assertSame(result, future.get());
108 testLegacyRpcImpl.verifyInput(legacyTestRpcIdentifier, RPC_INPUT);
110 // Test exception returned
112 TestLegacyDOMRpcException rpcEx = new TestLegacyDOMRpcException();
113 testLegacyRpcImpl.init(Futures.immediateFailedCheckedFuture(rpcEx));
116 legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT).get();
117 fail("Expected exception");
118 } catch (ExecutionException e) {
119 assertEquals(rpcEx, e.getCause());
122 // Test no input or output
124 testLegacyRpcImpl.init(Futures.immediateCheckedFuture(null));
126 future = legacyRpcRouter.invokeRpc(legacyTestRpcNoInputIdentifier.getType(), null);
128 assertNull(future.get());
129 testLegacyRpcImpl.verifyInput(legacyTestRpcNoInputIdentifier, null);
136 legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT).get();
137 fail("Expected exception");
138 } catch (ExecutionException e) {
139 assertTrue(e.getCause() instanceof DOMRpcImplementationNotAvailableException);
144 public void testLegacyRegistrationAndMdsalInvocation() throws InterruptedException, ExecutionException {
145 legacyRpcRouter.registerRpcImplementation(testLegacyRpcImpl, legacyTestRpcIdentifier,
146 legacyTestRpcNoInputIdentifier);
150 DefaultDOMRpcResult result = new DefaultDOMRpcResult(RPC_OUTPUT,
151 Collections.singleton(RpcResultBuilder.newError(ErrorType.RPC, "tag", "message")));
152 testLegacyRpcImpl.init(Futures.immediateCheckedFuture(result));
154 ListenableFuture<org.opendaylight.mdsal.dom.api.DOMRpcResult> future =
155 mdsalRpcRouter.getRpcService().invokeRpc(mdsalTestRpcIdentifier.getType(), RPC_INPUT);
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);
164 // Test exception returned
166 TestLegacyDOMRpcException rpcEx = new TestLegacyDOMRpcException();
167 testLegacyRpcImpl.init(Futures.immediateFailedCheckedFuture(rpcEx));
170 mdsalRpcRouter.getRpcService().invokeRpc(mdsalTestRpcIdentifier.getType(), RPC_INPUT).get();
171 fail("Expected exception");
172 } catch (ExecutionException e) {
173 assertEquals(rpcEx, e.getCause());
176 // Test no input or output
178 testLegacyRpcImpl.init(Futures.immediateCheckedFuture(null));
180 future = mdsalRpcRouter.getRpcService().invokeRpc(mdsalTestRpcNoInputIdentifier.getType(), null);
182 assertNull(future.get());
183 testLegacyRpcImpl.verifyInput(legacyTestRpcNoInputIdentifier, null);
187 public void testMdsalRegistrationAndLegacyInvocation() throws InterruptedException, ExecutionException {
188 mdsalRpcRouter.getRpcProviderService().registerRpcImplementation(testMdsalRpcImpl, mdsalTestRpcIdentifier,
189 mdsalTestRpcNoInputIdentifier);
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));
198 ListenableFuture<DOMRpcResult> future = legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT);
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);
207 // Test exception returned
209 TestMdsalDOMRpcException rpcEx = new TestMdsalDOMRpcException();
210 testMdsalRpcImpl.init(FluentFutures.immediateFailedFluentFuture(rpcEx));
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());
220 // Test no input or output
222 testMdsalRpcImpl.init(FluentFutures.immediateNullFluentFuture());
224 future = legacyRpcRouter.invokeRpc(legacyTestRpcNoInputIdentifier.getType(), null);
226 assertNull(future.get());
227 testMdsalRpcImpl.verifyInput(mdsalTestRpcNoInputIdentifier, null);
231 public void testRegisterRpcListener() {
232 final TestLegacyDOMRpcImplementation2 testRpcImpl2 = new TestLegacyDOMRpcImplementation2();
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);
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);
247 final DOMRpcImplementationRegistration<?> testRpcReg =
248 legacyRpcRouter.registerRpcImplementation(testLegacyRpcImpl, legacyTestRpcIdentifier);
250 verify(listener, timeout(5000)).onRpcAvailable(ImmutableList.of(legacyTestRpcIdentifier));
251 verify(filteredListener, timeout(5000)).onRpcAvailable(ImmutableList.of(legacyTestRpcIdentifier));
253 final DOMRpcImplementationRegistration<?> testRpcNoInputReg =
254 legacyRpcRouter.registerRpcImplementation(testRpcImpl2, legacyTestRpcNoInputIdentifier);
256 verify(listener, timeout(5000)).onRpcAvailable(ImmutableList.of(legacyTestRpcNoInputIdentifier));
257 verify(filteredListener, after(200).never()).onRpcAvailable(ImmutableList.of(legacyTestRpcNoInputIdentifier));
261 verify(listener, timeout(5000)).onRpcUnavailable(ImmutableList.of(legacyTestRpcIdentifier));
262 verify(filteredListener, timeout(5000)).onRpcUnavailable(ImmutableList.of(legacyTestRpcIdentifier));
264 testRpcNoInputReg.close();
266 verify(listener, timeout(5000)).onRpcUnavailable(ImmutableList.of(legacyTestRpcNoInputIdentifier));
267 verify(filteredListener, after(200).never()).onRpcUnavailable(ImmutableList.of(legacyTestRpcNoInputIdentifier));
269 reset(listener, filteredListener);
272 filteredListenerReg.close();
274 legacyRpcRouter.registerRpcImplementation(testLegacyRpcImpl, legacyTestRpcIdentifier);
276 verify(listener, after(200).never()).onRpcAvailable(ImmutableList.of(legacyTestRpcIdentifier));
277 verify(filteredListener, never()).onRpcAvailable(ImmutableList.of(legacyTestRpcIdentifier));
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)) {
290 assertNotNull(name + " rpc not found in " + testModule.getRpcs(), rpcDefinition);
291 return rpcDefinition.getPath();
294 private abstract static class AbstractDOMRpcImplementation<T> {
295 Entry<T, NormalizedNode<?, ?>> rpcInput;
297 void verifyInput(T expRpc, NormalizedNode<?, ?> expInput) {
298 assertNotNull(rpcInput);
299 assertEquals(expRpc, rpcInput.getKey());
300 assertEquals(expInput, rpcInput.getValue());
304 private static class TestLegacyDOMRpcImplementation extends AbstractDOMRpcImplementation<DOMRpcIdentifier>
305 implements DOMRpcImplementation {
306 CheckedFuture<DOMRpcResult, DOMRpcException> returnFuture;
309 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(
310 final DOMRpcIdentifier rpc, final NormalizedNode<?, ?> input) {
311 rpcInput = new SimpleEntry<>(rpc, input);
315 void init(CheckedFuture<DOMRpcResult, DOMRpcException> retFuture) {
316 this.returnFuture = retFuture;
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;
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);
333 void init(FluentFuture<org.opendaylight.mdsal.dom.api.DOMRpcResult> 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() {