Bump upstreams for Silicon
[openflowplugin.git] / applications / forwardingrules-sync / src / test / java / org / opendaylight / openflowplugin / applications / frsync / util / ReconcileUtilTest.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, 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 package org.opendaylight.openflowplugin.applications.frsync.util;
9
10 import com.google.common.base.Splitter;
11 import com.google.common.collect.Maps;
12 import com.google.common.util.concurrent.Futures;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import com.google.common.util.concurrent.MoreExecutors;
15 import com.google.common.util.concurrent.SettableFuture;
16 import java.util.ArrayList;
17 import java.util.Arrays;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Set;
23 import org.junit.Assert;
24 import org.junit.Test;
25 import org.junit.runner.RunWith;
26 import org.mockito.ArgumentCaptor;
27 import org.mockito.ArgumentMatchers;
28 import org.mockito.Captor;
29 import org.mockito.Mock;
30 import org.mockito.Mockito;
31 import org.mockito.junit.MockitoJUnitRunner;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCaseBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupActionBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev150304.FlowCapableTransactionService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev150304.SendBarrierInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev150304.SendBarrierOutput;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
52 import org.opendaylight.yangtools.yang.common.RpcResult;
53 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
54 import org.opendaylight.yangtools.yang.common.Uint32;
55
56 /**
57  * Test for {@link ReconcileUtil}.
58  */
59 @RunWith(MockitoJUnitRunner.class)
60 public class ReconcileUtilTest {
61
62     private static final NodeId NODE_ID = new NodeId("unit-node-id");
63     private static final InstanceIdentifier<Node> NODE_IDENT = InstanceIdentifier.create(Nodes.class)
64             .child(Node.class, new NodeKey(NODE_ID));
65     private static final Splitter COMMA_SPLITTER = Splitter.on(",");
66
67     @Mock
68     private FlowCapableTransactionService flowCapableService;
69     @Captor
70     private ArgumentCaptor<SendBarrierInput> barrierInputCaptor;
71
72     @Test
73     public void testChainBarrierFlush() throws Exception {
74         SettableFuture<RpcResult<Void>> testRabbit = SettableFuture.create();
75         final ListenableFuture<RpcResult<Void>> vehicle =
76                 Futures.transformAsync(testRabbit, ReconcileUtil.chainBarrierFlush(NODE_IDENT, flowCapableService),
77                         MoreExecutors.directExecutor());
78         Mockito.when(flowCapableService.sendBarrier(barrierInputCaptor.capture()))
79                 .thenReturn(RpcResultBuilder.<SendBarrierOutput>success().buildFuture());
80
81         Mockito.verify(flowCapableService, Mockito.never()).sendBarrier(ArgumentMatchers.any());
82         Assert.assertFalse(vehicle.isDone());
83
84         testRabbit.set(RpcResultBuilder.<Void>success().build());
85         Mockito.verify(flowCapableService).sendBarrier(ArgumentMatchers.any());
86         Assert.assertTrue(vehicle.isDone());
87         Assert.assertTrue(vehicle.get().isSuccessful());
88     }
89
90     /**
91      * add one missing group.
92      */
93     @Test
94     public void testResolveAndDivideGroupDiffs1() {
95         final Map<Uint32, Group> installedGroups = createGroups(1, 2, 3);
96
97         final List<Group> pendingGroups = new ArrayList<>();
98         pendingGroups.add(createGroup(2L));
99         pendingGroups.add(createGroup(3L));
100         pendingGroups.add(createGroup(4L));
101
102         final List<ItemSyncBox<Group>> plan = ReconcileUtil.resolveAndDivideGroupDiffs(
103                 NODE_ID, installedGroups, pendingGroups);
104
105         Assert.assertEquals(1, plan.size());
106
107         Assert.assertEquals(1, plan.get(0).getItemsToPush().size());
108         Assert.assertEquals(4L, plan.get(0).getItemsToPush().iterator().next().key()
109                 .getGroupId().getValue().longValue());
110         Assert.assertEquals(0, plan.get(0).getItemsToUpdate().size());
111     }
112
113     /**
114      * add 3 groups with dependencies - 3 steps involved.
115      */
116     @Test
117     public void testResolveAndDivideGroupDiffs2() {
118         final Map<Uint32, Group> installedGroups = createGroups(1);
119
120         final List<Group> pendingGroups = new ArrayList<>();
121         pendingGroups.add(createGroup(2L));
122         pendingGroups.add(createGroupWithPreconditions(3L, 2L, 4L));
123         pendingGroups.add(createGroupWithPreconditions(4L, 2L));
124
125         final List<ItemSyncBox<Group>> plan = ReconcileUtil.resolveAndDivideGroupDiffs(
126                 NODE_ID, installedGroups, pendingGroups);
127
128         Assert.assertEquals(3, plan.size());
129
130         Assert.assertEquals(1, plan.get(0).getItemsToPush().size());
131         Assert.assertEquals(2L, plan.get(0).getItemsToPush().iterator().next().key()
132                 .getGroupId().getValue().longValue());
133         Assert.assertEquals(0, plan.get(0).getItemsToUpdate().size());
134
135         Assert.assertEquals(1, plan.get(1).getItemsToPush().size());
136         Assert.assertEquals(4L, plan.get(1).getItemsToPush().iterator().next().key()
137                 .getGroupId().getValue().longValue());
138         Assert.assertEquals(0, plan.get(1).getItemsToUpdate().size());
139
140         Assert.assertEquals(1, plan.get(2).getItemsToPush().size());
141         Assert.assertEquals(3L, plan.get(2).getItemsToPush().iterator().next().key()
142                 .getGroupId().getValue().longValue());
143         Assert.assertEquals(0, plan.get(2).getItemsToUpdate().size());
144     }
145
146     /**
147      * no actions taken - installed and pending groups are the same.
148      */
149     @Test
150     public void testResolveAndDivideGroupDiffs3() {
151         final Map<Uint32, Group> installedGroups = new HashMap<>();
152         installedGroups.put(Uint32.ONE, createGroup(1L));
153         installedGroups.put(Uint32.valueOf(2), createGroupWithPreconditions(2L, 1L));
154
155         final List<Group> pendingGroups = new ArrayList<>();
156         pendingGroups.add(createGroup(1L));
157         pendingGroups.add(createGroupWithPreconditions(2L, 1L));
158
159         final List<ItemSyncBox<Group>> plan = ReconcileUtil.resolveAndDivideGroupDiffs(
160                 NODE_ID, installedGroups, pendingGroups);
161
162         Assert.assertEquals(0, plan.size());
163     }
164
165     /**
166      * update 1 group.
167      */
168     @Test
169     public void testResolveAndDivideGroupDiffs4() {
170         final Map<Uint32, Group> installedGroups = createGroups(1, 2);
171
172         final List<Group> pendingGroups = new ArrayList<>();
173         pendingGroups.add(createGroupWithPreconditions(1L, 2L));
174         pendingGroups.add(createGroup(2L));
175
176         final List<ItemSyncBox<Group>> plan = ReconcileUtil.resolveAndDivideGroupDiffs(
177                 NODE_ID, installedGroups, pendingGroups);
178
179         Assert.assertEquals(1, plan.size());
180         Assert.assertEquals(0, plan.get(0).getItemsToPush().size());
181         Assert.assertEquals(1, plan.get(0).getItemsToUpdate().size());
182         final ItemSyncBox.ItemUpdateTuple<Group> firstItemUpdateTuple =
183                 plan.get(0).getItemsToUpdate().iterator().next();
184         Assert.assertEquals(1L, firstItemUpdateTuple.getOriginal().getGroupId().getValue().longValue());
185         Assert.assertEquals(1L, firstItemUpdateTuple.getUpdated().getGroupId().getValue().longValue());
186     }
187
188     /**
189      * no action taken - update 1 group will be ignored.
190      */
191     @Test
192     public void testResolveAndDivideGroupDiffs5() {
193         final Map<Uint32, Group> installedGroups = createGroups(1, 2);
194
195         final List<Group> pendingGroups = new ArrayList<>();
196         pendingGroups.add(createGroupWithPreconditions(1L, 2L));
197         pendingGroups.add(createGroup(2L));
198
199         final List<ItemSyncBox<Group>> plan = ReconcileUtil.resolveAndDivideGroupDiffs(
200                 NODE_ID, installedGroups, pendingGroups, false);
201
202         Assert.assertEquals(0, plan.size());
203     }
204
205     /**
206      * should add 1 group but preconditions are not met.
207      */
208     @Test
209     public void testResolveAndDivideGroupDiffs_negative1() {
210         final Map<Uint32, Group> installedGroups = createGroups(1, 2);
211
212         final List<Group> pendingGroups = new ArrayList<>();
213         pendingGroups.add(createGroupWithPreconditions(3L, 4L));
214
215         Assert.assertThrows(IllegalStateException.class,
216             () -> ReconcileUtil.resolveAndDivideGroupDiffs(NODE_ID, installedGroups, pendingGroups));
217     }
218
219     /**
220      * should update 1 group but preconditions are not met.
221      */
222     @Test
223     public void testResolveAndDivideGroupDiffs_negative2() {
224         final Map<Uint32, Group> installedGroups = createGroups(1, 2);
225
226         final List<Group> pendingGroups = new ArrayList<>();
227         pendingGroups.add(createGroupWithPreconditions(1L, 3L));
228
229         Assert.assertThrows(IllegalStateException.class,
230             () -> ReconcileUtil.resolveAndDivideGroupDiffs(NODE_ID, installedGroups, pendingGroups));
231     }
232
233     @Test
234     public void testCheckGroupPrecondition() {
235         final Set<Uint32> installedGroups = new HashSet<>(Arrays.asList(Uint32.ONE, Uint32.valueOf(2)));
236
237         final Group pendingGroup1 = createGroupWithPreconditions(3L, 2L, 4L);
238         Assert.assertFalse(ReconcileUtil.checkGroupPrecondition(installedGroups, pendingGroup1));
239
240         final Group pendingGroup2 = createGroupWithPreconditions(1L, 2L);
241         Assert.assertTrue(ReconcileUtil.checkGroupPrecondition(installedGroups, pendingGroup2));
242
243         final Group pendingGroup3 = createGroupWithPreconditions(1L);
244         Assert.assertTrue(ReconcileUtil.checkGroupPrecondition(installedGroups, pendingGroup3));
245     }
246
247     private static Group createGroupWithPreconditions(final long groupIdValue, final long... requiredId) {
248         final BindingMap.Builder<ActionKey, Action> actionBag = BindingMap.builder(requiredId.length);
249         int key = 0;
250         for (long groupIdPrecondition : requiredId) {
251             actionBag.add(new ActionBuilder()
252                 .setOrder(key)
253                 .setAction(new GroupActionCaseBuilder()
254                     .setGroupAction(new GroupActionBuilder()
255                         .setGroupId(Uint32.valueOf(groupIdPrecondition))
256                         .build())
257                     .build())
258                 .withKey(new ActionKey(key++))
259                 .build());
260         }
261
262         return new GroupBuilder()
263                 .setGroupId(new GroupId(Uint32.valueOf(groupIdValue)))
264                 .setBuckets(new BucketsBuilder()
265                     .setBucket(BindingMap.of(new BucketBuilder()
266                         .setBucketId(new BucketId(Uint32.ZERO))
267                         .setAction(actionBag.build())
268                         .build()))
269                     .build())
270                 .build();
271     }
272
273     private static Map<Uint32, Group> createGroups(final long... groupIds) {
274         final Map<Uint32, Group> ret = Maps.newHashMapWithExpectedSize(groupIds.length);
275         for (long groupId : groupIds) {
276             ret.put(Uint32.valueOf(groupId), createGroup(groupId));
277         }
278         return ret;
279     }
280
281     private static Group createGroup(final long groupIdValue) {
282         return new GroupBuilder()
283                 .setGroupId(new GroupId(Uint32.valueOf(groupIdValue)))
284                 .setBuckets(new BucketsBuilder().build())
285                 .build();
286     }
287
288     /**
289      * covers {@link ReconcileUtil#countTotalUpdated(Iterable)} too.
290      */
291     @Test
292     public void testCountTotalAdds() {
293         List<ItemSyncBox<String>> syncPlan = new ArrayList<>();
294         ItemSyncBox<String> syncBox1 = createSyncBox("a,b", "x,y,z");
295         syncPlan.add(syncBox1);
296         syncPlan.add(syncBox1);
297         Assert.assertEquals(4, ReconcileUtil.countTotalPushed(syncPlan));
298         Assert.assertEquals(6, ReconcileUtil.countTotalUpdated(syncPlan));
299     }
300
301     private static ItemSyncBox<String> createSyncBox(final String pushes, final String updates) {
302         ItemSyncBox<String> syncBox1 = new ItemSyncBox<>();
303         syncBox1.getItemsToPush().addAll(COMMA_SPLITTER.splitToList(pushes));
304         for (String orig : COMMA_SPLITTER.splitToList(updates)) {
305             syncBox1.getItemsToUpdate().add(new ItemSyncBox.ItemUpdateTuple<>(orig, orig + "_updated"));
306         }
307         return syncBox1;
308     }
309 }