Refactored implementation of Notification Invoker
[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.ReferencableObject;
32 import org.opendaylight.controller.sal.binding.test.mock.ReferencableObjectKey;
33 import org.opendaylight.controller.sal.binding.test.mock.SimpleInput;
34 import org.opendaylight.yangtools.yang.binding.Augmentation;
35 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
36 import org.opendaylight.yangtools.yang.binding.DataContainer;
37 import org.opendaylight.yangtools.yang.binding.DataObject;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
41
42 import static org.mockito.Mockito.*;
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);
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(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     private InstanceIdentifier<?>[][] identifiers(int serviceSize, int instancesPerService) {
161         InstanceIdentifier<?>[][] ret = new InstanceIdentifier[serviceSize][];
162         int service = 0;
163         for (int i = 0; i < serviceSize; i++) {
164
165             InstanceIdentifier<?>[] instanceIdentifiers = new InstanceIdentifier[instancesPerService];
166             ret[i] = instanceIdentifiers;
167             for (int id = 0; id < instancesPerService; id++) {
168                 instanceIdentifiers[id] = referencableIdentifier(service * instancesPerService + id);
169             }
170             service++;
171         }
172
173         return ret;
174     }
175
176     private InstanceIdentifier<?> referencableIdentifier(int i) {
177         ReferencableObjectKey key = new ReferencableObjectKey(i);
178         IdentifiableItem<ReferencableObject, ReferencableObjectKey> pathArg = new IdentifiableItem<>(
179                 ReferencableObject.class, key);
180         return new InstanceIdentifier<ReferencableObject>(Arrays.<PathArgument> asList(pathArg),
181                 ReferencableObject.class);
182     }
183
184     private static class SimpleInputImpl implements SimpleInput {
185         private final InstanceIdentifier<?> identifier;
186
187         public SimpleInputImpl(InstanceIdentifier<?> _identifier) {
188             this.identifier = _identifier;
189         }
190
191         @Override
192         public <E extends Augmentation<SimpleInput>> E getAugmentation(Class<E> augmentationType) {
193             return null;
194         }
195
196         @Override
197         public InstanceIdentifier<?> getIdentifier() {
198             return this.identifier;
199         }
200
201         @Override
202         public Class<? extends DataObject> getImplementedInterface() {
203             return SimpleInput.class;
204         }
205     }
206
207     private static class FooUpdateImpl implements FooUpdate {
208         @Override
209         public Class<? extends DataContainer> getImplementedInterface() {
210             return FooUpdate.class;
211         }
212     }
213
214     private static class BarUpdateImpl implements BarUpdate {
215         @Override
216         public Class<? extends DataContainer> getImplementedInterface() {
217             return BarUpdate.class;
218         }
219
220         @Override
221         public InstanceIdentifier<?> getInheritedIdentifier() {
222             return null;
223         }
224     }
225
226     private static class FooListenerImpl implements FooListener {
227
228         List<FooUpdate> receivedFoos = new ArrayList<>();
229
230         @Override
231         public void onFooUpdate(FooUpdate notification) {
232             receivedFoos.add(notification);
233         }
234
235     }
236
237     private static class CompositeListenerImpl extends FooListenerImpl implements BarListener {
238
239         List<BarUpdate> receivedBars = new ArrayList<>();
240         List<FlowDelete> receivedDeletes = new ArrayList<>();
241
242         @Override
243         public void onBarUpdate(BarUpdate notification) {
244             receivedBars.add(notification);
245         }
246
247         @Override
248         public void onFlowDelete(FlowDelete notification) {
249             receivedDeletes.add(notification);
250         }
251
252     }
253 }