2 * Copyright © 2014, 2017 EBay Software Foundation
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
8 package org.opendaylight.ovsdb.integrationtest.ovsdbclient;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.assertTrue;
15 import static org.junit.Assert.fail;
16 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
18 import com.google.common.collect.ImmutableMap;
19 import com.google.common.collect.Sets;
20 import com.google.common.util.concurrent.ListenableFuture;
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.List;
27 import java.util.concurrent.ExecutionException;
28 import org.junit.After;
29 import org.junit.Before;
30 import org.junit.Test;
31 import org.junit.runner.RunWith;
32 import org.opendaylight.ovsdb.lib.MonitorCallBack;
33 import org.opendaylight.ovsdb.lib.OvsdbClient;
34 import org.opendaylight.ovsdb.lib.it.LibraryIntegrationTestBase;
35 import org.opendaylight.ovsdb.lib.it.LibraryIntegrationTestUtils;
36 import org.opendaylight.ovsdb.lib.message.MonitorRequest;
37 import org.opendaylight.ovsdb.lib.message.MonitorRequestBuilder;
38 import org.opendaylight.ovsdb.lib.message.MonitorSelect;
39 import org.opendaylight.ovsdb.lib.message.TableUpdate;
40 import org.opendaylight.ovsdb.lib.message.TableUpdates;
41 import org.opendaylight.ovsdb.lib.notation.Column;
42 import org.opendaylight.ovsdb.lib.notation.Mutator;
43 import org.opendaylight.ovsdb.lib.notation.Row;
44 import org.opendaylight.ovsdb.lib.notation.UUID;
45 import org.opendaylight.ovsdb.lib.operations.OperationResult;
46 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
47 import org.opendaylight.ovsdb.lib.schema.ColumnSchema;
48 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
49 import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
50 import org.opendaylight.ovsdb.lib.schema.TableSchema;
51 import org.ops4j.pax.exam.junit.PaxExam;
52 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
53 import org.ops4j.pax.exam.spi.reactors.PerClass;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
57 @RunWith(PaxExam.class)
58 @ExamReactorStrategy(PerClass.class)
59 public class OvsdbClientTestIT extends LibraryIntegrationTestBase {
60 private static final Logger LOG = LoggerFactory.getLogger(OvsdbClientTestIT.class);
62 DatabaseSchema dbSchema = null;
63 private static final String TEST_BRIDGE_NAME = "br-test";
64 private static UUID testBridgeUuid = null;
67 * Test general OVSDB transactions (viz., insert, select, update,
68 * mutate, comment, delete, where, commit) as well as the special
69 * transactions (viz., abort and assert).
72 public void testTransact() throws IOException, InterruptedException, ExecutionException {
73 assertNotNull(dbSchema);
74 TableSchema<GenericTableSchema> bridge = dbSchema.table("Bridge", GenericTableSchema.class);
75 bridge.column("name", String.class);
77 createBridgeTransaction();
83 * Test OVS monitor request and reply, with and without specific column filters,
84 * for the Bridge table in the OVSDB. The setup involves creating a test bridge with 5
85 * flood_vlans and 2 key-value pairs, and monitoring the DB update.
88 public void testMonitorRequest() throws ExecutionException, InterruptedException, IOException {
89 assertNotNull(dbSchema);
90 // Create Test Bridge before testing the Monitor operation
91 createBridgeTransaction();
92 sendBridgeMonitorRequest(true); // Test monitor request with Column filters
93 sendBridgeMonitorRequest(false); // Test monitor request without filters
96 public void sendBridgeMonitorRequest(boolean filter) throws ExecutionException, InterruptedException, IOException {
97 assertNotNull(dbSchema);
98 GenericTableSchema bridge = dbSchema.table("Bridge", GenericTableSchema.class);
100 List<MonitorRequest> monitorRequests = new ArrayList<>();
101 ColumnSchema<GenericTableSchema, Set<Integer>> floodVlans =
102 bridge.multiValuedColumn("flood_vlans", Integer.class);
103 ColumnSchema<GenericTableSchema, Map<String, String>> externalIds =
104 bridge.multiValuedColumn("external_ids", String.class, String.class);
105 ColumnSchema<GenericTableSchema, String> name = bridge.column("name", String.class);
106 MonitorRequestBuilder<GenericTableSchema> builder = new MonitorRequestBuilder<>(bridge);
108 builder.addColumn(bridge.column("name"))
109 .addColumn(bridge.column("fail_mode", String.class))
110 .addColumn(floodVlans)
111 .addColumn(externalIds);
113 monitorRequests.add(builder.with(new MonitorSelect(true, true, true, true))
116 final List<Object> results = new ArrayList<>();
118 TableUpdates updates = ovs.monitor(dbSchema, monitorRequests, new MonitorCallBack() {
120 public void update(TableUpdates result, DatabaseSchema unused) {
122 LOG.info("result = {}", result);
126 public void exception(Throwable ex) {
128 LOG.warn("t = ", ex);
131 if (updates != null) {
132 results.add(updates);
134 for (int i = 0; i < 3 ; i++) { //wait 3 seconds to get a result
135 LOG.info("waiting on monitor response for Bridge Table...");
136 if (!results.isEmpty()) {
142 assertTrue(!results.isEmpty());
143 Object result = results.get(0);
144 assertTrue(result instanceof TableUpdates);
145 updates = (TableUpdates) result;
146 TableUpdate<GenericTableSchema> update = updates.getUpdate(bridge);
147 assertTrue(update.getRows().size() > 0);
148 for (UUID uuid : update.getRows().keySet()) {
149 Row<GenericTableSchema> row = update.getNew(uuid);
150 if (!row.getColumn(name).getData().equals(TEST_BRIDGE_NAME)) {
154 assertEquals(builder.getColumns().size(), row.getColumns().size());
156 // As per RFC7047, Section 4.1.5 : If "columns" is omitted, all columns in the table, except
157 // for "_uuid", are monitored.
158 assertEquals(bridge.getColumns().size() - 1, row.getColumns().size());
160 for (Column<GenericTableSchema, ?> column: row.getColumns()) {
161 if (column.getSchema().equals(floodVlans)) {
162 // Test for the 5 flood_vlans inserted in Bridge br-test in createBridgeTransaction
163 Set<Integer> data = column.getData(floodVlans);
165 assertTrue(!data.isEmpty());
166 assertEquals(5, data.size());
167 } else if (column.getSchema().equals(externalIds)) {
168 // Test for the {"key", "value"} external_ids inserted in Bridge br-test in createBridgeTransaction
169 Map<String, String> data = column.getData(externalIds);
171 assertNotNull(data.get("key"));
172 assertEquals("value", data.get("key"));
173 // Test for {"key2", "value2"} external_ids mutation-inserted in Bridge br-test in
174 // createBridgeTransaction
175 assertNotNull(data.get("key2"));
176 assertEquals("value2", data.get("key2"));
181 fail("Bridge being monitored :" + TEST_BRIDGE_NAME + " Not found");
185 * TODO : selectOpenVSwitchTableUuid method isn't working as expected due to the Jackson
186 * parsing challenges on the Row object returned by the Select operation.
188 private UUID selectOpenVSwitchTableUuid() throws ExecutionException, InterruptedException {
189 assertNotNull(dbSchema);
190 GenericTableSchema ovsTable = dbSchema.table("Open_vSwitch", GenericTableSchema.class);
192 ColumnSchema<GenericTableSchema, UUID> uuid = ovsTable.column("_uuid", UUID.class);
194 List<OperationResult> results = ovs.transactBuilder(dbSchema)
195 .add(op.select(ovsTable)
200 assertTrue(!results.isEmpty());
201 OperationResult result = results.get(0);
202 List<Row<GenericTableSchema>> rows = result.getRows();
203 Row<GenericTableSchema> ovsTableRow = rows.get(0);
204 return ovsTableRow.getColumn(uuid).getData();
207 private void createBridgeTransaction() throws IOException, InterruptedException, ExecutionException {
208 assertNotNull(dbSchema);
209 TableSchema<GenericTableSchema> bridge = dbSchema.table("Bridge", GenericTableSchema.class);
210 GenericTableSchema ovsTable = dbSchema.table("Open_vSwitch", GenericTableSchema.class);
212 ColumnSchema<GenericTableSchema, String> name = bridge.column("name", String.class);
213 ColumnSchema<GenericTableSchema, String> failMode = bridge.column("fail_mode", String.class);
214 ColumnSchema<GenericTableSchema, Set<Integer>> floodVlans =
215 bridge.multiValuedColumn("flood_vlans", Integer.class);
216 ColumnSchema<GenericTableSchema, Map<String, String>> externalIds =
217 bridge.multiValuedColumn("external_ids", String.class, String.class);
218 ColumnSchema<GenericTableSchema, Set<UUID>> bridges = ovsTable.multiValuedColumn("bridges", UUID.class);
219 ColumnSchema<GenericTableSchema, UUID> uuid = ovsTable.column("_uuid", UUID.class);
221 String namedUuid = "br_test";
222 UUID parentTable = selectOpenVSwitchTableUuid();
223 TransactionBuilder transactionBuilder = ovs.transactBuilder(dbSchema)
225 * Make sure that the position of insert operation matches the insertOperationIndex.
226 * This will be used later when the Results are processed.
228 .add(op.insert(bridge)
230 .value(name, TEST_BRIDGE_NAME)
231 .value(floodVlans, Sets.newHashSet(100, 101, 4001))
232 .value(externalIds, ImmutableMap.of("key","value")))
233 .add(op.comment("Inserting Bridge br-int"))
234 .add(op.update(bridge)
235 .set(failMode, "secure")
236 .where(name.opEqual(TEST_BRIDGE_NAME))
238 .add(op.select(bridge)
241 .where(name.opEqual(TEST_BRIDGE_NAME))
243 .add(op.mutate(bridge)
244 .addMutation(floodVlans, Mutator.INSERT, Sets.newHashSet(200,400))
245 .where(name.opEqual(TEST_BRIDGE_NAME))
247 .add(op.mutate(bridge)
248 .addMutation(externalIds, Mutator.INSERT, ImmutableMap.of("key2","value2"))
249 .where(name.opEqual(TEST_BRIDGE_NAME))
251 .add(op.mutate(ovsTable)
252 .addMutation(bridges, Mutator.INSERT, Collections.singleton(new UUID(namedUuid)))
253 .where(uuid.opEqual(parentTable))
255 .add(op.commit(true));
257 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
258 List<OperationResult> operationResults = results.get();
259 assertFalse(operationResults.isEmpty());
260 // Check if Results matches the number of operations in transaction
261 assertEquals(transactionBuilder.getOperations().size(), operationResults.size());
262 LOG.info("Insert & Update operation results = {}", operationResults);
263 for (OperationResult result : operationResults) {
264 assertNull(result.getError());
267 int insertOperationIndex = 0;
268 testBridgeUuid = operationResults.get(insertOperationIndex).getUuid();
271 private void assertTransaction() throws InterruptedException, ExecutionException {
272 assertNotNull(dbSchema);
273 TableSchema<GenericTableSchema> bridge = dbSchema.table("Bridge", GenericTableSchema.class);
274 ColumnSchema<GenericTableSchema, String> name = bridge.column("name", String.class);
277 * Adding a separate Assert operation in a transaction. Lets not mix this with other
278 * valid transactions as above.
280 ListenableFuture<List<OperationResult>> results = ovs.transactBuilder(dbSchema)
281 .add(op.delete(bridge)
282 .where(name.opEqual(TEST_BRIDGE_NAME))
284 .add(op.assertion("Assert12345")) // Failing intentionally
287 List<OperationResult> operationResults = results.get();
288 assertFalse(operationResults.isEmpty());
289 /* Testing for an Assertion Error */
290 assertFalse(operationResults.get(1).getError() == null);
291 LOG.info("Assert operation results = {}", operationResults);
294 private void abortTransaction() throws InterruptedException, ExecutionException {
295 assertNotNull(dbSchema);
296 TableSchema<GenericTableSchema> bridge = dbSchema.table("Bridge", GenericTableSchema.class);
297 ColumnSchema<GenericTableSchema, String> name = bridge.column("name", String.class);
300 * Adding a separate Abort operation in a transaction. Lets not mix this with other
301 * valid transactions as above.
303 ListenableFuture<List<OperationResult>> results = ovs.transactBuilder(dbSchema)
304 .add(op.delete(bridge)
305 .where(name.opEqual(TEST_BRIDGE_NAME))
310 List<OperationResult> operationResults = results.get();
311 assertFalse(operationResults.isEmpty());
312 /* Testing for Abort Error */
313 assertFalse(operationResults.get(1).getError() == null);
314 LOG.info("Abort operation results = {}", operationResults);
317 public void testGetDBs() throws ExecutionException, InterruptedException {
318 ListenableFuture<List<String>> databases = ovs.getDatabases();
319 List<String> dbNames = databases.get();
320 assertNotNull(dbNames);
321 boolean hasOpenVswitchSchema = false;
322 for (String dbName : dbNames) {
323 if (dbName.equals(LibraryIntegrationTestUtils.OPEN_VSWITCH)) {
324 hasOpenVswitchSchema = true;
328 assertTrue(LibraryIntegrationTestUtils.OPEN_VSWITCH
329 + " schema is not supported by the switch", hasOpenVswitchSchema);
334 public void setup() throws Exception {
335 schema = LibraryIntegrationTestUtils.OPEN_VSWITCH;
342 ovs = LibraryIntegrationTestUtils.getTestConnection(this);
343 assertNotNull("Failed to get connection to ovsdb node", ovs);
344 LOG.info("Connection Info: {}", ovs.getConnectionInfo());
346 dbSchema = ovs.getSchema(LibraryIntegrationTestUtils.OPEN_VSWITCH).get();
350 public void tearDown() throws InterruptedException, ExecutionException {
351 if (dbSchema == null) {
354 TableSchema<GenericTableSchema> bridge = dbSchema.table("Bridge", GenericTableSchema.class);
355 ColumnSchema<GenericTableSchema, String> name = bridge.column("name", String.class);
356 GenericTableSchema ovsTable = dbSchema.table("Open_vSwitch", GenericTableSchema.class);
357 ColumnSchema<GenericTableSchema, Set<UUID>> bridges = ovsTable.multiValuedColumn("bridges", UUID.class);
358 ColumnSchema<GenericTableSchema, UUID> uuid = ovsTable.column("_uuid", UUID.class);
359 UUID parentTable = selectOpenVSwitchTableUuid();
361 ListenableFuture<List<OperationResult>> results = ovs.transactBuilder(dbSchema)
362 .add(op.delete(bridge)
363 .where(name.opEqual(TEST_BRIDGE_NAME))
365 .add(op.mutate(ovsTable)
366 .addMutation(bridges, Mutator.DELETE, Collections.singleton(testBridgeUuid))
367 .where(uuid.opEqual(parentTable))
369 .add(op.commit(true))
372 List<OperationResult> operationResults = results.get();
373 LOG.info("Delete operation results = {}", operationResults);