blob: 2e184302766b1f253929826b7ec45fe26c3aa8b6 [file] [log] [blame]
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -08001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.net.group.impl;
17
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080018import java.util.ArrayList;
19import java.util.Arrays;
20import java.util.Collections;
21import java.util.List;
22
23import org.junit.After;
24import org.junit.Before;
25import org.junit.Test;
26import org.onlab.packet.MacAddress;
27import org.onosproject.core.ApplicationId;
28import org.onosproject.core.DefaultApplicationId;
29import org.onosproject.core.DefaultGroupId;
30import org.onosproject.core.GroupId;
31import org.onosproject.event.impl.TestEventDispatcher;
32import org.onosproject.net.DeviceId;
33import org.onosproject.net.PortNumber;
34import org.onosproject.net.flow.DefaultTrafficTreatment;
35import org.onosproject.net.flow.TrafficTreatment;
36import org.onosproject.net.group.DefaultGroup;
37import org.onosproject.net.group.DefaultGroupBucket;
38import org.onosproject.net.group.DefaultGroupDescription;
39import org.onosproject.net.group.Group;
40import org.onosproject.net.group.GroupBucket;
41import org.onosproject.net.group.GroupBuckets;
42import org.onosproject.net.group.GroupDescription;
43import org.onosproject.net.group.GroupEvent;
44import org.onosproject.net.group.GroupKey;
45import org.onosproject.net.group.GroupListener;
46import org.onosproject.net.group.GroupOperation;
47import org.onosproject.net.group.GroupOperations;
48import org.onosproject.net.group.GroupProvider;
49import org.onosproject.net.group.GroupProviderRegistry;
50import org.onosproject.net.group.GroupProviderService;
51import org.onosproject.net.group.GroupService;
52import org.onosproject.net.group.StoredGroupEntry;
53import org.onosproject.net.provider.AbstractProvider;
54import org.onosproject.net.provider.ProviderId;
55import org.onosproject.store.trivial.impl.SimpleGroupStore;
56
57import com.google.common.collect.Iterables;
58
sangho7ff01812015-02-09 16:21:53 -080059import static org.junit.Assert.*;
60
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080061/**
62 * Test codifying the group service & group provider service contracts.
63 */
64public class GroupManagerTest {
65
66 private static final ProviderId PID = new ProviderId("of", "groupfoo");
67 private static final DeviceId DID = DeviceId.deviceId("of:001");
68
69 private GroupManager mgr;
70 private GroupService groupService;
71 private GroupProviderRegistry providerRegistry;
72 private TestGroupListener internalListener = new TestGroupListener();
73 private GroupListener listener = internalListener;
74 private TestGroupProvider internalProvider;
75 private GroupProvider provider;
76 private GroupProviderService providerService;
77 private ApplicationId appId;
78
79 @Before
80 public void setUp() {
81 mgr = new GroupManager();
82 groupService = mgr;
83 mgr.store = new SimpleGroupStore();
84 mgr.eventDispatcher = new TestEventDispatcher();
85 providerRegistry = mgr;
86
87 mgr.activate();
88 mgr.addListener(listener);
89
90 internalProvider = new TestGroupProvider(PID);
91 provider = internalProvider;
92 providerService = providerRegistry.register(provider);
93 appId = new DefaultApplicationId(2, "org.groupmanager.test");
94 assertTrue("provider should be registered",
95 providerRegistry.getProviders().contains(provider.id()));
96 }
97
98 @After
99 public void tearDown() {
100 providerRegistry.unregister(provider);
101 assertFalse("provider should not be registered",
102 providerRegistry.getProviders().contains(provider.id()));
103 mgr.removeListener(listener);
104 mgr.deactivate();
105 mgr.eventDispatcher = null;
106 }
107
108 private class TestGroupKey implements GroupKey {
109 private String groupId;
110
111 public TestGroupKey(String id) {
112 this.groupId = id;
113 }
114
115 public String id() {
116 return this.groupId;
117 }
118
119 @Override
120 public int hashCode() {
121 return groupId.hashCode();
122 }
123
124 @Override
125 public boolean equals(Object obj) {
126 if (obj instanceof TestGroupKey) {
127 return this.groupId.equals(((TestGroupKey) obj).id());
128 }
129 return false;
130 }
131 }
132
133 /**
134 * Tests group service north bound and south bound interfaces.
135 * The following operations are tested:
136 * a)Tests group creation before the device group AUDIT completes
137 * b)Tests initial device group AUDIT process
138 * c)Tests deletion process of any extraneous groups
139 * d)Tests execution of any pending group creation requests
140 * after the device group AUDIT completes
141 * e)Tests re-apply process of any missing groups
142 * f)Tests event notifications after receiving confirmation for
143 * any operations from data plane
144 * g)Tests group bucket modifications (additions and deletions)
145 * h)Tests group deletion
146 */
147 @Test
148 public void testGroupService() {
149 PortNumber[] ports1 = {PortNumber.portNumber(31),
150 PortNumber.portNumber(32)};
151 PortNumber[] ports2 = {PortNumber.portNumber(41),
152 PortNumber.portNumber(42)};
153 // Test Group creation before AUDIT process
154 TestGroupKey key = new TestGroupKey("group1BeforeAudit");
155 List<GroupBucket> buckets = new ArrayList<GroupBucket>();
156 List<PortNumber> outPorts = new ArrayList<PortNumber>();
157 outPorts.addAll(Arrays.asList(ports1));
158 outPorts.addAll(Arrays.asList(ports2));
159 for (PortNumber portNumber: outPorts) {
160 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
161 tBuilder.setOutput(portNumber)
162 .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
163 .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
164 .pushMpls()
165 .setMpls(106);
166 buckets.add(DefaultGroupBucket.createSelectGroupBucket(
167 tBuilder.build()));
168 }
169 GroupBuckets groupBuckets = new GroupBuckets(buckets);
170 GroupDescription newGroupDesc = new DefaultGroupDescription(DID,
171 Group.Type.SELECT,
172 groupBuckets,
173 key,
174 appId);
175 groupService.addGroup(newGroupDesc);
176 internalProvider.validate(DID, null);
177 assertEquals(null, groupService.getGroup(DID, key));
178 assertEquals(0, Iterables.size(groupService.getGroups(DID, appId)));
179
180 // Test initial group audit process
181 GroupId gId1 = new DefaultGroupId(1);
182 Group group1 = createSouthboundGroupEntry(gId1,
183 Arrays.asList(ports1),
184 0);
185 GroupId gId2 = new DefaultGroupId(2);
186 // Non zero reference count will make the group manager to queue
187 // the extraneous groups until reference count is zero.
188 Group group2 = createSouthboundGroupEntry(gId2,
189 Arrays.asList(ports2),
190 2);
191 List<Group> groupEntries = Arrays.asList(group1, group2);
192 providerService.pushGroupMetrics(DID, groupEntries);
193 // First group metrics would trigger the device audit completion
194 // post which all pending group requests are also executed.
195 Group createdGroup = groupService.getGroup(DID, key);
196 int createdGroupId = createdGroup.id().id();
197 assertNotEquals(gId1.id(), createdGroupId);
198 assertNotEquals(gId2.id(), createdGroupId);
199 List<GroupOperation> expectedGroupOps = Arrays.asList(
200 GroupOperation.createDeleteGroupOperation(gId1,
201 Group.Type.SELECT),
202 GroupOperation.createAddGroupOperation(
203 createdGroup.id(),
204 Group.Type.SELECT,
205 groupBuckets));
206 internalProvider.validate(DID, expectedGroupOps);
207
208 group1 = createSouthboundGroupEntry(gId1,
209 Arrays.asList(ports1),
210 0);
211 group2 = createSouthboundGroupEntry(gId2,
212 Arrays.asList(ports2),
213 0);
214 groupEntries = Arrays.asList(group1, group2);
215 providerService.pushGroupMetrics(DID, groupEntries);
216 expectedGroupOps = Arrays.asList(
217 GroupOperation.createDeleteGroupOperation(gId1,
218 Group.Type.SELECT),
219 GroupOperation.createDeleteGroupOperation(gId2,
220 Group.Type.SELECT),
221 GroupOperation.createAddGroupOperation(createdGroup.id(),
222 Group.Type.SELECT,
223 groupBuckets));
224 internalProvider.validate(DID, expectedGroupOps);
225
226 createdGroup = new DefaultGroup(createdGroup.id(),
227 DID,
228 Group.Type.SELECT,
229 groupBuckets);
230 groupEntries = Arrays.asList(createdGroup);
231 providerService.pushGroupMetrics(DID, groupEntries);
232 internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_ADDED));
233
234 // Test group add bucket operations
235 TestGroupKey addKey = new TestGroupKey("group1AddBuckets");
236 PortNumber[] addPorts = {PortNumber.portNumber(51),
237 PortNumber.portNumber(52)};
238 outPorts.clear();
239 outPorts.addAll(Arrays.asList(addPorts));
240 List<GroupBucket> addBuckets = new ArrayList<GroupBucket>();
241 for (PortNumber portNumber: outPorts) {
242 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
243 tBuilder.setOutput(portNumber)
244 .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
245 .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
246 .pushMpls()
247 .setMpls(106);
248 addBuckets.add(DefaultGroupBucket.createSelectGroupBucket(
249 tBuilder.build()));
250 buckets.add(DefaultGroupBucket.createSelectGroupBucket(
251 tBuilder.build()));
252 }
253 GroupBuckets groupAddBuckets = new GroupBuckets(addBuckets);
254 groupService.addBucketsToGroup(DID,
255 key,
256 groupAddBuckets,
257 addKey,
258 appId);
259 GroupBuckets updatedBuckets = new GroupBuckets(buckets);
260 expectedGroupOps = Arrays.asList(
261 GroupOperation.createModifyGroupOperation(createdGroup.id(),
262 Group.Type.SELECT,
263 updatedBuckets));
264 internalProvider.validate(DID, expectedGroupOps);
265 Group existingGroup = groupService.getGroup(DID, addKey);
266 groupEntries = Arrays.asList(existingGroup);
267 providerService.pushGroupMetrics(DID, groupEntries);
268 internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_UPDATED));
269
270 // Test group remove bucket operations
271 TestGroupKey removeKey = new TestGroupKey("group1RemoveBuckets");
272 PortNumber[] removePorts = {PortNumber.portNumber(31),
273 PortNumber.portNumber(32)};
274 outPorts.clear();
275 outPorts.addAll(Arrays.asList(removePorts));
276 List<GroupBucket> removeBuckets = new ArrayList<GroupBucket>();
277 for (PortNumber portNumber: outPorts) {
278 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
279 tBuilder.setOutput(portNumber)
280 .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
281 .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
282 .pushMpls()
283 .setMpls(106);
284 removeBuckets.add(DefaultGroupBucket.createSelectGroupBucket(
285 tBuilder.build()));
286 buckets.remove(DefaultGroupBucket.createSelectGroupBucket(
287 tBuilder.build()));
288 }
289 GroupBuckets groupRemoveBuckets = new GroupBuckets(removeBuckets);
290 groupService.removeBucketsFromGroup(DID,
291 addKey,
292 groupRemoveBuckets,
293 removeKey,
294 appId);
295 updatedBuckets = new GroupBuckets(buckets);
296 expectedGroupOps = Arrays.asList(
297 GroupOperation.createModifyGroupOperation(createdGroup.id(),
298 Group.Type.SELECT,
299 updatedBuckets));
300 internalProvider.validate(DID, expectedGroupOps);
301 existingGroup = groupService.getGroup(DID, removeKey);
302 groupEntries = Arrays.asList(existingGroup);
303 providerService.pushGroupMetrics(DID, groupEntries);
304 internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_UPDATED));
305
306 // Test group remove operations
307 groupService.removeGroup(DID, removeKey, appId);
308 expectedGroupOps = Arrays.asList(
309 GroupOperation.createDeleteGroupOperation(createdGroup.id(),
310 Group.Type.SELECT));
311 internalProvider.validate(DID, expectedGroupOps);
312 groupEntries = Collections.emptyList();
313 providerService.pushGroupMetrics(DID, groupEntries);
314 internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_REMOVED));
315 }
316
sangho7ff01812015-02-09 16:21:53 -0800317 /**
318 * Test GroupOperationFailure function in Group Manager.
319 * a)GroupAddFailure
320 * b)GroupUpdateFailure
321 * c)GroupRemoteFailure
322 */
323 @Test
324 public void testGroupOperationFailure() {
325 PortNumber[] ports1 = {PortNumber.portNumber(31),
326 PortNumber.portNumber(32)};
327 PortNumber[] ports2 = {PortNumber.portNumber(41),
328 PortNumber.portNumber(42)};
329 // Test Group creation before AUDIT process
330 TestGroupKey key = new TestGroupKey("group1BeforeAudit");
331 List<GroupBucket> buckets = new ArrayList<GroupBucket>();
332 List<PortNumber> outPorts = new ArrayList<PortNumber>();
333 outPorts.addAll(Arrays.asList(ports1));
334 outPorts.addAll(Arrays.asList(ports2));
335 for (PortNumber portNumber: outPorts) {
336 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
337 tBuilder.setOutput(portNumber)
338 .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
339 .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
340 .pushMpls()
341 .setMpls(106);
342 buckets.add(DefaultGroupBucket.createSelectGroupBucket(
343 tBuilder.build()));
344 }
345 GroupBuckets groupBuckets = new GroupBuckets(buckets);
346 GroupDescription newGroupDesc = new DefaultGroupDescription(DID,
347 Group.Type.SELECT,
348 groupBuckets,
349 key,
350 appId);
351 groupService.addGroup(newGroupDesc);
352
353 // Test initial group audit process
354 GroupId gId1 = new DefaultGroupId(1);
355 Group group1 = createSouthboundGroupEntry(gId1,
356 Arrays.asList(ports1),
357 0);
358 GroupId gId2 = new DefaultGroupId(2);
359 // Non zero reference count will make the group manager to queue
360 // the extraneous groups until reference count is zero.
361 Group group2 = createSouthboundGroupEntry(gId2,
362 Arrays.asList(ports2),
363 2);
364 List<Group> groupEntries = Arrays.asList(group1, group2);
365 providerService.pushGroupMetrics(DID, groupEntries);
366 Group createdGroup = groupService.getGroup(DID, key);
367
368 // Group Add failure test
369 GroupOperation groupAddOp = GroupOperation.
370 createAddGroupOperation(createdGroup.id(),
371 createdGroup.type(),
372 createdGroup.buckets());
373 providerService.groupOperationFailed(DID, groupAddOp);
374 internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_ADD_FAILED));
375
376 // Group Mod failure test
377 groupService.addGroup(newGroupDesc);
378 createdGroup = groupService.getGroup(DID, key);
379 assertNotNull(createdGroup);
380
381 GroupOperation groupModOp = GroupOperation.
382 createModifyGroupOperation(createdGroup.id(),
383 createdGroup.type(),
384 createdGroup.buckets());
385 providerService.groupOperationFailed(DID, groupModOp);
386 internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_UPDATE_FAILED));
387
388 // Group Delete failure test
389 groupService.addGroup(newGroupDesc);
390 createdGroup = groupService.getGroup(DID, key);
391 assertNotNull(createdGroup);
392
393 GroupOperation groupDelOp = GroupOperation.
394 createDeleteGroupOperation(createdGroup.id(),
395 createdGroup.type());
396 providerService.groupOperationFailed(DID, groupDelOp);
397 internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_REMOVE_FAILED));
398
399 }
400
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800401 private Group createSouthboundGroupEntry(GroupId gId,
402 List<PortNumber> ports,
403 long referenceCount) {
404 List<PortNumber> outPorts = new ArrayList<PortNumber>();
405 outPorts.addAll(ports);
406
407 List<GroupBucket> buckets = new ArrayList<GroupBucket>();
408 for (PortNumber portNumber: outPorts) {
409 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
410 tBuilder.setOutput(portNumber)
411 .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
412 .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
413 .pushMpls()
414 .setMpls(106);
415 buckets.add(DefaultGroupBucket.createSelectGroupBucket(
416 tBuilder.build()));
417 }
418 GroupBuckets groupBuckets = new GroupBuckets(buckets);
419 StoredGroupEntry group = new DefaultGroup(
420 gId, DID, Group.Type.SELECT, groupBuckets);
421 group.setReferenceCount(referenceCount);
422 return group;
423 }
424
425 private static class TestGroupListener implements GroupListener {
426 final List<GroupEvent> events = new ArrayList<>();
427
428 @Override
429 public void event(GroupEvent event) {
430 events.add(event);
431 }
432
433 public void validateEvent(List<GroupEvent.Type> expectedEvents) {
434 int i = 0;
435 System.err.println("events :" + events);
436 for (GroupEvent e : events) {
437 assertEquals("unexpected event", expectedEvents.get(i), e.type());
438 i++;
439 }
440 assertEquals("mispredicted number of events",
441 expectedEvents.size(), events.size());
442 events.clear();
443 }
444 }
445
446 private class TestGroupProvider
447 extends AbstractProvider implements GroupProvider {
448 DeviceId lastDeviceId;
449 List<GroupOperation> groupOperations = new ArrayList<GroupOperation>();
450
451 protected TestGroupProvider(ProviderId id) {
452 super(id);
453 }
454
455 @Override
456 public void performGroupOperation(DeviceId deviceId,
457 GroupOperations groupOps) {
458 lastDeviceId = deviceId;
459 groupOperations.addAll(groupOps.operations());
460 }
461
462 public void validate(DeviceId expectedDeviceId,
463 List<GroupOperation> expectedGroupOps) {
464 if (expectedGroupOps == null) {
465 assertTrue("events generated", groupOperations.isEmpty());
466 return;
467 }
468
469 assertEquals(lastDeviceId, expectedDeviceId);
470 assertTrue((this.groupOperations.containsAll(expectedGroupOps) &&
471 expectedGroupOps.containsAll(groupOperations)));
472
473 groupOperations.clear();
474 lastDeviceId = null;
475 }
476
477 }
478
479}
480
481