BUG-5006: rework SouthboundMapperTest without PowerMock 84/34484/3
authorStephen Kitt <skitt@redhat.com>
Thu, 11 Feb 2016 17:09:34 +0000 (18:09 +0100)
committerSam Hague <shague@redhat.com>
Fri, 12 Feb 2016 01:01:00 +0000 (20:01 -0500)
A number of tests were meaningless, these have all been fixed to
verify SouthboundMapper's behaviour.

Conflicts:
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/SouthboundMapperTest.java

Change-Id: Ia349e545bde9706d2b1840530abd46c09ac55e45
Signed-off-by: Stephen Kitt <skitt@redhat.com>
Signed-off-by: Sam Hague <shague@redhat.com>
southbound/southbound-impl/pom.xml
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/SouthboundMapperTest.java
southbound/southbound-impl/src/test/resources/org/opendaylight/ovsdb/southbound/openvswitch_schema.json [new file with mode: 0644]

index 328733b3c447349ba72eabe0e08263539116afd8..a50867d24515e19ac9823399033c8622ad348f3a 100644 (file)
@@ -98,6 +98,13 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <version>${powermock.version}</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-broker-impl</artifactId>
+      <version>1.3.0-SNAPSHOT</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
   <build>
     <plugins>
index 566ff3718b86e77cd85b7e5a5c1f6bf61a387d9f..430240248cbe8429b0e0307792963ccb69d88128 100644 (file)
@@ -11,44 +11,39 @@ package org.opendaylight.ovsdb.southbound;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.when;
 
-import java.net.Inet4Address;
-import java.net.Inet6Address;
+import java.io.InputStream;
 import java.net.InetAddress;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import org.junit.Before;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 import org.mockito.Mockito;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
 import org.opendaylight.ovsdb.lib.OvsdbClient;
 import org.opendaylight.ovsdb.lib.notation.Column;
 import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
 import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
-import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
 import org.opendaylight.ovsdb.schema.openvswitch.Controller;
 import org.opendaylight.ovsdb.schema.openvswitch.Manager;
 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddressBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
@@ -59,62 +54,36 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.re
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeInternal;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeVxlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentationBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolBase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolOpenflow10;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntry;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfoBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagerEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ManagerEntryBuilder;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
 import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
 
