Merge "Bug 2435 - Controller/MD-SAL throwing ModifiedNodeDoesNotExistException except...
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / test / java / org / opendaylight / controller / sal / binding / codegen / impl / DefaultRuntimeCodeGeneratorTest.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.sal.binding.codegen.impl;
9
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;
40
41 public class DefaultRuntimeCodeGeneratorTest {
42
43     private RuntimeCodeGenerator codeGenerator;
44     private NotificationInvokerFactory invokerFactory;
45
46     @Before
47     public void initialize() {
48         this.codeGenerator = new DefaultRuntimeCodeGenerator(ClassPool.getDefault());
49         this.invokerFactory = codeGenerator.getInvokerFactory();
50     }
51
52     @Test
53     public void testGenerateDirectProxy() {
54         FooService product = codeGenerator.getDirectProxyFor(FooService.class);
55         assertNotNull(product);
56     }
57
58     @Test
59     public void testGenerateRouter() throws Exception {
60         RpcRouter<FooService> product = codeGenerator.getRouterFor(FooService.class,"test");
61         assertNotNull(product);
62         assertNotNull(product.getInvocationProxy());
63
64         assertEquals("2 fields should be generated.", 2, product.getInvocationProxy().getClass().getFields().length);
65
66         verifyRouting(product);
67     }
68
69     @Test
70     public void testInvoker() throws Exception {
71
72         FooListenerImpl fooListener = new FooListenerImpl();
73
74         NotificationInvoker invokerFoo = invokerFactory.invokerFor(fooListener);
75
76
77         assertSame(fooListener,invokerFoo.getDelegate());
78         assertNotNull(invokerFoo.getSupportedNotifications());
79         assertEquals(1, invokerFoo.getSupportedNotifications().size());
80         assertNotNull(invokerFoo.getInvocationProxy());
81
82         FooUpdateImpl fooOne = new FooUpdateImpl();
83         invokerFoo.getInvocationProxy().onNotification(fooOne);
84
85         assertEquals(1, fooListener.receivedFoos.size());
86         assertSame(fooOne, fooListener.receivedFoos.get(0));
87
88         CompositeListenerImpl composite = new CompositeListenerImpl();
89
90         NotificationInvoker invokerComposite = invokerFactory.invokerFor(composite);
91
92         assertNotNull(invokerComposite.getSupportedNotifications());
93         assertEquals(3, invokerComposite.getSupportedNotifications().size());
94         assertNotNull(invokerComposite.getInvocationProxy());
95
96         invokerComposite.getInvocationProxy().onNotification(fooOne);
97
98         assertEquals(1, composite.receivedFoos.size());
99         assertSame(fooOne, composite.receivedFoos.get(0));
100
101         assertEquals(0, composite.receivedBars.size());
102
103         BarUpdateImpl barOne = new BarUpdateImpl();
104
105         invokerComposite.getInvocationProxy().onNotification(barOne);
106
107         assertEquals(1, composite.receivedFoos.size());
108         assertEquals(1, composite.receivedBars.size());
109         assertSame(barOne, composite.receivedBars.get(0));
110
111     }
112
113     private void verifyRouting(final RpcRouter<FooService> product) {
114         assertNotNull("Routing table should be initialized", product.getRoutingTable(BaseIdentity.class));
115
116         RpcRoutingTable<BaseIdentity, FooService> routingTable = product.getRoutingTable(BaseIdentity.class);
117
118         int servicesCount = 2;
119         int instancesPerService = 3;
120
121         InstanceIdentifier<?>[][] identifiers = identifiers(servicesCount, instancesPerService);
122         FooService service[] = new FooService[] { mock(FooService.class, "Instance 0"),
123                 mock(FooService.class, "Instance 1") };
124
125         for (int i = 0; i < service.length; i++) {
126             for (InstanceIdentifier<?> instance : identifiers[i]) {
127                 routingTable.updateRoute(instance, service[i]);
128             }
129         }
130
131         assertEquals("All instances should be registered.", servicesCount * instancesPerService, routingTable
132                 .getRoutes().size());
133
134         SimpleInput[] instance_0_input = new SimpleInputImpl[] { new SimpleInputImpl(identifiers[0][0]),
135                 new SimpleInputImpl(identifiers[0][1]), new SimpleInputImpl(identifiers[0][2]) };
136
137         SimpleInput[] instance_1_input = new SimpleInputImpl[] { new SimpleInputImpl(identifiers[1][0]),
138                 new SimpleInputImpl(identifiers[1][1]), new SimpleInputImpl(identifiers[1][2]) };
139
140         // We test sending mock messages
141
142         product.getInvocationProxy().simple(instance_0_input[0]);
143         verify(service[0]).simple(instance_0_input[0]);
144
145         product.getInvocationProxy().simple(instance_0_input[1]);
146         product.getInvocationProxy().simple(instance_0_input[2]);
147
148         verify(service[0]).simple(instance_0_input[1]);
149         verify(service[0]).simple(instance_0_input[2]);
150
151         product.getInvocationProxy().simple(instance_1_input[0]);
152
153         // We should have call to instance 1
154         verify(service[1]).simple(instance_1_input[0]);
155
156         /*
157          * Generated RPC service should throw illegalArgumentException
158          * with message if rpc input is null.
159          */
160         try {
161             product.getInvocationProxy().simple(null);
162             fail("Generated RPC router should throw IllegalArgumentException on null input");
163         } catch (IllegalArgumentException e){
164             assertNotNull(e.getMessage());
165         }
166
167
168         /*
169          * Generated RPC service should throw illegalArgumentException
170          * with message if rpc route is null.
171          */
172         try {
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());
178         }
179
180     }
181
182     private InstanceIdentifier<?>[][] identifiers(final int serviceSize, final int instancesPerService) {
183         InstanceIdentifier<?>[][] ret = new InstanceIdentifier[serviceSize][];
184         int service = 0;
185         for (int i = 0; i < serviceSize; i++) {
186
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);
191             }
192             service++;
193         }
194
195         return ret;
196     }
197
198     private InstanceIdentifier<?> referencableIdentifier(final int i) {
199         return InstanceIdentifier.builder(ReferencableObject.class, new ReferencableObjectKey(i)).build();
200     }
201
202     private static class SimpleInputImpl implements SimpleInput {
203         private final InstanceIdentifier<?> identifier;
204
205         public SimpleInputImpl(final InstanceIdentifier<?> _identifier) {
206             this.identifier = _identifier;
207         }
208
209         @Override
210         public <E extends Augmentation<SimpleInput>> E getAugmentation(final Class<E> augmentationType) {
211             return null;
212         }
213
214         @Override
215         public InstanceIdentifier<?> getIdentifier() {
216             return this.identifier;
217         }
218
219         @Override
220         public Class<? extends DataObject> getImplementedInterface() {
221             return SimpleInput.class;
222         }
223     }
224
225     private static class FooUpdateImpl implements FooUpdate {
226         @Override
227         public Class<? extends DataContainer> getImplementedInterface() {
228             return FooUpdate.class;
229         }
230     }
231
232     private static class BarUpdateImpl implements BarUpdate {
233         @Override
234         public Class<? extends DataContainer> getImplementedInterface() {
235             return BarUpdate.class;
236         }
237
238         @Override
239         public InstanceIdentifier<?> getInheritedIdentifier() {
240             return null;
241         }
242     }
243
244     private static class FooListenerImpl implements FooListener {
245
246         List<FooUpdate> receivedFoos = new ArrayList<>();
247
248         @Override
249         public void onFooUpdate(final FooUpdate notification) {
250             receivedFoos.add(notification);
251         }
252
253     }
254
255     private static class CompositeListenerImpl extends FooListenerImpl implements BarListener {
256
257         List<BarUpdate> receivedBars = new ArrayList<>();
258         List<FlowDelete> receivedDeletes = new ArrayList<>();
259
260         @Override
261         public void onBarUpdate(final BarUpdate notification) {
262             receivedBars.add(notification);
263         }
264
265         @Override
266         public void onFlowDelete(final FlowDelete notification) {
267             receivedDeletes.add(notification);
268         }
269
270     }
271 }