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