2 * Copyright (c) 2016, 2017 Cisco Systems, Inc. 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.mdsal.dom.broker;
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.assertFalse;
14 import static org.junit.Assert.assertNotEquals;
15 import static org.junit.Assert.assertNotNull;
16 import static org.junit.Assert.assertThrows;
17 import static org.junit.Assert.assertTrue;
18 import static org.mockito.ArgumentMatchers.any;
19 import static org.mockito.Mockito.doCallRealMethod;
20 import static org.mockito.Mockito.doNothing;
21 import static org.mockito.Mockito.doReturn;
22 import static org.mockito.Mockito.mock;
23 import static org.mockito.Mockito.timeout;
24 import static org.mockito.Mockito.verify;
25 import static org.opendaylight.mdsal.dom.broker.TestUtils.getTestRpcImplementation;
27 import com.google.common.util.concurrent.Futures;
28 import com.google.common.util.concurrent.ListenableFuture;
29 import java.util.List;
30 import java.util.concurrent.ExecutionException;
31 import java.util.concurrent.RejectedExecutionException;
32 import org.junit.BeforeClass;
33 import org.junit.Test;
34 import org.junit.runner.RunWith;
35 import org.mockito.junit.MockitoJUnitRunner;
36 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
37 import org.opendaylight.mdsal.dom.api.DOMActionAvailabilityExtension;
38 import org.opendaylight.mdsal.dom.api.DOMActionAvailabilityExtension.AvailabilityListener;
39 import org.opendaylight.mdsal.dom.api.DOMActionImplementation;
40 import org.opendaylight.mdsal.dom.api.DOMActionInstance;
41 import org.opendaylight.mdsal.dom.api.DOMActionNotAvailableException;
42 import org.opendaylight.mdsal.dom.api.DOMActionProviderService;
43 import org.opendaylight.mdsal.dom.api.DOMActionResult;
44 import org.opendaylight.mdsal.dom.api.DOMActionService;
45 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
46 import org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener;
47 import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier;
48 import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException;
49 import org.opendaylight.mdsal.dom.api.DOMRpcProviderService;
50 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
51 import org.opendaylight.mdsal.dom.broker.util.TestModel;
52 import org.opendaylight.mdsal.dom.spi.SimpleDOMActionResult;
53 import org.opendaylight.yangtools.concepts.ListenerRegistration;
54 import org.opendaylight.yangtools.concepts.ObjectRegistration;
55 import org.opendaylight.yangtools.concepts.Registration;
56 import org.opendaylight.yangtools.yang.common.QName;
57 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
58 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
59 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
60 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
61 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
62 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextListener;
63 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
64 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
66 @RunWith(MockitoJUnitRunner.StrictStubs.class)
67 public class DOMRpcRouterTest {
68 private static final QName FOO = QName.create("actions", "foo");
69 private static final QName BAR = QName.create(FOO, "bar");
70 private static final QName BAZ = QName.create(FOO, "baz");
71 private static final QName INPUT = QName.create(FOO, "input");
72 private static final QName OUTPUT = QName.create(FOO, "output");
74 private static final Absolute BAZ_TYPE = Absolute.of(FOO, BAZ);
75 private static final YangInstanceIdentifier BAZ_PATH_BAD = YangInstanceIdentifier.create(
76 new NodeIdentifier(FOO), NodeIdentifierWithPredicates.of(FOO, BAR, "bad"));
77 private static final YangInstanceIdentifier BAZ_PATH_GOOD = YangInstanceIdentifier.create(
78 new NodeIdentifier(FOO), NodeIdentifierWithPredicates.of(FOO, BAR, "good"));
80 private static final DOMActionImplementation IMPL =
81 (type, path, input) -> Futures.immediateFuture(new SimpleDOMActionResult(
82 Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(OUTPUT)).build()));
84 private static EffectiveModelContext ACTIONS_CONTEXT;
87 public static void beforeClass() {
88 ACTIONS_CONTEXT = YangParserTestUtils.parseYangResource("/actions.yang");
92 public void registerRpcImplementation() {
93 try (DOMRpcRouter rpcRouter = new DOMRpcRouter()) {
94 DOMRpcRoutingTable routingTable = rpcRouter.routingTable();
95 assertFalse(routingTable.getOperations().containsKey(TestModel.TEST_QNAME));
97 rpcRouter.getRpcProviderService().registerRpcImplementation(getTestRpcImplementation(),
98 DOMRpcIdentifier.create(TestModel.TEST_QNAME, null));
99 routingTable = rpcRouter.routingTable();
100 assertTrue(routingTable.getOperations().containsKey(TestModel.TEST_QNAME));
102 rpcRouter.getRpcProviderService().registerRpcImplementation(getTestRpcImplementation(),
103 DOMRpcIdentifier.create(TestModel.TEST2_QNAME, null));
104 routingTable = rpcRouter.routingTable();
105 assertTrue(routingTable.getOperations().containsKey(TestModel.TEST2_QNAME));
110 public void testFailedInvokeRpc() {
111 try (DOMRpcRouter rpcRouter = new DOMRpcRouter()) {
112 final ListenableFuture<?> future = rpcRouter.getRpcService().invokeRpc(TestModel.TEST_QNAME, null);
113 final Throwable cause = assertThrows(ExecutionException.class, () -> Futures.getDone(future)).getCause();
114 assertThat(cause, instanceOf(DOMRpcImplementationNotAvailableException.class));
115 assertEquals("No implementation of RPC "
116 + "(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test "
117 + "available", cause.getMessage());
122 public void testRpcListener() {
123 try (DOMRpcRouter rpcRouter = new DOMRpcRouter()) {
124 assertEquals(List.of(), rpcRouter.listeners());
126 final DOMRpcAvailabilityListener listener = mock(DOMRpcAvailabilityListener.class);
127 doCallRealMethod().when(listener).acceptsImplementation(any());
128 doNothing().when(listener).onRpcAvailable(any());
129 doNothing().when(listener).onRpcUnavailable(any());
131 final Registration reg = rpcRouter.getRpcService().registerRpcListener(listener);
133 assertEquals(List.of(reg), rpcRouter.listeners());
135 final Registration implReg = rpcRouter.getRpcProviderService().registerRpcImplementation(
136 getTestRpcImplementation(), DOMRpcIdentifier.create(TestModel.TEST_QNAME, null));
137 verify(listener, timeout(1000)).onRpcAvailable(any());
140 verify(listener, timeout(1000)).onRpcUnavailable(any());
143 assertEquals(List.of(), rpcRouter.listeners());
148 public void testActionListener() {
149 try (DOMRpcRouter rpcRouter = new DOMRpcRouter()) {
150 assertEquals(List.of(), rpcRouter.actionListeners());
152 final AvailabilityListener listener = mock(AvailabilityListener.class);
153 final Registration reg = rpcRouter.getActionService().getExtensions()
154 .getInstance(DOMActionAvailabilityExtension.class).registerAvailabilityListener(listener);
156 assertEquals(List.of(reg), rpcRouter.actionListeners());
158 // FIXME: register implementation and verify notification
161 assertEquals(List.of(), rpcRouter.actionListeners());
166 public void onGlobalContextUpdated() {
167 try (DOMRpcRouter rpcRouter = new DOMRpcRouter()) {
169 final DOMRpcRoutingTable routingTableOriginal = rpcRouter.routingTable();
171 rpcRouter.onModelContextUpdated(TestModel.createTestContext());
173 final DOMRpcRoutingTable routingTableChanged = rpcRouter.routingTable();
174 assertNotEquals(routingTableOriginal, routingTableChanged);
179 public void testClose() {
180 final ListenerRegistration<EffectiveModelContextListener> reg = mock(ListenerRegistration.class);
181 doNothing().when(reg).close();
182 final DOMSchemaService schema = mock(DOMSchemaService.class);
183 doReturn(reg).when(schema).registerSchemaContextListener(any());
185 final DOMRpcRouter rpcRouter = new DOMRpcRouter(schema);
188 final DOMRpcProviderService svc = rpcRouter.getRpcProviderService();
189 assertThrows(RejectedExecutionException.class, () -> svc.registerRpcImplementation(getTestRpcImplementation(),
190 DOMRpcIdentifier.create(TestModel.TEST_QNAME, null)));
194 public void testActionInstanceRouting() throws ExecutionException {
195 try (DOMRpcRouter rpcRouter = new DOMRpcRouter()) {
196 rpcRouter.onModelContextUpdated(ACTIONS_CONTEXT);
198 final DOMActionProviderService actionProvider = rpcRouter.getActionProviderService();
199 assertNotNull(actionProvider);
200 final DOMActionService actionConsumer = rpcRouter.getActionService();
201 assertNotNull(actionConsumer);
203 try (ObjectRegistration<?> reg = actionProvider.registerActionImplementation(IMPL,
204 DOMActionInstance.of(BAZ_TYPE, LogicalDatastoreType.OPERATIONAL, BAZ_PATH_GOOD))) {
206 assertAvailable(actionConsumer, BAZ_PATH_GOOD);
207 assertUnavailable(actionConsumer, BAZ_PATH_BAD);
210 assertUnavailable(actionConsumer, BAZ_PATH_BAD);
211 assertUnavailable(actionConsumer, BAZ_PATH_GOOD);
216 public void testActionDatastoreRouting() throws ExecutionException {
217 try (DOMRpcRouter rpcRouter = new DOMRpcRouter()) {
218 rpcRouter.onModelContextUpdated(ACTIONS_CONTEXT);
220 final DOMActionProviderService actionProvider = rpcRouter.getActionProviderService();
221 assertNotNull(actionProvider);
222 final DOMActionService actionConsumer = rpcRouter.getActionService();
223 assertNotNull(actionConsumer);
225 try (ObjectRegistration<?> reg = actionProvider.registerActionImplementation(IMPL,
226 DOMActionInstance.of(BAZ_TYPE, LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.empty()))) {
228 assertAvailable(actionConsumer, BAZ_PATH_GOOD);
229 assertAvailable(actionConsumer, BAZ_PATH_BAD);
232 assertUnavailable(actionConsumer, BAZ_PATH_BAD);
233 assertUnavailable(actionConsumer, BAZ_PATH_GOOD);
237 private static void assertAvailable(final DOMActionService actionService, final YangInstanceIdentifier path) {
238 final DOMActionResult result;
240 result = Futures.getDone(invokeBaz(actionService, path));
241 } catch (ExecutionException e) {
242 throw new AssertionError("Unexpected invocation failure", e);
244 assertEquals(List.of(), result.getErrors());
247 private static void assertUnavailable(final DOMActionService actionService, final YangInstanceIdentifier path) {
248 final ListenableFuture<? extends DOMActionResult> future = invokeBaz(actionService, path);
249 final ExecutionException ex = assertThrows(ExecutionException.class, () -> Futures.getDone(future));
250 assertThat(ex.getCause(), instanceOf(DOMActionNotAvailableException.class));
253 private static ListenableFuture<? extends DOMActionResult> invokeBaz(final DOMActionService actionService,
254 final YangInstanceIdentifier path) {
255 return actionService.invokeAction(BAZ_TYPE, new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, path),
256 Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(INPUT)).build());