edfcee9744b1c84d8dc351f201e5da0f6f7f2be6
[ovsdb.git] / southbound / southbound-it / src / test / java / org / opendaylight / ovsdb / southbound / it / SouthboundIT.java
1 /*
2  * Copyright (c) 2015 Red Hat, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.ovsdb.southbound.it;
9
10 import static org.junit.Assert.assertNotNull;
11 import static org.junit.Assert.fail;
12 import static org.ops4j.pax.exam.CoreOptions.composite;
13 import static org.ops4j.pax.exam.CoreOptions.maven;
14 import static org.ops4j.pax.exam.CoreOptions.vmOption;
15 import static org.ops4j.pax.exam.CoreOptions.when;
16 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
17 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.karafDistributionConfiguration;
18 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
19
20 import com.google.common.collect.ImmutableBiMap;
21 import com.google.common.collect.Lists;
22 import com.google.common.collect.Sets;
23
24 import java.io.File;
25 import java.lang.reflect.Array;
26 import java.net.InetAddress;
27 import java.net.UnknownHostException;
28 import java.util.ArrayList;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.Properties;
32 import java.util.Set;
33 import java.util.concurrent.ExecutionException;
34 import java.util.concurrent.ExecutorService;
35 import java.util.concurrent.Executors;
36 import java.util.concurrent.TimeUnit;
37
38 import javax.inject.Inject;
39
40 import org.junit.Assert;
41 import org.junit.Before;
42 import org.junit.Test;
43 import org.junit.runner.RunWith;
44 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
45 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
46 import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
47 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
48 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
49 import org.opendaylight.ovsdb.southbound.SouthboundProvider;
50 import org.opendaylight.ovsdb.southbound.SouthboundUtil;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeBase;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeBase;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentationBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeName;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeProtocolBase;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbFailModeBase;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentationBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeRef;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbPortInterfaceAttributes.VlanMode;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeExternalIds;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeExternalIdsBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigs;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.BridgeOtherConfigsBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntryBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntry;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntryBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfoBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.DatapathTypeEntry;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.InterfaceTypeEntryBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.OpenvswitchOtherConfigs;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIds;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIdsBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceOtherConfigs;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceOtherConfigsBuilder;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.OptionsBuilder;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortExternalIds;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortExternalIdsBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortOtherConfigs;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortOtherConfigsBuilder;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Trunks;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.TrunksBuilder;
93 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
94 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
95 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
96 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
97 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
98 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
99 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
100 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
101 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
102 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
103 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
104 import org.opendaylight.yangtools.concepts.Builder;
105 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
106 import org.ops4j.pax.exam.Configuration;
107 import org.ops4j.pax.exam.Option;
108 import org.ops4j.pax.exam.junit.PaxExam;
109 import org.ops4j.pax.exam.karaf.options.KarafDistributionOption;
110 import org.ops4j.pax.exam.karaf.options.LogLevelOption;
111 import org.ops4j.pax.exam.options.MavenUrlReference;
112 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
113 import org.ops4j.pax.exam.spi.reactors.PerClass;
114 import org.osgi.framework.BundleContext;
115 import org.slf4j.Logger;
116 import org.slf4j.LoggerFactory;
117
118 /**
119  * Integration tests for southbound-impl
120  *
121  * @author Sam Hague (shague@redhat.com)
122  */
123 @RunWith(PaxExam.class)
124 @ExamReactorStrategy(PerClass.class)
125 public class SouthboundIT extends AbstractMdsalTestBase {
126     private static final String NETDEV_DP_TYPE = "netdev";
127     private static final Logger LOG = LoggerFactory.getLogger(SouthboundIT.class);
128     private static final int OVSDB_UPDATE_TIMEOUT = 1000;
129     private static final String FORMAT_STR = "%s_%s_%d";
130     public static final int NUM_THREADS = 4;
131     private static String addressStr;
132     private static String portStr;
133     private static String connectionType;
134     private static Boolean setup = false;
135     private static MdsalUtils mdsalUtils = null;
136
137     // TODO Constants copied from AbstractConfigTestBase, need to be removed (see TODO below)
138     private static final String PAX_EXAM_UNPACK_DIRECTORY = "target/exam";
139     private static final String KARAF_DEBUG_PORT = "5005";
140     private static final String KARAF_DEBUG_PROP = "karaf.debug";
141     private static final String KEEP_UNPACK_DIRECTORY_PROP = "karaf.keep.unpack";
142
143     @Inject
144     private BundleContext bundleContext;
145
146     @Configuration
147     public Option[] config() {
148         // TODO Figure out how to use the parent Karaf setup, then just use super.config()
149         Option[] options = new Option[] {
150                 when(Boolean.getBoolean(KARAF_DEBUG_PROP))
151                         .useOptions(KarafDistributionOption.debugConfiguration(KARAF_DEBUG_PORT, true)),
152                 karafDistributionConfiguration().frameworkUrl(getKarafDistro())
153                         .unpackDirectory(new File(PAX_EXAM_UNPACK_DIRECTORY))
154                         .useDeployFolder(false),
155                 when(Boolean.getBoolean(KEEP_UNPACK_DIRECTORY_PROP)).useOptions(keepRuntimeFolder()),
156                 // Works only if we don't specify the feature repo and name
157                 getLoggingOption()};
158         Option[] propertyOptions = getPropertiesOptions();
159         Option[] otherOptions = getOtherOptions();
160         Option[] combinedOptions = new Option[options.length + propertyOptions.length + otherOptions.length];
161         System.arraycopy(options, 0, combinedOptions, 0, options.length);
162         System.arraycopy(propertyOptions, 0, combinedOptions, options.length, propertyOptions.length);
163         System.arraycopy(otherOptions, 0, combinedOptions, options.length + propertyOptions.length,
164                 otherOptions.length);
165         return combinedOptions;
166     }
167
168     private Option[] getOtherOptions() {
169         return new Option[] {
170                 vmOption("-javaagent:../jars/org.jacoco.agent.jar=destfile=../../jacoco-it.exec"),
171                 keepRuntimeFolder()
172         };
173     }
174
175     @Override
176     public String getKarafDistro() {
177         return maven()
178                 .groupId("org.opendaylight.ovsdb")
179                 .artifactId("southbound-karaf")
180                 .versionAsInProject()
181                 .type("zip")
182                 .getURL();
183     }
184
185     @Override
186     public String getModuleName() {
187         return "southbound-impl";
188     }
189
190     @Override
191     public String getInstanceName() {
192         return "southbound-default";
193     }
194
195     @Override
196     public MavenUrlReference getFeatureRepo() {
197         return maven()
198                 .groupId("org.opendaylight.ovsdb")
199                 .artifactId("southbound-features")
200                 .classifier("features")
201                 .type("xml")
202                 .versionAsInProject();
203     }
204
205     @Override
206     public String getFeatureName() {
207         return "odl-ovsdb-southbound-impl-ui";
208     }
209
210     protected String usage() {
211         return "Integration Test needs a valid connection configuration as follows :\n"
212                 + "active connection : mvn -Dovsdbserver.ipaddress=x.x.x.x -Dovsdbserver.port=yyyy verify\n"
213                 + "passive connection : mvn -Dovsdbserver.connection=passive verify\n";
214     }
215
216     @Override
217     public Option getLoggingOption() {
218         return composite(
219                 editConfigurationFilePut(SouthboundITConstants.ORG_OPS4J_PAX_LOGGING_CFG,
220                         "log4j.logger.org.opendaylight.ovsdb",
221                         LogLevelOption.LogLevel.TRACE.name()),
222                 super.getLoggingOption());
223     }
224
225     private Option[] getPropertiesOptions() {
226         Properties props = new Properties(System.getProperties());
227         String addressStr = props.getProperty(SouthboundITConstants.SERVER_IPADDRESS,
228                 SouthboundITConstants.DEFAULT_SERVER_IPADDRESS);
229         String portStr = props.getProperty(SouthboundITConstants.SERVER_PORT,
230                 SouthboundITConstants.DEFAULT_SERVER_PORT);
231         String connectionType = props.getProperty(SouthboundITConstants.CONNECTION_TYPE,
232                 SouthboundITConstants.CONNECTION_TYPE_ACTIVE);
233
234         LOG.info("getPropertiesOptions: Using the following properties: mode= {}, ip:port= {}:{}",
235                 connectionType, addressStr, portStr);
236
237         return new Option[] {
238                 editConfigurationFilePut(SouthboundITConstants.CUSTOM_PROPERTIES,
239                         SouthboundITConstants.SERVER_IPADDRESS, addressStr),
240                 editConfigurationFilePut(SouthboundITConstants.CUSTOM_PROPERTIES,
241                         SouthboundITConstants.SERVER_PORT, portStr),
242                 editConfigurationFilePut(SouthboundITConstants.CUSTOM_PROPERTIES,
243                         SouthboundITConstants.CONNECTION_TYPE, connectionType),
244         };
245     }
246
247     @Before
248     @Override
249     public void setup() throws InterruptedException {
250         if (setup) {
251             LOG.info("Skipping setUp, already initialized");
252             return;
253         }
254
255         try {
256             super.setup();
257         } catch (Exception e) {
258             e.printStackTrace();
259         }
260         //dataBroker = getSession().getSALService(DataBroker.class);
261         Thread.sleep(3000);
262         DataBroker dataBroker = SouthboundProvider.getDb();
263         Assert.assertNotNull("db should not be null", dataBroker);
264
265         addressStr = bundleContext.getProperty(SouthboundITConstants.SERVER_IPADDRESS);
266         portStr = bundleContext.getProperty(SouthboundITConstants.SERVER_PORT);
267         connectionType = bundleContext.getProperty(SouthboundITConstants.CONNECTION_TYPE);
268
269         LOG.info("setUp: Using the following properties: mode= {}, ip:port= {}:{}",
270                 connectionType, addressStr, portStr);
271         if (connectionType.equalsIgnoreCase(SouthboundITConstants.CONNECTION_TYPE_ACTIVE)) {
272             if (addressStr == null) {
273                 fail(usage());
274             }
275         }
276
277         mdsalUtils = new MdsalUtils(dataBroker);
278         setup = true;
279     }
280
281     /**
282      * Test passive connection mode. The southbound starts in a listening mode waiting for connections on port
283      * 6640. This test will wait for incoming connections for {@link SouthboundITConstants#CONNECTION_INIT_TIMEOUT} ms.
284      *
285      * @throws InterruptedException
286      */
287     @Test
288     public void testPassiveNode() throws InterruptedException {
289         if (connectionType.equalsIgnoreCase(SouthboundITConstants.CONNECTION_TYPE_PASSIVE)) {
290             //Wait for CONNECTION_INIT_TIMEOUT for the Passive connection to be initiated by the ovsdb-server.
291             Thread.sleep(SouthboundITConstants.CONNECTION_INIT_TIMEOUT);
292         }
293     }
294
295     private ConnectionInfo getConnectionInfo(final String addressStr, final String portStr) {
296         InetAddress inetAddress = null;
297         try {
298             inetAddress = InetAddress.getByName(addressStr);
299         } catch (UnknownHostException e) {
300             fail("Could not allocate InetAddress: " + e);
301         }
302
303         IpAddress address = SouthboundMapper.createIpAddress(inetAddress);
304         PortNumber port = new PortNumber(Integer.parseInt(portStr));
305
306         LOG.info("connectionInfo: {}", new ConnectionInfoBuilder()
307                 .setRemoteIp(address)
308                 .setRemotePort(port)
309                 .build());
310         return new ConnectionInfoBuilder()
311                 .setRemoteIp(address)
312                 .setRemotePort(port)
313                 .build();
314     }
315
316     private String connectionInfoToString(final ConnectionInfo connectionInfo) {
317         return new String(connectionInfo.getRemoteIp().getValue()) + ":" + connectionInfo.getRemotePort().getValue();
318     }
319
320     @Test
321     public void testNetworkTopology() throws InterruptedException {
322         NetworkTopology networkTopology = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION,
323                 InstanceIdentifier.create(NetworkTopology.class));
324         Assert.assertNotNull("NetworkTopology could not be found in " + LogicalDatastoreType.CONFIGURATION,
325                 networkTopology);
326
327         networkTopology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
328                 InstanceIdentifier.create(NetworkTopology.class));
329         Assert.assertNotNull("NetworkTopology could not be found in " + LogicalDatastoreType.OPERATIONAL,
330                 networkTopology);
331     }
332
333     @Test
334     public void testOvsdbTopology() throws InterruptedException {
335         InstanceIdentifier<Topology> path = InstanceIdentifier
336                 .create(NetworkTopology.class)
337                 .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID));
338
339         Topology topology = mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, path);
340         Assert.assertNotNull("Topology could not be found in " + LogicalDatastoreType.CONFIGURATION,
341                 topology);
342
343         topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
344
345         Assert.assertNotNull("Topology could not be found in " + LogicalDatastoreType.OPERATIONAL,
346                 topology);
347     }
348
349     private boolean addOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
350         InstanceIdentifier<Node> iid = createInstanceIdentifier(connectionInfo);
351         // Check that the node doesn't already exist (we don't support connecting twice)
352         Assert.assertNull("The OVSDB node has already been added",
353                 mdsalUtils.read(LogicalDatastoreType.CONFIGURATION, iid));
354         boolean result = mdsalUtils.put(LogicalDatastoreType.CONFIGURATION,
355                 iid,
356                 createNode(connectionInfo));
357         Thread.sleep(OVSDB_UPDATE_TIMEOUT);
358         return result;
359     }
360
361     private InstanceIdentifier<Node> createInstanceIdentifier(
362             ConnectionInfo connectionInfo) {
363         return InstanceIdentifier
364                 .create(NetworkTopology.class)
365                 .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
366                 .child(Node.class,
367                         createNodeKey(connectionInfo.getRemoteIp(), connectionInfo.getRemotePort()));
368     }
369
370     private Node getOvsdbNode(final ConnectionInfo connectionInfo) {
371         return mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
372                 createInstanceIdentifier(connectionInfo));
373     }
374
375     private boolean deleteOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
376         boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION,
377                 createInstanceIdentifier(connectionInfo));
378         Thread.sleep(OVSDB_UPDATE_TIMEOUT);
379         return result;
380     }
381
382     private Node connectOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
383         Assert.assertTrue(addOvsdbNode(connectionInfo));
384         Node node = getOvsdbNode(connectionInfo);
385         Assert.assertNotNull(node);
386         LOG.info("Connected to {}", connectionInfoToString(connectionInfo));
387         return node;
388     }
389
390     private boolean disconnectOvsdbNode(final ConnectionInfo connectionInfo) throws InterruptedException {
391         Assert.assertTrue(deleteOvsdbNode(connectionInfo));
392         Node node = getOvsdbNode(connectionInfo);
393         Assert.assertNull(node);
394         LOG.info("Disconnected from {}", connectionInfoToString(connectionInfo));
395         return true;
396     }
397
398     @Test
399     public void testAddDeleteOvsdbNode() throws InterruptedException {
400         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
401         connectOvsdbNode(connectionInfo);
402         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
403     }
404
405     @Test
406     public void testDpdkSwitch() throws InterruptedException {
407         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
408         Node ovsdbNode = connectOvsdbNode(connectionInfo);
409         List<DatapathTypeEntry> datapathTypeEntries = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class)
410                 .getDatapathTypeEntry();
411         if (datapathTypeEntries == null) {
412             LOG.info("DPDK not supported on this node.");
413         } else {
414             for (DatapathTypeEntry dpTypeEntry : datapathTypeEntries) {
415                 Class<? extends DatapathTypeBase> dpType = dpTypeEntry.getDatapathType();
416                 String dpTypeStr = SouthboundConstants.DATAPATH_TYPE_MAP.get(dpType);
417                 LOG.info("dp type is {}", dpTypeStr);
418                 if (dpTypeStr.equals(NETDEV_DP_TYPE)) {
419                     LOG.info("Found a DPDK node; adding a corresponding netdev device");
420                     InstanceIdentifier<Node> bridgeIid = createInstanceIdentifier(connectionInfo,
421                             new OvsdbBridgeName(SouthboundITConstants.BRIDGE_NAME));
422                     NodeId bridgeNodeId = createManagedNodeId(bridgeIid);
423                     addBridge(connectionInfo, bridgeIid, SouthboundITConstants.BRIDGE_NAME, bridgeNodeId, false, null,
424                             true, dpType, null, null, null);
425
426                     // Verify that the device is netdev
427                     OvsdbBridgeAugmentation bridge = getBridge(connectionInfo);
428                     Assert.assertNotNull(bridge);
429                     Assert.assertEquals(dpType, bridge.getDatapathType());
430
431                     // Add dpdk port
432                     final String TEST_PORT_NAME = "testDPDKPort";
433                     OvsdbTerminationPointAugmentationBuilder ovsdbTerminationBuilder =
434                             createGenericDpdkOvsdbTerminationPointAugmentationBuilder(TEST_PORT_NAME);
435                     Assert.assertTrue(addTerminationPoint(bridgeNodeId, TEST_PORT_NAME, ovsdbTerminationBuilder));
436
437                     // Verify that DPDK port was created
438                     InstanceIdentifier<Node> terminationPointIid = getTpIid(connectionInfo, bridge);
439                     Node terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL,
440                             terminationPointIid);
441                     Assert.assertNotNull(terminationPointNode);
442
443                     // Verify that each termination point has DPDK ifType
444                     Class<? extends InterfaceTypeBase> dpdkIfType = SouthboundConstants.OVSDB_INTERFACE_TYPE_MAP
445                             .get("dpdk");
446                     List<TerminationPoint> terminationPoints = terminationPointNode.getTerminationPoint();
447                     for (TerminationPoint terminationPoint : terminationPoints) {
448                         OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation = terminationPoint
449                                 .getAugmentation(OvsdbTerminationPointAugmentation.class);
450                         if (ovsdbTerminationPointAugmentation.getName().equals(TEST_PORT_NAME)) {
451                             Class<? extends InterfaceTypeBase> opPort = ovsdbTerminationPointAugmentation
452                                     .getInterfaceType();
453                             Assert.assertEquals(dpdkIfType, opPort);
454                         }
455                     }
456                     Assert.assertTrue(deleteBridge(connectionInfo));
457                     break;
458                 }
459             }
460         }
461         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
462     }
463
464     @Test
465     public void testOvsdbNodeOvsVersion() throws InterruptedException {
466         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
467         Node ovsdbNode = connectOvsdbNode(connectionInfo);
468         OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
469         Assert.assertNotNull(ovsdbNodeAugmentation);
470         assertNotNull(ovsdbNodeAugmentation.getOvsVersion());
471         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
472     }
473
474     @Test
475     public void testOpenVSwitchOtherConfig() throws InterruptedException {
476         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
477         Node ovsdbNode = connectOvsdbNode(connectionInfo);
478         OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
479         Assert.assertNotNull(ovsdbNodeAugmentation);
480         List<OpenvswitchOtherConfigs> otherConfigsList = ovsdbNodeAugmentation.getOpenvswitchOtherConfigs();
481         if (otherConfigsList != null) {
482             for (OpenvswitchOtherConfigs otherConfig : otherConfigsList) {
483                 if (otherConfig.getOtherConfigKey().equals("local_ip")) {
484                     LOG.info("local_ip: {}", otherConfig.getOtherConfigValue());
485                     break;
486                 } else {
487                     LOG.info("other_config {}:{}", otherConfig.getOtherConfigKey(), otherConfig.getOtherConfigValue());
488                 }
489             }
490         } else {
491             LOG.info("other_config is not present");
492         }
493         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
494     }
495
496     @Test
497     public void testOvsdbBridgeControllerInfo() throws InterruptedException {
498         ConnectionInfo connectionInfo = getConnectionInfo(addressStr,portStr);
499         Node ovsdbNode = connectOvsdbNode(connectionInfo);
500         String controllerTarget = SouthboundUtil.getControllerTarget(ovsdbNode);
501         assertNotNull("Failed to get controller target", controllerTarget);
502         List<ControllerEntry> setControllerEntry = createControllerEntry(controllerTarget);
503         Uri setUri = new Uri(controllerTarget);
504         Assert.assertTrue(addBridge(connectionInfo, null, SouthboundITConstants.BRIDGE_NAME,null, true,
505                 SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null,
506                 setControllerEntry, null));
507         OvsdbBridgeAugmentation bridge = getBridge(connectionInfo);
508         Assert.assertNotNull("bridge was not found: " + SouthboundITConstants.BRIDGE_NAME,  bridge);
509         Assert.assertNotNull("ControllerEntry was not found: " + setControllerEntry.iterator().next(),
510                 bridge.getControllerEntry());
511         List<ControllerEntry> getControllerEntries = bridge.getControllerEntry();
512         for (ControllerEntry entry : getControllerEntries) {
513             if (entry.getTarget() != null) {
514                 Assert.assertEquals(setUri.toString(), entry.getTarget().toString());
515             }
516         }
517
518         Assert.assertTrue(deleteBridge(connectionInfo));
519         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
520     }
521
522     private List<ControllerEntry> createControllerEntry(String controllerTarget) {
523         List<ControllerEntry> controllerEntriesList = new ArrayList<>();
524         controllerEntriesList.add(new ControllerEntryBuilder()
525                 .setTarget(new Uri(controllerTarget))
526                 .build());
527         return controllerEntriesList;
528     }
529
530     private void setManagedBy(final OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder,
531                               final ConnectionInfo connectionInfo) {
532         InstanceIdentifier<Node> connectionNodePath = createInstanceIdentifier(connectionInfo);
533         ovsdbBridgeAugmentationBuilder.setManagedBy(new OvsdbNodeRef(connectionNodePath));
534     }
535
536     private List<ProtocolEntry> createMdsalProtocols() {
537         List<ProtocolEntry> protocolList = new ArrayList<>();
538         ImmutableBiMap<String, Class<? extends OvsdbBridgeProtocolBase>> mapper =
539                 SouthboundConstants.OVSDB_PROTOCOL_MAP.inverse();
540         protocolList.add(new ProtocolEntryBuilder().setProtocol(mapper.get("OpenFlow13")).build());
541         return protocolList;
542     }
543
544     private OvsdbTerminationPointAugmentationBuilder createGenericOvsdbTerminationPointAugmentationBuilder() {
545         OvsdbTerminationPointAugmentationBuilder ovsdbTerminationPointAugmentationBuilder =
546                 new OvsdbTerminationPointAugmentationBuilder();
547         ovsdbTerminationPointAugmentationBuilder.setInterfaceType(
548                 new InterfaceTypeEntryBuilder()
549                         .setInterfaceType(
550                                 SouthboundMapper.createInterfaceType("internal"))
551                         .build().getInterfaceType());
552         return ovsdbTerminationPointAugmentationBuilder;
553     }
554
555     private OvsdbTerminationPointAugmentationBuilder createGenericDpdkOvsdbTerminationPointAugmentationBuilder(
556             final String portName) {
557         OvsdbTerminationPointAugmentationBuilder ovsdbTerminationBuilder =
558                 createGenericOvsdbTerminationPointAugmentationBuilder();
559         ovsdbTerminationBuilder.setName(portName);
560         Class<? extends InterfaceTypeBase> ifType = SouthboundConstants.OVSDB_INTERFACE_TYPE_MAP
561                 .get("dpdk");
562         ovsdbTerminationBuilder.setInterfaceType(ifType);
563         return ovsdbTerminationBuilder;
564     }
565
566     private boolean addTerminationPoint(final NodeId bridgeNodeId, final String portName,
567                                         final OvsdbTerminationPointAugmentationBuilder
568                                                 ovsdbTerminationPointAugmentationBuilder)
569             throws InterruptedException {
570
571         InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(bridgeNodeId);
572         NodeBuilder portNodeBuilder = new NodeBuilder();
573         NodeId portNodeId = SouthboundMapper.createManagedNodeId(portIid);
574         portNodeBuilder.setNodeId(portNodeId);
575         TerminationPointBuilder entry = new TerminationPointBuilder();
576         entry.setKey(new TerminationPointKey(new TpId(portName)));
577         entry.addAugmentation(
578                 OvsdbTerminationPointAugmentation.class,
579                 ovsdbTerminationPointAugmentationBuilder.build());
580         portNodeBuilder.setTerminationPoint(Lists.newArrayList(entry.build()));
581         boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
582                 portIid, portNodeBuilder.build());
583         Thread.sleep(OVSDB_UPDATE_TIMEOUT);
584         return result;
585     }
586
587     /*
588      * base method for adding test bridges.  Other helper methods used to create bridges should utilize this method.
589      *
590      * @param connectionInfo
591      * @param bridgeIid if passed null, one is created
592      * @param bridgeName cannot be null
593      * @param bridgeNodeId if passed null, one is created based on <code>bridgeIid</code>
594      * @param setProtocolEntries toggles whether default protocol entries are set for the bridge
595      * @param failMode toggles whether default fail mode is set for the bridge
596      * @param setManagedBy toggles whether to setManagedBy for the bridge
597      * @param dpType if passed null, this parameter is ignored
598      * @param externalIds if passed null, this parameter is ignored
599      * @param otherConfig if passed null, this parameter is ignored
600      * @return success of bridge addition
601      * @throws InterruptedException
602      */
603     private boolean addBridge(final ConnectionInfo connectionInfo, InstanceIdentifier<Node> bridgeIid,
604                               final String bridgeName, NodeId bridgeNodeId, final boolean setProtocolEntries,
605                               final Class<? extends OvsdbFailModeBase> failMode, final boolean setManagedBy,
606                               final Class<? extends DatapathTypeBase> dpType,
607                               final List<BridgeExternalIds> externalIds,
608                               final List<ControllerEntry> controllerEntries,
609                               final List<BridgeOtherConfigs> otherConfigs) throws InterruptedException {
610
611         NodeBuilder bridgeNodeBuilder = new NodeBuilder();
612         if (bridgeIid == null) {
613             bridgeIid = createInstanceIdentifier(connectionInfo, new OvsdbBridgeName(bridgeName));
614         }
615         if (bridgeNodeId == null) {
616             bridgeNodeId = SouthboundMapper.createManagedNodeId(bridgeIid);
617         }
618         bridgeNodeBuilder.setNodeId(bridgeNodeId);
619         OvsdbBridgeAugmentationBuilder ovsdbBridgeAugmentationBuilder = new OvsdbBridgeAugmentationBuilder();
620         ovsdbBridgeAugmentationBuilder.setBridgeName(new OvsdbBridgeName(bridgeName));
621         if (setProtocolEntries) {
622             ovsdbBridgeAugmentationBuilder.setProtocolEntry(createMdsalProtocols());
623         }
624         if (failMode != null) {
625             ovsdbBridgeAugmentationBuilder.setFailMode(failMode);
626         }
627         if (setManagedBy) {
628             setManagedBy(ovsdbBridgeAugmentationBuilder, connectionInfo);
629         }
630         if (dpType != null) {
631             ovsdbBridgeAugmentationBuilder.setDatapathType(dpType);
632         }
633         if (externalIds != null) {
634             ovsdbBridgeAugmentationBuilder.setBridgeExternalIds(externalIds);
635         }
636         if (controllerEntries != null) {
637             ovsdbBridgeAugmentationBuilder.setControllerEntry(controllerEntries);
638         }
639         if (otherConfigs != null) {
640             ovsdbBridgeAugmentationBuilder.setBridgeOtherConfigs(otherConfigs);
641         }
642         bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, ovsdbBridgeAugmentationBuilder.build());
643         LOG.debug("Built with the intent to store bridge data {}",
644                 ovsdbBridgeAugmentationBuilder.toString());
645         boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
646                 bridgeIid, bridgeNodeBuilder.build());
647         Thread.sleep(OVSDB_UPDATE_TIMEOUT);
648         return result;
649     }
650
651     private boolean addBridge(final ConnectionInfo connectionInfo, final String bridgeName)
652             throws InterruptedException {
653
654         return addBridge(connectionInfo, null, bridgeName, null, true,
655                 SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"), true, null, null, null, null);
656     }
657
658     private OvsdbBridgeAugmentation getBridge(ConnectionInfo connectionInfo) {
659         return getBridge(connectionInfo, SouthboundITConstants.BRIDGE_NAME);
660     }
661
662     /**
663      * Extract the <code>store</code> type data store contents for the particular bridge identified by
664      * <code>bridgeName</code>.
665      *
666      * @param connectionInfo the connection information
667      * @param bridgeName the bridge name
668      * @param store defined by the <code>LogicalDatastoreType</code> enumeration
669      * @return <code>store</code> type data store contents
670      */
671     private OvsdbBridgeAugmentation getBridge(ConnectionInfo connectionInfo, String bridgeName,
672                                               LogicalDatastoreType store) {
673         Node bridgeNode = getBridgeNode(connectionInfo, bridgeName, store);
674         Assert.assertNotNull(bridgeNode);
675         OvsdbBridgeAugmentation ovsdbBridgeAugmentation = bridgeNode.getAugmentation(OvsdbBridgeAugmentation.class);
676         Assert.assertNotNull(ovsdbBridgeAugmentation);
677         return ovsdbBridgeAugmentation;
678     }
679
680     /**
681      * extract the <code>LogicalDataStoreType.OPERATIONAL</code> type data store contents for the particular bridge
682      * identified by <code>bridgeName</code>
683      *
684      * @param connectionInfo the connection information
685      * @param bridgeName the bridge name
686      * @see <code>SouthboundIT.getBridge(ConnectionInfo, String, LogicalDatastoreType)</code>
687      * @return <code>LogicalDatastoreType.OPERATIONAL</code> type data store contents
688      */
689     private OvsdbBridgeAugmentation getBridge(ConnectionInfo connectionInfo, String bridgeName) {
690         return getBridge(connectionInfo, bridgeName, LogicalDatastoreType.OPERATIONAL);
691     }
692
693     /**
694      * Extract the node contents from <code>store</code> type data store for the
695      * bridge identified by <code>bridgeName</code>
696      *
697      * @param connectionInfo the connection information
698      * @param bridgeName the bridge name
699      * @param store defined by the <code>LogicalDatastoreType</code> enumeration
700      * @return <code>store</code> type data store contents
701      */
702     private Node getBridgeNode(ConnectionInfo connectionInfo, String bridgeName, LogicalDatastoreType store) {
703         InstanceIdentifier<Node> bridgeIid =
704                 createInstanceIdentifier(connectionInfo,
705                         new OvsdbBridgeName(bridgeName));
706         return mdsalUtils.read(store, bridgeIid);
707     }
708
709     /**
710      * Extract the node contents from <code>LogicalDataStoreType.OPERATIONAL</code> data store for the
711      * bridge identified by <code>bridgeName</code>
712      *
713      * @param connectionInfo the connection information
714      * @param bridgeName the bridge name
715      * @return <code>LogicalDatastoreType.OPERATIONAL</code> type data store contents
716      */
717     private Node getBridgeNode(ConnectionInfo connectionInfo, String bridgeName) {
718         return getBridgeNode(connectionInfo, bridgeName, LogicalDatastoreType.OPERATIONAL);
719     }
720
721     private boolean deleteBridge(ConnectionInfo connectionInfo) throws InterruptedException {
722         return deleteBridge(connectionInfo, SouthboundITConstants.BRIDGE_NAME);
723     }
724
725     private boolean deleteBridge(final ConnectionInfo connectionInfo, final String bridgeName)
726             throws InterruptedException {
727
728         boolean result = mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION,
729                 createInstanceIdentifier(connectionInfo,
730                         new OvsdbBridgeName(bridgeName)));
731         Thread.sleep(OVSDB_UPDATE_TIMEOUT);
732         return result;
733     }
734
735     @Test
736     public void testAddDeleteBridge() throws InterruptedException {
737         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
738         connectOvsdbNode(connectionInfo);
739
740         Assert.assertTrue(addBridge(connectionInfo, SouthboundITConstants.BRIDGE_NAME));
741         OvsdbBridgeAugmentation bridge = getBridge(connectionInfo);
742         Assert.assertNotNull(bridge);
743         LOG.info("bridge: {}", bridge);
744
745         Assert.assertTrue(deleteBridge(connectionInfo));
746
747         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
748     }
749
750     private InstanceIdentifier<Node> getTpIid(ConnectionInfo connectionInfo, OvsdbBridgeAugmentation bridge) {
751         return createInstanceIdentifier(connectionInfo,
752                 bridge.getBridgeName());
753     }
754
755     /**
756      * Extracts the <code>TerminationPointAugmentation</code> for the <code>index</code> <code>TerminationPoint</code>
757      * on <code>bridgeName</code>
758      *
759      * @param connectionInfo the connection information
760      * @param bridgeName the bridge name
761      * @param store defined by the <code>LogicalDatastoreType</code> enumeration
762      * @param index the index we're interested in
763      * @return the augmentation (or {@code null} if none)
764      */
765     private OvsdbTerminationPointAugmentation getOvsdbTerminationPointAugmentation(
766             ConnectionInfo connectionInfo, String bridgeName, LogicalDatastoreType store, int index ) {
767
768         List<TerminationPoint> tpList = getBridgeNode(connectionInfo, bridgeName, store).getTerminationPoint();
769         if (tpList == null) {
770             return null;
771         }
772         return tpList.get(index).getAugmentation(OvsdbTerminationPointAugmentation.class);
773     }
774
775     @Test
776     public void testCRDTerminationPointOfPort() throws InterruptedException {
777         final Long OFPORT_EXPECTED = 45002L;
778
779         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
780         connectOvsdbNode(connectionInfo);
781
782         // CREATE
783         Assert.assertTrue(addBridge(connectionInfo, SouthboundITConstants.BRIDGE_NAME));
784         OvsdbBridgeAugmentation bridge = getBridge(connectionInfo);
785         Assert.assertNotNull(bridge);
786         LOG.info("bridge: {}", bridge);
787         NodeId nodeId = SouthboundMapper.createManagedNodeId(createInstanceIdentifier(
788                 connectionInfo, bridge.getBridgeName()));
789         OvsdbTerminationPointAugmentationBuilder ovsdbTerminationBuilder =
790                 createGenericOvsdbTerminationPointAugmentationBuilder();
791         String portName = "testOfPort";
792         ovsdbTerminationBuilder.setName(portName);
793
794         ovsdbTerminationBuilder.setOfport(OFPORT_EXPECTED);
795         Assert.assertTrue(addTerminationPoint(nodeId, portName, ovsdbTerminationBuilder));
796         InstanceIdentifier<Node> terminationPointIid = getTpIid(connectionInfo, bridge);
797         Node terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, terminationPointIid);
798         Assert.assertNotNull(terminationPointNode);
799
800         // READ
801         List<TerminationPoint> terminationPoints = terminationPointNode.getTerminationPoint();
802         for (TerminationPoint terminationPoint : terminationPoints) {
803             OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
804                     terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class);
805             if (ovsdbTerminationPointAugmentation.getName().equals(portName)) {
806                 Long ofPort = ovsdbTerminationPointAugmentation.getOfport();
807                 // if ephemeral port 45002 is in use, ofPort is set to 1
808                 Assert.assertTrue(ofPort.equals(OFPORT_EXPECTED) || ofPort.equals(new Long(1)));
809                 LOG.info("ofPort: {}", ofPort);
810             }
811         }
812
813         // UPDATE- Not Applicable.  From the OpenVSwitch Documentation:
814         //   "A client should ideally set this column’s value in the same database transaction that it uses to create
815         //   the interface."
816
817         // DELETE
818         Assert.assertTrue(deleteBridge(connectionInfo));
819         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
820     }
821
822     @Test
823     public void testCRDTerminationPointOfPortRequest() throws InterruptedException {
824         final Long OFPORT_EXPECTED = 45008L;
825         final Long OFPORT_INPUT = 45008L;
826
827         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
828         connectOvsdbNode(connectionInfo);
829
830         // CREATE
831         Assert.assertTrue(addBridge(connectionInfo, SouthboundITConstants.BRIDGE_NAME));
832         OvsdbBridgeAugmentation bridge = getBridge(connectionInfo);
833         Assert.assertNotNull(bridge);
834         NodeId nodeId = createManagedNodeId(createInstanceIdentifier(
835                 connectionInfo, bridge.getBridgeName()));
836         OvsdbTerminationPointAugmentationBuilder ovsdbTerminationBuilder =
837                 createGenericOvsdbTerminationPointAugmentationBuilder();
838         String portName = "testOfPortRequest";
839         ovsdbTerminationBuilder.setName(portName);
840         Integer ofPortRequestExpected = OFPORT_EXPECTED.intValue();
841         ovsdbTerminationBuilder.setOfport(OFPORT_INPUT);
842         ovsdbTerminationBuilder.setOfportRequest(ofPortRequestExpected);
843         Assert.assertTrue(addTerminationPoint(nodeId, portName, ovsdbTerminationBuilder));
844         InstanceIdentifier<Node> terminationPointIid = getTpIid(connectionInfo, bridge);
845         Node terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, terminationPointIid);
846         Assert.assertNotNull(terminationPointNode);
847
848         // READ
849         List<TerminationPoint> terminationPoints = terminationPointNode.getTerminationPoint();
850         for (TerminationPoint terminationPoint : terminationPoints) {
851             OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
852                     terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class);
853             if (ovsdbTerminationPointAugmentation.getName().equals(portName)) {
854                 Long ofPort = ovsdbTerminationPointAugmentation.getOfport();
855                 // if ephemeral port 45008 is in use, ofPort is set to 1
856                 Assert.assertTrue(ofPort.equals(OFPORT_EXPECTED) || ofPort.equals(new Long(1)));
857                 LOG.info("ofPort: {}", ofPort);
858
859                 Integer ofPortRequest = ovsdbTerminationPointAugmentation.getOfportRequest();
860                 Assert.assertTrue(ofPortRequest.equals(ofPortRequestExpected));
861                 LOG.info("ofPortRequest: {}", ofPortRequest);
862             }
863         }
864
865         // UPDATE- Not Applicable.  From the OpenVSwitch documentation:
866         //   "A client should ideally set this column’s value in the same database transaction that it uses to create
867         //   the interface. "
868
869         // DELETE
870         Assert.assertTrue(deleteBridge(connectionInfo));
871         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
872     }
873
874     private interface KeyValueBuilder<T> {
875         T build(String testName, String key, String value);
876         T[] build(String testName, int count, String key, String value);
877         void reset();
878     }
879
880     private abstract static class BaseKeyValueBuilder<T> implements KeyValueBuilder<T> {
881         private static final int COUNTER_START = 0;
882         private int counter = COUNTER_START;
883         private final Class<T> builtClass;
884
885         protected abstract Builder<T> builder();
886
887         protected abstract void setKey(Builder<T> builder, String key);
888
889         protected abstract void setValue(Builder<T> builder, String value);
890
891         @SuppressWarnings("unchecked")
892         private BaseKeyValueBuilder() {
893             builtClass = (Class<T>) this.getClass().getSuperclass().getTypeParameters()[0].getClass();
894         }
895
896         @Override
897         public final T build(final String testName, final String key, final String value) {
898             final Builder<T> builder = builder();
899             this.counter++;
900             if (key != null) {
901                 setKey(builder, String.format(FORMAT_STR, testName, key, this.counter));
902             }
903             if (value != null) {
904                 setValue(builder, String.format(FORMAT_STR, testName, value, this.counter));
905             }
906             return builder.build();
907         }
908
909         @SuppressWarnings("unchecked")
910         @Override
911         public final T[] build(final String testName, final int count, final String key, final String value) {
912             final T[] instances = (T[]) Array.newInstance(builtClass, count);
913             for (int idx = 0; idx < count; idx++) {
914                 instances[idx] = build(testName, key, value);
915             }
916             return instances;
917         }
918
919         @Override
920         public final void reset() {
921             this.counter = COUNTER_START;
922         }
923     }
924
925     private static final class SouthboundPortExternalIdsBuilder extends BaseKeyValueBuilder<PortExternalIds> {
926         @Override
927         protected Builder<PortExternalIds> builder() {
928             return new PortExternalIdsBuilder();
929         }
930
931         @Override
932         protected void setKey(Builder<PortExternalIds> builder, String key) {
933             ((PortExternalIdsBuilder) builder).setExternalIdKey(key);
934         }
935
936         @Override
937         protected void setValue(Builder<PortExternalIds> builder, String value) {
938             ((PortExternalIdsBuilder) builder).setExternalIdValue(value);
939         }
940     }
941
942     private static final class SouthboundInterfaceExternalIdsBuilder extends BaseKeyValueBuilder<InterfaceExternalIds> {
943         @Override
944         protected Builder<InterfaceExternalIds> builder() {
945             return new InterfaceExternalIdsBuilder();
946         }
947
948         @Override
949         protected void setKey(Builder<InterfaceExternalIds> builder, String key) {
950             ((InterfaceExternalIdsBuilder) builder).setExternalIdKey(key);
951         }
952
953         @Override
954         protected void setValue(Builder<InterfaceExternalIds> builder, String value) {
955             ((InterfaceExternalIdsBuilder) builder).setExternalIdValue(value);
956         }
957     }
958
959     private static final class SouthboundOptionsBuilder extends BaseKeyValueBuilder<Options> {
960         @Override
961         protected Builder<Options> builder() {
962             return new OptionsBuilder();
963         }
964
965         @Override
966         protected void setKey(Builder<Options> builder, String key) {
967             ((OptionsBuilder) builder).setOption(key);
968         }
969
970         @Override
971         protected void setValue(Builder<Options> builder, String value) {
972             ((OptionsBuilder) builder).setValue(value);
973         }
974     }
975
976     private static final class SouthboundInterfaceOtherConfigsBuilder extends BaseKeyValueBuilder<InterfaceOtherConfigs> {
977         @Override
978         protected Builder<InterfaceOtherConfigs> builder() {
979             return new InterfaceOtherConfigsBuilder();
980         }
981
982         @Override
983         protected void setKey(Builder<InterfaceOtherConfigs> builder, String key) {
984             ((InterfaceOtherConfigsBuilder) builder).setOtherConfigKey(key);
985         }
986
987         @Override
988         protected void setValue(Builder<InterfaceOtherConfigs> builder, String value) {
989             ((InterfaceOtherConfigsBuilder) builder).setOtherConfigValue(value);
990         }
991     }
992
993     private static final class SouthboundPortOtherConfigsBuilder extends BaseKeyValueBuilder<PortOtherConfigs> {
994         @Override
995         protected Builder<PortOtherConfigs> builder() {
996             return new PortOtherConfigsBuilder();
997         }
998
999         @Override
1000         protected void setKey(Builder<PortOtherConfigs> builder, String key) {
1001             ((PortOtherConfigsBuilder) builder).setOtherConfigKey(key);
1002         }
1003
1004         @Override
1005         protected void setValue(Builder<PortOtherConfigs> builder, String value) {
1006             ((PortOtherConfigsBuilder) builder).setOtherConfigValue(value);
1007         }
1008     }
1009
1010     private static final class SouthboundBridgeOtherConfigsBuilder extends BaseKeyValueBuilder<BridgeOtherConfigs> {
1011         @Override
1012         protected Builder<BridgeOtherConfigs> builder() {
1013             return new BridgeOtherConfigsBuilder();
1014         }
1015
1016         @Override
1017         protected void setKey(Builder<BridgeOtherConfigs> builder, String key) {
1018             ((BridgeOtherConfigsBuilder) builder).setBridgeOtherConfigKey(key);
1019         }
1020
1021         @Override
1022         protected void setValue(Builder<BridgeOtherConfigs> builder, String value) {
1023             ((BridgeOtherConfigsBuilder) builder).setBridgeOtherConfigValue(value);
1024         }
1025     }
1026
1027     private static final class SouthboundBridgeExternalIdsBuilder extends BaseKeyValueBuilder<BridgeExternalIds> {
1028         @Override
1029         protected Builder<BridgeExternalIds> builder() {
1030             return new BridgeExternalIdsBuilder();
1031         }
1032
1033         @Override
1034         protected void setKey(Builder<BridgeExternalIds> builder, String key) {
1035             ((BridgeExternalIdsBuilder) builder).setBridgeExternalIdKey(key);
1036         }
1037
1038         @Override
1039         protected void setValue(Builder<BridgeExternalIds> builder, String value) {
1040             ((BridgeExternalIdsBuilder) builder).setBridgeExternalIdValue(value);
1041         }
1042     }
1043
1044     /*
1045      * Generates the test cases involved in testing key-value-based data.  See inline comments for descriptions of
1046      * the particular cases considered.
1047      */
1048     private static <T> List<SouthboundTestCase<T>> generateKeyValueTestCases(
1049             KeyValueBuilder<T> builder, String idKey, String idValue) {
1050         List<SouthboundTestCase<T>> testCases = new ArrayList<>();
1051
1052         final String GOOD_KEY = "GoodKey";
1053         final String GOOD_VALUE = "GoodValue";
1054         final String NO_VALUE_FOR_KEY = "NoValueForKey";
1055         final String NO_KEY_FOR_VALUE = "NoKeyForValue";
1056
1057         // Test Case 1:  TestOne
1058         // Test Type:    Positive
1059         // Description:  Create a termination point with one value
1060         // Expected:     A port is created with the single value specified below
1061         final String testOneName = "TestOne";
1062         testCases.add(new SouthboundTestCaseBuilder<T>()
1063                 .name(testOneName)
1064                 .input(builder.build(testOneName, idKey, idValue))
1065                 .expectInputAsOutput()
1066                 .build());
1067         builder.reset();
1068
1069         // Test Case 2:  TestFive
1070         // Test Type:    Positive
1071         // Description:  Create a termination point with multiple (five) values
1072         // Expected:     A port is created with the five values specified below
1073         final String testFiveName = "TestFive";
1074         testCases.add(new SouthboundTestCaseBuilder<T>()
1075                 .name(testFiveName)
1076                 .input(builder.build(testFiveName, 5, idKey, idValue))
1077                 .expectInputAsOutput()
1078                 .build());
1079         builder.reset();
1080
1081         // Test Case 3:  TestOneGoodOneMalformedValue
1082         // Test Type:    Negative
1083         // Description:
1084         //     One perfectly fine input
1085         //        (TestOneGoodOneMalformedValue_GoodKey_1,
1086         //        TestOneGoodOneMalformedValue_GoodValue_1)
1087         //     and one malformed input which only has key specified
1088         //        (TestOneGoodOneMalformedValue_NoValueForKey_2,
1089         //        UNSPECIFIED)
1090         // Expected:     A port is created without any values
1091         final String testOneGoodOneMalformedValueName = "TestOneGoodOneMalformedValue";
1092         testCases.add(new SouthboundTestCaseBuilder<T>()
1093                 .name(testOneGoodOneMalformedValueName)
1094                 .input(
1095                         builder.build(testOneGoodOneMalformedValueName, GOOD_KEY, GOOD_VALUE),
1096                         builder.build(testOneGoodOneMalformedValueName, NO_VALUE_FOR_KEY, null)
1097                 )
1098                 .expect()
1099                 .build());
1100         builder.reset();
1101
1102         // Test Case 4:  TestOneGoodOneMalformedKey
1103         // Test Type:    Negative
1104         // Description:
1105         //     One perfectly fine input
1106         //        (TestOneGoodOneMalformedKey_GoodKey_1,
1107         //        TestOneGoodOneMalformedKey_GoodValue_1)
1108         //     and one malformed input which only has value specified
1109         //        (UNSPECIFIED,
1110         //        TestOneGoodOneMalformedKey_NoKeyForValue_2)
1111         // Expected:     A port is created without any values
1112         final String testOneGoodOneMalformedKeyName = "TestOneGoodOneMalformedKey";
1113         testCases.add(new SouthboundTestCaseBuilder<T>()
1114                 .name(testOneGoodOneMalformedKeyName)
1115                 .input(
1116                         builder.build(testOneGoodOneMalformedKeyName, GOOD_KEY, GOOD_VALUE),
1117                         builder.build(testOneGoodOneMalformedKeyName, null, NO_KEY_FOR_VALUE)
1118                 )
1119                 .expect()
1120                 .build());
1121         builder.reset();
1122
1123         return testCases;
1124     }
1125
1126     /*
1127      * Generates the test cases involved in testing PortExternalIds.  See inline comments for descriptions of
1128      * the particular cases considered.
1129      */
1130     private List<SouthboundTestCase<PortExternalIds>> generatePortExternalIdsTestCases() {
1131         return generateKeyValueTestCases(new SouthboundPortExternalIdsBuilder(), "PortExternalIdKey",
1132                 "PortExternalIdValue");
1133     }
1134
1135     /*
1136      * Tests the CRUD operations for <code>Port</code>
1137      * <code>external_ids</code>.
1138      *
1139      * @see <code>SouthboundIT.generatePortExternalIdsTestCases()</code> for
1140      * specific test case information
1141      */
1142     @Test
1143     public void testCRUDTerminationPointPortExternalIds()
1144             throws InterruptedException, ExecutionException {
1145
1146         final String TEST_PREFIX = "CRUDTPPortExternalIds";
1147
1148         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
1149         connectOvsdbNode(connectionInfo);
1150
1151         // updateFromTestCases represent the original test case value.
1152         // updateToTestCases represent the new value after the update has been
1153         // performed.
1154         List<SouthboundTestCase<PortExternalIds>> updateFromTestCases = generatePortExternalIdsTestCases();
1155         List<SouthboundTestCase<PortExternalIds>> updateToTestCases = generatePortExternalIdsTestCases();
1156         String testBridgeName;
1157         String testPortName;
1158
1159         int counter = 1;
1160         // multihreads the test using NUM_THREADS
1161         ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
1162         for (SouthboundTestCase<PortExternalIds> fromTestCase : updateFromTestCases) {
1163             for (SouthboundTestCase<PortExternalIds> toTestCase : updateToTestCases) {
1164                 testPortName = testBridgeName = String.format(FORMAT_STR,
1165                         TEST_PREFIX, toTestCase.name, counter);
1166                 counter += 1;
1167                 executor.submit(new TestCRUDTerminationPointRunnable<>(
1168                         new SouthboundTestHelper<PortExternalIds>() {
1169                             @Override
1170                             public List<PortExternalIds> readValues(
1171                                     OvsdbTerminationPointAugmentation augmentation) {
1172                                 return augmentation.getPortExternalIds();
1173                             }
1174
1175                             @Override
1176                             public void writeValues(
1177                                     OvsdbTerminationPointAugmentationBuilder augmentationBuilder,
1178                                     List<PortExternalIds> updateFromInput) {
1179                                 augmentationBuilder.setPortExternalIds(updateFromInput);
1180                             }
1181                         },
1182                         connectionInfo, testBridgeName, testPortName,
1183                         fromTestCase.inputValues,
1184                         fromTestCase.expectedValues,
1185                         toTestCase.inputValues,
1186                         toTestCase.expectedValues));
1187             }
1188         }
1189         executor.shutdown();
1190         executor.awaitTermination(5, TimeUnit.MINUTES);
1191         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
1192     }
1193
1194     /**
1195      * Southbound test helper. Classes implementing this interface are used to provide concrete access to the input and
1196      * output of the underlying augmentation for the type being managed.
1197      *
1198      * @param <T> The type of data used for the test case.
1199      */
1200     private interface SouthboundTestHelper<T> {
1201         /**
1202          * Read the values from the augmentation. These would usually be checked against the expected values provided
1203          * for the test case.
1204          *
1205          * @param augmentation The augmentation to read from.
1206          * @return The values read.
1207          */
1208         List<T> readValues(OvsdbTerminationPointAugmentation augmentation);
1209
1210         /**
1211          * Write the values to the augmentation (via its builder). This would usually be used to apply the input values
1212          * provided for the test case.
1213          *
1214          * @param augmentationBuilder The augmentation builder.
1215          * @param values The values to write.
1216          */
1217         void writeValues(OvsdbTerminationPointAugmentationBuilder augmentationBuilder, List<T> values);
1218     }
1219
1220     /**
1221      * <p>
1222      * Test runner used to apply a suite of create/read/update/delete tests. Each instance of a runner expects:
1223      * </p>
1224      * <ul>
1225      * <li>a helper used to manipulate the appropriate data structures in the termination point augmentation (see
1226      * {@link SouthboundTestHelper});</li>
1227      * <li>connection information for the southbound;</li>
1228      * <li>a name to use for the test bridge (this allows multiple tests to be conducted in parallel against different
1229      * bridges);</li>
1230      * <li>a name to use for the test port;</li>
1231      * <li>the initial input values to use for the termination point augmentation;</li>
1232      * <li>the initial expected values to check the augmentation against;</li>
1233      * <li>the target input values to update the terminal point to;</li>
1234      * <li>the target expected values to check the augmentation point against.</li>
1235      * </ul>
1236      * <p>The following tests are performed:</p>
1237      * <ol>
1238      * <li>the bridge is added;</li>
1239      * <li>the termination point is added, with the provided initial input values;</li>
1240      * <li>the termination point is read from the <em>configuration</em> data store, and checked against the provided
1241      * initial expected values;</li>
1242      * <li>the termination point is read from the <em>operational</em> data store, and checked against the provided
1243      * initial expected values;</li>
1244      * <li>the termination point is updated by merging the provided target input values;</li>
1245      * <li>the termination point is read from the <em>configuration</em> data store, and checked against the provided
1246      * initial <b>and</b> target expected values;</li>
1247      * <li>the termination point is read from the <em>operational</em> data store, and checked against the provided
1248      * initial <b>and</b> target expected values;</li>
1249      * <li>the bridge is deleted.</li>
1250      * </ol>
1251      *
1252      * @param <T> The type of data used for the test case.
1253      */
1254     private final class TestCRUDTerminationPointRunnable<T> implements Runnable {
1255         private final SouthboundTestHelper<T> helper;
1256         private final ConnectionInfo connectionInfo;
1257         private final String testBridgeName;
1258         private final String testPortName;
1259         private final List<T> updateFromInput;
1260         private final List<T> updateFromExpected;
1261         private final List<T> updateToInput;
1262         private final List<T> updateToExpected;
1263
1264         private TestCRUDTerminationPointRunnable(
1265                 SouthboundTestHelper<T> helper, ConnectionInfo connectionInfo, String testBridgeName,
1266                 String testPortName, List<T> updateFromInput, List<T> updateFromExpected, List<T> updateToInput,
1267                 List<T> updateToExpected) {
1268             this.helper = helper;
1269             this.connectionInfo = connectionInfo;
1270             this.testBridgeName = testBridgeName;
1271             this.testPortName = testPortName;
1272             this.updateFromInput = updateFromInput;
1273             this.updateFromExpected = updateFromExpected;
1274             this.updateToInput = updateToInput;
1275             this.updateToExpected = updateToExpected;
1276         }
1277
1278         @Override
1279         public void run() {
1280             try {
1281                 final int TERMINATION_POINT_TEST_INDEX = 0;
1282                 // CREATE: Create the test bridge
1283                 Assert.assertTrue(addBridge(connectionInfo, null,
1284                         testBridgeName, null, true,
1285                         SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"),
1286                         true, null, null, null, null));
1287                 NodeId testBridgeNodeId = createManagedNodeId(createInstanceIdentifier(
1288                         connectionInfo, new OvsdbBridgeName(testBridgeName)));
1289                 OvsdbTerminationPointAugmentationBuilder tpCreateAugmentationBuilder =
1290                         createGenericOvsdbTerminationPointAugmentationBuilder();
1291                 tpCreateAugmentationBuilder.setName(testPortName);
1292                 helper.writeValues(tpCreateAugmentationBuilder, updateFromInput);
1293                 Assert.assertTrue(addTerminationPoint(testBridgeNodeId, testPortName, tpCreateAugmentationBuilder));
1294
1295                 // READ: Read the test port and ensure changes are propagated to the CONFIGURATION data store,
1296                 // then repeat for OPERATIONAL data store
1297                 OvsdbTerminationPointAugmentation updateFromConfigurationTerminationPointAugmentation =
1298                         getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
1299                                 LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
1300                 List<T> updateFromConfiguration = null;
1301                 if (updateFromConfigurationTerminationPointAugmentation != null) {
1302                     updateFromConfiguration =
1303                         helper.readValues(updateFromConfigurationTerminationPointAugmentation);
1304                 }
1305                 if (updateFromConfiguration != null) {
1306                     Assert.assertTrue(updateFromConfiguration.containsAll(updateFromExpected));
1307                 }
1308                 OvsdbTerminationPointAugmentation updateFromOperationalTerminationPointAugmentation =
1309                         getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
1310                                 LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
1311                 List<T> updateFromOperational = null;
1312                 if (updateFromOperationalTerminationPointAugmentation != null) {
1313                     updateFromOperational = helper.readValues(updateFromOperationalTerminationPointAugmentation);
1314                 }
1315                 if (updateFromOperational != null) {
1316                     Assert.assertTrue(updateFromOperational.containsAll(updateFromExpected));
1317                 }
1318
1319                 // UPDATE:  update the external_ids
1320                 testBridgeNodeId = getBridgeNode(connectionInfo, testBridgeName).getNodeId();
1321                 OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
1322                         new OvsdbTerminationPointAugmentationBuilder();
1323                 helper.writeValues(tpUpdateAugmentationBuilder, updateToInput);
1324                 InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
1325                 NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
1326                 NodeId portUpdateNodeId = createManagedNodeId(portIid);
1327                 portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
1328                 TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
1329                 tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(testPortName)));
1330                 tpUpdateBuilder.addAugmentation(
1331                         OvsdbTerminationPointAugmentation.class,
1332                         tpUpdateAugmentationBuilder.build());
1333                 portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
1334                 boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
1335                         portIid, portUpdateNodeBuilder.build());
1336                 Thread.sleep(OVSDB_UPDATE_TIMEOUT);
1337                 Assert.assertTrue(result);
1338
1339                 // READ: the test port and ensure changes are propagated to the CONFIGURATION data store,
1340                 // then repeat for OPERATIONAL data store
1341                 OvsdbTerminationPointAugmentation updateToConfigurationTerminationPointAugmentation =
1342                         getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
1343                                 LogicalDatastoreType.CONFIGURATION, TERMINATION_POINT_TEST_INDEX);
1344                 List<T> updateToConfiguration = helper.readValues(updateToConfigurationTerminationPointAugmentation);
1345                 Assert.assertTrue(updateToConfiguration.containsAll(updateToExpected));
1346                 Assert.assertTrue(updateToConfiguration.containsAll(updateFromExpected));
1347                 OvsdbTerminationPointAugmentation updateToOperationalTerminationPointAugmentation =
1348                         getOvsdbTerminationPointAugmentation(connectionInfo, testBridgeName,
1349                                 LogicalDatastoreType.OPERATIONAL, TERMINATION_POINT_TEST_INDEX);
1350                 List<T> updateToOperational = helper.readValues(updateToOperationalTerminationPointAugmentation);
1351                 Assert.assertTrue(updateToOperational.containsAll(updateToExpected));
1352                 Assert.assertTrue(updateToOperational.containsAll(updateFromExpected));
1353
1354                 // DELETE
1355                 Assert.assertTrue(deleteBridge(connectionInfo, testBridgeName));
1356             } catch (InterruptedException e) {
1357                 LOG.error("Test interrupted", e);
1358             }
1359         }
1360     }
1361
1362
1363     /*
1364      * Generates the test cases involved in testing InterfaceExternalIds.  See inline comments for descriptions of
1365      * the particular cases considered.
1366      */
1367     private static List<SouthboundTestCase<InterfaceExternalIds>> generateInterfaceExternalIdsTestCases() {
1368         return generateKeyValueTestCases(new SouthboundInterfaceExternalIdsBuilder(), "IntExternalIdKey",
1369                 "IntExternalIdValue");
1370     }
1371
1372     /*
1373      * Tests the CRUD operations for <code>Interface</code> <code>external_ids</code>.
1374      *
1375      * @see <code>SouthboundIT.generateInterfaceExternalIdsTestCases()</code> for specific test case information
1376      */
1377     @Test
1378     public void testCRUDTerminationPointInterfaceExternalIds() throws InterruptedException, ExecutionException {
1379         final String TEST_PREFIX = "CRUDTPInterfaceExternalIds";
1380
1381         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
1382         connectOvsdbNode(connectionInfo);
1383
1384         // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
1385         // the update has been performed.
1386         List<SouthboundTestCase<InterfaceExternalIds>> updateFromTestCases = generateInterfaceExternalIdsTestCases();
1387         List<SouthboundTestCase<InterfaceExternalIds>> updateToTestCases = generateInterfaceExternalIdsTestCases();
1388         String testBridgeName;
1389         String testPortName;
1390
1391         int counter = 1;
1392         // multithreads the test using NUM_THREADS
1393         ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
1394         for (SouthboundTestCase<InterfaceExternalIds> fromTestCase : updateFromTestCases) {
1395             for (SouthboundTestCase<InterfaceExternalIds> toTestCase : updateToTestCases) {
1396                 testPortName = testBridgeName = String.format(FORMAT_STR,
1397                         TEST_PREFIX, toTestCase.name, counter);
1398                 counter += 1;
1399                 executor.submit(new TestCRUDTerminationPointRunnable<>(
1400                         new SouthboundTestHelper<InterfaceExternalIds>() {
1401                             @Override
1402                             public List<InterfaceExternalIds> readValues(
1403                                     OvsdbTerminationPointAugmentation augmentation) {
1404                                 return augmentation.getInterfaceExternalIds();
1405                             }
1406
1407                             @Override
1408                             public void writeValues(
1409                                     OvsdbTerminationPointAugmentationBuilder augmentationBuilder,
1410                                     List<InterfaceExternalIds> values) {
1411                                 augmentationBuilder.setInterfaceExternalIds(values);
1412                             }
1413                         },
1414                         connectionInfo, testBridgeName, testPortName,
1415                         fromTestCase.inputValues,
1416                         fromTestCase.expectedValues,
1417                         toTestCase.inputValues,
1418                         toTestCase.expectedValues));
1419             }
1420         }
1421         executor.shutdown();
1422         executor.awaitTermination(5, TimeUnit.MINUTES);
1423         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
1424     }
1425
1426     /*
1427      * Generates the test cases involved in testing TP Options.  See inline comments for descriptions of
1428      * the particular cases considered.
1429      */
1430     private List<SouthboundTestCase<Options>> generateTerminationPointOptionsTestCases() {
1431         return generateKeyValueTestCases(new SouthboundOptionsBuilder(), "TOPOptionsKey", "TPOptionsValue");
1432     }
1433
1434     /*
1435      * Tests the CRUD operations for <code>TerminationPoint</code> <code>options</code>.
1436      *
1437      * @see <code>SouthboundIT.generateTerminationPointOptions()</code> for specific test case information
1438      */
1439     @Test
1440     public void testCRUDTerminationPointOptions() throws InterruptedException {
1441         final String TEST_PREFIX = "CRUDTPOptions";
1442
1443         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
1444         connectOvsdbNode(connectionInfo);
1445
1446         // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
1447         // the update has been performed.
1448         List<SouthboundTestCase<Options>> updateFromTestCases = generateTerminationPointOptionsTestCases();
1449         List<SouthboundTestCase<Options>> updateToTestCases = generateTerminationPointOptionsTestCases();
1450         String testBridgeName;
1451         String testPortName;
1452
1453         int counter = 1;
1454         ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
1455         for (SouthboundTestCase<Options> fromTestCase : updateFromTestCases) {
1456             for (SouthboundTestCase<Options> toTestCase : updateToTestCases) {
1457                 testPortName = testBridgeName = String.format(FORMAT_STR,
1458                         TEST_PREFIX, toTestCase.name, counter);
1459                 counter += 1;
1460                 executor.submit(new TestCRUDTerminationPointRunnable<>(
1461                         new SouthboundTestHelper<Options>() {
1462                             @Override
1463                             public List<Options> readValues(
1464                                     OvsdbTerminationPointAugmentation augmentation) {
1465                                 return augmentation.getOptions();
1466                             }
1467
1468                             @Override
1469                             public void writeValues(
1470                                     OvsdbTerminationPointAugmentationBuilder augmentationBuilder,
1471                                     List<Options> values) {
1472                                 augmentationBuilder.setOptions(values);
1473                             }
1474                         },
1475                         connectionInfo, testBridgeName, testPortName,
1476                         fromTestCase.inputValues,
1477                         fromTestCase.expectedValues,
1478                         toTestCase.inputValues,
1479                         toTestCase.expectedValues));
1480             }
1481         }
1482         executor.shutdown();
1483         executor.awaitTermination(5, TimeUnit.MINUTES);
1484         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
1485     }
1486
1487     /*
1488      * Generates the test cases involved in testing Interface other_configs.  See inline comments for descriptions of
1489      * the particular cases considered.
1490      */
1491     private List<SouthboundTestCase<InterfaceOtherConfigs>> generateInterfaceOtherConfigsTestCases() {
1492         return generateKeyValueTestCases(new SouthboundInterfaceOtherConfigsBuilder(), "IntOtherConfigsKey",
1493                 "IntOtherConfigsValue");
1494     }
1495
1496     /*
1497      * Tests the CRUD operations for <code>Interface</code> <code>other_configs</code>.
1498      *
1499      * @see <code>SouthboundIT.generateInterfaceExternalIdsTestCases()</code> for specific test case information
1500      */
1501     @Test
1502     public void testCRUDTerminationPointInterfaceOtherConfigs() throws InterruptedException {
1503         final String TEST_PREFIX = "CRUDTPInterfaceOtherConfigs";
1504
1505         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
1506         connectOvsdbNode(connectionInfo);
1507
1508         // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
1509         // the update has been performed.
1510         List<SouthboundTestCase<InterfaceOtherConfigs>> updateFromTestCases = generateInterfaceOtherConfigsTestCases();
1511         List<SouthboundTestCase<InterfaceOtherConfigs>> updateToTestCases = generateInterfaceOtherConfigsTestCases();
1512         String testBridgeName;
1513         String testPortName;
1514
1515         int counter = 1;
1516         ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
1517         for (SouthboundTestCase<InterfaceOtherConfigs> fromTestCase : updateFromTestCases) {
1518             for (SouthboundTestCase<InterfaceOtherConfigs> toTestCase : updateToTestCases) {
1519                 testPortName = testBridgeName = String.format(FORMAT_STR,
1520                         TEST_PREFIX, toTestCase.name, counter);
1521                 counter += 1;
1522                 executor.submit(new TestCRUDTerminationPointRunnable<>(
1523                         new SouthboundTestHelper<InterfaceOtherConfigs>() {
1524                             @Override
1525                             public List<InterfaceOtherConfigs> readValues(
1526                                     OvsdbTerminationPointAugmentation augmentation) {
1527                                 return augmentation.getInterfaceOtherConfigs();
1528                             }
1529
1530                             @Override
1531                             public void writeValues(
1532                                     OvsdbTerminationPointAugmentationBuilder augmentationBuilder,
1533                                     List<InterfaceOtherConfigs> values) {
1534                                 augmentationBuilder.setInterfaceOtherConfigs(values);
1535                             }
1536                         },
1537                         connectionInfo, testBridgeName, testPortName,
1538                         fromTestCase.inputValues,
1539                         fromTestCase.expectedValues,
1540                         toTestCase.inputValues,
1541                         toTestCase.expectedValues));
1542             }
1543         }
1544         executor.shutdown();
1545         executor.awaitTermination(5, TimeUnit.MINUTES);
1546         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
1547     }
1548
1549     /*
1550      * Generates the test cases involved in testing Port other_configs.  See inline comments for descriptions of
1551      * the particular cases considered.
1552      */
1553     private List<SouthboundTestCase<PortOtherConfigs>> generatePortOtherConfigsTestCases() {
1554         return generateKeyValueTestCases(new SouthboundPortOtherConfigsBuilder(), "PortOtherConfigsKey",
1555                 "PortOtherConfigsValue");
1556     }
1557
1558     /*
1559      * Tests the CRUD operations for <code>Port</code> <code>other_configs</code>.
1560      *
1561      * @see <code>SouthboundIT.generatePortExternalIdsTestCases()</code> for specific test case information
1562      */
1563     @Test
1564     public void testCRUDTerminationPointPortOtherConfigs() throws InterruptedException {
1565         final String TEST_PREFIX = "CRUDTPPortOtherConfigs";
1566
1567         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
1568         connectOvsdbNode(connectionInfo);
1569
1570         // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
1571         // the update has been performed.
1572         List<SouthboundTestCase<PortOtherConfigs>> updateFromTestCases = generatePortOtherConfigsTestCases();
1573         List<SouthboundTestCase<PortOtherConfigs>> updateToTestCases = generatePortOtherConfigsTestCases();
1574         String testBridgeName;
1575         String testPortName;
1576
1577         int counter = 1;
1578         ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
1579         for (SouthboundTestCase<PortOtherConfigs> fromTestCase : updateFromTestCases) {
1580             for (SouthboundTestCase<PortOtherConfigs> toTestCase : updateToTestCases) {
1581                 testPortName = testBridgeName = String.format(FORMAT_STR,
1582                         TEST_PREFIX, toTestCase.name, counter);
1583                 counter += 1;
1584                 executor.submit(new TestCRUDTerminationPointRunnable<>(
1585                         new SouthboundTestHelper<PortOtherConfigs>() {
1586                             @Override
1587                             public List<PortOtherConfigs> readValues(
1588                                     OvsdbTerminationPointAugmentation augmentation) {
1589                                 return augmentation.getPortOtherConfigs();
1590                             }
1591
1592                             @Override
1593                             public void writeValues(
1594                                     OvsdbTerminationPointAugmentationBuilder augmentationBuilder,
1595                                     List<PortOtherConfigs> values) {
1596                                 augmentationBuilder.setPortOtherConfigs(values);
1597                             }
1598                         },
1599                         connectionInfo, testBridgeName, testPortName,
1600                         fromTestCase.inputValues,
1601                         fromTestCase.expectedValues,
1602                         toTestCase.inputValues,
1603                         toTestCase.expectedValues));
1604             }
1605         }
1606         executor.shutdown();
1607         executor.awaitTermination(5, TimeUnit.MINUTES);
1608         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
1609     }
1610
1611     @Test
1612     public void testCRUDTerminationPointVlan() throws InterruptedException {
1613         final Integer CREATED_VLAN_ID = 4000;
1614         final Integer UPDATED_VLAN_ID = 4001;
1615
1616         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
1617         connectOvsdbNode(connectionInfo);
1618
1619         // CREATE
1620         Assert.assertTrue(addBridge(connectionInfo, SouthboundITConstants.BRIDGE_NAME));
1621         OvsdbBridgeAugmentation bridge = getBridge(connectionInfo, SouthboundITConstants.BRIDGE_NAME);
1622         Assert.assertNotNull(bridge);
1623         NodeId nodeId = createManagedNodeId(createInstanceIdentifier(
1624                 connectionInfo, bridge.getBridgeName()));
1625         OvsdbTerminationPointAugmentationBuilder ovsdbTerminationBuilder =
1626                 createGenericOvsdbTerminationPointAugmentationBuilder();
1627         String portName = "testTerminationPointVlanId";
1628         ovsdbTerminationBuilder.setName(portName);
1629         ovsdbTerminationBuilder.setVlanTag(new VlanId(CREATED_VLAN_ID));
1630         Assert.assertTrue(addTerminationPoint(nodeId, portName, ovsdbTerminationBuilder));
1631         InstanceIdentifier<Node> terminationPointIid = getTpIid(connectionInfo, bridge);
1632         Node terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, terminationPointIid);
1633         Assert.assertNotNull(terminationPointNode);
1634
1635         // READ
1636         List<TerminationPoint> terminationPoints = terminationPointNode.getTerminationPoint();
1637         OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation;
1638         for (TerminationPoint terminationPoint : terminationPoints) {
1639             ovsdbTerminationPointAugmentation = terminationPoint.getAugmentation(
1640                     OvsdbTerminationPointAugmentation.class);
1641             if (ovsdbTerminationPointAugmentation.getName().equals(portName)) {
1642                 VlanId actualVlanId = ovsdbTerminationPointAugmentation.getVlanTag();
1643                 Assert.assertNotNull(actualVlanId);
1644                 Integer actualVlanIdInt = actualVlanId.getValue();
1645                 Assert.assertEquals(CREATED_VLAN_ID, actualVlanIdInt);
1646             }
1647         }
1648
1649         // UPDATE
1650         NodeId testBridgeNodeId = getBridgeNode(connectionInfo, SouthboundITConstants.BRIDGE_NAME).getNodeId();
1651         OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
1652                 new OvsdbTerminationPointAugmentationBuilder();
1653         tpUpdateAugmentationBuilder.setVlanTag(new VlanId(UPDATED_VLAN_ID));
1654         InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
1655         NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
1656         NodeId portUpdateNodeId = createManagedNodeId(portIid);
1657         portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
1658         TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
1659         tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(portName)));
1660         tpUpdateBuilder.addAugmentation(
1661                 OvsdbTerminationPointAugmentation.class,
1662                 tpUpdateAugmentationBuilder.build());
1663         tpUpdateBuilder.setTpId(new TpId(portName));
1664         portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
1665         boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
1666                 portIid, portUpdateNodeBuilder.build());
1667         Assert.assertTrue(result);
1668         Thread.sleep(OVSDB_UPDATE_TIMEOUT);
1669
1670         terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, terminationPointIid);
1671         terminationPoints = terminationPointNode.getTerminationPoint();
1672         for (TerminationPoint terminationPoint : terminationPoints) {
1673             ovsdbTerminationPointAugmentation = terminationPoint.getAugmentation(
1674                     OvsdbTerminationPointAugmentation.class);
1675             if (ovsdbTerminationPointAugmentation.getName().equals(portName)) {
1676                 VlanId actualVlanId = ovsdbTerminationPointAugmentation.getVlanTag();
1677                 Assert.assertNotNull(actualVlanId);
1678                 Integer actualVlanIdInt = actualVlanId.getValue();
1679                 Assert.assertEquals(UPDATED_VLAN_ID, actualVlanIdInt);
1680             }
1681         }
1682
1683         // DELETE
1684         Assert.assertTrue(deleteBridge(connectionInfo));
1685         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
1686     }
1687
1688     @Test
1689     public void testCRUDTerminationPointVlanModes() throws InterruptedException {
1690         final VlanMode UPDATED_VLAN_MODE = VlanMode.Access;
1691         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
1692         connectOvsdbNode(connectionInfo);
1693         VlanMode []vlanModes = VlanMode.values();
1694         for (VlanMode vlanMode : vlanModes) {
1695             // CREATE
1696             Assert.assertTrue(addBridge(connectionInfo, SouthboundITConstants.BRIDGE_NAME));
1697             OvsdbBridgeAugmentation bridge = getBridge(connectionInfo);
1698             Assert.assertNotNull(bridge);
1699             NodeId nodeId = createManagedNodeId(createInstanceIdentifier(
1700                     connectionInfo, bridge.getBridgeName()));
1701             OvsdbTerminationPointAugmentationBuilder ovsdbTerminationBuilder =
1702                     createGenericOvsdbTerminationPointAugmentationBuilder();
1703             String portName = "testTerminationPointVlanMode" + vlanMode.toString();
1704             ovsdbTerminationBuilder.setName(portName);
1705             ovsdbTerminationBuilder.setVlanMode(vlanMode);
1706             Assert.assertTrue(addTerminationPoint(nodeId, portName, ovsdbTerminationBuilder));
1707             InstanceIdentifier<Node> terminationPointIid = getTpIid(connectionInfo, bridge);
1708             Node terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, terminationPointIid);
1709             Assert.assertNotNull(terminationPointNode);
1710
1711             // READ
1712             List<TerminationPoint> terminationPoints = terminationPointNode.getTerminationPoint();
1713             for (TerminationPoint terminationPoint : terminationPoints) {
1714                 OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
1715                         terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class);
1716                 if (ovsdbTerminationPointAugmentation.getName().equals(portName)) {
1717                     //test
1718                     Assert.assertTrue(ovsdbTerminationPointAugmentation.getVlanMode().equals(vlanMode));
1719                 }
1720             }
1721
1722             // UPDATE
1723             NodeId testBridgeNodeId = getBridgeNode(connectionInfo, SouthboundITConstants.BRIDGE_NAME).getNodeId();
1724             OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
1725                     new OvsdbTerminationPointAugmentationBuilder();
1726             tpUpdateAugmentationBuilder.setVlanMode(UPDATED_VLAN_MODE);
1727             InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
1728             NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
1729             NodeId portUpdateNodeId = createManagedNodeId(portIid);
1730             portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
1731             TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
1732             tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(portName)));
1733             tpUpdateBuilder.addAugmentation(
1734                     OvsdbTerminationPointAugmentation.class,
1735                     tpUpdateAugmentationBuilder.build());
1736             tpUpdateBuilder.setTpId(new TpId(portName));
1737             portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
1738             boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
1739                     portIid, portUpdateNodeBuilder.build());
1740             Assert.assertTrue(result);
1741             Thread.sleep(OVSDB_UPDATE_TIMEOUT);
1742
1743             terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, terminationPointIid);
1744             terminationPoints = terminationPointNode.getTerminationPoint();
1745             for (TerminationPoint terminationPoint : terminationPoints) {
1746                 OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
1747                         terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class);
1748                 if (ovsdbTerminationPointAugmentation.getName().equals(portName)) {
1749                     //test
1750                     Assert.assertEquals(UPDATED_VLAN_MODE, ovsdbTerminationPointAugmentation.getVlanMode());
1751                 }
1752             }
1753
1754             // DELETE
1755             Assert.assertTrue(deleteBridge(connectionInfo));
1756         }
1757         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
1758     }
1759
1760     private ArrayList<Set<Integer>> generateVlanSets() {
1761         ArrayList<Set<Integer>> vlanSets = new ArrayList<>();
1762
1763         Set<Integer> emptySet = new HashSet<>();
1764         vlanSets.add(emptySet);
1765
1766         Set<Integer> singleSet = new HashSet<>();
1767         Integer single = 2222;
1768         singleSet.add(single);
1769         vlanSets.add(singleSet);
1770
1771         Set<Integer> minMaxMiddleSet = new HashSet<>();
1772         Integer min = 0;
1773         minMaxMiddleSet.add(min);
1774         Integer max = 4095;
1775         minMaxMiddleSet.add(max);
1776         Integer minPlusOne = min + 1;
1777         minMaxMiddleSet.add(minPlusOne);
1778         Integer maxMinusOne = max - 1;
1779         minMaxMiddleSet.add(maxMinusOne);
1780         Integer middle = (max - min) / 2;
1781         minMaxMiddleSet.add(middle);
1782         vlanSets.add(minMaxMiddleSet);
1783
1784         return vlanSets;
1785     }
1786
1787     private List<Trunks> buildTrunkList(Set<Integer> trunkSet) {
1788         List<Trunks> trunkList = Lists.newArrayList();
1789         for (Integer trunk : trunkSet) {
1790             TrunksBuilder trunkBuilder = new TrunksBuilder();
1791             trunkBuilder.setTrunk(new VlanId(trunk));
1792             trunkList.add(trunkBuilder.build());
1793         }
1794         return trunkList;
1795     }
1796
1797     @Test
1798     public void testCRUDTerminationPointVlanTrunks() throws InterruptedException {
1799         final List<Trunks> UPDATED_TRUNKS = buildTrunkList(Sets.newHashSet(2011));
1800         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
1801         connectOvsdbNode(connectionInfo);
1802         Iterable<Set<Integer>> vlanSets = generateVlanSets();
1803         int testCase = 0;
1804         for (Set<Integer> vlanSet : vlanSets) {
1805             ++testCase;
1806             // CREATE
1807             Assert.assertTrue(addBridge(connectionInfo, SouthboundITConstants.BRIDGE_NAME));
1808             OvsdbBridgeAugmentation bridge = getBridge(connectionInfo);
1809             Assert.assertNotNull(bridge);
1810             NodeId nodeId = createManagedNodeId(createInstanceIdentifier(
1811                     connectionInfo, bridge.getBridgeName()));
1812             OvsdbTerminationPointAugmentationBuilder ovsdbTerminationBuilder =
1813                     createGenericOvsdbTerminationPointAugmentationBuilder();
1814             String portName = "testTerminationPointVlanTrunks" + testCase;
1815             ovsdbTerminationBuilder.setName(portName);
1816             List<Trunks> trunks = buildTrunkList(vlanSet);
1817             ovsdbTerminationBuilder.setTrunks(trunks);
1818             Assert.assertTrue(addTerminationPoint(nodeId, portName, ovsdbTerminationBuilder));
1819             InstanceIdentifier<Node> terminationPointIid = getTpIid(connectionInfo, bridge);
1820             Node terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, terminationPointIid);
1821             Assert.assertNotNull(terminationPointNode);
1822
1823             // READ
1824             List<TerminationPoint> terminationPoints = terminationPointNode.getTerminationPoint();
1825             for (TerminationPoint terminationPoint : terminationPoints) {
1826                 OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
1827                         terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class);
1828                 if (ovsdbTerminationPointAugmentation.getName().equals(portName)) {
1829                     List<Trunks> actualTrunks = ovsdbTerminationPointAugmentation.getTrunks();
1830                     for (Trunks trunk : trunks) {
1831                         Assert.assertTrue(actualTrunks.contains(trunk));
1832                     }
1833                 }
1834             }
1835
1836
1837             // UPDATE
1838             NodeId testBridgeNodeId = getBridgeNode(connectionInfo, SouthboundITConstants.BRIDGE_NAME).getNodeId();
1839             OvsdbTerminationPointAugmentationBuilder tpUpdateAugmentationBuilder =
1840                     new OvsdbTerminationPointAugmentationBuilder();
1841             tpUpdateAugmentationBuilder.setTrunks(UPDATED_TRUNKS);
1842             InstanceIdentifier<Node> portIid = SouthboundMapper.createInstanceIdentifier(testBridgeNodeId);
1843             NodeBuilder portUpdateNodeBuilder = new NodeBuilder();
1844             NodeId portUpdateNodeId = createManagedNodeId(portIid);
1845             portUpdateNodeBuilder.setNodeId(portUpdateNodeId);
1846             TerminationPointBuilder tpUpdateBuilder = new TerminationPointBuilder();
1847             tpUpdateBuilder.setKey(new TerminationPointKey(new TpId(portName)));
1848             tpUpdateBuilder.addAugmentation(
1849                     OvsdbTerminationPointAugmentation.class,
1850                     tpUpdateAugmentationBuilder.build());
1851             tpUpdateBuilder.setTpId(new TpId(portName));
1852             portUpdateNodeBuilder.setTerminationPoint(Lists.newArrayList(tpUpdateBuilder.build()));
1853             boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION,
1854                     portIid, portUpdateNodeBuilder.build());
1855             Assert.assertTrue(result);
1856             Thread.sleep(OVSDB_UPDATE_TIMEOUT);
1857
1858             terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, terminationPointIid);
1859             terminationPoints = terminationPointNode.getTerminationPoint();
1860             for (TerminationPoint terminationPoint : terminationPoints) {
1861                 OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
1862                         terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class);
1863                 if (ovsdbTerminationPointAugmentation.getName().equals(portName)) {
1864                     //test
1865                     Assert.assertEquals(UPDATED_TRUNKS, ovsdbTerminationPointAugmentation.getTrunks());
1866                 }
1867             }
1868
1869             // DELETE
1870             Assert.assertTrue(deleteBridge(connectionInfo));
1871         }
1872         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
1873     }
1874
1875     @Test
1876     public void testGetOvsdbNodes() throws InterruptedException {
1877         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
1878         connectOvsdbNode(connectionInfo);
1879         InstanceIdentifier<Topology> topologyPath = InstanceIdentifier
1880                 .create(NetworkTopology.class)
1881                 .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID));
1882
1883         Topology topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, topologyPath);
1884         InstanceIdentifier<Node> expectedNodeIid = createInstanceIdentifier(connectionInfo);
1885         NodeId expectedNodeId = expectedNodeIid.firstKeyOf(Node.class, NodeKey.class).getNodeId();
1886         Node foundNode = null;
1887         Assert.assertNotNull("Expected to find topology: " + topologyPath, topology);
1888         Assert.assertNotNull("Expected to find some nodes" + topology.getNode());
1889         LOG.info("expectedNodeId: {}, getNode: {}", expectedNodeId, topology.getNode());
1890         for (Node node : topology.getNode()) {
1891             if (node.getNodeId().getValue().equals(expectedNodeId.getValue())) {
1892                 foundNode = node;
1893                 break;
1894             }
1895         }
1896         Assert.assertNotNull("Expected to find Node: " + expectedNodeId, foundNode);
1897         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
1898     }
1899
1900     /*
1901      * Generates the test cases involved in testing BridgeOtherConfigs.  See inline comments for descriptions of
1902      * the particular cases considered.
1903      */
1904     private List<SouthboundTestCase<BridgeOtherConfigs>> generateBridgeOtherConfigsTestCases() {
1905         return generateKeyValueTestCases(new SouthboundBridgeOtherConfigsBuilder(), "BridgeOtherConfigsKey",
1906                 "BridgeOtherConfigsValue");
1907     }
1908
1909     /*
1910      * @see <code>SouthboundIT.testCRUDBridgeOtherConfigs()</code>
1911      * This is helper test method to compare a test "set" of BridgeExternalIds against an expected "set"
1912      */
1913     private void assertExpectedBridgeOtherConfigsExist( List<BridgeOtherConfigs> expected,
1914                                                         List<BridgeOtherConfigs> test ) {
1915
1916         if (expected != null) {
1917             for (BridgeOtherConfigs expectedOtherConfig : expected) {
1918                 Assert.assertTrue(test.contains(expectedOtherConfig));
1919             }
1920         }
1921     }
1922
1923     /*
1924      * @see <code>SouthboundIT.generateBridgeOtherConfigsTestCases()</code> for specific test case information.
1925      */
1926     @Test
1927     public void testCRUDBridgeOtherConfigs() throws InterruptedException {
1928         final String TEST_BRIDGE_PREFIX = "CRUDBridgeOtherConfigs";
1929         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
1930         connectOvsdbNode(connectionInfo);
1931         // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
1932         // the update has been performed.
1933         List<SouthboundTestCase<BridgeOtherConfigs>> updateFromTestCases = generateBridgeOtherConfigsTestCases();
1934         List<SouthboundTestCase<BridgeOtherConfigs>> updateToTestCases = generateBridgeOtherConfigsTestCases();
1935         String testBridgeName;
1936
1937         int counter = 1;
1938         ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
1939         for (SouthboundTestCase<BridgeOtherConfigs> fromTestCase : updateFromTestCases) {
1940             for (SouthboundTestCase<BridgeOtherConfigs> toTestCase : updateToTestCases) {
1941                 testBridgeName = String.format(FORMAT_STR, TEST_BRIDGE_PREFIX, toTestCase.name, counter);
1942                 counter += 1;
1943                 TestCRUDBridgeOtherConfigsRunnable testRunnable =
1944                         new TestCRUDBridgeOtherConfigsRunnable(
1945                                 connectionInfo, testBridgeName,
1946                                 fromTestCase.inputValues,
1947                                 fromTestCase.expectedValues,
1948                                 toTestCase.inputValues,
1949                                 toTestCase.expectedValues);
1950                 executor.submit(testRunnable);
1951             }
1952         }
1953         executor.shutdown();
1954         executor.awaitTermination(5, TimeUnit.MINUTES);
1955
1956         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
1957     }
1958
1959     class TestCRUDBridgeOtherConfigsRunnable implements Runnable {
1960
1961         ConnectionInfo connectionInfo;
1962         String testBridgeName;
1963         List<BridgeOtherConfigs> updateFromInputOtherConfigs;
1964         List<BridgeOtherConfigs> updateFromExpectedOtherConfigs;
1965         List<BridgeOtherConfigs> updateToInputOtherConfigs;
1966         List<BridgeOtherConfigs> updateToExpectedOtherConfigs;
1967
1968         TestCRUDBridgeOtherConfigsRunnable(
1969                 ConnectionInfo connectionInfo, String testBridgeName,
1970                 List<BridgeOtherConfigs> updateFromInputOtherConfigs,
1971                 List<BridgeOtherConfigs> updateFromExpectedOtherConfigs,
1972                 List<BridgeOtherConfigs> updateToInputOtherConfigs,
1973                 List<BridgeOtherConfigs> updateToExpectedOtherConfigs) {
1974
1975             this.connectionInfo = connectionInfo;
1976             this.testBridgeName = testBridgeName;
1977             this.updateFromInputOtherConfigs = updateFromInputOtherConfigs;
1978             this.updateFromExpectedOtherConfigs = updateFromExpectedOtherConfigs;
1979             this.updateToInputOtherConfigs = updateToInputOtherConfigs;
1980             this.updateToExpectedOtherConfigs = updateToExpectedOtherConfigs;
1981         }
1982
1983         @Override
1984         public void run() {
1985             try {
1986                 test();
1987             } catch (InterruptedException e) {
1988                 e.printStackTrace();
1989             }
1990         }
1991
1992         public void test() throws InterruptedException {
1993             // CREATE: Create the test bridge
1994             boolean bridgeAdded = addBridge(connectionInfo, null,
1995                     testBridgeName, null, true, SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"),
1996                     true, null, null, null, updateFromInputOtherConfigs);
1997             Assert.assertTrue(bridgeAdded);
1998
1999             // READ: Read the test bridge and ensure changes are propagated to the CONFIGURATION data store,
2000             // then repeat for OPERATIONAL data store
2001             List<BridgeOtherConfigs> updateFromConfigurationOtherConfigs = getBridge(connectionInfo, testBridgeName,
2002                     LogicalDatastoreType.CONFIGURATION).getBridgeOtherConfigs();
2003             assertExpectedBridgeOtherConfigsExist(updateFromExpectedOtherConfigs,
2004                     updateFromConfigurationOtherConfigs);
2005             List<BridgeOtherConfigs> updateFromOperationalOtherConfigs = getBridge(connectionInfo, testBridgeName)
2006                     .getBridgeOtherConfigs();
2007             assertExpectedBridgeOtherConfigsExist(updateFromExpectedOtherConfigs,
2008                     updateFromOperationalOtherConfigs);
2009
2010             // UPDATE:  update the external_ids
2011             OvsdbBridgeAugmentationBuilder bridgeAugmentationBuilder = new OvsdbBridgeAugmentationBuilder();
2012             bridgeAugmentationBuilder.setBridgeOtherConfigs(updateToInputOtherConfigs);
2013             InstanceIdentifier<Node> bridgeIid =
2014                     createInstanceIdentifier(connectionInfo,
2015                             new OvsdbBridgeName(testBridgeName));
2016             NodeBuilder bridgeNodeBuilder = new NodeBuilder();
2017             Node bridgeNode = getBridgeNode(connectionInfo, testBridgeName);
2018             bridgeNodeBuilder.setNodeId(bridgeNode.getNodeId());
2019             bridgeNodeBuilder.setKey(bridgeNode.getKey());
2020             bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, bridgeAugmentationBuilder.build());
2021             boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, bridgeIid,
2022                     bridgeNodeBuilder.build());
2023             Thread.sleep(OVSDB_UPDATE_TIMEOUT);
2024             Assert.assertTrue(result);
2025
2026             // READ: the test bridge and ensure changes are propagated to the CONFIGURATION data store,
2027             // then repeat for OPERATIONAL data store
2028             List<BridgeOtherConfigs> updateToConfigurationOtherConfigs = getBridge(connectionInfo, testBridgeName,
2029                     LogicalDatastoreType.CONFIGURATION).getBridgeOtherConfigs();
2030             assertExpectedBridgeOtherConfigsExist(updateToExpectedOtherConfigs, updateToConfigurationOtherConfigs);
2031             assertExpectedBridgeOtherConfigsExist(updateFromExpectedOtherConfigs,
2032                     updateToConfigurationOtherConfigs);
2033             List<BridgeOtherConfigs> updateToOperationalOtherConfigs = getBridge(connectionInfo, testBridgeName)
2034                     .getBridgeOtherConfigs();
2035             if (updateFromExpectedOtherConfigs != null) {
2036                 assertExpectedBridgeOtherConfigsExist(updateToExpectedOtherConfigs,
2037                         updateToOperationalOtherConfigs);
2038                 assertExpectedBridgeOtherConfigsExist(updateFromExpectedOtherConfigs,
2039                         updateToOperationalOtherConfigs);
2040             }
2041
2042             // DELETE
2043             Assert.assertTrue(deleteBridge(connectionInfo, testBridgeName));
2044         }
2045     }
2046
2047     /*
2048      * Generates the test cases involved in testing BridgeExternalIds.  See inline comments for descriptions of
2049      * the particular cases considered.
2050      */
2051     private List<SouthboundTestCase<BridgeExternalIds>> generateBridgeExternalIdsTestCases() {
2052         return generateKeyValueTestCases(new SouthboundBridgeExternalIdsBuilder(), "BridgeExternalIdsKey",
2053                 "BridgeExternalIdsValue");
2054     }
2055
2056     /*
2057      * @see <code>SouthboundIT.testCRUDBridgeExternalIds()</code>
2058      * This is helper test method to compare a test "set" of BridgeExternalIds against an expected "set"
2059      */
2060     private void assertExpectedBridgeExternalIdsExist( List<BridgeExternalIds> expected,
2061                                                        List<BridgeExternalIds> test ) {
2062
2063         if (expected != null) {
2064             for (BridgeExternalIds expectedExternalId : expected) {
2065                 Assert.assertTrue(test.contains(expectedExternalId));
2066             }
2067         }
2068     }
2069
2070     /*
2071      * @see <code>SouthboundIT.generateBridgeExternalIdsTestCases()</code> for specific test case information
2072      */
2073     @Test
2074     public void testCRUDBridgeExternalIds() throws InterruptedException {
2075         final String TEST_BRIDGE_PREFIX = "CRUDBridgeExternalIds";
2076         ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portStr);
2077         connectOvsdbNode(connectionInfo);
2078         // updateFromTestCases represent the original test case value.  updateToTestCases represent the new value after
2079         // the update has been performed.
2080         List<SouthboundTestCase<BridgeExternalIds>> updateFromTestCases = generateBridgeExternalIdsTestCases();
2081         List<SouthboundTestCase<BridgeExternalIds>> updateToTestCases = generateBridgeExternalIdsTestCases();
2082         String testBridgeName;
2083
2084         int counter = 1;
2085         ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
2086         for (SouthboundTestCase<BridgeExternalIds> fromTestCase : updateFromTestCases) {
2087             for (SouthboundTestCase<BridgeExternalIds> toTestCase : updateToTestCases) {
2088                 testBridgeName = String.format(FORMAT_STR, TEST_BRIDGE_PREFIX, toTestCase.name, counter);
2089                 counter += 1;
2090                 TestCRUDBridgeExternalIdsRunnable testRunnable =
2091                         new TestCRUDBridgeExternalIdsRunnable(
2092                                 connectionInfo, testBridgeName,
2093                                 fromTestCase.inputValues,
2094                                 fromTestCase.expectedValues,
2095                                 toTestCase.inputValues,
2096                                 toTestCase.expectedValues);
2097                 executor.submit(testRunnable);
2098             }
2099         }
2100         executor.shutdown();
2101         executor.awaitTermination(5, TimeUnit.MINUTES);
2102
2103         Assert.assertTrue(disconnectOvsdbNode(connectionInfo));
2104     }
2105
2106     class TestCRUDBridgeExternalIdsRunnable implements Runnable {
2107         ConnectionInfo connectionInfo;
2108         String testBridgeName;
2109         List<BridgeExternalIds> updateFromInputExternalIds;
2110         List<BridgeExternalIds> updateFromExpectedExternalIds;
2111         List<BridgeExternalIds> updateToInputExternalIds;
2112         List<BridgeExternalIds> updateToExpectedExternalIds;
2113
2114         TestCRUDBridgeExternalIdsRunnable(
2115                 ConnectionInfo connectionInfo, String testBridgeName,
2116                 List<BridgeExternalIds> updateFromInputExternalIds,
2117                 List<BridgeExternalIds> updateFromExpectedExternalIds,
2118                 List<BridgeExternalIds> updateToInputExternalIds,
2119                 List<BridgeExternalIds> updateToExpectedExternalIds) {
2120
2121             this.connectionInfo = connectionInfo;
2122             this.testBridgeName = testBridgeName;
2123             this.updateFromInputExternalIds = updateFromInputExternalIds;
2124             this.updateFromExpectedExternalIds = updateFromExpectedExternalIds;
2125             this.updateToInputExternalIds = updateToInputExternalIds;
2126             this.updateToExpectedExternalIds = updateToExpectedExternalIds;
2127         }
2128
2129         @Override
2130         public void run() {
2131             try {
2132                 test();
2133             } catch (InterruptedException e) {
2134                 e.printStackTrace();
2135             }
2136         }
2137
2138         public void test() throws InterruptedException {
2139             // CREATE: Create the test bridge
2140             boolean bridgeAdded = addBridge(connectionInfo, null,
2141                     testBridgeName, null, true, SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"),
2142                     true, null, updateFromInputExternalIds, null, null);
2143             Assert.assertTrue(bridgeAdded);
2144
2145             // READ: Read the test bridge and ensure changes are propagated to the CONFIGURATION data store,
2146             // then repeat for OPERATIONAL data store
2147             List<BridgeExternalIds> updateFromConfigurationExternalIds = getBridge(connectionInfo, testBridgeName,
2148                     LogicalDatastoreType.CONFIGURATION).getBridgeExternalIds();
2149             assertExpectedBridgeExternalIdsExist(updateFromExpectedExternalIds, updateFromConfigurationExternalIds);
2150             List<BridgeExternalIds> updateFromOperationalExternalIds = getBridge(connectionInfo, testBridgeName)
2151                     .getBridgeExternalIds();
2152             assertExpectedBridgeExternalIdsExist(updateFromExpectedExternalIds, updateFromOperationalExternalIds);
2153
2154             // UPDATE:  update the external_ids
2155             OvsdbBridgeAugmentationBuilder bridgeAugmentationBuilder = new OvsdbBridgeAugmentationBuilder();
2156             bridgeAugmentationBuilder.setBridgeExternalIds(updateToInputExternalIds);
2157             InstanceIdentifier<Node> bridgeIid =
2158                     createInstanceIdentifier(connectionInfo,
2159                             new OvsdbBridgeName(testBridgeName));
2160             NodeBuilder bridgeNodeBuilder = new NodeBuilder();
2161             Node bridgeNode = getBridgeNode(connectionInfo, testBridgeName);
2162             bridgeNodeBuilder.setNodeId(bridgeNode.getNodeId());
2163             bridgeNodeBuilder.setKey(bridgeNode.getKey());
2164             bridgeNodeBuilder.addAugmentation(OvsdbBridgeAugmentation.class, bridgeAugmentationBuilder.build());
2165             boolean result = mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, bridgeIid,
2166                     bridgeNodeBuilder.build());
2167             Thread.sleep(OVSDB_UPDATE_TIMEOUT);
2168             Assert.assertTrue(result);
2169
2170             // READ: the test bridge and ensure changes are propagated to the CONFIGURATION data store,
2171             // then repeat for OPERATIONAL data store
2172             List<BridgeExternalIds> updateToConfigurationExternalIds = getBridge(connectionInfo, testBridgeName,
2173                     LogicalDatastoreType.CONFIGURATION).getBridgeExternalIds();
2174             assertExpectedBridgeExternalIdsExist(updateToExpectedExternalIds, updateToConfigurationExternalIds);
2175             assertExpectedBridgeExternalIdsExist(updateFromExpectedExternalIds, updateToConfigurationExternalIds);
2176             List<BridgeExternalIds> updateToOperationalExternalIds = getBridge(connectionInfo, testBridgeName)
2177                     .getBridgeExternalIds();
2178             if (updateFromExpectedExternalIds != null) {
2179                 assertExpectedBridgeExternalIdsExist(updateToExpectedExternalIds, updateToOperationalExternalIds);
2180                 assertExpectedBridgeExternalIdsExist(updateFromExpectedExternalIds, updateToOperationalExternalIds);
2181             }
2182
2183             // DELETE
2184             Assert.assertTrue(deleteBridge(connectionInfo, testBridgeName));
2185         }
2186     }
2187
2188     public static InstanceIdentifier<Node> createInstanceIdentifier(ConnectionInfo key,OvsdbBridgeName bridgeName) {
2189         return SouthboundMapper.createInstanceIdentifier(createManagedNodeId(key, bridgeName));
2190     }
2191
2192     public static NodeId createManagedNodeId(ConnectionInfo key, OvsdbBridgeName bridgeName) {
2193         return createManagedNodeId(key.getRemoteIp(), key.getRemotePort(), bridgeName);
2194     }
2195
2196     public static NodeId createManagedNodeId(IpAddress ip, PortNumber port, OvsdbBridgeName bridgeName) {
2197         return new NodeId(createNodeId(ip,port).getValue()
2198                 + "/" + SouthboundConstants.BRIDGE_URI_PREFIX + "/" + bridgeName.getValue());
2199     }
2200
2201     public static NodeId createNodeId(IpAddress ip, PortNumber port) {
2202         String uriString = SouthboundConstants.OVSDB_URI_PREFIX + "://"
2203                 + new String(ip.getValue()) + ":" + port.getValue();
2204         Uri uri = new Uri(uriString);
2205         return new NodeId(uri);
2206     }
2207
2208     public static NodeKey createNodeKey(IpAddress ip, PortNumber port) {
2209         return new NodeKey(createNodeId(ip,port));
2210     }
2211
2212     public static Node createNode(ConnectionInfo key) {
2213         NodeBuilder nodeBuilder = new NodeBuilder();
2214         nodeBuilder.setNodeId(createNodeId(key.getRemoteIp(),key.getRemotePort()));
2215         nodeBuilder.addAugmentation(OvsdbNodeAugmentation.class, createOvsdbAugmentation(key));
2216         return nodeBuilder.build();
2217     }
2218
2219     public static OvsdbNodeAugmentation createOvsdbAugmentation(ConnectionInfo key) {
2220         OvsdbNodeAugmentationBuilder ovsdbNodeBuilder = new OvsdbNodeAugmentationBuilder();
2221         ovsdbNodeBuilder.setConnectionInfo(key);
2222         return ovsdbNodeBuilder.build();
2223     }
2224
2225     public static NodeId createManagedNodeId(InstanceIdentifier<Node> iid) {
2226         NodeKey nodeKey = iid.firstKeyOf(Node.class, NodeKey.class);
2227         return nodeKey.getNodeId();
2228     }
2229
2230     /**
2231      * <p>
2232      * Representation of a southbound test case. Each test case has a name, a list of input values and a list of
2233      * expected values. The input values are provided to the augmentation builder, and the expected values are checked
2234      * against the output of the resulting augmentation.
2235      * </p>
2236      * <p>
2237      * Instances of this class are immutable.
2238      * </p>
2239      *
2240      * @param <T> The type of data used for the test case.
2241      */
2242     private static final class SouthboundTestCase<T> {
2243         private final String name;
2244         private final List<T> inputValues;
2245         private final List<T> expectedValues;
2246
2247         /**
2248          * Creates an instance of a southbound test case.
2249          *
2250          * @param name The test case's name.
2251          * @param inputValues The input values (provided as input to the underlying augmentation builder).
2252          * @param expectedValues The expected values (checked against the output of the underlying augmentation).
2253          */
2254         public SouthboundTestCase(
2255                 final String name, final List<T> inputValues, final List<T> expectedValues) {
2256             this.name = name;
2257             this.inputValues = inputValues;
2258             this.expectedValues = expectedValues;
2259         }
2260     }
2261
2262     /**
2263      * Southbound test case builder.
2264      *
2265      * @param <T> The type of data used for the test case.
2266      */
2267     private static final class SouthboundTestCaseBuilder<T> {
2268         private String name;
2269         private List<T> inputValues;
2270         private List<T> expectedValues;
2271
2272         /**
2273          * Creates a builder. Builders may be reused, the generated immutable instances are independent of the
2274          * builders. There are no default values.
2275          */
2276         public SouthboundTestCaseBuilder() {
2277             // Nothing to do
2278         }
2279
2280         /**
2281          * Sets the test case's name.
2282          *
2283          * @param name The test case's name.
2284          * @return The builder.
2285          */
2286         public SouthboundTestCaseBuilder<T> name(final String name) {
2287             this.name = name;
2288             return this;
2289         }
2290
2291         /**
2292          * Sets the input values.
2293          *
2294          * @param inputValues The input values.
2295          * @return The builder.
2296          */
2297         @SafeVarargs
2298         public final SouthboundTestCaseBuilder<T> input(final T... inputValues) {
2299             this.inputValues = Lists.newArrayList(inputValues);
2300             return this;
2301         }
2302
2303         /**
2304          * Sets the expected output values.
2305          *
2306          * @param expectedValues The expected output values.
2307          * @return The builder.
2308          */
2309         @SafeVarargs
2310         public final SouthboundTestCaseBuilder<T> expect(final T... expectedValues) {
2311             this.expectedValues = Lists.newArrayList(expectedValues);
2312             return this;
2313         }
2314
2315         /**
2316          * Indicates that the provided input values should be expected as output values.
2317          *
2318          * @return The builder.
2319          */
2320         public SouthboundTestCaseBuilder<T> expectInputAsOutput() {
2321             this.expectedValues = this.inputValues;
2322             return this;
2323         }
2324
2325         /**
2326          * Builds an immutable instance representing the test case.
2327          *
2328          * @return The test case.
2329          */
2330         @SuppressWarnings("unchecked")
2331         public SouthboundTestCase<T> build() {
2332             return new SouthboundTestCase<>(name, inputValues, expectedValues);
2333         }
2334     }
2335 }