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;
55 import org.opendaylight.yangtools.yang.common.Uint8;
58 * Test for {@link DeviceFlowRegistryImpl}.
60 @RunWith(MockitoJUnitRunner.class)
61 public class DeviceFlowRegistryImplTest {
62 private static final String NODE_ID = "openflow:1";
63 private static final Pattern INDEX_PATTERN = Pattern.compile("^#UF\\$TABLE\\*1-([0-9]+)$");
64 private static final Uint8 DUMMY_TABLE_ID = Uint8.ONE;
66 private DeviceFlowRegistryImpl deviceFlowRegistry;
67 private FlowRegistryKey key;
68 private FlowDescriptor descriptor;
69 private KeyedInstanceIdentifier<Node, NodeKey> nodeInstanceIdentifier;
71 private DataBroker dataBroker;
73 private ReadTransaction readOnlyTransaction;
77 nodeInstanceIdentifier =
78 InstanceIdentifier.create(Nodes.class).child(Node.class, new NodeKey(new NodeId(NODE_ID)));
79 when(dataBroker.newReadOnlyTransaction()).thenReturn(readOnlyTransaction);
81 new DeviceFlowRegistryImpl(OFConstants.OFP_VERSION_1_3, dataBroker, nodeInstanceIdentifier);
82 final FlowAndStatisticsMapList flowStats = TestFlowHelper.createFlowAndStatisticsMapListBuilder(1).build();
83 key = FlowRegistryKeyFactory.create(OFConstants.OFP_VERSION_1_3, flowStats);
84 descriptor = FlowDescriptorFactory.create(Uint8.valueOf(key.getTableId()), new FlowId("ut:1"));
86 Assert.assertEquals(0, deviceFlowRegistry.getAllFlowDescriptors().size());
87 deviceFlowRegistry.storeDescriptor(key, descriptor);
88 Assert.assertEquals(1, deviceFlowRegistry.getAllFlowDescriptors().size());
92 public void testFill() throws Exception {
93 final InstanceIdentifier<FlowCapableNode> path = nodeInstanceIdentifier.augmentation(FlowCapableNode.class);
95 final Flow flow = new FlowBuilder()
98 .setCookie(new FlowCookie(BigInteger.TEN))
99 .setId(new FlowId("HELLO"))
102 final Table table = new TableBuilder()
103 .setFlow(Collections.singletonList(flow))
106 final FlowCapableNode flowCapableNode = new FlowCapableNodeBuilder()
107 .setTable(Collections.singletonList(table))
110 final Map<FlowRegistryKey, FlowDescriptor> allFlowDescriptors = fillRegistry(path, flowCapableNode);
111 key = FlowRegistryKeyFactory.create(OFConstants.OFP_VERSION_1_3, flow);
113 InOrder order = inOrder(dataBroker, readOnlyTransaction);
114 order.verify(dataBroker).newReadOnlyTransaction();
115 order.verify(readOnlyTransaction).read(LogicalDatastoreType.CONFIGURATION, path);
116 order.verify(dataBroker).newReadOnlyTransaction();
117 order.verify(readOnlyTransaction).read(LogicalDatastoreType.OPERATIONAL, path);
118 assertTrue(allFlowDescriptors.containsKey(key));
120 deviceFlowRegistry.addMark(key);
124 public void testFailedFill() throws Exception {
125 final InstanceIdentifier<FlowCapableNode> path = nodeInstanceIdentifier.augmentation(FlowCapableNode.class);
127 fillRegistry(path, null);
129 fillRegistry(path, new FlowCapableNodeBuilder()
133 fillRegistry(path, new FlowCapableNodeBuilder()
134 .setTable(Collections.singletonList(null))
137 fillRegistry(path, new FlowCapableNodeBuilder()
138 .setTable(Collections.singletonList(new TableBuilder()
143 fillRegistry(path, new FlowCapableNodeBuilder()
144 .setTable(Collections.singletonList(new TableBuilder()
145 .setFlow(Collections.singletonList(null))
149 fillRegistry(path, new FlowCapableNodeBuilder()
150 .setTable(Collections.singletonList(new TableBuilder()
151 .setFlow(Collections.singletonList(new FlowBuilder()
157 verify(dataBroker, times(12)).newReadOnlyTransaction();
158 verify(readOnlyTransaction, times(6)).read(LogicalDatastoreType.CONFIGURATION, path);
159 verify(readOnlyTransaction, times(6)).read(LogicalDatastoreType.OPERATIONAL, path);
161 Assert.assertEquals(1, deviceFlowRegistry.getAllFlowDescriptors().size());
164 private Map<FlowRegistryKey, FlowDescriptor> fillRegistry(final InstanceIdentifier<FlowCapableNode> path,
165 final FlowCapableNode flowCapableNode) throws Exception {
166 doReturn(FluentFutures.immediateFluentFuture(Optional.ofNullable(flowCapableNode))).when(readOnlyTransaction)
168 deviceFlowRegistry.fill().get();
169 return deviceFlowRegistry.getAllFlowDescriptors();
173 public void testRetrieveIdForFlow() {
174 Assert.assertEquals(descriptor, deviceFlowRegistry.retrieveDescriptor(key));
178 public void testStore() {
179 //store the same key with different value
180 final FlowDescriptor descriptor2 = FlowDescriptorFactory.create(Uint8.valueOf(key.getTableId()),
182 deviceFlowRegistry.storeDescriptor(key, descriptor2);
183 Assert.assertEquals(1, deviceFlowRegistry.getAllFlowDescriptors().size());
184 Assert.assertEquals("ut:2", deviceFlowRegistry.retrieveDescriptor(key).getFlowId().getValue());
186 // store new key with old value
187 final FlowAndStatisticsMapList flowStats = TestFlowHelper.createFlowAndStatisticsMapListBuilder(2).build();
188 final FlowRegistryKey key2 = FlowRegistryKeyFactory.create(OFConstants.OFP_VERSION_1_3, flowStats);
189 deviceFlowRegistry.storeDescriptor(key2, descriptor);
190 Assert.assertEquals(2, deviceFlowRegistry.getAllFlowDescriptors().size());
191 Assert.assertEquals("ut:1", deviceFlowRegistry.retrieveDescriptor(key2).getFlowId().getValue());
195 public void testStoreIfNecessary() {
199 deviceFlowRegistry.store(key);
200 newFlowId = deviceFlowRegistry.retrieveDescriptor(key).getFlowId();
202 Assert.assertEquals(1, deviceFlowRegistry.getAllFlowDescriptors().size());
203 Assert.assertEquals(descriptor, deviceFlowRegistry.retrieveDescriptor(key));
204 Assert.assertEquals(descriptor.getFlowId(), newFlowId);
207 final String alienPrefix = "#UF$TABLE*2-";
208 final FlowRegistryKey key2 = FlowRegistryKeyFactory.create(OFConstants.OFP_VERSION_1_3,
209 TestFlowHelper.createFlowAndStatisticsMapListBuilder(2).build());
210 deviceFlowRegistry.store(key2);
211 newFlowId = deviceFlowRegistry.retrieveDescriptor(key2).getFlowId();
213 Assert.assertTrue(newFlowId.getValue().startsWith(alienPrefix));
214 Assert.assertTrue(deviceFlowRegistry.retrieveDescriptor(key2).getFlowId().getValue().startsWith(alienPrefix));
215 Assert.assertEquals(2, deviceFlowRegistry.getAllFlowDescriptors().size());
219 public void testRemoveDescriptor() {
220 deviceFlowRegistry.addMark(key);
221 Assert.assertEquals(0, deviceFlowRegistry.getAllFlowDescriptors().size());
225 public void testClose() {
226 deviceFlowRegistry.close();
227 Assert.assertEquals(0, deviceFlowRegistry.getAllFlowDescriptors().size());
231 public void createAlienFlowIdTest() {
232 final String alienFlowId1 = DeviceFlowRegistryImpl.createAlienFlowId(DUMMY_TABLE_ID).getValue();
233 final Integer index1 = parseIndex(alienFlowId1);
234 final String alienFlowId2 = DeviceFlowRegistryImpl.createAlienFlowId(DUMMY_TABLE_ID).getValue();
235 final Integer index2 = parseIndex(alienFlowId2);
237 assertNotNull("index1 parsing failed: " + alienFlowId1, index1);
238 assertNotNull("index2 parsing failed: " + alienFlowId2, index2);
239 assertTrue(index1 < index2);
243 public void testForEach() {
244 final AtomicInteger counter = new AtomicInteger(0);
245 deviceFlowRegistry.forEach(k -> counter.incrementAndGet());
246 Assert.assertEquals(1, counter.get());
249 private static Integer parseIndex(final String alienFlowIdValue) {
250 final Matcher mach = INDEX_PATTERN.matcher(alienFlowIdValue);
253 return Integer.valueOf(mach.group(1));