+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
package org.opendaylight.controller.sal.binding.test;
-import static org.junit.Assert.*;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.util.ArrayList;
+import java.util.List;
import javassist.ClassPool;
import org.junit.Before;
import org.junit.Test;
-import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*;
+import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
+import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable;
import org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator;
+import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory;
+import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker;
+import org.opendaylight.controller.sal.binding.test.mock.BarListener;
+import org.opendaylight.controller.sal.binding.test.mock.BarUpdate;
+import org.opendaylight.controller.sal.binding.test.mock.FlowDelete;
+import org.opendaylight.controller.sal.binding.test.mock.FooListener;
import org.opendaylight.controller.sal.binding.test.mock.FooService;
+import org.opendaylight.controller.sal.binding.test.mock.FooUpdate;
import org.opendaylight.controller.sal.binding.test.mock.ReferencableObject;
import org.opendaylight.controller.sal.binding.test.mock.ReferencableObjectKey;
import org.opendaylight.controller.sal.binding.test.mock.SimpleInput;
import org.opendaylight.yangtools.yang.binding.Augmentation;
import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
-
-import static org.mockito.Mockito.*;
-
public class RuntimeCodeGeneratorTest {
private RuntimeCodeGenerator codeGenerator;
+ private NotificationInvokerFactory invokerFactory;
-
@Before
public void initialize() {
this.codeGenerator = new RuntimeCodeGenerator(ClassPool.getDefault());
+ this.invokerFactory = codeGenerator.getInvokerFactory();
}
-
+
@Test
public void testGenerateDirectProxy() {
- Class<? extends FooService> product = codeGenerator.generateDirectProxy(FooService.class);
+ FooService product = codeGenerator.getDirectProxyFor(FooService.class);
assertNotNull(product);
}
@Test
public void testGenerateRouter() throws Exception {
- Class<? extends FooService> product = codeGenerator.generateRouter(FooService.class);
+ RpcRouter<FooService> product = codeGenerator.getRouterFor(FooService.class,"test");
assertNotNull(product);
- assertNotNull(product.getSimpleName());
- assertEquals("2 fields should be generated.",2,product.getFields().length);
-
- verifyRouting(product.newInstance());
+ assertNotNull(product.getInvocationProxy());
+
+ assertEquals("2 fields should be generated.", 2, product.getInvocationProxy().getClass().getFields().length);
+
+ verifyRouting(product);
}
- private void verifyRouting(FooService product) {
- Map<InstanceIdentifier,FooService> routingTable = new HashMap<>();
- setRoutingTable(product, BaseIdentity.class, routingTable);
-
- assertSame("Returned routing table should be same instance",routingTable,getRoutingTable(product, BaseIdentity.class));
-
+ @Test
+ public void testInvoker() throws Exception {
+
+ FooListenerImpl fooListener = new FooListenerImpl();
+
+ NotificationInvoker invokerFoo = invokerFactory.invokerFor(fooListener);
+
+
+ assertSame(fooListener,invokerFoo.getDelegate());
+ assertNotNull(invokerFoo.getSupportedNotifications());
+ assertEquals(1, invokerFoo.getSupportedNotifications().size());
+ assertNotNull(invokerFoo.getInvocationProxy());
+
+ FooUpdateImpl fooOne = new FooUpdateImpl();
+ invokerFoo.getInvocationProxy().onNotification(fooOne);
+
+ assertEquals(1, fooListener.receivedFoos.size());
+ assertSame(fooOne, fooListener.receivedFoos.get(0));
+
+ CompositeListenerImpl composite = new CompositeListenerImpl();
+
+ NotificationInvoker invokerComposite = invokerFactory.invokerFor(composite);
+
+ assertNotNull(invokerComposite.getSupportedNotifications());
+ assertEquals(3, invokerComposite.getSupportedNotifications().size());
+ assertNotNull(invokerComposite.getInvocationProxy());
+
+ invokerComposite.getInvocationProxy().onNotification(fooOne);
+
+ assertEquals(1, composite.receivedFoos.size());
+ assertSame(fooOne, composite.receivedFoos.get(0));
+
+ assertEquals(0, composite.receivedBars.size());
+
+ BarUpdateImpl barOne = new BarUpdateImpl();
+
+ invokerComposite.getInvocationProxy().onNotification(barOne);
+
+ assertEquals(1, composite.receivedFoos.size());
+ assertEquals(1, composite.receivedBars.size());
+ assertSame(barOne, composite.receivedBars.get(0));
+
+ }
+
+ private void verifyRouting(final RpcRouter<FooService> product) {
+ assertNotNull("Routing table should be initialized", product.getRoutingTable(BaseIdentity.class));
+
+ RpcRoutingTable<BaseIdentity, FooService> routingTable = product.getRoutingTable(BaseIdentity.class);
+
int servicesCount = 2;
int instancesPerService = 3;
-
- InstanceIdentifier[][] identifiers = identifiers(servicesCount,instancesPerService);
- FooService service[] = new FooService[] {
- mock(FooService.class, "Instance 0"),
- mock(FooService.class,"Instance 1")
- };
-
- for(int i = 0;i<service.length;i++) {
- for (InstanceIdentifier instance : identifiers[i]) {
- routingTable.put(instance, service[i]);
+
+ InstanceIdentifier<?>[][] identifiers = identifiers(servicesCount, instancesPerService);
+ FooService service[] = new FooService[] { mock(FooService.class, "Instance 0"),
+ mock(FooService.class, "Instance 1") };
+
+ for (int i = 0; i < service.length; i++) {
+ for (InstanceIdentifier<?> instance : identifiers[i]) {
+ routingTable.updateRoute(instance, service[i]);
}
}
-
- assertEquals("All instances should be registered.", servicesCount*instancesPerService, routingTable.size());
-
- SimpleInput[] instance_0_input = new SimpleInputImpl[] {
- new SimpleInputImpl(identifiers[0][0]),
- new SimpleInputImpl(identifiers[0][1]),
- new SimpleInputImpl(identifiers[0][2])
- };
-
- SimpleInput[] instance_1_input = new SimpleInputImpl[] {
- new SimpleInputImpl(identifiers[1][0]),
- new SimpleInputImpl(identifiers[1][1]),
- new SimpleInputImpl(identifiers[1][2])
- };
-
+
+ assertEquals("All instances should be registered.", servicesCount * instancesPerService, routingTable
+ .getRoutes().size());
+
+ SimpleInput[] instance_0_input = new SimpleInputImpl[] { new SimpleInputImpl(identifiers[0][0]),
+ new SimpleInputImpl(identifiers[0][1]), new SimpleInputImpl(identifiers[0][2]) };
+
+ SimpleInput[] instance_1_input = new SimpleInputImpl[] { new SimpleInputImpl(identifiers[1][0]),
+ new SimpleInputImpl(identifiers[1][1]), new SimpleInputImpl(identifiers[1][2]) };
+
// We test sending mock messages
-
- product.simple(instance_0_input[0]);
+
+ product.getInvocationProxy().simple(instance_0_input[0]);
verify(service[0]).simple(instance_0_input[0]);
-
- product.simple(instance_0_input[1]);
- product.simple(instance_0_input[2]);
-
+
+ product.getInvocationProxy().simple(instance_0_input[1]);
+ product.getInvocationProxy().simple(instance_0_input[2]);
+
verify(service[0]).simple(instance_0_input[1]);
verify(service[0]).simple(instance_0_input[2]);
-
- product.simple(instance_1_input[0]);
+
+ product.getInvocationProxy().simple(instance_1_input[0]);
+
+ // We should have call to instance 1
verify(service[1]).simple(instance_1_input[0]);
+
+ /*
+ * Generated RPC service should throw illegalArgumentException
+ * with message if rpc input is null.
+ */
+ try {
+ product.getInvocationProxy().simple(null);
+ fail("Generated RPC router should throw IllegalArgumentException on null input");
+ } catch (IllegalArgumentException e){
+ assertNotNull(e.getMessage());
+ }
+
+
+ /*
+ * Generated RPC service should throw illegalArgumentException
+ * with message if rpc route is null.
+ */
+ try {
+ SimpleInput withoutValue = new SimpleInputImpl(null);
+ product.getInvocationProxy().simple(withoutValue);
+ fail("Generated RPC router should throw IllegalArgumentException on null value for route");
+ } catch (IllegalArgumentException e){
+ assertNotNull(e.getMessage());
+ }
+
}
- private InstanceIdentifier[][] identifiers(int serviceSize, int instancesPerService) {
- InstanceIdentifier[][] ret = new InstanceIdentifier[serviceSize][];
+ private InstanceIdentifier<?>[][] identifiers(final int serviceSize, final int instancesPerService) {
+ InstanceIdentifier<?>[][] ret = new InstanceIdentifier[serviceSize][];
int service = 0;
- for (int i = 0;i<serviceSize;i++) {
-
- InstanceIdentifier[] instanceIdentifiers = new InstanceIdentifier[instancesPerService];
+ for (int i = 0; i < serviceSize; i++) {
+
+ InstanceIdentifier<?>[] instanceIdentifiers = new InstanceIdentifier[instancesPerService];
ret[i] = instanceIdentifiers;
- for(int id = 0;id<instancesPerService;id++) {
- instanceIdentifiers[id] = referencableIdentifier(service*instancesPerService+id);
+ for (int id = 0; id < instancesPerService; id++) {
+ instanceIdentifiers[id] = referencableIdentifier(service * instancesPerService + id);
}
service++;
}
-
+
return ret;
}
- private InstanceIdentifier referencableIdentifier(int i) {
- ReferencableObjectKey key = new ReferencableObjectKey(i);
- IdentifiableItem<ReferencableObject,ReferencableObjectKey> pathArg = new IdentifiableItem<>(ReferencableObject.class,key);
- return new InstanceIdentifier(Arrays.<PathArgument>asList(pathArg), ReferencableObject.class);
+ private InstanceIdentifier<?> referencableIdentifier(final int i) {
+ return InstanceIdentifier.builder(ReferencableObject.class, new ReferencableObjectKey(i)).build();
}
private static class SimpleInputImpl implements SimpleInput {
- private final InstanceIdentifier identifier;
+ private final InstanceIdentifier<?> identifier;
- public SimpleInputImpl(InstanceIdentifier _identifier) {
+ public SimpleInputImpl(final InstanceIdentifier<?> _identifier) {
this.identifier = _identifier;
}
@Override
- public <E extends Augmentation<SimpleInput>> E getAugmentation(Class<E> augmentationType) {
+ public <E extends Augmentation<SimpleInput>> E getAugmentation(final Class<E> augmentationType) {
return null;
}
@Override
- public InstanceIdentifier getIdentifier() {
+ public InstanceIdentifier<?> getIdentifier() {
return this.identifier;
}
+
+ @Override
+ public Class<? extends DataObject> getImplementedInterface() {
+ return SimpleInput.class;
+ }
+ }
+
+ private static class FooUpdateImpl implements FooUpdate {
+ @Override
+ public Class<? extends DataContainer> getImplementedInterface() {
+ return FooUpdate.class;
+ }
+ }
+
+ private static class BarUpdateImpl implements BarUpdate {
+ @Override
+ public Class<? extends DataContainer> getImplementedInterface() {
+ return BarUpdate.class;
+ }
+
+ @Override
+ public InstanceIdentifier<?> getInheritedIdentifier() {
+ return null;
+ }
+ }
+
+ private static class FooListenerImpl implements FooListener {
+
+ List<FooUpdate> receivedFoos = new ArrayList<>();
+
+ @Override
+ public void onFooUpdate(final FooUpdate notification) {
+ receivedFoos.add(notification);
+ }
+
+ }
+
+ private static class CompositeListenerImpl extends FooListenerImpl implements BarListener {
+
+ List<BarUpdate> receivedBars = new ArrayList<>();
+ List<FlowDelete> receivedDeletes = new ArrayList<>();
+
+ @Override
+ public void onBarUpdate(final BarUpdate notification) {
+ receivedBars.add(notification);
+ }
+
+ @Override
+ public void onFlowDelete(final FlowDelete notification) {
+ receivedDeletes.add(notification);
+ }
+
}
}