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