Do not use Foo.toString() when logging
[ovsdb.git] / library / it / src / test / java / org / opendaylight / ovsdb / integrationtest / ovsdbclient / OvsdbClientTestIT.java
1 /*
2  * Copyright © 2014, 2017 EBay Software Foundation
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.integrationtest.ovsdbclient;
9
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;
17
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;
25 import java.util.Map;
26 import java.util.Set;
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;
56
57 @RunWith(PaxExam.class)
58 @ExamReactorStrategy(PerClass.class)
59 public class OvsdbClientTestIT extends LibraryIntegrationTestBase {
60     private static final Logger LOG = LoggerFactory.getLogger(OvsdbClientTestIT.class);
61     OvsdbClient ovs;
62     DatabaseSchema dbSchema = null;
63     private static final String TEST_BRIDGE_NAME = "br-test";
64     private static UUID testBridgeUuid = null;
65
66     /**
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).
70      */
71     @Test
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);
76
77         createBridgeTransaction();
78         abortTransaction();
79         assertTransaction();
80     }
81
82     /**
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.
86      */
87     @Test
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
94     }
95
96     public void sendBridgeMonitorRequest(boolean filter) throws ExecutionException, InterruptedException, IOException {
97         assertNotNull(dbSchema);
98         GenericTableSchema bridge = dbSchema.table("Bridge", GenericTableSchema.class);
99
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);
107         if (filter) {
108             builder.addColumn(bridge.column("name"))
109                    .addColumn(bridge.column("fail_mode", String.class))
110                    .addColumn(floodVlans)
111                    .addColumn(externalIds);
112         }
113         monitorRequests.add(builder.with(new MonitorSelect(true, true, true, true))
114                                    .build());
115
116         final List<Object> results = new ArrayList<>();
117
118         TableUpdates updates = ovs.monitor(dbSchema, monitorRequests, new MonitorCallBack() {
119             @Override
120             public void update(TableUpdates result, DatabaseSchema unused) {
121                 results.add(result);
122                 LOG.info("result = {}", result);
123             }
124
125             @Override
126             public void exception(Throwable ex) {
127                 results.add(ex);
128                 LOG.warn("t = ", ex);
129             }
130         });
131         if (updates != null) {
132             results.add(updates);
133         }
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()) {
137                 break;
138             }
139             Thread.sleep(1000);
140         }
141
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)) {
151                 continue;
152             }
153             if (filter) {
154                 assertEquals(builder.getColumns().size(), row.getColumns().size());
155             } else {
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());
159             }
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);
164                     assertNotNull(data);
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);
170                     assertNotNull(data);
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"));
177                 }
178             }
179             return;
180         }
181         fail("Bridge being monitored :" + TEST_BRIDGE_NAME + " Not found");
182     }
183
184     /*
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.
187      */
188     private UUID selectOpenVSwitchTableUuid() throws ExecutionException, InterruptedException {
189         assertNotNull(dbSchema);
190         GenericTableSchema ovsTable = dbSchema.table("Open_vSwitch", GenericTableSchema.class);
191
192         ColumnSchema<GenericTableSchema, UUID> uuid = ovsTable.column("_uuid", UUID.class);
193
194         List<OperationResult> results = ovs.transactBuilder(dbSchema)
195                .add(op.select(ovsTable)
196                       .column(uuid))
197                       .execute()
198                       .get();
199
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();
205     }
206
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);
211
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);
220
221         String namedUuid = "br_test";
222         UUID parentTable = selectOpenVSwitchTableUuid();
223         TransactionBuilder transactionBuilder = ovs.transactBuilder(dbSchema)
224                  /*
225                   * Make sure that the position of insert operation matches the insertOperationIndex.
226                   * This will be used later when the Results are processed.
227                   */
228                 .add(op.insert(bridge)
229                         .withId(namedUuid)
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))
237                         .build())
238                 .add(op.select(bridge)
239                         .column(name)
240                         .column(uuid)
241                         .where(name.opEqual(TEST_BRIDGE_NAME))
242                         .build())
243                 .add(op.mutate(bridge)
244                         .addMutation(floodVlans, Mutator.INSERT, Sets.newHashSet(200,400))
245                         .where(name.opEqual(TEST_BRIDGE_NAME))
246                         .build())
247                 .add(op.mutate(bridge)
248                         .addMutation(externalIds, Mutator.INSERT, ImmutableMap.of("key2","value2"))
249                         .where(name.opEqual(TEST_BRIDGE_NAME))
250                         .build())
251                 .add(op.mutate(ovsTable)
252                         .addMutation(bridges, Mutator.INSERT, Collections.singleton(new UUID(namedUuid)))
253                         .where(uuid.opEqual(parentTable))
254                         .build())
255                 .add(op.commit(true));
256
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());
265         }
266
267         int insertOperationIndex = 0;
268         testBridgeUuid = operationResults.get(insertOperationIndex).getUuid();
269     }
270
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);
275
276         /*
277          * Adding a separate Assert operation in a transaction. Lets not mix this with other
278          * valid transactions as above.
279          */
280         ListenableFuture<List<OperationResult>> results = ovs.transactBuilder(dbSchema)
281                 .add(op.delete(bridge)
282                         .where(name.opEqual(TEST_BRIDGE_NAME))
283                         .build())
284                 .add(op.assertion("Assert12345")) // Failing intentionally
285                 .execute();
286
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);
292     }
293
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);
298
299         /*
300          * Adding a separate Abort operation in a transaction. Lets not mix this with other
301          * valid transactions as above.
302          */
303         ListenableFuture<List<OperationResult>> results = ovs.transactBuilder(dbSchema)
304                 .add(op.delete(bridge)
305                         .where(name.opEqual(TEST_BRIDGE_NAME))
306                         .build())
307                 .add(op.abort())
308                 .execute();
309
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);
315     }
316
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;
325                 break;
326             }
327         }
328         assertTrue(LibraryIntegrationTestUtils.OPEN_VSWITCH
329                 + " schema is not supported by the switch", hasOpenVswitchSchema);
330     }
331
332     @Override
333     @Before
334     public void setup() throws Exception {
335         schema = LibraryIntegrationTestUtils.OPEN_VSWITCH;
336         super.setup2();
337
338         if (ovs != null) {
339             return;
340         }
341
342         ovs = LibraryIntegrationTestUtils.getTestConnection(this);
343         assertNotNull("Failed to get connection to ovsdb node", ovs);
344         LOG.info("Connection Info: {}", ovs.getConnectionInfo());
345         testGetDBs();
346         dbSchema = ovs.getSchema(LibraryIntegrationTestUtils.OPEN_VSWITCH).get();
347     }
348
349     @After
350     public void tearDown() throws InterruptedException, ExecutionException {
351         if (dbSchema == null) {
352             return;
353         }
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();
360
361         ListenableFuture<List<OperationResult>> results = ovs.transactBuilder(dbSchema)
362                 .add(op.delete(bridge)
363                         .where(name.opEqual(TEST_BRIDGE_NAME))
364                         .build())
365                 .add(op.mutate(ovsTable)
366                         .addMutation(bridges, Mutator.DELETE, Collections.singleton(testBridgeUuid))
367                         .where(uuid.opEqual(parentTable))
368                         .build())
369                 .add(op.commit(true))
370                 .execute();
371
372         List<OperationResult> operationResults = results.get();
373         LOG.info("Delete operation results = {}", operationResults);
374         ovs.disconnect();
375     }
376 }