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.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
63 public class DOMRpcRouterTest {
65 private static final NormalizedNode<?, ?> RPC_INPUT = ImmutableNodes.leafNode(
66 QName.create(TestModel.TEST_QNAME.getModule(), "input-leaf"), "foo");
67 private static final NormalizedNode<?, ?> RPC_OUTPUT = ImmutableNodes.leafNode(
68 QName.create(TestModel.TEST_QNAME.getModule(), "output-leaf"), "bar");
69 private final TestLegacyDOMRpcImplementation testLegacyRpcImpl = new TestLegacyDOMRpcImplementation();
70 private final TestMdsalDOMRpcImplementation testMdsalRpcImpl = new TestMdsalDOMRpcImplementation();
71 private org.opendaylight.mdsal.dom.broker.DOMRpcRouter mdsalRpcRouter;
72 private DOMRpcRouter legacyRpcRouter;
73 private DOMRpcIdentifier legacyTestRpcIdentifier;
74 private DOMRpcIdentifier legacyTestRpcNoInputIdentifier;
75 private org.opendaylight.mdsal.dom.api.DOMRpcIdentifier mdsalTestRpcIdentifier;
76 private org.opendaylight.mdsal.dom.api.DOMRpcIdentifier mdsalTestRpcNoInputIdentifier;
80 mdsalRpcRouter = new org.opendaylight.mdsal.dom.broker.DOMRpcRouter();
81 final SchemaContext schemaContext = TestModel.createTestContext();
82 mdsalRpcRouter.onGlobalContextUpdated(schemaContext);
83 legacyRpcRouter = new DOMRpcRouter(mdsalRpcRouter.getRpcService(), mdsalRpcRouter.getRpcProviderService());
85 legacyTestRpcIdentifier = DOMRpcIdentifier.create(findRpc(schemaContext, "test-rpc"));
86 legacyTestRpcNoInputIdentifier = DOMRpcIdentifier.create(findRpc(schemaContext, "test-rpc-no-input"));
87 mdsalTestRpcIdentifier = org.opendaylight.mdsal.dom.api.DOMRpcIdentifier.create(
88 findRpc(schemaContext, "test-rpc"));
89 mdsalTestRpcNoInputIdentifier = org.opendaylight.mdsal.dom.api.DOMRpcIdentifier.create(
90 findRpc(schemaContext, "test-rpc-no-input"));
94 public void testLegacyRegistrationAndInvocation() throws InterruptedException, ExecutionException {
95 final DOMRpcImplementationRegistration<TestLegacyDOMRpcImplementation> reg =
96 legacyRpcRouter.registerRpcImplementation(testLegacyRpcImpl, legacyTestRpcIdentifier,
97 legacyTestRpcNoInputIdentifier);
101 DefaultDOMRpcResult result = new DefaultDOMRpcResult(RPC_OUTPUT);
102 testLegacyRpcImpl.init(Futures.immediateCheckedFuture(result));
104 ListenableFuture<DOMRpcResult> future = legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT);
106 assertSame(result, future.get());
107 testLegacyRpcImpl.verifyInput(legacyTestRpcIdentifier, RPC_INPUT);
109 // Test exception returned
111 TestLegacyDOMRpcException rpcEx = new TestLegacyDOMRpcException();
112 testLegacyRpcImpl.init(Futures.immediateFailedCheckedFuture(rpcEx));
115 legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT).get();
116 fail("Expected exception");
117 } catch (ExecutionException e) {
118 assertEquals(rpcEx, e.getCause());
121 // Test no input or output
123 testLegacyRpcImpl.init(Futures.immediateCheckedFuture(null));
125 future = legacyRpcRouter.invokeRpc(legacyTestRpcNoInputIdentifier.getType(), null);
127 assertNull(future.get());
128 testLegacyRpcImpl.verifyInput(legacyTestRpcNoInputIdentifier, null);
135 legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT).get();
136 fail("Expected exception");
137 } catch (ExecutionException e) {
138 assertTrue(e.getCause() instanceof DOMRpcImplementationNotAvailableException);
143 public void testLegacyRegistrationAndMdsalInvocation() throws InterruptedException, ExecutionException {
144 legacyRpcRouter.registerRpcImplementation(testLegacyRpcImpl, legacyTestRpcIdentifier,
145 legacyTestRpcNoInputIdentifier);
149 DefaultDOMRpcResult result = new DefaultDOMRpcResult(RPC_OUTPUT,
150 Collections.singleton(RpcResultBuilder.newError(ErrorType.RPC, "tag", "message")));
151 testLegacyRpcImpl.init(Futures.immediateCheckedFuture(result));
153 ListenableFuture<org.opendaylight.mdsal.dom.api.DOMRpcResult> future =
154 mdsalRpcRouter.getRpcService().invokeRpc(mdsalTestRpcIdentifier.getType(), RPC_INPUT);
156 assertEquals(RPC_OUTPUT, future.get().getResult());
157 assertEquals(1, future.get().getErrors().size());
158 assertEquals(ErrorType.RPC, future.get().getErrors().iterator().next().getErrorType());
159 assertEquals("tag", future.get().getErrors().iterator().next().getTag());
160 assertEquals("message", future.get().getErrors().iterator().next().getMessage());
161 testLegacyRpcImpl.verifyInput(legacyTestRpcIdentifier, RPC_INPUT);
163 // Test exception returned
165 TestLegacyDOMRpcException rpcEx = new TestLegacyDOMRpcException();
166 testLegacyRpcImpl.init(Futures.immediateFailedCheckedFuture(rpcEx));
169 mdsalRpcRouter.getRpcService().invokeRpc(mdsalTestRpcIdentifier.getType(), RPC_INPUT).get();
170 fail("Expected exception");
171 } catch (ExecutionException e) {
172 assertEquals(rpcEx, e.getCause());
175 // Test no input or output
177 testLegacyRpcImpl.init(Futures.immediateCheckedFuture(null));
179 future = mdsalRpcRouter.getRpcService().invokeRpc(mdsalTestRpcNoInputIdentifier.getType(), null);
181 assertNull(future.get());
182 testLegacyRpcImpl.verifyInput(legacyTestRpcNoInputIdentifier, null);
186 public void testMdsalRegistrationAndLegacyInvocation() throws InterruptedException, ExecutionException {
187 mdsalRpcRouter.getRpcProviderService().registerRpcImplementation(testMdsalRpcImpl, mdsalTestRpcIdentifier,
188 mdsalTestRpcNoInputIdentifier);
192 org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult result =
193 new org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult(RPC_OUTPUT,
194 Collections.singleton(RpcResultBuilder.newError(ErrorType.RPC, "tag", "message")));
195 testMdsalRpcImpl.init(FluentFutures.immediateFluentFuture(result));
197 ListenableFuture<DOMRpcResult> future = legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT);
199 assertEquals(RPC_OUTPUT, future.get().getResult());
200 assertEquals(1, future.get().getErrors().size());
201 assertEquals(ErrorType.RPC, future.get().getErrors().iterator().next().getErrorType());
202 assertEquals("tag", future.get().getErrors().iterator().next().getTag());
203 assertEquals("message", future.get().getErrors().iterator().next().getMessage());
204 testMdsalRpcImpl.verifyInput(mdsalTestRpcIdentifier, RPC_INPUT);
206 // Test exception returned
208 TestMdsalDOMRpcException rpcEx = new TestMdsalDOMRpcException();
209 testMdsalRpcImpl.init(FluentFutures.immediateFailedFluentFuture(rpcEx));
212 legacyRpcRouter.invokeRpc(legacyTestRpcIdentifier.getType(), RPC_INPUT).get();
213 fail("Expected exception");
214 } catch (ExecutionException e) {
215 assertTrue("Unexpected exception " + e.getCause(), e.getCause() instanceof DOMRpcException);
216 assertEquals(rpcEx, e.getCause().getCause());
219 // Test no input or output
221 testMdsalRpcImpl.init(FluentFutures.immediateNullFluentFuture());
223 future = legacyRpcRouter.invokeRpc(legacyTestRpcNoInputIdentifier.getType(), null);
225 assertNull(future.get());
226 testMdsalRpcImpl.verifyInput(mdsalTestRpcNoInputIdentifier, null);
230 public void testRegisterRpcListener() {
231 final TestLegacyDOMRpcImplementation2 testRpcImpl2 = new TestLegacyDOMRpcImplementation2();
233 DOMRpcAvailabilityListener listener = mock(DOMRpcAvailabilityListener.class);
234 doNothing().when(listener).onRpcAvailable(any());
235 doNothing().when(listener).onRpcUnavailable(any());
236 doReturn(true).when(listener).acceptsImplementation(any());
237 final ListenerRegistration<?> listenerReg = legacyRpcRouter.registerRpcListener(listener);
239 DOMRpcAvailabilityListener filteredListener = mock(DOMRpcAvailabilityListener.class);
240 doNothing().when(filteredListener).onRpcAvailable(any());
241 doNothing().when(filteredListener).onRpcUnavailable(any());
242 doReturn(true).when(filteredListener).acceptsImplementation(testLegacyRpcImpl);
243 doReturn(false).when(filteredListener).acceptsImplementation(testRpcImpl2);
244 final ListenerRegistration<?> filteredListenerReg = legacyRpcRouter.registerRpcListener(filteredListener);
246 final DOMRpcImplementationRegistration<?> testRpcReg =
247 legacyRpcRouter.registerRpcImplementation(testLegacyRpcImpl, legacyTestRpcIdentifier);
249 verify(listener, timeout(5000)).onRpcAvailable(ImmutableList.of(legacyTestRpcIdentifier));
250 verify(filteredListener, timeout(5000)).onRpcAvailable(ImmutableList.of(legacyTestRpcIdentifier));
252 final DOMRpcImplementationRegistration<?> testRpcNoInputReg =
253 legacyRpcRouter.registerRpcImplementation(testRpcImpl2, legacyTestRpcNoInputIdentifier);
255 verify(listener, timeout(5000)).onRpcAvailable(ImmutableList.of(legacyTestRpcNoInputIdentifier));
256 verify(filteredListener, after(200).never()).onRpcAvailable(ImmutableList.of(legacyTestRpcNoInputIdentifier));
260 verify(listener, timeout(5000)).onRpcUnavailable(ImmutableList.of(legacyTestRpcIdentifier));
261 verify(filteredListener, timeout(5000)).onRpcUnavailable(ImmutableList.of(legacyTestRpcIdentifier));
263 testRpcNoInputReg.close();
265 verify(listener, timeout(5000)).onRpcUnavailable(ImmutableList.of(legacyTestRpcNoInputIdentifier));
266 verify(filteredListener, after(200).never()).onRpcUnavailable(ImmutableList.of(legacyTestRpcNoInputIdentifier));
268 reset(listener, filteredListener);
271 filteredListenerReg.close();
273 legacyRpcRouter.registerRpcImplementation(testLegacyRpcImpl, legacyTestRpcIdentifier);
275 verify(listener, after(200).never()).onRpcAvailable(ImmutableList.of(legacyTestRpcIdentifier));
276 verify(filteredListener, never()).onRpcAvailable(ImmutableList.of(legacyTestRpcIdentifier));
279 private static SchemaPath findRpc(SchemaContext schemaContext, String name) {
280 Module testModule = schemaContext.findModule("odl-datastore-test", TestModel.TEST_QNAME.getRevision()).get();
281 RpcDefinition rpcDefinition = null;
282 for (RpcDefinition def: testModule.getRpcs()) {
283 if (def.getQName().getLocalName().equals(name)) {
289 assertNotNull(name + " rpc not found in " + testModule.getRpcs(), rpcDefinition);
290 return rpcDefinition.getPath();
293 private abstract static class AbstractDOMRpcImplementation<T> {
294 Entry<T, NormalizedNode<?, ?>> rpcInput;
296 void verifyInput(T expRpc, NormalizedNode<?, ?> expInput) {
297 assertNotNull(rpcInput);
298 assertEquals(expRpc, rpcInput.getKey());
299 assertEquals(expInput, rpcInput.getValue());
303 private static class TestLegacyDOMRpcImplementation extends AbstractDOMRpcImplementation<DOMRpcIdentifier>
304 implements DOMRpcImplementation {
305 CheckedFuture<DOMRpcResult, DOMRpcException> returnFuture;
308 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(
309 final DOMRpcIdentifier rpc, final NormalizedNode<?, ?> input) {
310 rpcInput = new SimpleEntry<>(rpc, input);
314 void init(CheckedFuture<DOMRpcResult, DOMRpcException> retFuture) {
315 this.returnFuture = retFuture;
320 private static class TestMdsalDOMRpcImplementation
321 extends AbstractDOMRpcImplementation<org.opendaylight.mdsal.dom.api.DOMRpcIdentifier>
322 implements org.opendaylight.mdsal.dom.api.DOMRpcImplementation {
323 FluentFuture<org.opendaylight.mdsal.dom.api.DOMRpcResult> returnFuture;
326 public FluentFuture<org.opendaylight.mdsal.dom.api.DOMRpcResult> invokeRpc(
327 final org.opendaylight.mdsal.dom.api.DOMRpcIdentifier rpc, final NormalizedNode<?, ?> input) {
328 rpcInput = new SimpleEntry<>(rpc, input);
332 void init(FluentFuture<org.opendaylight.mdsal.dom.api.DOMRpcResult> retFuture) {
333 this.returnFuture = retFuture;
338 private static class TestLegacyDOMRpcImplementation2 implements DOMRpcImplementation {
340 public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(
341 final DOMRpcIdentifier rpc, final NormalizedNode<?, ?> input) {
346 private static class TestLegacyDOMRpcException extends DOMRpcException {
347 private static final long serialVersionUID = 1L;
349 TestLegacyDOMRpcException() {
354 private static class TestMdsalDOMRpcException extends org.opendaylight.mdsal.dom.api.DOMRpcException {
355 private static final long serialVersionUID = 1L;
357 TestMdsalDOMRpcException() {