2 * Copyright © 2015, 2017 Red Hat, Inc. and others. All rights reserved.
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
9 package org.opendaylight.ovsdb.lib.it;
11 import static org.junit.Assert.assertEquals;
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.Assume.assumeTrue;
16 import static org.ops4j.pax.exam.CoreOptions.composite;
17 import static org.ops4j.pax.exam.CoreOptions.maven;
18 import static org.ops4j.pax.exam.CoreOptions.propagateSystemProperties;
19 import static org.ops4j.pax.exam.CoreOptions.vmOption;
20 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
21 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
23 import com.google.common.util.concurrent.ListenableFuture;
24 import java.io.IOException;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.List;
30 import java.util.concurrent.ExecutionException;
31 import java.util.concurrent.TimeoutException;
32 import java.util.concurrent.atomic.AtomicBoolean;
33 import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
34 import org.opendaylight.ovsdb.lib.MonitorCallBack;
35 import org.opendaylight.ovsdb.lib.OvsdbClient;
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.Row;
42 import org.opendaylight.ovsdb.lib.notation.UUID;
43 import org.opendaylight.ovsdb.lib.notation.Version;
44 import org.opendaylight.ovsdb.lib.operations.OperationResult;
45 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
46 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
47 import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
48 import org.opendaylight.ovsdb.lib.schema.TableSchema;
49 import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
50 import org.ops4j.pax.exam.Configuration;
51 import org.ops4j.pax.exam.Option;
52 import org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel;
53 import org.ops4j.pax.exam.options.MavenUrlReference;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
58 * Base class for library IT.
60 public abstract class LibraryIntegrationTestBase extends AbstractMdsalTestBase {
61 private static final Logger LOG = LoggerFactory.getLogger(LibraryIntegrationTestBase.class);
62 protected static final String ASSERT_TRANS_ERROR = "Transaction should not have errors";
63 protected static final String ASSERT_TRANS_RESULT_EMPTY = "Transaction should not be empty";
64 protected static final String ASSERT_TRANS_OPERATION_COUNT = "Transaction should match number of operations";
65 protected static final String ASSERT_TRANS_UUID = "Transaction UUID should not be null";
66 protected static Version schemaVersion;
67 protected static DatabaseSchema dbSchema;
68 private static boolean schemaSupported = false;
69 private static AtomicBoolean setup = new AtomicBoolean(false);
70 protected static OvsdbClient ovsdbClient;
71 private static Map<String, Map<UUID, Row>> tableCache = new HashMap<>();
72 private static boolean monitorReady = false;
75 protected static Map<String, Map<UUID, Row>> getTableCache() {
79 protected OvsdbClient getClient() {
83 protected DatabaseSchema getDbSchema() {
87 protected static boolean getSetup() {
91 protected static void setSetup(boolean setup) {
92 LibraryIntegrationTestBase.setup.set(setup);
96 public MavenUrlReference getFeatureRepo() {
98 .groupId("org.opendaylight.ovsdb")
99 .artifactId("library-features")
100 .classifier("features")
102 .versionAsInProject();
106 public String getFeatureName() {
107 return "odl-ovsdb-library";
112 public Option[] config() {
113 Option[] parentOptions = super.config();
114 Option[] propertiesOptions = getPropertiesOptions();
115 Option[] otherOptions = getOtherOptions();
116 Option[] options = new Option[parentOptions.length + propertiesOptions.length + otherOptions.length];
117 System.arraycopy(parentOptions, 0, options, 0, parentOptions.length);
118 System.arraycopy(propertiesOptions, 0, options, parentOptions.length, propertiesOptions.length);
119 System.arraycopy(otherOptions, 0, options, parentOptions.length + propertiesOptions.length,
120 otherOptions.length);
124 private Option[] getOtherOptions() {
125 return new Option[] {
126 vmOption("-javaagent:../jars/org.jacoco.agent.jar=destfile=../../jacoco-it.exec"),
131 public Option[] getPropertiesOptions() {
132 return new Option[] {
133 propagateSystemProperties(
134 LibraryIntegrationTestUtils.SERVER_IPADDRESS,
135 LibraryIntegrationTestUtils.SERVER_PORT,
136 LibraryIntegrationTestUtils.CONNECTION_TYPE),
141 public Option getLoggingOption() {
142 Option option = editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
143 "log4j2.logger.library-it.name",
144 getClass().getPackage().getName());
145 option = composite(option, editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
146 "log4j2.logger.library-it.level",
147 LogLevel.INFO.name()));
148 option = composite(option, super.getLoggingOption());
152 public boolean checkSchema(String schemaStr)
153 throws IOException, InterruptedException, ExecutionException, TimeoutException {
154 if (schemaSupported) {
155 LOG.info("Schema ({}) is supported", schemaStr);
159 ovsdbClient = LibraryIntegrationTestUtils.getTestConnection(this);
160 assertNotNull("Invalid Client. Check connection params", ovsdbClient);
161 if (isSchemaSupported(ovsdbClient, schemaStr)) {
162 dbSchema = ovsdbClient.getSchema(schemaStr).get();
163 assertNotNull(dbSchema);
164 LOG.info("{} schema in {} with tables: {}",
165 schemaStr, ovsdbClient.getConnectionInfo(), dbSchema.getTables());
166 schemaSupported = true;
170 LOG.info("Schema ({}) is not supported", schemaStr);
174 public boolean isSchemaSupported(String schemaStr) throws ExecutionException,
175 InterruptedException {
176 return isSchemaSupported(ovsdbClient, schemaStr);
179 public boolean isSchemaSupported(OvsdbClient client, String schemaStr)
180 throws ExecutionException, InterruptedException {
181 ListenableFuture<List<String>> databases = client.getDatabases();
182 List<String> dbNames = databases.get();
183 assertNotNull(dbNames);
184 return dbNames.contains(schemaStr);
188 * As per RFC 7047, section 4.1.5, if a Monitor request is sent without any columns, the update response will
189 * not include the _uuid column.
190 * ---------------------------------------------------------------------------------------------------------------
191 * Each <monitor-request> specifies one or more columns and the manner in which the columns (or the entire
192 * table) are to be monitored. The "columns" member specifies the columns whose values are monitored. It MUST NOT
193 * contain duplicates. If "columns" is omitted, all columns in the table, except for "_uuid", are monitored.
194 * ---------------------------------------------------------------------------------------------------------------
195 * In order to overcome this limitation, this method
197 * @return MonitorRequest that includes all the Bridge Columns including _uuid
199 public <T extends TypedBaseTable<GenericTableSchema>> MonitorRequest getAllColumnsMonitorRequest(Class<T> klazz) {
200 TypedBaseTable<GenericTableSchema> table = getClient().createTypedRowWrapper(klazz);
201 GenericTableSchema tableSchema = table.getSchema();
202 Set<String> columns = tableSchema.getColumns();
203 MonitorRequestBuilder<GenericTableSchema> bridgeBuilder = new MonitorRequestBuilder<>(table.getSchema());
204 for (String column : columns) {
205 bridgeBuilder.addColumn(column);
207 return bridgeBuilder.with(new MonitorSelect(true, true, true, true)).build();
210 public <T extends TableSchema<T>> MonitorRequest getAllColumnsMonitorRequest(T tableSchema) {
211 Set<String> columns = tableSchema.getColumns();
212 MonitorRequestBuilder<T> monitorBuilder = new MonitorRequestBuilder<>(tableSchema);
213 for (String column : columns) {
214 monitorBuilder.addColumn(column);
216 return monitorBuilder.with(new MonitorSelect(true, true, true, true)).build();
219 public boolean monitorTables() throws ExecutionException, InterruptedException, IOException {
221 LOG.info("Monitoring is already initialized.");
225 assertNotNull(getDbSchema());
227 List<MonitorRequest> monitorRequests = new ArrayList<>();
228 Set<String> tables = getDbSchema().getTables();
229 assertNotNull("ovsdb tables should not be null", tables);
231 for (String tableName : tables) {
232 GenericTableSchema tableSchema = getDbSchema().table(tableName, GenericTableSchema.class);
233 monitorRequests.add(this.getAllColumnsMonitorRequest(tableSchema));
235 TableUpdates updates = getClient().monitor(getDbSchema(), monitorRequests, new UpdateMonitor());
236 assertNotNull(updates);
237 this.updateTableCache(updates);
240 LOG.info("Monitoring is initialized.");
244 @SuppressWarnings("unchecked")
245 protected void updateTableCache(TableUpdates updates) {
246 for (String tableName : updates.getUpdates().keySet()) {
247 Map<UUID, Row> rowUpdates = getTableCache().get(tableName);
248 TableUpdate update = updates.getUpdates().get(tableName);
249 for (UUID uuid : (Set<UUID>)update.getRows().keySet()) {
250 if (update.getNew(uuid) != null) {
251 if (rowUpdates == null) {
252 rowUpdates = new HashMap<>();
253 getTableCache().put(tableName, rowUpdates);
255 rowUpdates.put(uuid, update.getNew(uuid));
257 rowUpdates.remove(uuid);
263 public List<OperationResult> executeTransaction(TransactionBuilder transactionBuilder, String text)
264 throws ExecutionException, InterruptedException {
265 ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
266 List<OperationResult> operationResults = results.get();
267 LOG.info("{}: {}", text, operationResults);
268 org.junit.Assert.assertFalse(ASSERT_TRANS_RESULT_EMPTY, operationResults.isEmpty());
269 assertEquals(ASSERT_TRANS_OPERATION_COUNT, transactionBuilder.getOperations().size(), operationResults.size());
270 for (OperationResult result : operationResults) {
271 assertNull(ASSERT_TRANS_ERROR, result.getError());
273 //Thread.sleep(500); // Wait for a few seconds to ensure the cache updates
274 return operationResults;
278 public void setup() throws Exception {
280 LOG.info("Skipping setUp, already initialized");
286 if (schema.equals(LibraryIntegrationTestUtils.OPEN_VSWITCH)) {
287 assertTrue(schema + " is required.", checkSchema(schema));
289 assumeTrue(schema + " is required.", checkSchema(schema));
291 schemaVersion = getClient().getDatabaseSchema(schema).getVersion();
292 LOG.info("{} schema version = {}", schema, schemaVersion);
293 assertTrue("Failed to monitor tables", monitorTables());
297 public void setup2() throws Exception {
299 LOG.info("Skipping setUp, already initialized");
308 private class UpdateMonitor implements MonitorCallBack {
310 public void update(TableUpdates result, DatabaseSchema unused) {
311 updateTableCache(result);
315 public void exception(Throwable ex) {
316 LOG.error("Exception t = " + ex);