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