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