Merge "Speed up SouthboundIT through multi-threading test cases"
[ovsdb.git] / library / it / src / test / java / org / opendaylight / ovsdb / integrationtest / ovsdbclient / OvsdbClientTestIT.java
1 /*
2  * Copyright (C) 2014 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  * Authors : Ashwin Raveendran
9  */
10 package org.opendaylight.ovsdb.integrationtest.ovsdbclient;
11
12 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
13
14 import com.google.common.collect.ImmutableMap;
15 import com.google.common.collect.Lists;
16 import com.google.common.collect.Sets;
17 import com.google.common.util.concurrent.ListenableFuture;
18 import java.io.IOException;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22 import java.util.concurrent.ExecutionException;
23 import java.util.concurrent.TimeoutException;
24 import org.junit.After;
25 import org.junit.Assert;
26 import org.junit.Before;
27 import org.junit.Test;
28 import org.junit.runner.RunWith;
29 import org.opendaylight.ovsdb.lib.MonitorCallBack;
30 import org.opendaylight.ovsdb.lib.OvsdbClient;
31 import org.opendaylight.ovsdb.lib.it.LibraryIntegrationTestBase;
32 import org.opendaylight.ovsdb.lib.it.LibraryIntegrationTestUtils;
33 import org.opendaylight.ovsdb.lib.message.MonitorRequest;
34 import org.opendaylight.ovsdb.lib.message.MonitorRequestBuilder;
35 import org.opendaylight.ovsdb.lib.message.MonitorSelect;
36 import org.opendaylight.ovsdb.lib.message.TableUpdate;
37 import org.opendaylight.ovsdb.lib.message.TableUpdates;
38 import org.opendaylight.ovsdb.lib.notation.Column;
39 import org.opendaylight.ovsdb.lib.notation.Mutator;
40 import org.opendaylight.ovsdb.lib.notation.Row;
41 import org.opendaylight.ovsdb.lib.notation.UUID;
42 import org.opendaylight.ovsdb.lib.operations.OperationResult;
43 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
44 import org.opendaylight.ovsdb.lib.schema.ColumnSchema;
45 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
46 import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
47 import org.opendaylight.ovsdb.lib.schema.TableSchema;
48 import org.ops4j.pax.exam.junit.PaxExam;
49 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
50 import org.ops4j.pax.exam.spi.reactors.PerSuite;
51
52 @RunWith(PaxExam.class)
53 @ExamReactorStrategy(PerSuite.class)
54 public class OvsdbClientTestIT extends LibraryIntegrationTestBase {
55
56     OvsdbClient ovs;
57     DatabaseSchema dbSchema = null;
58     static String testBridgeName = "br-test";
59     static UUID testBridgeUuid = null;
60
61     /**
62      * Test general OVSDB transactions (viz., insert, select, update,
63      * mutate, comment, delete, where, commit) as well as the special
64      * transactions (viz., abort and assert)
65      */
66     @Test
67     public void testTransact() throws IOException, InterruptedException, ExecutionException {
68         Assert.assertNotNull(dbSchema);
69         TableSchema<GenericTableSchema> bridge = dbSchema.table("Bridge", GenericTableSchema.class);
70         ColumnSchema<GenericTableSchema, String> name = bridge.column("name", String.class);
71
72         createBridgeTransaction();
73         abortTransaction();
74         assertTransaction();
75     }
76
77     /**
78      * Test OVS monitor request and reply, with and without specific column filters,
79      * for the Bridge table in the OVSDB. The setup involves creating a test bridge with 5
80      * flood_vlans and 2 key-value pairs, and monitoring the DB update.
81      */
82     @Test
83     public void testMonitorRequest() throws ExecutionException, InterruptedException, IOException {
84         Assert.assertNotNull(dbSchema);
85         // Create Test Bridge before testing the Monitor operation
86         createBridgeTransaction();
87         sendBridgeMonitorRequest(true); // Test monitor request with Column filters
88         sendBridgeMonitorRequest(false); // Test monitor request without filters
89     }
90
91     public void sendBridgeMonitorRequest(boolean filter) throws ExecutionException, InterruptedException, IOException {
92         Assert.assertNotNull(dbSchema);
93         GenericTableSchema bridge = dbSchema.table("Bridge", GenericTableSchema.class);
94
95         List<MonitorRequest<GenericTableSchema>> monitorRequests = Lists.newArrayList();
96         ColumnSchema<GenericTableSchema, Set<Integer>> flood_vlans = bridge.multiValuedColumn("flood_vlans", Integer.class);
97         ColumnSchema<GenericTableSchema, Map<String, String>> externalIds = bridge.multiValuedColumn("external_ids", String.class, String.class);
98         ColumnSchema<GenericTableSchema, String> name = bridge.column("name", String.class);
99         MonitorRequestBuilder<GenericTableSchema> builder = MonitorRequestBuilder.builder(bridge);
100         if (filter) {
101             builder.addColumn(bridge.column("name"))
102                    .addColumn(bridge.column("fail_mode", String.class))
103                    .addColumn(flood_vlans)
104                    .addColumn(externalIds);
105         }
106         monitorRequests.add(builder.with(new MonitorSelect(true, true, true, true))
107                                    .build());
108
109         final List<Object> results = Lists.newArrayList();
110
111         TableUpdates updates = ovs.monitor(dbSchema, monitorRequests, new MonitorCallBack() {
112             @Override
113             public void update(TableUpdates result, DatabaseSchema dbSchema) {
114                 results.add(result);
115                 System.out.println("result = " + result);
116             }
117
118             @Override
119             public void exception(Throwable t) {
120                 results.add(t);
121                 System.out.println("t = " + t);
122             }
123         });
124         if (updates != null) {
125             results.add(updates);
126         }
127         for (int i = 0; i < 3 ; i++) { //wait 3 seconds to get a result
128             System.out.println("waiting on monitor response for Bridge Table...");
129             if (!results.isEmpty()) {
130                 break;
131             }
132             Thread.sleep(1000);
133         }
134
135         Assert.assertTrue(!results.isEmpty());
136         Object result = results.get(0);
137         Assert.assertTrue(result instanceof TableUpdates);
138         updates = (TableUpdates) result;
139         TableUpdate<GenericTableSchema> update = updates.getUpdate(bridge);
140         Assert.assertTrue(update.getRows().size() > 0);
141         for (UUID uuid : update.getRows().keySet()) {
142             Row<GenericTableSchema> aNew = update.getNew(uuid);
143             if (!aNew.getColumn(name).getData().equals(testBridgeName)) {
144                 continue;
145             }
146             if (filter) {
147                 Assert.assertEquals(builder.getColumns().size(), aNew.getColumns().size());
148             } else {
149                 // As per RFC7047, Section 4.1.5 : If "columns" is omitted, all columns in the table, except for "_uuid", are monitored.
150                 Assert.assertEquals(bridge.getColumns().size() - 1, aNew.getColumns().size());
151             }
152             for (Column<GenericTableSchema, ?> column: aNew.getColumns()) {
153                 if (column.getSchema().equals(flood_vlans)) {
154                     // Test for the 5 flood_vlans inserted in Bridge br-test in createBridgeTransaction
155                     Set<Integer> data = column.getData(flood_vlans);
156                     Assert.assertNotNull(data);
157                     Assert.assertTrue(!data.isEmpty());
158                     Assert.assertEquals(5, data.size());
159                 } else if (column.getSchema().equals(externalIds)) {
160                     // Test for the {"key", "value"} external_ids inserted in Bridge br-test in createBridgeTransaction
161                     Map<String, String> data = column.getData(externalIds);
162                     Assert.assertNotNull(data);
163                     Assert.assertNotNull(data.get("key"));
164                     Assert.assertEquals("value", data.get("key"));
165                     // Test for {"key2", "value2"} external_ids mutation-inserted in Bridge br-test in createBridgeTransaction
166                     Assert.assertNotNull(data.get("key2"));
167                     Assert.assertEquals("value2", data.get("key2"));
168                 }
169             }
170             return;
171         }
172         Assert.fail("Bridge being monitored :"+testBridgeName+" Not found");
173     }
174
175     /*
176      * TODO : selectOpenVSwitchTableUuid method isn't working as expected due to the Jackson
177      * parsing challenges on the Row object returned by the Select operation.
178      */
179     private UUID selectOpenVSwitchTableUuid() throws ExecutionException, InterruptedException {
180         Assert.assertNotNull(dbSchema);
181         GenericTableSchema ovsTable = dbSchema.table("Open_vSwitch", GenericTableSchema.class);
182
183         List<MonitorRequest<GenericTableSchema>> monitorRequests = Lists.newArrayList();
184         ColumnSchema<GenericTableSchema, UUID> _uuid = ovsTable.column("_uuid", UUID.class);
185
186         List<OperationResult> results = ovs.transactBuilder(dbSchema)
187                .add(op.select(ovsTable)
188                       .column(_uuid))
189                       .execute()
190                       .get();
191
192         Assert.assertTrue(!results.isEmpty());
193         OperationResult result = results.get(0);
194         List<Row<GenericTableSchema>> rows = result.getRows();
195         Row<GenericTableSchema> ovsTableRow = rows.get(0);
196         return ovsTableRow.getColumn(_uuid).getData();
197     }
198
199     private void createBridgeTransaction() throws IOException, InterruptedException, ExecutionException {
200         Assert.assertNotNull(dbSchema);
201         TableSchema<GenericTableSchema> bridge = dbSchema.table("Bridge", GenericTableSchema.class);
202         GenericTableSchema ovsTable = dbSchema.table("Open_vSwitch", GenericTableSchema.class);
203
204         ColumnSchema<GenericTableSchema, String> name = bridge.column("name", String.class);
205         ColumnSchema<GenericTableSchema, String> fail_mode = bridge.column("fail_mode", String.class);
206         ColumnSchema<GenericTableSchema, Set<Integer>> flood_vlans = bridge.multiValuedColumn("flood_vlans", Integer.class);
207         ColumnSchema<GenericTableSchema, Map<String, String>> externalIds = bridge.multiValuedColumn("external_ids", String.class, String.class);
208         ColumnSchema<GenericTableSchema, Set<UUID>> bridges = ovsTable.multiValuedColumn("bridges", UUID.class);
209         ColumnSchema<GenericTableSchema, UUID> _uuid = ovsTable.column("_uuid", UUID.class);
210
211         String namedUuid = "br_test";
212         int insertOperationIndex = 0;
213         UUID parentTable = selectOpenVSwitchTableUuid();
214         TransactionBuilder transactionBuilder = ovs.transactBuilder(dbSchema)
215                  /*
216                   * Make sure that the position of insert operation matches the insertOperationIndex.
217                   * This will be used later when the Results are processed.
218                   */
219                 .add(op.insert(bridge)
220                         .withId(namedUuid)
221                         .value(name, testBridgeName)
222                         .value(flood_vlans, Sets.newHashSet(100, 101, 4001))
223                         .value(externalIds, ImmutableMap.of("key","value")))
224                 .add(op.comment("Inserting Bridge br-int"))
225                 .add(op.update(bridge)
226                         .set(fail_mode, "secure")
227                         .where(name.opEqual(testBridgeName))
228                         .build())
229                 .add(op.select(bridge)
230                         .column(name)
231                         .column(_uuid)
232                         .where(name.opEqual(testBridgeName))
233                         .build())
234                 .add(op.mutate(bridge)
235                         .addMutation(flood_vlans, Mutator.INSERT, Sets.newHashSet(200,400))
236                         .where(name.opEqual(testBridgeName))
237                         .build())
238                 .add(op.mutate(bridge)
239                         .addMutation(externalIds, Mutator.INSERT, ImmutableMap.of("key2","value2"))
240                         .where(name.opEqual(testBridgeName))
241                         .build())
242                 .add(op.mutate(ovsTable)
243                         .addMutation(bridges, Mutator.INSERT, Sets.newHashSet(new UUID(namedUuid)))
244                         .where(_uuid.opEqual(parentTable))
245                         .build())
246                 .add(op.commit(true));
247
248         ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
249         List<OperationResult> operationResults = results.get();
250         Assert.assertFalse(operationResults.isEmpty());
251         // Check if Results matches the number of operations in transaction
252         Assert.assertEquals(transactionBuilder.getOperations().size(), operationResults.size());
253         System.out.println("Insert & Update operation results = " + operationResults);
254         for (OperationResult result : operationResults) {
255             Assert.assertNull(result.getError());
256         }
257         testBridgeUuid = operationResults.get(insertOperationIndex).getUuid();
258     }
259
260     private void assertTransaction() throws InterruptedException, ExecutionException {
261         Assert.assertNotNull(dbSchema);
262         TableSchema<GenericTableSchema> bridge = dbSchema.table("Bridge", GenericTableSchema.class);
263         ColumnSchema<GenericTableSchema, String> name = bridge.column("name", String.class);
264
265         /*
266          * Adding a separate Assert operation in a transaction. Lets not mix this with other
267          * valid transactions as above.
268          */
269         ListenableFuture<List<OperationResult>> results = ovs.transactBuilder(dbSchema)
270                 .add(op.delete(bridge)
271                         .where(name.opEqual(testBridgeName))
272                         .build())
273                 .add(op.assertion("Assert12345")) // Failing intentionally
274                 .execute();
275
276         List<OperationResult> operationResults = results.get();
277         Assert.assertFalse(operationResults.isEmpty());
278         /* Testing for an Assertion Error */
279         Assert.assertFalse(operationResults.get(1).getError() == null);
280         System.out.println("Assert operation results = " + operationResults);
281     }
282
283     private void abortTransaction() throws InterruptedException, ExecutionException {
284         Assert.assertNotNull(dbSchema);
285         TableSchema<GenericTableSchema> bridge = dbSchema.table("Bridge", GenericTableSchema.class);
286         ColumnSchema<GenericTableSchema, String> name = bridge.column("name", String.class);
287
288         /*
289          * Adding a separate Abort operation in a transaction. Lets not mix this with other
290          * valid transactions as above.
291          */
292         ListenableFuture<List<OperationResult>> results = ovs.transactBuilder(dbSchema)
293                 .add(op.delete(bridge)
294                         .where(name.opEqual(testBridgeName))
295                         .build())
296                 .add(op.abort())
297                 .execute();
298
299         List<OperationResult> operationResults = results.get();
300         Assert.assertFalse(operationResults.isEmpty());
301         /* Testing for Abort Error */
302         Assert.assertFalse(operationResults.get(1).getError() == null);
303         System.out.println("Abort operation results = " + operationResults);
304     }
305
306     public void testGetDBs() throws ExecutionException, InterruptedException {
307         ListenableFuture<List<String>> databases = ovs.getDatabases();
308         List<String> dbNames = databases.get();
309         Assert.assertNotNull(dbNames);
310         boolean hasOpenVswitchSchema = false;
311         for(String dbName : dbNames) {
312            if (dbName.equals(LibraryIntegrationTestUtils.OPEN_VSWITCH_SCHEMA)) {
313                 hasOpenVswitchSchema = true;
314                 break;
315            }
316         }
317         Assert.assertTrue(LibraryIntegrationTestUtils.OPEN_VSWITCH_SCHEMA
318                 + " schema is not supported by the switch", hasOpenVswitchSchema);
319     }
320
321     @Before
322     public  void setUp() throws IOException, ExecutionException, InterruptedException, TimeoutException {
323         if (ovs != null) {
324             return;
325         }
326
327         ovs = LibraryIntegrationTestUtils.getTestConnection(this);
328         System.out.println("Connection Info :" + ovs.getConnectionInfo().toString());
329         testGetDBs();
330         dbSchema = ovs.getSchema(LibraryIntegrationTestUtils.OPEN_VSWITCH_SCHEMA).get();
331     }
332
333     @After
334     public void tearDown() throws InterruptedException, ExecutionException {
335         if (dbSchema == null) {
336             return;
337         }
338         TableSchema<GenericTableSchema> bridge = dbSchema.table("Bridge", GenericTableSchema.class);
339         ColumnSchema<GenericTableSchema, String> name = bridge.column("name", String.class);
340         GenericTableSchema ovsTable = dbSchema.table("Open_vSwitch", GenericTableSchema.class);
341         ColumnSchema<GenericTableSchema, Set<UUID>> bridges = ovsTable.multiValuedColumn("bridges", UUID.class);
342         ColumnSchema<GenericTableSchema, UUID> _uuid = ovsTable.column("_uuid", UUID.class);
343         UUID parentTable = selectOpenVSwitchTableUuid();
344
345         ListenableFuture<List<OperationResult>> results = ovs.transactBuilder(dbSchema)
346                 .add(op.delete(bridge)
347                         .where(name.opEqual(testBridgeName))
348                         .build())
349                 .add(op.mutate(ovsTable)
350                         .addMutation(bridges, Mutator.DELETE, Sets.newHashSet(testBridgeUuid))
351                         .where(_uuid.opEqual(parentTable))
352                         .build())
353                 .add(op.commit(true))
354                 .execute();
355
356         List<OperationResult> operationResults = results.get();
357         System.out.println("Delete operation results = " + operationResults);
358         ovs.disconnect();
359     }
360 }