Revert "Removing ovsdb plugin dependency on sal.utils classes"
[netvirt.git] / integrationtest / src / test / java / org / opendaylight / ovsdb / integrationtest / plugin / OvsdbPluginIT.java
1 /*
2  * Copyright (c) 2014 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  * Authors : Madhu Venugopal
9  */
10 package org.opendaylight.ovsdb.integrationtest.plugin;
11
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertFalse;
14 import static org.junit.Assert.assertNotNull;
15 import static org.junit.Assert.assertNull;
16 import static org.junit.Assert.assertTrue;
17 import static org.junit.Assert.fail;
18 import static org.ops4j.pax.exam.CoreOptions.junitBundles;
19 import static org.ops4j.pax.exam.CoreOptions.options;
20 import static org.ops4j.pax.exam.CoreOptions.propagateSystemProperty;
21 import static org.ops4j.pax.exam.CoreOptions.systemProperty;
22
23 import org.junit.After;
24 import org.opendaylight.controller.sal.core.Node;
25 import org.opendaylight.controller.sal.utils.ServiceHelper;
26 import org.opendaylight.controller.sal.utils.Status;
27 import org.opendaylight.ovsdb.integrationtest.ConfigurationBundles;
28 import org.opendaylight.ovsdb.integrationtest.OvsdbIntegrationTestBase;
29 import org.opendaylight.ovsdb.lib.OvsdbClient;
30 import org.opendaylight.ovsdb.lib.OvsdbConnectionInfo;
31 import org.opendaylight.ovsdb.lib.notation.Row;
32 import org.opendaylight.ovsdb.plugin.api.Connection;
33 import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
34 import org.opendaylight.ovsdb.plugin.api.OvsdbConnectionService;
35 import org.opendaylight.ovsdb.plugin.api.OvsdbInventoryListener;
36 import org.opendaylight.ovsdb.plugin.api.OvsdbInventoryService;
37 import org.opendaylight.ovsdb.plugin.api.StatusWithUuid;
38 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
39 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
40
41 import com.google.common.collect.ImmutableMap;
42 import com.google.common.collect.Sets;
43 import org.apache.felix.dm.Component;
44 import org.apache.felix.dm.DependencyManager;
45 import org.junit.Before;
46 import org.junit.Test;
47 import org.junit.runner.RunWith;
48 import org.mockito.Mockito;
49 import org.ops4j.pax.exam.Configuration;
50 import org.ops4j.pax.exam.Option;
51 import org.ops4j.pax.exam.junit.PaxExam;
52 import org.ops4j.pax.exam.util.PathUtils;
53 import org.osgi.framework.Bundle;
54 import org.osgi.framework.BundleContext;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 import java.net.InetAddress;
59 import java.net.UnknownHostException;
60 import java.util.List;
61 import java.util.Map;
62 import java.util.concurrent.ConcurrentMap;
63
64 import javax.inject.Inject;
65
66 @RunWith(PaxExam.class)
67 public class OvsdbPluginIT extends OvsdbIntegrationTestBase {
68     private Logger log = LoggerFactory.getLogger(OvsdbPluginIT.class);
69     @Inject
70     private BundleContext bc;
71     private OvsdbConfigurationService ovsdbConfigurationService = null;
72
73     @Inject
74     private OvsdbInventoryService ovsdbInventoryService;
75
76     private Node node = null;
77     private OvsdbClient client = null;
78
79     // Configure the OSGi container
80     @Configuration
81     public Option[] config() {
82         return options(
83             //
84             systemProperty("logback.configurationFile").value(
85                     "file:" + PathUtils.getBaseDir()
86                     + "/src/test/resources/logback.xml"
87             ),
88             // To start OSGi console for inspection remotely
89             systemProperty("osgi.console").value("2401"),
90
91             propagateSystemProperty("ovsdbserver.ipaddress"),
92             propagateSystemProperty("ovsdbserver.port"),
93
94             ConfigurationBundles.controllerBundles(),
95             ConfigurationBundles.ovsdbLibraryBundles(),
96             ConfigurationBundles.ovsdbDefaultSchemaBundles(),
97             ConfigurationBundles.ovsdbPluginBundles(),
98             junitBundles()
99         );
100     }
101
102     @Before
103     public void areWeReady() throws InterruptedException {
104         assertNotNull(bc);
105         boolean debugit = false;
106         Bundle b[] = bc.getBundles();
107         for (Bundle element : b) {
108             int state = element.getState();
109             if (state != Bundle.ACTIVE && state != Bundle.RESOLVED) {
110                 log.info("Bundle:" + element.getSymbolicName() + " state:"
111                           + stateToString(state));
112                 debugit = true;
113             }
114         }
115         if (debugit) {
116             log.debug("Do some debugging because some bundle is unresolved");
117         }
118
119         assertFalse(debugit);
120         try {
121             node = getPluginTestConnection();
122         } catch (Exception e) {
123             fail("Exception : "+e.getMessage());
124         }
125         this.ovsdbConfigurationService = (OvsdbConfigurationService)ServiceHelper.getGlobalInstance(OvsdbConfigurationService.class, this);
126     }
127
128     @Test
129     public void apiTests() throws Exception {
130         Thread.sleep(5000);
131         OvsdbConnectionService
132                 connectionService = (OvsdbConnectionService)ServiceHelper.getGlobalInstance(OvsdbConnectionService.class, this);
133
134         // Check for the ovsdb Connection as seen by the Plugin layer
135         assertNotNull(connectionService.getNodes());
136         assertTrue(connectionService.getNodes().size() > 0);
137         Node node = connectionService.getNodes().get(0);
138         Connection connection = connectionService.getConnection(node);
139         OvsdbConnectionInfo connectionInfo = connection.getClient().getConnectionInfo();
140         String identifier = IDENTIFIER;
141         if (connectionInfo.getType().equals(OvsdbConnectionInfo.ConnectionType.PASSIVE)) {
142             identifier = connectionInfo.getRemoteAddress().getHostAddress()+":"+connectionInfo.getRemotePort();
143         }
144         assertEquals(node, connectionService.getNode("OVS|" + identifier));
145         System.out.println("Nodes = "+ connectionService.getNodes());
146         /*
147          * Test sequence :
148          * 1. Print Cache and Assert to make sure the bridge is not created yet.
149          * 2. Create a bridge with a valid parent_uuid & Assert to make sure the return status is success.
150          * 3. Assert to make sure the bridge is created with a valid Uuid.
151          * 4. Delete the bridge & Assert to make sure the return status is success.
152          * 5. Assert to make sure the bridge is deleted
153          */
154
155         this.endToEndApiTest(connection, getOpenVSwitchTableUUID(connection));
156
157         /*
158          * Repeat all of the above tests without the parent_uuid
159          */
160
161         this.endToEndApiTest(connection, null);
162     }
163
164     @Test
165     public void testInventoryListeners() throws UnknownHostException {
166         DependencyManager dm = new DependencyManager(bc);
167
168         OvsdbInventoryListener listenerA = Mockito.mock(FakeListener.class);
169         OvsdbInventoryListener listenerB = Mockito.mock(FakeListener.class);
170
171         Component componentA = dm.createComponent();
172         componentA.setInterface(OvsdbInventoryListener.class.getName(), null);
173         componentA.setImplementation(listenerA);
174         dm.add(componentA);
175
176         Component componentB = dm.createComponent();
177         componentB.setInterface(OvsdbInventoryListener.class.getName(), null);
178         componentB.setImplementation(listenerB);
179         dm.add(componentB);
180
181         Node newNode = Node.fromString("OVS|10.10.10.10:65342");
182         InetAddress address = InetAddress.getByName("10.10.10.10");
183         int port = 65342;
184
185         // Trigger event
186         ovsdbInventoryService.notifyNodeAdded(newNode, address, port);
187
188         Mockito.verify(listenerA, Mockito.times(1)).nodeAdded(newNode, address, port);
189         Mockito.verify(listenerB, Mockito.times(1)).nodeAdded(newNode, address, port);
190
191         dm.remove(componentA);
192         dm.remove(componentB);
193
194     }
195
196     @Test
197     public void testSetOFControllers() throws Exception {
198         Thread.sleep(5000);
199         OvsdbConnectionService
200                 connectionService = (OvsdbConnectionService)ServiceHelper.getGlobalInstance(OvsdbConnectionService.class, this);
201
202         // 1. Check for the ovsdb Connection as seen by the Plugin layer
203         assertNotNull(connectionService.getNodes());
204         assertTrue(connectionService.getNodes().size() > 0);
205         Node node = connectionService.getNodes().get(0);
206         Connection connection = connectionService.getConnection(node);
207         assertNotNull(connection);
208
209         // 2. Create a bridge with a valid parent_uuid & Assert to make sure the return status is success.
210         final StatusWithUuid status = insertBridge(connection, getOpenVSwitchTableUUID(connection));
211         assertTrue(status.isSuccess());
212
213         // Thread.sleep(3000);  // wait for _real_ controller to be added to bridge... or not (see below **)
214
215         // 3. Test against bug 960: Add same controller multiple times and make sure we do not end up with duplicates.
216         ovsdbConfigurationService.setOFController(node, status.getUuid().toString());
217         ovsdbConfigurationService.setOFController(node, status.getUuid().toString());
218         ovsdbConfigurationService.setOFController(node, status.getUuid().toString());
219         ovsdbConfigurationService.setOFController(node, status.getUuid().toString());
220
221         Row bridgeRow = ovsdbConfigurationService.getRow(node,
222                                                   ovsdbConfigurationService.getTableName(node, Bridge.class),
223                                                   status.getUuid().toString());
224         assertNotNull(bridgeRow);
225         Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeRow);
226         assertTrue(bridge.getUuid().equals(status.getUuid()));
227
228         final int currControllersSize = bridge.getControllerColumn().getData().size();
229
230         log.debug("Bridge has " + bridge.getControllerColumn().getData().size() + " controllers");
231
232         // ** Note: we assert against 2 or less -- instead of 1 -- to account for the _real_ controller's connection
233         assertTrue( "Too few controllers added to bridge object. Is this bug 960?", currControllersSize >= 1 );
234         assertTrue( "Too many controllers added to bridge object. Is this bug 960?", currControllersSize <= 2 );
235
236         // Removal of bridge created in this test is done via tearDown(). It is done that way, so cleanup is ran
237         // even if test fails.
238     }
239
240     @After
241     public void tearDown() throws InterruptedException {
242         Thread.sleep(5000);
243         OvsdbConnectionService
244                 connectionService = (OvsdbConnectionService)ServiceHelper.getGlobalInstance(OvsdbConnectionService.class, this);
245
246         if (connectionService.getNodes() == null) {
247             return;  // no nodes: noop
248         }
249
250         int bridgesRemoved = 0;
251         List<Node> nodes = connectionService.getNodes();
252         for (Node node : nodes) {
253             Map<String, Row> bridgeRows =
254                     ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
255             if (bridgeRows == null) {
256                 continue;
257             }
258             for (Row bridgeRow : bridgeRows.values()) {
259                 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeRow);
260                 log.trace("Test clean up removing Bridge " + bridge.getUuid());
261                 Status delStatus = ovsdbConfigurationService.deleteRow(node,
262                                                                 bridge.getSchema().getName(),
263                                                                 bridge.getUuid().toString());
264                 assertTrue(delStatus.isSuccess());
265                 bridgesRemoved++;
266             }
267         }
268
269         if (bridgesRemoved > 0) {
270             log.debug("Test clean up removed " + bridgesRemoved + " bridges");
271             Thread.sleep(2000); // TODO : Remove this Sleep once the Select operation is resolved.
272         }
273     }
274
275     public void endToEndApiTest(Connection connection, String parentUuid) throws Exception {
276         // 1. Print Cache and Assert to make sure the bridge is not created yet.
277         printCache();
278
279         // 2. Create a bridge with a valid parent_uuid & Assert to make sure the return status is success.
280         StatusWithUuid status = insertBridge(connection, parentUuid);
281         assertTrue(status.isSuccess());
282
283         Thread.sleep(2000); // TODO : Remove this Sleep once the Select operation is resolved.
284
285         // 3. Assert to make sure the bridge is created with a valid Uuid.
286         printCache();
287         Bridge bridge = connection.getClient().getTypedRowWrapper(Bridge.class, null);
288         Row bridgeRow = ovsdbConfigurationService.getRow(node, bridge.getSchema().getName(), status.getUuid().toString());
289         assertNotNull(bridgeRow);
290         bridge = connection.getClient().getTypedRowWrapper(Bridge.class, bridgeRow);
291         assertEquals(bridge.getUuid(), status.getUuid());
292
293         // 4. Delete the bridge & Assert to make sure the return status is success.
294         Status delStatus = ovsdbConfigurationService.deleteRow(node, bridge.getSchema().getName(), status.getUuid().toString());
295         assertTrue(delStatus.isSuccess());
296         Thread.sleep(2000); // TODO : Remove this Sleep once the Select operation is resolved.
297
298         // 5. Assert to make sure the bridge is deleted
299         bridgeRow = ovsdbConfigurationService.getRow(node, bridge.getSchema().getName(), status.getUuid().toString());
300         assertNull(bridgeRow);
301     }
302
303     public StatusWithUuid insertBridge(Connection connection, String parentUuid) throws Exception {
304         Bridge bridge = connection.getClient().createTypedRowWrapper(Bridge.class);
305         bridge.setName("br_test1");
306         bridge.setStatus(ImmutableMap.of("key", "value"));
307         bridge.setFloodVlans(Sets.newHashSet(34L));
308         return ovsdbConfigurationService.insertRow(node, bridge.getSchema().getName(), parentUuid, bridge.getRow());
309     }
310
311     public String getOpenVSwitchTableUUID(Connection connection) throws Exception {
312         OpenVSwitch openVSwitch = connection.getClient().getTypedRowWrapper(OpenVSwitch.class, null);
313         ConcurrentMap<String, Row> row = ovsdbConfigurationService.getRows(node, openVSwitch.getSchema().getName());
314         if (row == null || row.size() == 0) return null;
315         return (String)row.keySet().toArray()[0];
316     }
317
318     public void printCache() throws Exception {
319         List<String> tables = ovsdbConfigurationService.getTables(node);
320         System.out.println("Tables = "+tables);
321         assertNotNull(tables);
322         for (String table : tables) {
323             System.out.println("Table "+table);
324             ConcurrentMap<String,Row> row = ovsdbConfigurationService.getRows(node, table);
325             System.out.println(row);
326         }
327     }
328
329     public class FakeListener implements OvsdbInventoryListener {
330
331         @Override
332         public void nodeAdded(Node node, InetAddress address, int port) {
333
334         }
335
336         @Override
337         public void nodeRemoved(Node node) {
338
339         }
340
341         @Override
342         public void rowAdded(Node node, String tableName, String uuid, Row row) {
343
344         }
345
346         @Override
347         public void rowUpdated(Node node, String tableName, String uuid, Row old, Row row) {
348
349         }
350
351         @Override
352         public void rowRemoved(Node node, String tableName, String uuid, Row row, Object context) {
353
354         }
355     }
356
357 }