Merge "Add IT for southbound"
[ovsdb.git] / southbound / southbound-it / src / test / java / org / opendaylight / ovsdb / southbound / it / SouthboundIT.java
1 package org.opendaylight.ovsdb.southbound.it;
2
3 import static org.junit.Assert.assertFalse;
4 import static org.junit.Assert.assertNotNull;
5 import static org.junit.Assert.assertNull;
6 import static org.junit.Assert.assertTrue;
7 import static org.junit.Assert.fail;
8 import static org.ops4j.pax.exam.CoreOptions.maven;
9 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
10
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.CheckedFuture;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import java.net.InetAddress;
17 import java.net.UnknownHostException;
18 import java.util.Properties;
19 import java.util.concurrent.ExecutionException;
20 import javax.inject.Inject;
21 import org.junit.Before;
22 import org.junit.Test;
23 import org.junit.runner.RunWith;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
26 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
29 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
30 import org.opendaylight.ovsdb.southbound.OvsdbClientKey;
31 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
34 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
35 import org.ops4j.pax.exam.Configuration;
36 import org.ops4j.pax.exam.Option;
37 import org.ops4j.pax.exam.junit.PaxExam;
38 import org.ops4j.pax.exam.options.MavenUrlReference;
39 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
40 import org.ops4j.pax.exam.spi.reactors.PerClass;
41 import org.osgi.framework.BundleContext;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 @RunWith(PaxExam.class)
46 @ExamReactorStrategy(PerClass.class)
47 public class SouthboundIT extends AbstractMdsalTestBase {
48     private static final Logger LOG = LoggerFactory.getLogger(SouthboundIT.class);
49     private static final String SERVER_IPADDRESS = "ovsdbserver.ipaddress";
50     private static final String SERVER_PORT = "ovsdbserver.port";
51     private static final String CONNECTION_TYPE = "ovsdbserver.connection";
52     private static final String CONNECTION_TYPE_ACTIVE = "active";
53     private static final String CONNECTION_TYPE_PASSIVE = "passive";
54     private static final int CONNECTION_INIT_TIMEOUT = 10000;
55     private static final String DEFAULT_SERVER_IPADDRESS = "127.0.0.1";
56     private static final String DEFAULT_SERVER_PORT = "6640";
57     private static Boolean writeStatus = false;
58     private static Boolean readStatus = false;
59     private static Boolean deleteStatus = false;
60     private static DataBroker dataBroker = null;
61     private static String addressStr;
62     private static String portStr;
63     private static String connectionType;
64     private static Boolean setup = false;
65
66     @Inject
67     private BundleContext bc;
68
69     @Configuration
70     public Option[] config() {
71         return super.config();
72     }
73
74     @Override
75     public String getModuleName() {
76         return "southbound-impl";
77     }
78
79     @Override
80     public String getInstanceName() {
81         return "southbound-default";
82     }
83
84     @Override
85     public MavenUrlReference getFeatureRepo() {
86         return maven()
87                 .groupId("org.opendaylight.ovsdb")
88                 .artifactId("southbound-features")
89                 .classifier("features")
90                 .type("xml")
91                 .versionAsInProject();
92     }
93
94     @Override
95     public String getFeatureName() {
96         return "odl-ovsdb-southbound-impl-ui";
97     }
98
99     protected String usage() {
100         return "Integration Test needs a valid connection configuration as follows :\n"
101                 + "active connection : mvn -Dovsdbserver.ipaddress=x.x.x.x -Dovsdbserver.port=yyyy verify\n"
102                 + "passive connection : mvn -Dovsdbserver.connection=passive verify\n";
103     }
104
105     @Override
106     public Option[] getPropertiesOptions() {
107         Properties props = new Properties(System.getProperties());
108         String addressStr = props.getProperty(SERVER_IPADDRESS, DEFAULT_SERVER_IPADDRESS);
109         String portStr = props.getProperty(SERVER_PORT, DEFAULT_SERVER_PORT);
110         String connectionType = props.getProperty(CONNECTION_TYPE, CONNECTION_TYPE_ACTIVE);
111
112         LOG.info("1: Using the following properties: mode= {}, ip:port= {}:{}",
113                 connectionType, addressStr, portStr);
114
115         Option[] options = new Option[] {
116                 editConfigurationFilePut(CUSTOM_PROPERTIES, SERVER_IPADDRESS, addressStr),
117                 editConfigurationFilePut(CUSTOM_PROPERTIES, SERVER_PORT, portStr),
118                 editConfigurationFilePut(CUSTOM_PROPERTIES, CONNECTION_TYPE, connectionType)
119         };
120         return options;
121     }
122
123     @Before
124     public void setUp() {
125         if (setup == true) {
126             LOG.info("Skipping setUp, already initialized");
127             return;
128         }
129
130         try {
131             super.setup();
132         } catch (Exception e) {
133             e.printStackTrace();
134         }
135         dataBroker = getSession().getSALService(DataBroker.class);
136
137         addressStr = bc.getProperty(SERVER_IPADDRESS);
138         portStr = bc.getProperty(SERVER_PORT);
139         connectionType = bc.getProperty(CONNECTION_TYPE);
140
141         LOG.info("Using the following properties: mode= {}, ip:port= {}:{}",
142                 connectionType, addressStr, portStr);
143         if (connectionType.equalsIgnoreCase(CONNECTION_TYPE_ACTIVE)) {
144             if (addressStr == null) {
145                 fail(usage());
146             }
147         }
148
149         setup = true;
150     }
151
152     @Test
153     public void testPassiveNode() throws InterruptedException {
154         if (connectionType.equalsIgnoreCase(CONNECTION_TYPE_PASSIVE)) {
155             //Wait for CONNECTION_INIT_TIMEOUT for the Passive connection to be initiated by the ovsdb-server.
156             Thread.sleep(CONNECTION_INIT_TIMEOUT);
157         }
158     }
159
160     @Test
161     public void testAddRemoveOvsdbNode() throws InterruptedException {
162         OvsdbClientKey ovsdbClientKey = getOvsdbClientKey(addressStr, portStr);
163         DataBroker dataBroker = getSession().getSALService(DataBroker.class);
164
165         // Write OVSDB node to configuration
166         final ReadWriteTransaction configNodeTx = dataBroker.newReadWriteTransaction();
167         configNodeTx.put(LogicalDatastoreType.CONFIGURATION, ovsdbClientKey.toInstanceIndentifier(),
168                 SouthboundMapper.createNode(ovsdbClientKey));
169         Futures.addCallback(configNodeTx.submit(), new FutureCallback<Void>() {
170             @Override
171             public void onSuccess(final Void result) {
172                 LOG.info("success writing node to configuration: " + configNodeTx);
173                 writeStatus = true;
174             }
175
176             @Override
177             public void onFailure(final Throwable throwable) {
178                 fail("failed writing node to configuration: " + configNodeTx);
179             }
180         });
181
182         Thread.sleep(1000);
183
184         assertTrue("Failed to write node to configuration", writeStatus);
185
186         // Read from operational to verify if the OVSDB node is connected
187         final ReadOnlyTransaction readNodeTx = dataBroker.newReadOnlyTransaction();
188         ListenableFuture<Optional<Node>> dataFuture = readNodeTx.read(
189                 LogicalDatastoreType.OPERATIONAL, ovsdbClientKey.toInstanceIndentifier());
190         Futures.addCallback(dataFuture, new FutureCallback<Optional<Node>>() {
191             @Override
192             public void onSuccess(final Optional<Node> result) {
193                 LOG.info("success reading node from operational: " + readNodeTx);
194                 LOG.info("Optional result: {}", result);
195                 if (result.isPresent()) {
196                     LOG.info("node: {}", result.get());
197                     readStatus = true;
198                 }
199             }
200
201             @Override
202             public void onFailure(final Throwable throwable) {
203                 fail("failed reading node from operational: " + readNodeTx);
204             }
205         });
206
207         Thread.sleep(1000);
208
209         assertTrue("Failed to read node from operational", readStatus);
210
211         // Delete OVSDB node from configuration
212         final ReadWriteTransaction deleteNodeTx = dataBroker.newReadWriteTransaction();
213         deleteNodeTx.delete(LogicalDatastoreType.CONFIGURATION, ovsdbClientKey.toInstanceIndentifier());
214         Futures.addCallback(deleteNodeTx.submit(), new FutureCallback<Void>() {
215             @Override
216             public void onSuccess(final Void result) {
217                 LOG.info("success deleting node from configuration: " + deleteNodeTx);
218                 deleteStatus = true;
219             }
220
221             @Override
222             public void onFailure(final Throwable throwable) {
223                 fail("failed deleting node from configuration: " + deleteNodeTx);
224             }
225         });
226
227         Thread.sleep(1000);
228
229         assertTrue("Failed to delete node from configuration", deleteStatus);
230
231         // Read from operational to verify if the OVSDB node is disconnected
232         // Similar to the earlier read, but this time synchronously
233         final ReadOnlyTransaction readNodeTx2 = dataBroker.newReadOnlyTransaction();
234         Optional<Node> node = Optional.absent();
235         try {
236             node = readNodeTx2.read(LogicalDatastoreType.OPERATIONAL,
237                     ovsdbClientKey.toInstanceIndentifier()).checkedGet();
238             assertFalse("Failed to delete node from configuration and node is still connected",
239                     node.isPresent());
240         } catch (final ReadFailedException e) {
241             LOG.debug("Read Operational/DS for Node fail! {}", ovsdbClientKey.toInstanceIndentifier(), e);
242             fail("failed reading node from operational: " + readNodeTx2 + e);
243         }
244     }
245
246     @Test
247     public void testAddRemoveOvsdbNode2() throws InterruptedException {
248         addNode("192.168.120.31", "6640");
249         Thread.sleep(1000);
250         Node node = readNode("192.168.120.31", "6640", LogicalDatastoreType.OPERATIONAL);
251         assertNotNull(node);
252         LOG.info("Connected node: {}", node);
253         deleteNode("192.168.120.31", "6640");
254         Thread.sleep(1000);
255         node = readNode("192.168.120.31", "6640", LogicalDatastoreType.OPERATIONAL);
256         assertNull(node);
257     }
258
259     private OvsdbClientKey getOvsdbClientKey(String addressStr, String portStr) {
260         InetAddress inetAddress = null;
261         try {
262             inetAddress = InetAddress.getByName(addressStr);
263         } catch (UnknownHostException e) {
264             fail("Could not allocate InetAddress: " + e);
265         }
266
267         IpAddress address = SouthboundMapper.createIpAddress(inetAddress);
268         PortNumber port = new PortNumber(Integer.parseInt(portStr));
269
270         return new OvsdbClientKey(address, port);
271     }
272
273     private void addNode(String addressStr, String portStr) {
274         OvsdbClientKey ovsdbClientKey = getOvsdbClientKey(addressStr, portStr);
275
276         final ReadWriteTransaction rwTx = dataBroker.newReadWriteTransaction();
277         rwTx.put(LogicalDatastoreType.CONFIGURATION, ovsdbClientKey.toInstanceIndentifier(),
278                 SouthboundMapper.createNode(ovsdbClientKey));
279         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = rwTx.submit();
280         try {
281             commitFuture.get();
282         } catch (ExecutionException | InterruptedException e) {
283             fail("Failed transaction: " + rwTx + e);
284         }
285     }
286
287     private Node readNode(String addressStr, String portStr, LogicalDatastoreType type) {
288         OvsdbClientKey ovsdbClientKey = getOvsdbClientKey(addressStr, portStr);
289
290         final ReadWriteTransaction rwTx = dataBroker.newReadWriteTransaction();
291         Optional<Node> node = Optional.absent();
292         CheckedFuture<Optional<Node>, ReadFailedException> read;
293         read = rwTx.read(type, ovsdbClientKey.toInstanceIndentifier());
294         try {
295             node = read.checkedGet();
296             if (node.isPresent()) {
297                 return node.get();
298             }
299         } catch (ReadFailedException e) {
300             fail("Failed transaction: " + rwTx + e);
301         }
302
303         return null;
304     }
305
306     private void deleteNode(String addressStr, String portStr) {
307         OvsdbClientKey ovsdbClientKey = getOvsdbClientKey(addressStr, portStr);
308
309         final ReadWriteTransaction rwTx = dataBroker.newReadWriteTransaction();
310         rwTx.delete(LogicalDatastoreType.CONFIGURATION, ovsdbClientKey.toInstanceIndentifier());
311         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = rwTx.submit();
312         try {
313             commitFuture.get();
314         } catch (ExecutionException | InterruptedException e) {
315             fail("Failed transaction: " + rwTx + e);
316         }
317     }
318 }