2 * Copyright (C) 2014 Red Hat, Inc.
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 * Authors : Sam Hague, Matt Oswalt
10 package org.opendaylight.ovsdb.integrationtest.schema.hardwarevtep;
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertNotNull;
14 import static org.junit.Assert.assertNull;
15 import static org.junit.Assert.assertTrue;
16 import static org.junit.Assert.fail;
17 import static org.junit.Assume.assumeTrue;
18 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
20 import com.google.common.collect.Lists;
21 import com.google.common.collect.Sets;
22 import com.google.common.util.concurrent.ListenableFuture;
23 import java.io.IOException;
24 import java.util.HashMap;
25 import java.util.List;
28 import java.util.concurrent.ExecutionException;
29 import javax.inject.Inject;
30 import org.junit.Assert;
31 import org.junit.Before;
32 import org.junit.Test;
33 import org.junit.runner.RunWith;
34 import org.opendaylight.ovsdb.lib.MonitorCallBack;
35 import org.opendaylight.ovsdb.lib.OvsdbClient;
36 import org.opendaylight.ovsdb.lib.it.LibraryIntegrationTestBase;
37 import org.opendaylight.ovsdb.lib.it.LibraryIntegrationTestUtils;
38 import org.opendaylight.ovsdb.lib.message.MonitorRequest;
39 import org.opendaylight.ovsdb.lib.message.MonitorRequestBuilder;
40 import org.opendaylight.ovsdb.lib.message.MonitorSelect;
41 import org.opendaylight.ovsdb.lib.message.TableUpdate;
42 import org.opendaylight.ovsdb.lib.message.TableUpdates;
43 import org.opendaylight.ovsdb.lib.notation.Mutator;
44 import org.opendaylight.ovsdb.lib.notation.Row;
45 import org.opendaylight.ovsdb.lib.notation.UUID;
46 import org.opendaylight.ovsdb.lib.operations.OperationResult;
47 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
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.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
52 import org.opendaylight.ovsdb.schema.hardwarevtep.Global;
53 import org.opendaylight.ovsdb.schema.hardwarevtep.Manager;
54 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
55 import org.ops4j.pax.exam.junit.PaxExam;
56 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
57 import org.ops4j.pax.exam.spi.reactors.PerSuite;
58 import org.osgi.framework.BundleContext;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
62 @RunWith(PaxExam.class)
63 @ExamReactorStrategy(PerSuite.class)
64 public class HardwareVTEPIT extends LibraryIntegrationTestBase {
65 private static final Logger LOG = LoggerFactory.getLogger(HardwareVTEPIT.class);
66 private static boolean monitorReady = false;
67 private static boolean schemaSupported = false;
68 private static final String ASSERT_TRANS_ERROR = "Transaction should not have errors";
69 private static final String ASSERT_TRANS_RESULT_EMPTY = "Transaction should not be empty";
70 private static final String ASSERT_TRANS_OPERATION_COUNT = "Transaction should match number of operations";
71 private static final String ASSERT_TRANS_UUID = "Transaction UUID should not be null";
72 private UUID testManagerUuid = null;
74 private static Map<String, Map<UUID, Row>> tableCache = new HashMap<>();
75 private static Map<String, Map<UUID, Row>> getTableCache () {
79 private static OvsdbClient ovsdbClient;
80 private OvsdbClient getClient () {
84 private static DatabaseSchema dbSchema;
85 private DatabaseSchema getDbSchema () {
90 private BundleContext bc;
93 public void set() throws Exception {
95 assumeTrue(LibraryIntegrationTestUtils.HARDWARE_VTEP + " is required.", checkSchema(LibraryIntegrationTestUtils.HARDWARE_VTEP));
96 assertTrue("Failed to monitor tables", monitorTables());
97 LOG.info("{} schema version = {}", LibraryIntegrationTestUtils.OPEN_VSWITCH_SCHEMA,
98 getClient().getDatabaseSchema(LibraryIntegrationTestUtils.OPEN_VSWITCH_SCHEMA).getVersion());
101 public boolean checkSchema (String schema) {
102 if (schemaSupported) {
103 LOG.info("Schema ({}) is supported", schema);
107 ovsdbClient = LibraryIntegrationTestUtils.getTestConnection(this);
108 assertNotNull("Invalid Client. Check connection params", ovsdbClient);
109 //Thread.sleep(3000); // Wait for a few seconds to get the Schema exchange done
110 if (isSchemaSupported(ovsdbClient, schema)) {
111 dbSchema = ovsdbClient.getSchema(schema).get();
112 assertNotNull(dbSchema);
113 LOG.info("{} schema in {} with tables: {}",
114 schema, ovsdbClient.getConnectionInfo(), dbSchema.getTables());
115 schemaSupported = true;
118 } catch (Exception e) {
119 fail("Exception : "+e.getMessage());
122 LOG.info("Schema ({}) is not supported", schema);
126 public UUID getOpenVSwitchTableUuid (OvsdbClient ovs, Map<String, Map<UUID, Row>> tableCache) {
127 OpenVSwitch openVSwitch = getClient().getTypedRowWrapper(OpenVSwitch.class, null);
128 Map<UUID, Row> ovsTable = tableCache.get(openVSwitch.getSchema().getName());
129 if (ovsTable != null) {
130 if (ovsTable.keySet().size() >= 1) {
131 return (UUID)ovsTable.keySet().toArray()[0];
137 public UUID getGlobalTableUuid(OvsdbClient ovs, Map<String, Map<UUID, Row>> tableCache) {
138 Global glbl = getClient().getTypedRowWrapper(Global.class, null);
139 Map<UUID, Row> glblTbl = tableCache.get(glbl.getSchema().getName());
140 if (glblTbl != null) {
141 if (glblTbl.keySet().size() >= 1) {
142 return (UUID)glblTbl.keySet().toArray()[0];
148 public boolean isSchemaSupported (OvsdbClient client, String schema) throws ExecutionException, InterruptedException {
149 ListenableFuture<List<String>> databases = client.getDatabases();
150 List<String> dbNames = databases.get();
151 assertNotNull(dbNames);
152 return dbNames.contains(schema);
156 * As per RFC 7047, section 4.1.5, if a Monitor request is sent without any columns, the update response will not include
158 * ----------------------------------------------------------------------------------------------------------------------------------
159 * Each <monitor-request> specifies one or more columns and the manner in which the columns (or the entire table) are to be monitored.
160 * The "columns" member specifies the columns whose values are monitored. It MUST NOT contain duplicates.
161 * If "columns" is omitted, all columns in the table, except for "_uuid", are monitored.
162 * ----------------------------------------------------------------------------------------------------------------------------------
163 * In order to overcome this limitation, this method
165 * @return MonitorRequest that includes all the Bridge Columns including _uuid
167 public <T extends TypedBaseTable<GenericTableSchema>> MonitorRequest<GenericTableSchema> getAllColumnsMonitorRequest (Class <T> klazz) {
168 TypedBaseTable<GenericTableSchema> table = getClient().createTypedRowWrapper(klazz);
169 GenericTableSchema tableSchema = table.getSchema();
170 Set<String> columns = tableSchema.getColumns();
171 MonitorRequestBuilder<GenericTableSchema> bridgeBuilder = MonitorRequestBuilder.builder(table.getSchema());
172 for (String column : columns) {
173 bridgeBuilder.addColumn(column);
175 return bridgeBuilder.with(new MonitorSelect(true, true, true, true)).build();
178 public <T extends TableSchema<T>> MonitorRequest<T> getAllColumnsMonitorRequest (T tableSchema) {
179 Set<String> columns = tableSchema.getColumns();
180 MonitorRequestBuilder<T> monitorBuilder = MonitorRequestBuilder.builder(tableSchema);
181 for (String column : columns) {
182 monitorBuilder.addColumn(column);
184 return monitorBuilder.with(new MonitorSelect(true, true, true, true)).build();
187 public boolean monitorTables () throws ExecutionException, InterruptedException, IOException {
189 LOG.info("Monitoring is already initialized.");
193 assertNotNull(getDbSchema());
195 List<MonitorRequest<GenericTableSchema>> monitorRequests = Lists.newArrayList();
196 Set<String> tables = getDbSchema().getTables();
197 assertNotNull("ovsdb tables should not be null", tables);
199 for (String tableName : tables) {
200 GenericTableSchema tableSchema = getDbSchema().table(tableName, GenericTableSchema.class);
201 monitorRequests.add(this.getAllColumnsMonitorRequest(tableSchema));
203 TableUpdates updates = getClient().monitor(getDbSchema(), monitorRequests, new UpdateMonitor());
204 assertNotNull(updates);
205 this.updateTableCache(updates);
208 LOG.info("Monitoring is initialized.");
212 private void updateTableCache (TableUpdates updates) {
213 for (String tableName : updates.getUpdates().keySet()) {
214 Map<UUID, Row> tUpdate = getTableCache().get(tableName);
215 TableUpdate update = updates.getUpdates().get(tableName);
216 for (UUID uuid : (Set<UUID>)update.getRows().keySet()) {
217 if (update.getNew(uuid) != null) {
218 if (tUpdate == null) {
219 tUpdate = new HashMap<>();
220 getTableCache().put(tableName, tUpdate);
222 tUpdate.put(uuid, update.getNew(uuid));
224 tUpdate.remove(uuid);
230 private class UpdateMonitor implements MonitorCallBack {
232 public void update(TableUpdates result, DatabaseSchema dbSchema) {
233 updateTableCache(result);
237 public void exception(Throwable t) {
238 LOG.error("Exception t = " + t);
242 public List<OperationResult> executeTransaction (TransactionBuilder transactionBuilder, String text)
243 throws ExecutionException, InterruptedException {
244 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
245 List<OperationResult> operationResults = results.get();
246 LOG.info("{}: {}", text, operationResults);
247 org.junit.Assert.assertFalse(ASSERT_TRANS_RESULT_EMPTY, operationResults.isEmpty());
248 assertEquals(ASSERT_TRANS_OPERATION_COUNT, transactionBuilder.getOperations().size(), operationResults.size());
249 for (OperationResult result : operationResults) {
250 assertNull(ASSERT_TRANS_ERROR, result.getError());
252 //Thread.sleep(500); // Wait for a few seconds to ensure the cache updates
253 return operationResults;
257 * Create a new manager string in addition to whatever is already there
258 * Will modify the Global table to include the UUID to the new Manager row
260 public void managerInsert () throws ExecutionException, InterruptedException {
261 //Ensure test only proceeds if HW VTEP is supported
262 assumeTrue(isSchemaSupported(getClient(), LibraryIntegrationTestUtils.HARDWARE_VTEP));
264 //proceed only if schema was already retrieved successfully
265 Assert.assertNotNull(getDbSchema());
267 //create new manager and set target string
268 Manager manager = getClient().createTypedRowWrapper(Manager.class);
269 manager.setTarget("ptcp:6641");
271 String transactionUuidStr = "foobar";
273 Global glbl = this.getClient().createTypedRowWrapper(Global.class);
274 glbl.setManagers(Sets.newHashSet(new UUID(transactionUuidStr)));
276 TransactionBuilder transactionBuilder = getClient().transactBuilder(getDbSchema())
277 .add(op.insert(manager.getSchema())
278 .withId(transactionUuidStr)
279 .value(manager.getTargetColumn()))
280 .add(op.comment("Manager: Inserting " + transactionUuidStr))
281 .add(op.mutate(glbl.getSchema())
282 .addMutation(glbl.getManagersColumn().getSchema(), Mutator.INSERT,
283 glbl.getManagersColumn().getData()))
284 .add(op.comment("Global: Mutating " + transactionUuidStr));
286 int insertOperationIndex = 0;
287 List<OperationResult> operationResults = executeTransaction(transactionBuilder,
288 "Manager: Insert and Mutate results");
289 testManagerUuid = operationResults.get(insertOperationIndex).getUuid();
290 assertNotNull(ASSERT_TRANS_UUID, testManagerUuid);
292 // Verify that the local cache was updated with the remote changes
293 Row managerRow = getTableCache().get(manager.getSchema().getName()).get(testManagerUuid);
294 Manager monitoredManager = getClient().getTypedRowWrapper(Manager.class, managerRow);
295 assertEquals(manager.getTargetColumn().getData(), monitoredManager.getTargetColumn().getData());
296 assertNotNull(monitoredManager.getUuid());
297 assertNotNull(monitoredManager.getVersion());
298 assertNotNull(getGlobalTableUuid(getClient(), getTableCache()));
301 public void managerDelete () throws ExecutionException, InterruptedException {
302 assumeTrue(isSchemaSupported(getClient(), LibraryIntegrationTestUtils.HARDWARE_VTEP));
304 Manager manager = getClient().getTypedRowWrapper(Manager.class, null);
305 Global global = getClient().getTypedRowWrapper(Global.class, null);
307 TransactionBuilder transactionBuilder = getClient().transactBuilder(getDbSchema())
308 .add(op.delete(manager.getSchema())
309 .where(manager.getUuidColumn().getSchema().opEqual(testManagerUuid))
311 .add(op.comment("Manager: Deleting " + testManagerUuid))
312 .add(op.mutate(global.getSchema())
313 .addMutation(global.getManagersColumn().getSchema(), Mutator.DELETE,
314 Sets.newHashSet(testManagerUuid)))
315 .add(op.comment("Global: Mutating " + testManagerUuid))
316 .add(op.commit(true));
318 executeTransaction(transactionBuilder, "Manager delete operation results");
322 public void testManager () throws ExecutionException, InterruptedException {