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