2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.openflowplugin.impl.registry.flow;
10 import static org.junit.Assert.assertNotNull;
11 import static org.junit.Assert.assertTrue;
12 import static org.mockito.ArgumentMatchers.any;
13 import static org.mockito.Mockito.doReturn;
14 import static org.mockito.Mockito.inOrder;
15 import static org.mockito.Mockito.times;
16 import static org.mockito.Mockito.verify;
17 import static org.mockito.Mockito.when;
19 import java.math.BigInteger;
20 import java.util.Collections;
22 import java.util.Optional;
23 import java.util.concurrent.atomic.AtomicInteger;
24 import java.util.regex.Matcher;
25 import java.util.regex.Pattern;
26 import org.junit.Assert;
27 import org.junit.Before;
28 import org.junit.Test;
29 import org.junit.runner.RunWith;
30 import org.mockito.InOrder;
31 import org.mockito.Mock;
32 import org.mockito.junit.MockitoJUnitRunner;
33 import org.opendaylight.mdsal.binding.api.DataBroker;
34 import org.opendaylight.mdsal.binding.api.ReadTransaction;
35 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
36 import org.opendaylight.openflowplugin.api.OFConstants;
37 import org.opendaylight.openflowplugin.api.openflow.registry.flow.FlowDescriptor;
38 import org.opendaylight.openflowplugin.api.openflow.registry.flow.FlowRegistryKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
52 import org.opendaylight.yangtools.util.concurrent.FluentFutures;
53 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
54 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
57 * Test for {@link DeviceFlowRegistryImpl}.
59 @RunWith(MockitoJUnitRunner.class)
60 public class DeviceFlowRegistryImplTest {
61 private static final String NODE_ID = "openflow:1";
62 private static final Pattern INDEX_PATTERN = Pattern.compile("^#UF\\$TABLE\\*1-([0-9]+)$");
63 private static final Short DUMMY_TABLE_ID = 1;
65 private DeviceFlowRegistryImpl deviceFlowRegistry;
66 private FlowRegistryKey key;
67 private FlowDescriptor descriptor;
68 private KeyedInstanceIdentifier<Node, NodeKey> nodeInstanceIdentifier;
70 private DataBroker dataBroker;
72 private ReadTransaction readOnlyTransaction;
75 public void setUp() throws Exception {
76 nodeInstanceIdentifier =
77 InstanceIdentifier.create(Nodes.class).child(Node.class, new NodeKey(new NodeId(NODE_ID)));
78 when(dataBroker.newReadOnlyTransaction()).thenReturn(readOnlyTransaction);
80 new DeviceFlowRegistryImpl(OFConstants.OFP_VERSION_1_3, dataBroker, nodeInstanceIdentifier);
81 final FlowAndStatisticsMapList flowStats = TestFlowHelper.createFlowAndStatisticsMapListBuilder(1).build();
82 key = FlowRegistryKeyFactory.create(OFConstants.OFP_VERSION_1_3, flowStats);
83 descriptor = FlowDescriptorFactory.create(key.getTableId(), new FlowId("ut:1"));
85 Assert.assertEquals(0, deviceFlowRegistry.getAllFlowDescriptors().size());
86 deviceFlowRegistry.storeDescriptor(key, descriptor);
87 Assert.assertEquals(1, deviceFlowRegistry.getAllFlowDescriptors().size());
91 public void testFill() throws Exception {
92 final InstanceIdentifier<FlowCapableNode> path = nodeInstanceIdentifier.augmentation(FlowCapableNode.class);
94 final Flow flow = new FlowBuilder()
97 .setCookie(new FlowCookie(BigInteger.TEN))
98 .setId(new FlowId("HELLO"))
101 final Table table = new TableBuilder()
102 .setFlow(Collections.singletonList(flow))
105 final FlowCapableNode flowCapableNode = new FlowCapableNodeBuilder()
106 .setTable(Collections.singletonList(table))
109 final Map<FlowRegistryKey, FlowDescriptor> allFlowDescriptors = fillRegistry(path, flowCapableNode);
110 key = FlowRegistryKeyFactory.create(OFConstants.OFP_VERSION_1_3, flow);
112 InOrder order = inOrder(dataBroker, readOnlyTransaction);
113 order.verify(dataBroker).newReadOnlyTransaction();
114 order.verify(readOnlyTransaction).read(LogicalDatastoreType.CONFIGURATION, path);
115 order.verify(dataBroker).newReadOnlyTransaction();
116 order.verify(readOnlyTransaction).read(LogicalDatastoreType.OPERATIONAL, path);
117 assertTrue(allFlowDescriptors.containsKey(key));
119 deviceFlowRegistry.addMark(key);
123 public void testFailedFill() throws Exception {
124 final InstanceIdentifier<FlowCapableNode> path = nodeInstanceIdentifier.augmentation(FlowCapableNode.class);
126 fillRegistry(path, null);
128 fillRegistry(path, new FlowCapableNodeBuilder()
132 fillRegistry(path, new FlowCapableNodeBuilder()
133 .setTable(Collections.singletonList(null))
136 fillRegistry(path, new FlowCapableNodeBuilder()
137 .setTable(Collections.singletonList(new TableBuilder()
142 fillRegistry(path, new FlowCapableNodeBuilder()
143 .setTable(Collections.singletonList(new TableBuilder()
144 .setFlow(Collections.singletonList(null))
148 fillRegistry(path, new FlowCapableNodeBuilder()
149 .setTable(Collections.singletonList(new TableBuilder()
150 .setFlow(Collections.singletonList(new FlowBuilder()
156 verify(dataBroker, times(12)).newReadOnlyTransaction();
157 verify(readOnlyTransaction, times(6)).read(LogicalDatastoreType.CONFIGURATION, path);
158 verify(readOnlyTransaction, times(6)).read(LogicalDatastoreType.OPERATIONAL, path);
160 Assert.assertEquals(1, deviceFlowRegistry.getAllFlowDescriptors().size());
163 private Map<FlowRegistryKey, FlowDescriptor> fillRegistry(final InstanceIdentifier<FlowCapableNode> path,
164 final FlowCapableNode flowCapableNode) throws Exception {
165 doReturn(FluentFutures.immediateFluentFuture(Optional.ofNullable(flowCapableNode))).when(readOnlyTransaction)
167 deviceFlowRegistry.fill().get();
168 return deviceFlowRegistry.getAllFlowDescriptors();
172 public void testRetrieveIdForFlow() throws Exception {
173 Assert.assertEquals(descriptor, deviceFlowRegistry.retrieveDescriptor(key));
177 public void testStore() throws Exception {
178 //store the same key with different value
179 final FlowDescriptor descriptor2 = FlowDescriptorFactory.create(key.getTableId(), new FlowId("ut:2"));
180 deviceFlowRegistry.storeDescriptor(key, descriptor2);
181 Assert.assertEquals(1, deviceFlowRegistry.getAllFlowDescriptors().size());
182 Assert.assertEquals("ut:2", deviceFlowRegistry.retrieveDescriptor(key).getFlowId().getValue());
184 // store new key with old value
185 final FlowAndStatisticsMapList flowStats = TestFlowHelper.createFlowAndStatisticsMapListBuilder(2).build();
186 final FlowRegistryKey key2 = FlowRegistryKeyFactory.create(OFConstants.OFP_VERSION_1_3, flowStats);
187 deviceFlowRegistry.storeDescriptor(key2, descriptor);
188 Assert.assertEquals(2, deviceFlowRegistry.getAllFlowDescriptors().size());
189 Assert.assertEquals("ut:1", deviceFlowRegistry.retrieveDescriptor(key2).getFlowId().getValue());
193 public void testStoreIfNecessary() throws Exception {
197 deviceFlowRegistry.store(key);
198 newFlowId = deviceFlowRegistry.retrieveDescriptor(key).getFlowId();
200 Assert.assertEquals(1, deviceFlowRegistry.getAllFlowDescriptors().size());
201 Assert.assertEquals(descriptor, deviceFlowRegistry.retrieveDescriptor(key));
202 Assert.assertEquals(descriptor.getFlowId(), newFlowId);
205 final String alienPrefix = "#UF$TABLE*2-";
206 final FlowRegistryKey key2 = FlowRegistryKeyFactory.create(OFConstants.OFP_VERSION_1_3,
207 TestFlowHelper.createFlowAndStatisticsMapListBuilder(2).build());
208 deviceFlowRegistry.store(key2);
209 newFlowId = deviceFlowRegistry.retrieveDescriptor(key2).getFlowId();
211 Assert.assertTrue(newFlowId.getValue().startsWith(alienPrefix));
212 Assert.assertTrue(deviceFlowRegistry.retrieveDescriptor(key2).getFlowId().getValue().startsWith(alienPrefix));
213 Assert.assertEquals(2, deviceFlowRegistry.getAllFlowDescriptors().size());
217 public void testRemoveDescriptor() throws Exception {
218 deviceFlowRegistry.addMark(key);
219 Assert.assertEquals(0, deviceFlowRegistry.getAllFlowDescriptors().size());
223 public void testClose() throws Exception {
224 deviceFlowRegistry.close();
225 Assert.assertEquals(0, deviceFlowRegistry.getAllFlowDescriptors().size());
229 public void createAlienFlowIdTest() throws Exception {
230 final String alienFlowId1 = DeviceFlowRegistryImpl.createAlienFlowId(DUMMY_TABLE_ID).getValue();
231 final Integer index1 = parseIndex(alienFlowId1);
232 final String alienFlowId2 = DeviceFlowRegistryImpl.createAlienFlowId(DUMMY_TABLE_ID).getValue();
233 final Integer index2 = parseIndex(alienFlowId2);
235 assertNotNull("index1 parsing failed: " + alienFlowId1, index1);
236 assertNotNull("index2 parsing failed: " + alienFlowId2, index2);
237 assertTrue(index1 < index2);
241 public void testForEach() throws Exception {
242 final AtomicInteger counter = new AtomicInteger(0);
243 deviceFlowRegistry.forEach(k -> counter.incrementAndGet());
244 Assert.assertEquals(1, counter.get());
247 private static Integer parseIndex(String alienFlowIdValue) {
248 final Matcher mach = INDEX_PATTERN.matcher(alienFlowIdValue);
251 return Integer.valueOf(mach.group(1));