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