2 * Copyright (c) 2014 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.controller.sal.binding.codegen.impl;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertSame;
13 import static org.junit.Assert.fail;
14 import static org.mockito.Mockito.mock;
15 import static org.mockito.Mockito.verify;
16 import java.util.ArrayList;
17 import java.util.List;
18 import javassist.ClassPool;
19 import org.junit.Before;
20 import org.junit.Test;
21 import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
22 import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable;
23 import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator;
24 import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory;
25 import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker;
26 import org.opendaylight.controller.sal.binding.test.mock.BarListener;
27 import org.opendaylight.controller.sal.binding.test.mock.BarUpdate;
28 import org.opendaylight.controller.sal.binding.test.mock.FlowDelete;
29 import org.opendaylight.controller.sal.binding.test.mock.FooListener;
30 import org.opendaylight.controller.sal.binding.test.mock.FooService;
31 import org.opendaylight.controller.sal.binding.test.mock.FooUpdate;
32 import org.opendaylight.controller.sal.binding.test.mock.ReferencableObject;
33 import org.opendaylight.controller.sal.binding.test.mock.ReferencableObjectKey;
34 import org.opendaylight.controller.sal.binding.test.mock.SimpleInput;
35 import org.opendaylight.yangtools.yang.binding.Augmentation;
36 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
37 import org.opendaylight.yangtools.yang.binding.DataContainer;
38 import org.opendaylight.yangtools.yang.binding.DataObject;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 public class DefaultRuntimeCodeGeneratorTest {
43 private RuntimeCodeGenerator codeGenerator;
44 private NotificationInvokerFactory invokerFactory;
47 public void initialize() {
48 this.codeGenerator = new DefaultRuntimeCodeGenerator(ClassPool.getDefault());
49 this.invokerFactory = codeGenerator.getInvokerFactory();
53 public void testGenerateDirectProxy() {
54 FooService product = codeGenerator.getDirectProxyFor(FooService.class);
55 assertNotNull(product);
59 public void testGenerateRouter() throws Exception {
60 RpcRouter<FooService> product = codeGenerator.getRouterFor(FooService.class,"test");
61 assertNotNull(product);
62 assertNotNull(product.getInvocationProxy());
64 assertEquals("2 fields should be generated.", 2, product.getInvocationProxy().getClass().getFields().length);
66 verifyRouting(product);
70 public void testInvoker() throws Exception {
72 FooListenerImpl fooListener = new FooListenerImpl();
74 NotificationInvoker invokerFoo = invokerFactory.invokerFor(fooListener);
77 assertSame(fooListener,invokerFoo.getDelegate());
78 assertNotNull(invokerFoo.getSupportedNotifications());
79 assertEquals(1, invokerFoo.getSupportedNotifications().size());
80 assertNotNull(invokerFoo.getInvocationProxy());
82 FooUpdateImpl fooOne = new FooUpdateImpl();
83 invokerFoo.getInvocationProxy().onNotification(fooOne);
85 assertEquals(1, fooListener.receivedFoos.size());
86 assertSame(fooOne, fooListener.receivedFoos.get(0));
88 CompositeListenerImpl composite = new CompositeListenerImpl();
90 NotificationInvoker invokerComposite = invokerFactory.invokerFor(composite);
92 assertNotNull(invokerComposite.getSupportedNotifications());
93 assertEquals(3, invokerComposite.getSupportedNotifications().size());
94 assertNotNull(invokerComposite.getInvocationProxy());
96 invokerComposite.getInvocationProxy().onNotification(fooOne);
98 assertEquals(1, composite.receivedFoos.size());
99 assertSame(fooOne, composite.receivedFoos.get(0));
101 assertEquals(0, composite.receivedBars.size());
103 BarUpdateImpl barOne = new BarUpdateImpl();
105 invokerComposite.getInvocationProxy().onNotification(barOne);
107 assertEquals(1, composite.receivedFoos.size());
108 assertEquals(1, composite.receivedBars.size());
109 assertSame(barOne, composite.receivedBars.get(0));
113 private void verifyRouting(final RpcRouter<FooService> product) {
114 assertNotNull("Routing table should be initialized", product.getRoutingTable(BaseIdentity.class));
116 RpcRoutingTable<BaseIdentity, FooService> routingTable = product.getRoutingTable(BaseIdentity.class);
118 int servicesCount = 2;
119 int instancesPerService = 3;
121 InstanceIdentifier<?>[][] identifiers = identifiers(servicesCount, instancesPerService);
122 FooService service[] = new FooService[] { mock(FooService.class, "Instance 0"),
123 mock(FooService.class, "Instance 1") };
125 for (int i = 0; i < service.length; i++) {
126 for (InstanceIdentifier<?> instance : identifiers[i]) {
127 routingTable.updateRoute(instance, service[i]);
131 assertEquals("All instances should be registered.", servicesCount * instancesPerService, routingTable
132 .getRoutes().size());
134 SimpleInput[] instance_0_input = new SimpleInputImpl[] { new SimpleInputImpl(identifiers[0][0]),
135 new SimpleInputImpl(identifiers[0][1]), new SimpleInputImpl(identifiers[0][2]) };
137 SimpleInput[] instance_1_input = new SimpleInputImpl[] { new SimpleInputImpl(identifiers[1][0]),
138 new SimpleInputImpl(identifiers[1][1]), new SimpleInputImpl(identifiers[1][2]) };
140 // We test sending mock messages
142 product.getInvocationProxy().simple(instance_0_input[0]);
143 verify(service[0]).simple(instance_0_input[0]);
145 product.getInvocationProxy().simple(instance_0_input[1]);
146 product.getInvocationProxy().simple(instance_0_input[2]);
148 verify(service[0]).simple(instance_0_input[1]);
149 verify(service[0]).simple(instance_0_input[2]);
151 product.getInvocationProxy().simple(instance_1_input[0]);
153 // We should have call to instance 1
154 verify(service[1]).simple(instance_1_input[0]);
157 * Generated RPC service should throw illegalArgumentException
158 * with message if rpc input is null.
161 product.getInvocationProxy().simple(null);
162 fail("Generated RPC router should throw IllegalArgumentException on null input");
163 } catch (IllegalArgumentException e){
164 assertNotNull(e.getMessage());
169 * Generated RPC service should throw illegalArgumentException
170 * with message if rpc route is null.
173 SimpleInput withoutValue = new SimpleInputImpl(null);
174 product.getInvocationProxy().simple(withoutValue);
175 fail("Generated RPC router should throw IllegalArgumentException on null value for route");
176 } catch (IllegalArgumentException e){
177 assertNotNull(e.getMessage());
182 private InstanceIdentifier<?>[][] identifiers(final int serviceSize, final int instancesPerService) {
183 InstanceIdentifier<?>[][] ret = new InstanceIdentifier[serviceSize][];
185 for (int i = 0; i < serviceSize; i++) {
187 InstanceIdentifier<?>[] instanceIdentifiers = new InstanceIdentifier[instancesPerService];
188 ret[i] = instanceIdentifiers;
189 for (int id = 0; id < instancesPerService; id++) {
190 instanceIdentifiers[id] = referencableIdentifier(service * instancesPerService + id);
198 private InstanceIdentifier<?> referencableIdentifier(final int i) {
199 return InstanceIdentifier.builder(ReferencableObject.class, new ReferencableObjectKey(i)).build();
202 private static class SimpleInputImpl implements SimpleInput {
203 private final InstanceIdentifier<?> identifier;
205 public SimpleInputImpl(final InstanceIdentifier<?> _identifier) {
206 this.identifier = _identifier;
210 public <E extends Augmentation<SimpleInput>> E getAugmentation(final Class<E> augmentationType) {
215 public InstanceIdentifier<?> getIdentifier() {
216 return this.identifier;
220 public Class<? extends DataObject> getImplementedInterface() {
221 return SimpleInput.class;
225 private static class FooUpdateImpl implements FooUpdate {
227 public Class<? extends DataContainer> getImplementedInterface() {
228 return FooUpdate.class;
232 private static class BarUpdateImpl implements BarUpdate {
234 public Class<? extends DataContainer> getImplementedInterface() {
235 return BarUpdate.class;
239 public InstanceIdentifier<?> getInheritedIdentifier() {
244 private static class FooListenerImpl implements FooListener {
246 List<FooUpdate> receivedFoos = new ArrayList<>();
249 public void onFooUpdate(final FooUpdate notification) {
250 receivedFoos.add(notification);
255 private static class CompositeListenerImpl extends FooListenerImpl implements BarListener {
257 List<BarUpdate> receivedBars = new ArrayList<>();
258 List<FlowDelete> receivedDeletes = new ArrayList<>();
261 public void onBarUpdate(final BarUpdate notification) {
262 receivedBars.add(notification);
266 public void onFlowDelete(final FlowDelete notification) {
267 receivedDeletes.add(notification);