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