Fix checkstyle
[ovsdb.git] / library / it / src / test / java / org / opendaylight / ovsdb / lib / it / LibraryIntegrationTestBase.java
1 /*
2  * Copyright © 2015, 2017 Red Hat, Inc. and others. All rights reserved.
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
9 package org.opendaylight.ovsdb.lib.it;
10
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;
22
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;
28 import java.util.Map;
29 import java.util.Set;
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;
56
57 /**
58  * Base class for library IT.
59  */
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;
73     public String schema;
74
75     protected static Map<String, Map<UUID, Row>> getTableCache() {
76         return tableCache;
77     }
78
79     protected OvsdbClient getClient() {
80         return ovsdbClient;
81     }
82
83     protected DatabaseSchema getDbSchema() {
84         return dbSchema;
85     }
86
87     protected static boolean getSetup() {
88         return setup.get();
89     }
90
91     protected static void setSetup(boolean setup) {
92         LibraryIntegrationTestBase.setup.set(setup);
93     }
94
95     @Override
96     public MavenUrlReference getFeatureRepo() {
97         return maven()
98                 .groupId("org.opendaylight.ovsdb")
99                 .artifactId("library-features")
100                 .classifier("features")
101                 .type("xml")
102                 .versionAsInProject();
103     }
104
105     @Override
106     public String getFeatureName() {
107         return "odl-ovsdb-library";
108     }
109
110     @Configuration
111     @Override
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);
121         return options;
122     }
123
124     private Option[] getOtherOptions() {
125         return new Option[] {
126                 vmOption("-javaagent:../jars/org.jacoco.agent.jar=destfile=../../jacoco-it.exec"),
127                 keepRuntimeFolder()
128         };
129     }
130
131     public Option[] getPropertiesOptions() {
132         return new Option[] {
133                 propagateSystemProperties(
134                         LibraryIntegrationTestUtils.SERVER_IPADDRESS,
135                         LibraryIntegrationTestUtils.SERVER_PORT,
136                         LibraryIntegrationTestUtils.CONNECTION_TYPE),
137         };
138     }
139
140     @Override
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());
149         return option;
150     }
151
152     public boolean checkSchema(String schemaStr)
153             throws IOException, InterruptedException, ExecutionException, TimeoutException {
154         if (schemaSupported) {
155             LOG.info("Schema ({}) is supported", schemaStr);
156             return true;
157         }
158
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;
167             return true;
168         }
169
170         LOG.info("Schema ({}) is not supported", schemaStr);
171         return false;
172     }
173
174     public boolean isSchemaSupported(String schemaStr) throws ExecutionException,
175             InterruptedException {
176         return isSchemaSupported(ovsdbClient, schemaStr);
177     }
178
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);
185     }
186
187     /**
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 &lt;monitor-request&gt; 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
196      *
197      * @return MonitorRequest that includes all the Bridge Columns including _uuid
198      */
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);
206         }
207         return bridgeBuilder.with(new MonitorSelect(true, true, true, true)).build();
208     }
209
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);
215         }
216         return monitorBuilder.with(new MonitorSelect(true, true, true, true)).build();
217     }
218
219     public boolean monitorTables() throws ExecutionException, InterruptedException, IOException {
220         if (monitorReady) {
221             LOG.info("Monitoring is already initialized.");
222             return monitorReady;
223         }
224
225         assertNotNull(getDbSchema());
226
227         List<MonitorRequest> monitorRequests = new ArrayList<>();
228         Set<String> tables = getDbSchema().getTables();
229         assertNotNull("ovsdb tables should not be null", tables);
230
231         for (String tableName : tables) {
232             GenericTableSchema tableSchema = getDbSchema().table(tableName, GenericTableSchema.class);
233             monitorRequests.add(this.getAllColumnsMonitorRequest(tableSchema));
234         }
235         TableUpdates updates = getClient().monitor(getDbSchema(), monitorRequests, new UpdateMonitor());
236         assertNotNull(updates);
237         this.updateTableCache(updates);
238
239         monitorReady = true;
240         LOG.info("Monitoring is initialized.");
241         return monitorReady;
242     }
243
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);
254                     }
255                     rowUpdates.put(uuid, update.getNew(uuid));
256                 } else {
257                     rowUpdates.remove(uuid);
258                 }
259             }
260         }
261     }
262
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());
272         }
273         //Thread.sleep(500); // Wait for a few seconds to ensure the cache updates
274         return operationResults;
275     }
276
277     @Override
278     public void setup() throws Exception {
279         if (getSetup()) {
280             LOG.info("Skipping setUp, already initialized");
281             return;
282         }
283
284         super.setup();
285
286         if (schema.equals(LibraryIntegrationTestUtils.OPEN_VSWITCH)) {
287             assertTrue(schema + " is required.", checkSchema(schema));
288         } else {
289             assumeTrue(schema + " is required.", checkSchema(schema));
290         }
291         schemaVersion = getClient().getDatabaseSchema(schema).getVersion();
292         LOG.info("{} schema version = {}", schema, schemaVersion);
293         assertTrue("Failed to monitor tables", monitorTables());
294         setSetup(true);
295     }
296
297     public void setup2() throws Exception {
298         if (getSetup()) {
299             LOG.info("Skipping setUp, already initialized");
300             return;
301         }
302
303         super.setup();
304
305         setSetup(true);
306     }
307
308     private final class UpdateMonitor implements MonitorCallBack {
309         @Override
310         public void update(TableUpdates result, DatabaseSchema unused) {
311             updateTableCache(result);
312         }
313
314         @Override
315         public void exception(Throwable ex) {
316             LOG.error("Exception t = " + ex);
317         }
318     }
319 }