-@PrepareForTest({SouthboundMapper.class, InstanceIdentifier.class, Inet4Address.class,  Inet6Address.class, SouthboundUtil.class, SouthboundConstants.class, TyperUtils.class})
-@RunWith(PowerMockRunner.class)
-public class SouthboundMapperTest {
-
-
-    @Before
-    public void setUp() {
-        PowerMockito.mockStatic(SouthboundMapper.class, Mockito.CALLS_REAL_METHODS);
-    }
-
-    @Test
-    public void testCreateManagedNodeId() throws Exception {
-        PowerMockito.mockStatic(SouthboundMapper.class, Mockito.RETURNS_MOCKS);
-        assertTrue("Returned value is not an NodeId", SouthboundMapper.createManagedNodeId(null) instanceof NodeId);
-    }
+public class SouthboundMapperTest extends AbstractDataBrokerTest {
 
     @Test
     public void testCreateIpAddress() throws Exception {
-        IpAddress ip = mock(IpAddress.class);
-
-        //test for createIpAddress(Inet4Address address)
-        InetAddress addressInet4 = PowerMockito.mock(Inet4Address.class);
-        when(addressInet4.getHostAddress()).thenReturn("127.0.0.1");
-        Ipv4Address ipv4Add = mock(Ipv4Address.class);
-        PowerMockito.whenNew(Ipv4Address.class).withAnyArguments().thenReturn(ipv4Add);
-        PowerMockito.whenNew(IpAddress.class).withAnyArguments().thenReturn(ip);
-        assertEquals("Incorrect IP address received", ip, SouthboundMapper.createIpAddress(addressInet4));
+        IpAddress ipAddress = IpAddressBuilder.getDefaultInstance("127.0.0.1");
+        InetAddress inetAddress = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
+        assertEquals("Incorrect IP address created", ipAddress, SouthboundMapper.createIpAddress(inetAddress));
     }
 
     @Test
     public void testCreateInstanceIdentifier() throws Exception {
-        assertTrue(SouthboundMapper.createInstanceIdentifier(mock(NodeId.class)) instanceof InstanceIdentifier);
+        NodeId nodeId = NodeId.getDefaultInstance("test");
+        InstanceIdentifier<Node> iid = SouthboundMapper.createInstanceIdentifier(nodeId);
+        assertEquals(nodeId, iid.firstKeyOf(Node.class).getNodeId());
     }
 
     @SuppressWarnings("unchecked")
@@ -122,34 +91,28 @@ public class SouthboundMapperTest {
     public void testCreateInstanceIdentifier1() throws Exception {
         OvsdbConnectionInstance client = mock(OvsdbConnectionInstance.class, Mockito.RETURNS_DEEP_STUBS);
         Bridge bridge = mock(Bridge.class);
-        InstanceIdentifier<Node> iid = mock(InstanceIdentifier.class);
 
-        //when bridge is not empty
+        // When bridge is not empty, we expect a deserialized identifier
+        InstanceIdentifier deserializedIid = InstanceIdentifier.create(Node.class);
         Column<GenericTableSchema, Map<String, String>> column = mock(Column.class);
         when(bridge.getExternalIdsColumn()).thenReturn(column);
         Map<String, String> map = new HashMap<>();
         map.put(SouthboundConstants.IID_EXTERNAL_ID_KEY, "IID_EXTERNAL_ID_KEY");
         when(column.getData()).thenReturn(map);
-        PowerMockito.mockStatic(SouthboundUtil.class);
-        when((InstanceIdentifier<Node>) SouthboundUtil.deserializeInstanceIdentifier(anyString())).thenReturn(iid);
-        assertEquals("Incorrect Instance Identifier received", iid, SouthboundMapper.createInstanceIdentifier(client, bridge));
+        InstanceIdentifierCodec iidc = mock(InstanceIdentifierCodec.class);
+        when(iidc.bindingDeserializer("IID_EXTERNAL_ID_KEY")).thenReturn(deserializedIid);
+        SouthboundUtil.setInstanceIdentifierCodec(iidc);
+        assertEquals("Incorrect Instance Identifier received", deserializedIid,
+                SouthboundMapper.createInstanceIdentifier(client, bridge));
 
-        //when bridge is empty
+        // When bridge is empty, we expect a new identifier pointing to the bridge
         when(bridge.getExternalIdsColumn()).thenReturn(null);
         when(client.getNodeKey().getNodeId().getValue()).thenReturn("uri");
         when(bridge.getName()).thenReturn("bridgeName");
-        PowerMockito.whenNew(Uri.class).withArguments(anyString()).thenReturn(mock(Uri.class));
-        PowerMockito.whenNew(NodeId.class).withAnyArguments().thenReturn(mock(NodeId.class));
-        PowerMockito.mockStatic(InstanceIdentifier.class);
-        InstanceIdentifierBuilder<NetworkTopology> iidNetTopo = mock(InstanceIdentifierBuilder.class);
-        InstanceIdentifierBuilder<Topology> iidTopo = mock(InstanceIdentifierBuilder.class);
-        InstanceIdentifierBuilder<Node> iidNode = mock(InstanceIdentifierBuilder.class);
-        PowerMockito.when(InstanceIdentifier.builder(NetworkTopology.class)).thenReturn(iidNetTopo);
-        PowerMockito.whenNew(TopologyKey.class).withAnyArguments().thenReturn(mock(TopologyKey.class));
-        when(iidNetTopo.child(eq(Topology.class), any(TopologyKey.class))).thenReturn(iidTopo);
-        when(iidTopo.child(eq(Node.class), any(NodeKey.class))).thenReturn(iidNode);
-        when(iidNode.build()).thenReturn(iid);
-        assertEquals("Incorrect Instance Identifier received", iid, SouthboundMapper.createInstanceIdentifier(client, bridge));
+        InstanceIdentifier<Node> returnedIid = SouthboundMapper.createInstanceIdentifier(client, bridge);
+        assertEquals("Incorrect identifier type", Node.class, returnedIid.getTargetType());
+        assertEquals("Incorrect node key", new NodeId(new Uri("uri/bridge/bridgeName")),
+                returnedIid.firstKeyOf(Node.class).getNodeId());
     }
 
     @SuppressWarnings("unchecked")
@@ -157,52 +120,43 @@ public class SouthboundMapperTest {
     public void testCreateInstanceIdentifier2() throws Exception {
         OvsdbConnectionInstance client = mock(OvsdbConnectionInstance.class, Mockito.RETURNS_DEEP_STUBS);
         Controller controller = mock(Controller.class);
-        InstanceIdentifier<Node> iid = mock(InstanceIdentifier.class);
 
-        //when controller is not empty
+        // When controller is not empty, we expect a deserialized identifier
+        InstanceIdentifier deserializedIid = InstanceIdentifier.create(Node.class);
         Column<GenericTableSchema, Map<String, String>> column = mock(Column.class);
         when(controller.getExternalIdsColumn()).thenReturn(column);
         Map<String, String> map = new HashMap<>();
         map.put(SouthboundConstants.IID_EXTERNAL_ID_KEY, "IID_EXTERNAL_ID_KEY");
         when(column.getData()).thenReturn(map);
-        PowerMockito.mockStatic(SouthboundUtil.class);
-        when((InstanceIdentifier<Node>) SouthboundUtil.deserializeInstanceIdentifier(anyString())).thenReturn(iid);
-        assertEquals("Incorrect Instance Identifier received", iid, SouthboundMapper.createInstanceIdentifier(client, controller, "bridgeName"));
+        InstanceIdentifierCodec iidc = mock(InstanceIdentifierCodec.class);
+        when(iidc.bindingDeserializer("IID_EXTERNAL_ID_KEY")).thenReturn(deserializedIid);
+        SouthboundUtil.setInstanceIdentifierCodec(iidc);
+        assertEquals("Incorrect Instance Identifier received", deserializedIid,
+                SouthboundMapper.createInstanceIdentifier(client, controller, "bridgeName"));
 
-        //when controller is empty
+        // When controller is empty, we expect a new identifier pointing to the bridge
         when(controller.getExternalIdsColumn()).thenReturn(null);
         when(client.getNodeKey().getNodeId().getValue()).thenReturn("uri");
-        PowerMockito.whenNew(Uri.class).withArguments(anyString()).thenReturn(mock(Uri.class));
-        PowerMockito.whenNew(NodeId.class).withAnyArguments().thenReturn(mock(NodeId.class));
-        PowerMockito.mockStatic(InstanceIdentifier.class);
-        InstanceIdentifierBuilder<NetworkTopology> iidNetTopo = mock(InstanceIdentifierBuilder.class);
-        InstanceIdentifierBuilder<Topology> iidTopo = mock(InstanceIdentifierBuilder.class);
-        InstanceIdentifierBuilder<Node> iidNode = mock(InstanceIdentifierBuilder.class);
-        PowerMockito.when(InstanceIdentifier.builder(NetworkTopology.class)).thenReturn(iidNetTopo);
-        PowerMockito.whenNew(TopologyKey.class).withAnyArguments().thenReturn(mock(TopologyKey.class));
-        when(iidNetTopo.child(eq(Topology.class), any(TopologyKey.class))).thenReturn(iidTopo);
-        when(iidTopo.child(eq(Node.class), any(NodeKey.class))).thenReturn(iidNode);
-        when(iidNode.build()).thenReturn(iid);
-        assertEquals("Incorrect Instance Identifier received", iid, SouthboundMapper.createInstanceIdentifier(client, controller, "bridgeName"));
+        InstanceIdentifier<Node> returnedIid =
+                SouthboundMapper.createInstanceIdentifier(client, controller, "bridgeName");
+        assertEquals("Incorrect identifier type", Node.class, returnedIid.getTargetType());
+        assertEquals("Incorrect node key", new NodeId(new Uri("uri/bridge/bridgeName")),
+                returnedIid.firstKeyOf(Node.class).getNodeId());
     }
 
     @Test
     public void testCreateInetAddress() throws Exception {
-        IpAddress ip = mock(IpAddress.class, Mockito.RETURNS_DEEP_STUBS);
-        when(ip.getIpv4Address()).thenReturn(mock(Ipv4Address.class));
-        when(ip.getIpv4Address().getValue()).thenReturn("99.99.99.99");
-        PowerMockito.mockStatic(InetAddress.class);
-        InetAddress inetAddress = mock(InetAddress.class);
-        when(InetAddress.getByName(anyString())).thenReturn(inetAddress);
-
-        //Ipv4Address not null
-        assertEquals("Incorrect InetAddress received", inetAddress, SouthboundMapper.createInetAddress(ip));
-
-        //Ipv4Address null, Ipv6Address not null
-        when(ip.getIpv4Address()).thenReturn(null);
-        when(ip.getIpv6Address()).thenReturn(mock(Ipv6Address.class));
-        when(ip.getIpv6Address().getValue()).thenReturn("0000:0000:0000:0000:0000:9999:FE1E:8329");
-        assertEquals("Incorrect InetAddress received", inetAddress, SouthboundMapper.createInetAddress(ip));
+        // IPv4 address
+        IpAddress ipV4Address = IpAddressBuilder.getDefaultInstance("99.99.99.99");
+        assertEquals("Incorrect InetAddress received", InetAddress.getByAddress(new byte[] {99, 99, 99, 99}),
+                SouthboundMapper.createInetAddress(ipV4Address));
+
+        // IPv6 address
+        IpAddress ipV6Address = IpAddressBuilder.getDefaultInstance("0000:0000:0000:0000:0000:9999:FE1E:8329");
+        assertEquals("Incorrect InetAddress received", InetAddress.getByAddress(
+                new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0x99, (byte) 0x99, (byte) 0xFE, 0x1E, (byte) 0x83,
+                        0x29}),
+                SouthboundMapper.createInetAddress(ipV6Address));
     }
 
     @SuppressWarnings("unchecked")
@@ -215,21 +169,18 @@ public class SouthboundMapperTest {
         Column<GenericTableSchema, Set<String>> column = mock(Column.class);
         when(bridge.getDatapathIdColumn()).thenReturn(column);
         Set<String> set = new HashSet<>();
-        set.add("dpid");
+        set.add("00:11:22:33:44:55:66:77");
         when(column.getData()).thenReturn(set);
         assertNotNull(column.getData());
 
-        DatapathId dataPathId = mock(DatapathId.class);
+        DatapathId dataPathId = new DatapathId("00:11:22:33:44:55:66:77");
 
-        //test createDatapathId(Set<String> dpids) and createDatapathId(String dpid)
-        PowerMockito.whenNew(DatapathId.class).withAnyArguments().thenReturn(dataPathId);
         assertEquals(dataPathId, SouthboundMapper.createDatapathId(bridge));
     }
 
     @Test
     public void testCreateDatapathType() throws Exception {
         OvsdbBridgeAugmentation mdsalbridge = mock(OvsdbBridgeAugmentation.class);
-        PowerMockito.mockStatic(SouthboundConstants.class, Mockito.RETURNS_DEEP_STUBS);
         when(mdsalbridge.getDatapathType()).thenAnswer(new Answer<Class<? extends DatapathTypeBase>>() {
             public Class<? extends DatapathTypeBase> answer(
                     InvocationOnMock invocation) throws Throwable {
@@ -294,14 +245,9 @@ public class SouthboundMapperTest {
         when(bridge.getProtocolsColumn()).thenReturn(column);
         when(column.getData()).thenReturn(value);
 
-        List<ProtocolEntry> protocolList = new ArrayList<>();
-        ProtocolEntry protoEntry = mock(ProtocolEntry.class);
-        ProtocolEntryBuilder protocolEntryBuilder = mock(ProtocolEntryBuilder.class);
-        PowerMockito.whenNew(ProtocolEntryBuilder.class).withNoArguments().thenReturn(protocolEntryBuilder);
-        when(protocolEntryBuilder.setProtocol(any(Class.class))).thenReturn(protocolEntryBuilder);
-        when(protocolEntryBuilder.build()).thenReturn(protoEntry);
-        protocolList.add(protoEntry);
-        assertEquals(protocolList, SouthboundMapper.createMdsalProtocols(bridge));
+        List<ProtocolEntry> returnedProtocols = SouthboundMapper.createMdsalProtocols(bridge);
+        assertEquals(value.size(), returnedProtocols.size());
+        assertEquals(OvsdbBridgeProtocolOpenflow10.class, returnedProtocols.get(0).getProtocol());
     }
 
     @SuppressWarnings("unchecked")
@@ -309,37 +255,31 @@ public class SouthboundMapperTest {
     public void testCreateControllerEntries() throws Exception {
         Bridge bridge = mock(Bridge.class);
         Map<UUID, Controller> updatedControllerRows = new HashMap<>();
-        Column<GenericTableSchema, Set<UUID>> column = mock(Column.class);
-        when(bridge.getControllerColumn()).thenReturn(column);
+        Column<GenericTableSchema, Set<UUID>> controllerColumn = mock(Column.class);
+        when(bridge.getControllerColumn()).thenReturn(controllerColumn);
         Set<UUID> controllerUUIDs = new HashSet<>();
-        UUID uuid = mock(UUID.class);
+        String uuidString = "7da709ff-397f-4778-a0e8-994811272fdb";
+        UUID uuid = new UUID(uuidString);
         controllerUUIDs.add(uuid);
         Controller controller = mock(Controller.class);
+        Column<GenericTableSchema, String> targetColumn = mock(Column.class);
+        when(targetColumn.getData()).thenReturn("targetData");
+        when(controller.getTargetColumn()).thenReturn(targetColumn);
+        when(controller.getUuid()).thenReturn(uuid);
+        Column<GenericTableSchema, Boolean> isConnectedColumn = mock(Column.class);
+        when(isConnectedColumn.getData()).thenReturn(true);
+        when(controller.getIsConnectedColumn()).thenReturn(isConnectedColumn);
         updatedControllerRows.put(uuid, controller);
-        when(column.getData()).thenReturn(controllerUUIDs);
+        when(controllerColumn.getData()).thenReturn(controllerUUIDs);
+
         List<ControllerEntry> controllerEntries = new ArrayList<>();
-        ControllerEntry controllerEntry = mock(ControllerEntry.class);
+        ControllerEntry controllerEntry = new ControllerEntryBuilder()
+                .setControllerUuid(Uuid.getDefaultInstance(uuidString))
+                .setIsConnected(true)
+                .setTarget(Uri.getDefaultInstance("targetData"))
+                .build();
         controllerEntries.add(controllerEntry);
 
-        //Test addControllerEntries()
-        Column<GenericTableSchema, String> value = mock(Column.class);
-        when(controller.getTargetColumn()).thenReturn(value);
-        when(value.getData()).thenReturn("targetString");
-        when(controller.getUuid()).thenReturn(uuid);
-        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid testUuid = mock(Uuid.class);
-        PowerMockito.whenNew(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid.class).withAnyArguments().thenReturn(testUuid);
-        ControllerEntryBuilder controllerEntryBuilder = mock(ControllerEntryBuilder.class);
-        PowerMockito.whenNew(ControllerEntryBuilder.class).withAnyArguments().thenReturn(controllerEntryBuilder);
-        Uri uri = mock(Uri.class);
-        PowerMockito.whenNew(Uri.class).withAnyArguments().thenReturn(uri);
-        when(controllerEntryBuilder.setTarget(any(Uri.class))).thenReturn(controllerEntryBuilder);
-        Column<GenericTableSchema, Boolean> colConnected = mock(Column.class);
-        when(controller.getIsConnectedColumn()).thenReturn(colConnected );
-        when(colConnected.getData()).thenReturn(true);
-        when(controllerEntryBuilder.setIsConnected(any(Boolean.class))).thenReturn(controllerEntryBuilder);
-        when(controllerEntryBuilder.setControllerUuid(any(Uuid.class))).thenReturn(controllerEntryBuilder);
-        when(controllerEntryBuilder.build()).thenReturn(controllerEntry);
-
         assertEquals(controllerEntries, SouthboundMapper.createControllerEntries(bridge, updatedControllerRows));
     }
 
@@ -350,24 +290,26 @@ public class SouthboundMapperTest {
 
     @Test
     public void testCreateOvsdbController() throws Exception {
-        OvsdbBridgeAugmentation omn = mock(OvsdbBridgeAugmentation.class);
-        DatabaseSchema dbSchema = mock(DatabaseSchema.class);
-        List<ControllerEntry> controllerEntries = new ArrayList<>();
-        ControllerEntry controllerEntry = mock(ControllerEntry.class);
-        controllerEntries.add(controllerEntry);
-        when(omn.getControllerEntry()).thenReturn(controllerEntries);
-        Map<UUID,Controller> controllerMap = new HashMap<>();
-        PowerMockito.mockStatic(TyperUtils.class);
-        Controller controller = mock(Controller.class);
-        PowerMockito.when(TyperUtils.getTypedRowWrapper(any(DatabaseSchema.class), eq(Controller.class))).thenReturn(controller);
-        Uri uri = mock(Uri.class);
-        when(controllerEntry.getTarget()).thenReturn(uri);
-        when(uri.getValue()).thenReturn("uri");
-        UUID uuid = mock(UUID.class);
-        PowerMockito.whenNew(UUID.class).withAnyArguments().thenReturn(uuid);
-
-        controllerMap.put(uuid, controller);
-        assertEquals(controllerMap, SouthboundMapper.createOvsdbController(omn, dbSchema));
+        try (InputStream resourceAsStream = SouthboundMapperTest.class.getResourceAsStream("openvswitch_schema.json")) {
+            ObjectMapper mapper = new ObjectMapper();
+            JsonNode jsonNode = mapper.readTree(resourceAsStream);
+            System.out.println("jsonNode = " + jsonNode.get("id"));
+
+            DatabaseSchema dbSchema = DatabaseSchema.fromJson(OvsdbSchemaContants.databaseName, jsonNode.get("result"));
+
+            String uuidString = "7da709ff-397f-4778-a0e8-994811272fdb";
+            OvsdbBridgeAugmentation omn = new OvsdbBridgeAugmentationBuilder()
+                    .setControllerEntry(Collections.singletonList(new ControllerEntryBuilder()
+                            .setControllerUuid(Uuid.getDefaultInstance(uuidString))
+                            .setTarget(Uri.getDefaultInstance("uri"))
+                            .build()))
+                    .build();
+
+            Map<UUID, Controller> returnedControllers = SouthboundMapper.createOvsdbController(omn, dbSchema);
+            assertEquals(1, returnedControllers.size());
+            Controller returnedController = returnedControllers.values().iterator().next();
+            assertEquals("uri", returnedController.getTargetColumn().getData());
+        }
     }
 
     @Test
@@ -376,32 +318,32 @@ public class SouthboundMapperTest {
         ConnectionInfoBuilder connectionInfoBuilder = mock(ConnectionInfoBuilder.class);
         PowerMockito.whenNew(ConnectionInfoBuilder.class).withNoArguments().thenReturn(connectionInfoBuilder);
 
-        when(client.getConnectionInfo().getRemoteAddress()).thenReturn(mock(InetAddress.class));
+        InetAddress remoteAddress = InetAddress.getByAddress(new byte[] {1, 2, 3, 4});
+        when(client.getConnectionInfo().getRemoteAddress()).thenReturn(remoteAddress);
         when(client.getConnectionInfo().getRemotePort()).thenReturn(8080);
-        when(client.getConnectionInfo().getLocalAddress()).thenReturn(mock(InetAddress.class));
-        when(client.getConnectionInfo().getLocalPort()).thenReturn(8080);
-        PortNumber portNum = mock(PortNumber.class);
-        PowerMockito.whenNew(PortNumber.class).withAnyArguments().thenReturn(portNum);
-        when(connectionInfoBuilder.setRemoteIp(any(IpAddress .class))).thenReturn(connectionInfoBuilder);
-        when(connectionInfoBuilder.setRemotePort(any(PortNumber.class))).thenReturn(connectionInfoBuilder);
-        when(connectionInfoBuilder.setLocalIp(any(IpAddress .class))).thenReturn(connectionInfoBuilder);
-        when(connectionInfoBuilder.setLocalPort(any(PortNumber.class))).thenReturn(connectionInfoBuilder);
-        ConnectionInfo connectionInfo = mock(ConnectionInfo.class);
-        when(connectionInfoBuilder.build()).thenReturn(connectionInfo);
-        assertEquals(connectionInfo, SouthboundMapper.createConnectionInfo(client));
+        InetAddress localAddress = InetAddress.getByAddress(new byte[] {1, 2, 3, 5});
+        when(client.getConnectionInfo().getLocalAddress()).thenReturn(localAddress);
+        when(client.getConnectionInfo().getLocalPort()).thenReturn(8081);
+
+        ConnectionInfo returnedConnectionInfo = SouthboundMapper.createConnectionInfo(client);
+        assertEquals(IpAddressBuilder.getDefaultInstance("1.2.3.4"), returnedConnectionInfo.getRemoteIp());
+        assertEquals(8080, (int) returnedConnectionInfo.getRemotePort().getValue());
+        assertEquals(IpAddressBuilder.getDefaultInstance("1.2.3.5"), returnedConnectionInfo.getLocalIp());
+        assertEquals(8081, (int) returnedConnectionInfo.getLocalPort().getValue());
     }
 
     @Test
     public void testSuppressLocalIpPort() throws Exception {
         ConnectionInfo connectionInfo = mock(ConnectionInfo.class);
-        ConnectionInfoBuilder connectionInfoBuilder = mock(ConnectionInfoBuilder.class);
-        PowerMockito.whenNew(ConnectionInfoBuilder.class).withNoArguments().thenReturn(connectionInfoBuilder);
-        when(connectionInfo.getRemoteIp()).thenReturn(mock(IpAddress.class));
-        when(connectionInfo.getRemotePort()).thenReturn(mock(PortNumber.class));
-        when(connectionInfoBuilder.setRemoteIp(any(IpAddress .class))).thenReturn(connectionInfoBuilder);
-        when(connectionInfoBuilder.setRemotePort(any(PortNumber.class))).thenReturn(connectionInfoBuilder);
-        when(connectionInfoBuilder.build()).thenReturn(connectionInfo);
-        assertEquals(connectionInfo, SouthboundMapper.suppressLocalIpPort(connectionInfo));
+        IpAddress ipAddress = IpAddressBuilder.getDefaultInstance("1.2.3.4");
+        when(connectionInfo.getRemoteIp()).thenReturn(ipAddress);
+        PortNumber portNumber = PortNumber.getDefaultInstance("8080");
+        when(connectionInfo.getRemotePort()).thenReturn(portNumber);
+        ConnectionInfo returnedConnectionInfo = SouthboundMapper.suppressLocalIpPort(connectionInfo);
+        assertEquals(ipAddress, returnedConnectionInfo.getRemoteIp());
+        assertEquals(portNumber, returnedConnectionInfo.getRemotePort());
+        assertNull(returnedConnectionInfo.getLocalIp());
+        assertNull(returnedConnectionInfo.getLocalPort());
     }
 
     @SuppressWarnings("unchecked")
@@ -410,16 +352,13 @@ public class SouthboundMapperTest {
         OpenVSwitch ovsdbNode = mock(OpenVSwitch.class);
         Map<UUID, Manager> updatedManagerRows = new HashMap<>();
         Set<UUID> managerUUIDs = new HashSet<>();
-        UUID managerUUID = mock(UUID.class);
+        UUID managerUUID = new UUID("7da709ff-397f-4778-a0e8-994811272fdb");
         Manager manager = mock(Manager.class);
         managerUUIDs.add(managerUUID);
         updatedManagerRows.put(managerUUID, manager);
         Column<GenericTableSchema, Set<UUID>> column = mock(Column.class);
         when(ovsdbNode.getManagerOptionsColumn()).thenReturn(column);
         when(column.getData()).thenReturn(managerUUIDs);
-        List<ManagerEntry> managerEntries = new ArrayList<>();
-        ManagerEntry managerEntry = mock(ManagerEntry.class);
-        managerEntries.add(managerEntry);
 
         //Test addManagerEntries(managerEntriesCreated, manager)
         Column<GenericTableSchema, String> value = mock(Column.class);
@@ -438,20 +377,20 @@ public class SouthboundMapperTest {
         Column<GenericTableSchema, Boolean> isConnectedColumn = mock(Column.class);
         when(manager.getIsConnectedColumn()).thenReturn(isConnectedColumn);
         when(isConnectedColumn.getData()).thenReturn(true);
-        ManagerEntryBuilder managerEntryBuilder = mock(ManagerEntryBuilder.class);
-        PowerMockito.whenNew(ManagerEntryBuilder.class).withNoArguments().thenReturn(managerEntryBuilder);
-        PowerMockito.whenNew(Uri.class).withAnyArguments().thenReturn(mock(Uri.class));
-        when(managerEntryBuilder.setTarget(any(Uri.class))).thenReturn(managerEntryBuilder);
-        when(managerEntryBuilder.setNumberOfConnections(any(Long.class))).thenReturn(managerEntryBuilder);
-        when(managerEntryBuilder.setConnected(true)).thenReturn(managerEntryBuilder);
-
-        when(managerEntryBuilder.build()).thenReturn(managerEntry);
 
-        assertEquals(managerEntries, SouthboundMapper.createManagerEntries(ovsdbNode, updatedManagerRows));
+        assertEquals(Collections.singletonList(new ManagerEntryBuilder()
+                .setConnected(true)
+                .setNumberOfConnections(999L)
+                .setTarget(Uri.getDefaultInstance("dummy"))
+                .build()), SouthboundMapper.createManagerEntries(ovsdbNode, updatedManagerRows));
 
         //statusAttributeMap contains N_CONNECTIONS_STR key
         statusAttributeMap.remove("n_connections");
-        assertEquals(managerEntries, SouthboundMapper.createManagerEntries(ovsdbNode, updatedManagerRows));
+        assertEquals(Collections.singletonList(new ManagerEntryBuilder()
+                .setConnected(true)
+                .setNumberOfConnections(1L)
+                .setTarget(Uri.getDefaultInstance("dummy"))
+                .build()), SouthboundMapper.createManagerEntries(ovsdbNode, updatedManagerRows));
     }
 
     @SuppressWarnings("unchecked")
@@ -505,11 +444,19 @@ public class SouthboundMapperTest {
 
         when(managerEntryBuilder.build()).thenReturn(managerEntry);
 
-        assertEquals(managerEntries, SouthboundMapper.createManagerEntries(ovsdbNode, updatedManagerRows));
+        assertEquals(Collections.singletonList(new ManagerEntryBuilder()
+                .setConnected(true)
+                .setNumberOfConnections(999L)
+                .setTarget(Uri.getDefaultInstance("dummy"))
+                .build()), SouthboundMapper.createManagerEntries(ovsdbNode, updatedManagerRows));
 
         //statusAttributeMap contains N_CONNECTIONS_STR key
         statusAttributeMap.remove("n_connections");
-        assertEquals(managerEntries, SouthboundMapper.createManagerEntries(ovsdbNode, updatedManagerRows));
+        assertEquals(Collections.singletonList(new ManagerEntryBuilder()
+                .setConnected(true)
+                .setNumberOfConnections(1L)
+                .setTarget(Uri.getDefaultInstance("dummy"))
+                .build()), SouthboundMapper.createManagerEntries(ovsdbNode, updatedManagerRows));
     }
 
     @SuppressWarnings("unchecked")
diff --git a/southbound/southbound-impl/src/test/resources/org/opendaylight/ovsdb/southbound/openvswitch_schema.json b/southbound/southbound-impl/src/test/resources/org/opendaylight/ovsdb/southbound/openvswitch_schema.json
new file mode 100644 (file)
index 0000000..f7f8405
--- /dev/null
@@ -0,0 +1,1150 @@
+{
+  "id": 0,
+  "result": {
+    "tables": {
+      "Port": {
+        "columns": {
+          "name": {
+            "mutable": false,
+            "type": "string"
+          },
+          "statistics": {
+            "ephemeral": true,
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "integer",
+              "max": "unlimited"
+            }
+          },
+          "vlan_mode": {
+            "type": {
+              "key": {
+                "type": "string",
+                "enum": [
+                  "set",
+                  [
+                    "access",
+                    "native-tagged",
+                    "native-untagged",
+                    "trunk"
+                  ]
+                ]
+              },
+              "min": 0
+            }
+          },
+          "qos": {
+            "type": {
+              "key": {
+                "type": "uuid",
+                "refTable": "QoS"
+              },
+              "min": 0
+            }
+          },
+          "status": {
+            "ephemeral": true,
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "trunks": {
+            "type": {
+              "key": {
+                "maxInteger": 4095,
+                "minInteger": 0,
+                "type": "integer"
+              },
+              "min": 0,
+              "max": 4096
+            }
+          },
+          "mac": {
+            "type": {
+              "key": "string",
+              "min": 0
+            }
+          },
+          "interfaces": {
+            "type": {
+              "key": {
+                "type": "uuid",
+                "refTable": "Interface"
+              },
+              "max": "unlimited"
+            }
+          },
+          "bond_downdelay": {
+            "type": "integer"
+          },
+          "bond_mode": {
+            "type": {
+              "key": {
+                "type": "string",
+                "enum": [
+                  "set",
+                  [
+                    "active-backup",
+                    "balance-slb",
+                    "balance-tcp",
+                    "stable"
+                  ]
+                ]
+              },
+              "min": 0
+            }
+          },
+          "bond_updelay": {
+            "type": "integer"
+          },
+          "external_ids": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "other_config": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "tag": {
+            "type": {
+              "key": {
+                "maxInteger": 4095,
+                "minInteger": 0,
+                "type": "integer"
+              },
+              "min": 0
+            }
+          },
+          "bond_fake_iface": {
+            "type": "boolean"
+          },
+          "fake_bridge": {
+            "type": "boolean"
+          },
+          "lacp": {
+            "type": {
+              "key": {
+                "type": "string",
+                "enum": [
+                  "set",
+                  [
+                    "active",
+                    "off",
+                    "passive"
+                  ]
+                ]
+              },
+              "min": 0
+            }
+          }
+        },
+        "indexes": [
+          [
+            "name"
+          ]
+        ]
+      },
+      "Manager": {
+        "columns": {
+          "is_connected": {
+            "ephemeral": true,
+            "type": "boolean"
+          },
+          "target": {
+            "type": "string"
+          },
+          "other_config": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "external_ids": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "max_backoff": {
+            "type": {
+              "key": {
+                "minInteger": 1000,
+                "type": "integer"
+              },
+              "min": 0
+            }
+          },
+          "connection_mode": {
+            "type": {
+              "key": {
+                "type": "string",
+                "enum": [
+                  "set",
+                  [
+                    "in-band",
+                    "out-of-band"
+                  ]
+                ]
+              },
+              "min": 0
+            }
+          },
+          "status": {
+            "ephemeral": true,
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "inactivity_probe": {
+            "type": {
+              "key": "integer",
+              "min": 0
+            }
+          }
+        },
+        "indexes": [
+          [
+            "target"
+          ]
+        ]
+      },
+      "Bridge": {
+        "columns": {
+          "name": {
+            "mutable": false,
+            "type": "string"
+          },
+          "flood_vlans": {
+            "type": {
+              "key": {
+                "maxInteger": 4095,
+                "minInteger": 0,
+                "type": "integer"
+              },
+              "min": 0,
+              "max": 4096
+            }
+          },
+          "netflow": {
+            "type": {
+              "key": {
+                "type": "uuid",
+                "refTable": "NetFlow"
+              },
+              "min": 0
+            }
+          },
+          "mirrors": {
+            "type": {
+              "key": {
+                "type": "uuid",
+                "refTable": "Mirror"
+              },
+              "min": 0,
+              "max": "unlimited"
+            }
+          },
+          "status": {
+            "ephemeral": true,
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "datapath_id": {
+            "ephemeral": true,
+            "type": {
+              "key": "string",
+              "min": 0
+            }
+          },
+          "controller": {
+            "type": {
+              "key": {
+                "type": "uuid",
+                "refTable": "Controller"
+              },
+              "min": 0,
+              "max": "unlimited"
+            }
+          },
+          "protocols": {
+            "type": {
+              "key": {
+                "type": "string",
+                "enum": [
+                  "set",
+                  [
+                    "OpenFlow10",
+                    "OpenFlow12",
+                    "OpenFlow13"
+                  ]
+                ]
+              },
+              "min": 0,
+              "max": "unlimited"
+            }
+          },
+          "fail_mode": {
+            "type": {
+              "key": {
+                "type": "string",
+                "enum": [
+                  "set",
+                  [
+                    "secure",
+                    "standalone"
+                  ]
+                ]
+              },
+              "min": 0
+            }
+          },
+          "ports": {
+            "type": {
+              "key": {
+                "type": "uuid",
+                "refTable": "Port"
+              },
+              "min": 0,
+              "max": "unlimited"
+            }
+          },
+          "external_ids": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "flow_tables": {
+            "type": {
+              "key": {
+                "maxInteger": 254,
+                "minInteger": 0,
+                "type": "integer"
+              },
+              "min": 0,
+              "value": {
+                "type": "uuid",
+                "refTable": "Flow_Table"
+              },
+              "max": "unlimited"
+            }
+          },
+          "sflow": {
+            "type": {
+              "key": {
+                "type": "uuid",
+                "refTable": "sFlow"
+              },
+              "min": 0
+            }
+          },
+          "datapath_type": {
+            "type": "string"
+          },
+          "other_config": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "stp_enable": {
+            "type": "boolean"
+          }
+        },
+        "indexes": [
+          [
+            "name"
+          ]
+        ]
+      },
+      "Interface": {
+        "columns": {
+          "options": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "name": {
+            "mutable": false,
+            "type": "string"
+          },
+          "statistics": {
+            "ephemeral": true,
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "integer",
+              "max": "unlimited"
+            }
+          },
+          "link_speed": {
+            "ephemeral": true,
+            "type": {
+              "key": "integer",
+              "min": 0
+            }
+          },
+          "mtu": {
+            "ephemeral": true,
+            "type": {
+              "key": "integer",
+              "min": 0
+            }
+          },
+          "mac_in_use": {
+            "ephemeral": true,
+            "type": {
+              "key": "string",
+              "min": 0
+            }
+          },
+          "type": {
+            "type": "string"
+          },
+          "ingress_policing_rate": {
+            "type": {
+              "key": {
+                "minInteger": 0,
+                "type": "integer"
+              }
+            }
+          },
+          "cfm_remote_opstate": {
+            "ephemeral": true,
+            "type": {
+              "key": {
+                "type": "string",
+                "enum": [
+                  "set",
+                  [
+                    "down",
+                    "up"
+                  ]
+                ]
+              },
+              "min": 0
+            }
+          },
+          "status": {
+            "ephemeral": true,
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "mac": {
+            "type": {
+              "key": "string",
+              "min": 0
+            }
+          },
+          "ofport": {
+            "type": {
+              "key": "integer",
+              "min": 0
+            }
+          },
+          "cfm_fault_status": {
+            "ephemeral": true,
+            "type": {
+              "key": "string",
+              "min": 0,
+              "max": "unlimited"
+            }
+          },
+          "duplex": {
+            "ephemeral": true,
+            "type": {
+              "key": {
+                "type": "string",
+                "enum": [
+                  "set",
+                  [
+                    "full",
+                    "half"
+                  ]
+                ]
+              },
+              "min": 0
+            }
+          },
+          "lacp_current": {
+            "ephemeral": true,
+            "type": {
+              "key": "boolean",
+              "min": 0
+            }
+          },
+          "cfm_fault": {
+            "ephemeral": true,
+            "type": {
+              "key": "boolean",
+              "min": 0
+            }
+          },
+          "external_ids": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "other_config": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "admin_state": {
+            "ephemeral": true,
+            "type": {
+              "key": {
+                "type": "string",
+                "enum": [
+                  "set",
+                  [
+                    "down",
+                    "up"
+                  ]
+                ]
+              },
+              "min": 0
+            }
+          },
+          "link_state": {
+            "ephemeral": true,
+            "type": {
+              "key": {
+                "type": "string",
+                "enum": [
+                  "set",
+                  [
+                    "down",
+                    "up"
+                  ]
+                ]
+              },
+              "min": 0
+            }
+          },
+          "cfm_remote_mpids": {
+            "ephemeral": true,
+            "type": {
+              "key": "integer",
+              "min": 0,
+              "max": "unlimited"
+            }
+          },
+          "cfm_mpid": {
+            "type": {
+              "key": "integer",
+              "min": 0
+            }
+          },
+          "ofport_request": {
+            "type": {
+              "key": {
+                "maxInteger": 65279,
+                "minInteger": 1,
+                "type": "integer"
+              },
+              "min": 0
+            }
+          },
+          "ingress_policing_burst": {
+            "type": {
+              "key": {
+                "minInteger": 0,
+                "type": "integer"
+              }
+            }
+          },
+          "cfm_health": {
+            "ephemeral": true,
+            "type": {
+              "key": {
+                "maxInteger": 100,
+                "minInteger": 0,
+                "type": "integer"
+              },
+              "min": 0
+            }
+          },
+          "link_resets": {
+            "ephemeral": true,
+            "type": {
+              "key": "integer",
+              "min": 0
+            }
+          }
+        },
+        "indexes": [
+          [
+            "name"
+          ]
+        ]
+      },
+      "SSL": {
+        "columns": {
+          "ca_cert": {
+            "type": "string"
+          },
+          "private_key": {
+            "type": "string"
+          },
+          "bootstrap_ca_cert": {
+            "type": "boolean"
+          },
+          "external_ids": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "certificate": {
+            "type": "string"
+          }
+        },
+        "maxRows": 1
+      },
+      "Open_vSwitch": {
+        "columns": {
+          "ovs_version": {
+            "type": {
+              "key": "string",
+              "min": 0
+            }
+          },
+          "system_version": {
+            "type": {
+              "key": "string",
+              "min": 0
+            }
+          },
+          "bridges": {
+            "type": {
+              "key": {
+                "type": "uuid",
+                "refTable": "Bridge"
+              },
+              "min": 0,
+              "max": "unlimited"
+            }
+          },
+          "statistics": {
+            "ephemeral": true,
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "other_config": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "external_ids": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "next_cfg": {
+            "type": "integer"
+          },
+          "manager_options": {
+            "type": {
+              "key": {
+                "type": "uuid",
+                "refTable": "Manager"
+              },
+              "min": 0,
+              "max": "unlimited"
+            }
+          },
+          "system_type": {
+            "type": {
+              "key": "string",
+              "min": 0
+            }
+          },
+          "ssl": {
+            "type": {
+              "key": {
+                "type": "uuid",
+                "refTable": "SSL"
+              },
+              "min": 0
+            }
+          },
+          "db_version": {
+            "type": {
+              "key": "string",
+              "min": 0
+            }
+          },
+          "cur_cfg": {
+            "type": "integer"
+          }
+        },
+        "maxRows": 1,
+        "isRoot": true
+      },
+      "Queue": {
+        "columns": {
+          "external_ids": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "other_config": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "dscp": {
+            "type": {
+              "key": {
+                "maxInteger": 63,
+                "minInteger": 0,
+                "type": "integer"
+              },
+              "min": 0
+            }
+          }
+        },
+        "isRoot": true
+      },
+      "NetFlow": {
+        "columns": {
+          "engine_type": {
+            "type": {
+              "key": {
+                "maxInteger": 255,
+                "minInteger": 0,
+                "type": "integer"
+              },
+              "min": 0
+            }
+          },
+          "targets": {
+            "type": {
+              "key": "string",
+              "max": "unlimited"
+            }
+          },
+          "add_id_to_interface": {
+            "type": "boolean"
+          },
+          "active_timeout": {
+            "type": {
+              "key": {
+                "minInteger": -1,
+                "type": "integer"
+              }
+            }
+          },
+          "external_ids": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "engine_id": {
+            "type": {
+              "key": {
+                "maxInteger": 255,
+                "minInteger": 0,
+                "type": "integer"
+              },
+              "min": 0
+            }
+          }
+        }
+      },
+      "Mirror": {
+        "columns": {
+          "name": {
+            "type": "string"
+          },
+          "output_port": {
+            "type": {
+              "key": {
+                "refType": "weak",
+                "type": "uuid",
+                "refTable": "Port"
+              },
+              "min": 0
+            }
+          },
+          "output_vlan": {
+            "type": {
+              "key": {
+                "maxInteger": 4095,
+                "minInteger": 1,
+                "type": "integer"
+              },
+              "min": 0
+            }
+          },
+          "statistics": {
+            "ephemeral": true,
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "integer",
+              "max": "unlimited"
+            }
+          },
+          "external_ids": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "select_dst_port": {
+            "type": {
+              "key": {
+                "refType": "weak",
+                "type": "uuid",
+                "refTable": "Port"
+              },
+              "min": 0,
+              "max": "unlimited"
+            }
+          },
+          "select_all": {
+            "type": "boolean"
+          },
+          "select_vlan": {
+            "type": {
+              "key": {
+                "maxInteger": 4095,
+                "minInteger": 0,
+                "type": "integer"
+              },
+              "min": 0,
+              "max": 4096
+            }
+          },
+          "select_src_port": {
+            "type": {
+              "key": {
+                "refType": "weak",
+                "type": "uuid",
+                "refTable": "Port"
+              },
+              "min": 0,
+              "max": "unlimited"
+            }
+          }
+        }
+      },
+      "QoS": {
+        "columns": {
+          "queues": {
+            "type": {
+              "key": {
+                "maxInteger": 4294967295,
+                "minInteger": 0,
+                "type": "integer"
+              },
+              "min": 0,
+              "value": {
+                "type": "uuid",
+                "refTable": "Queue"
+              },
+              "max": "unlimited"
+            }
+          },
+          "other_config": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "external_ids": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "type": {
+            "type": "string"
+          }
+        },
+        "isRoot": true
+      },
+      "Controller": {
+        "columns": {
+          "is_connected": {
+            "ephemeral": true,
+            "type": "boolean"
+          },
+          "enable_async_messages": {
+            "type": {
+              "key": "boolean",
+              "min": 0
+            }
+          },
+          "controller_rate_limit": {
+            "type": {
+              "key": {
+                "minInteger": 100,
+                "type": "integer"
+              },
+              "min": 0
+            }
+          },
+          "target": {
+            "type": "string"
+          },
+          "external_ids": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "other_config": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "local_netmask": {
+            "type": {
+              "key": "string",
+              "min": 0
+            }
+          },
+          "local_gateway": {
+            "type": {
+              "key": "string",
+              "min": 0
+            }
+          },
+          "max_backoff": {
+            "type": {
+              "key": {
+                "minInteger": 1000,
+                "type": "integer"
+              },
+              "min": 0
+            }
+          },
+          "local_ip": {
+            "type": {
+              "key": "string",
+              "min": 0
+            }
+          },
+          "connection_mode": {
+            "type": {
+              "key": {
+                "type": "string",
+                "enum": [
+                  "set",
+                  [
+                    "in-band",
+                    "out-of-band"
+                  ]
+                ]
+              },
+              "min": 0
+            }
+          },
+          "status": {
+            "ephemeral": true,
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "role": {
+            "ephemeral": true,
+            "type": {
+              "key": {
+                "type": "string",
+                "enum": [
+                  "set",
+                  [
+                    "master",
+                    "other",
+                    "slave"
+                  ]
+                ]
+              },
+              "min": 0
+            }
+          },
+          "inactivity_probe": {
+            "type": {
+              "key": "integer",
+              "min": 0
+            }
+          },
+          "controller_burst_limit": {
+            "type": {
+              "key": {
+                "minInteger": 25,
+                "type": "integer"
+              },
+              "min": 0
+            }
+          }
+        }
+      },
+      "Flow_Table": {
+        "columns": {
+          "groups": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "max": "unlimited"
+            }
+          },
+          "name": {
+            "type": {
+              "key": "string",
+              "min": 0
+            }
+          },
+          "overflow_policy": {
+            "type": {
+              "key": {
+                "type": "string",
+                "enum": [
+                  "set",
+                  [
+                    "evict",
+                    "refuse"
+                  ]
+                ]
+              },
+              "min": 0
+            }
+          },
+          "flow_limit": {
+            "type": {
+              "key": {
+                "minInteger": 0,
+                "type": "integer"
+              },
+              "min": 0
+            }
+          }
+        }
+      },
+      "sFlow": {
+        "columns": {
+          "polling": {
+            "type": {
+              "key": "integer",
+              "min": 0
+            }
+          },
+          "targets": {
+            "type": {
+              "key": "string",
+              "max": "unlimited"
+            }
+          },
+          "header": {
+            "type": {
+              "key": "integer",
+              "min": 0
+            }
+          },
+          "agent": {
+            "type": {
+              "key": "string",
+              "min": 0
+            }
+          },
+          "external_ids": {
+            "type": {
+              "key": "string",
+              "min": 0,
+              "value": "string",
+              "max": "unlimited"
+            }
+          },
+          "sampling": {
+            "type": {
+              "key": "integer",
+              "min": 0
+            }
+          }
+        }
+      }
+    },
+    "cksum": "2180939265 17455",
+    "name": "Open_vSwitch",
+    "version": "6.12.0"
+  },
+  "error": null
+}