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