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