blob: 11ec79513b632b2b8dfb06f46f000cb56b59da11 [file] [log] [blame]
/*
* Copyright 2015-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.store.trivial;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.onosproject.net.DeviceId.deviceId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.DefaultApplicationId;
import org.onosproject.core.GroupId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.group.DefaultGroup;
import org.onosproject.net.group.DefaultGroupBucket;
import org.onosproject.net.group.DefaultGroupDescription;
import org.onosproject.net.group.DefaultGroupKey;
import org.onosproject.net.group.Group;
import org.onosproject.net.group.GroupBucket;
import org.onosproject.net.group.GroupBuckets;
import org.onosproject.net.group.GroupDescription;
import org.onosproject.net.group.GroupEvent;
import org.onosproject.net.group.GroupKey;
import org.onosproject.net.group.GroupOperation;
import org.onosproject.net.group.GroupStore.UpdateType;
import org.onosproject.net.group.GroupStoreDelegate;
import org.onosproject.net.group.StoredGroupBucketEntry;
import org.onosproject.net.group.StoredGroupEntry;
import com.google.common.collect.Iterables;
/**
* Test of the simple DeviceStore implementation.
*/
public class SimpleGroupStoreTest {
private SimpleGroupStore simpleGroupStore;
private final ApplicationId appId =
new DefaultApplicationId(2, "org.groupstore.test");
public static final DeviceId D1 = deviceId("of:1");
@Before
public void setUp() throws Exception {
simpleGroupStore = new SimpleGroupStore();
simpleGroupStore.activate();
}
@After
public void tearDown() throws Exception {
simpleGroupStore.deactivate();
}
private class InternalGroupStoreDelegate
implements GroupStoreDelegate {
private GroupId createdGroupId = null;
private GroupKey createdGroupKey;
private GroupBuckets createdBuckets;
private GroupEvent.Type expectedEvent;
public InternalGroupStoreDelegate(GroupKey key,
GroupBuckets buckets,
GroupEvent.Type expectedEvent) {
this.createdBuckets = buckets;
this.createdGroupKey = key;
this.expectedEvent = expectedEvent;
}
@Override
public void notify(GroupEvent event) {
assertEquals(expectedEvent, event.type());
assertEquals(Group.Type.SELECT, event.subject().type());
assertEquals(D1, event.subject().deviceId());
assertEquals(createdGroupKey, event.subject().appCookie());
assertEquals(createdBuckets.buckets(), event.subject().buckets().buckets());
if (expectedEvent == GroupEvent.Type.GROUP_ADD_REQUESTED) {
createdGroupId = event.subject().id();
assertEquals(Group.GroupState.PENDING_ADD,
event.subject().state());
} else if (expectedEvent == GroupEvent.Type.GROUP_ADDED) {
createdGroupId = event.subject().id();
assertEquals(Group.GroupState.ADDED,
event.subject().state());
} else if (expectedEvent == GroupEvent.Type.GROUP_UPDATED) {
createdGroupId = event.subject().id();
assertEquals(true,
event.subject().buckets().
buckets().containsAll(createdBuckets.buckets()));
assertEquals(true,
createdBuckets.buckets().
containsAll(event.subject().buckets().buckets()));
for (GroupBucket bucket:event.subject().buckets().buckets()) {
Optional<GroupBucket> matched = createdBuckets.buckets()
.stream()
.filter((expected) -> expected.equals(bucket))
.findFirst();
assertEquals(matched.get().packets(),
bucket.packets());
assertEquals(matched.get().bytes(),
bucket.bytes());
}
assertEquals(Group.GroupState.ADDED,
event.subject().state());
} else if (expectedEvent == GroupEvent.Type.GROUP_UPDATE_REQUESTED) {
assertEquals(Group.GroupState.PENDING_UPDATE,
event.subject().state());
} else if (expectedEvent == GroupEvent.Type.GROUP_REMOVE_REQUESTED) {
assertEquals(Group.GroupState.PENDING_DELETE,
event.subject().state());
} else if (expectedEvent == GroupEvent.Type.GROUP_REMOVED) {
createdGroupId = event.subject().id();
assertEquals(Group.GroupState.PENDING_DELETE,
event.subject().state());
} else if (expectedEvent == GroupEvent.Type.GROUP_ADD_FAILED) {
createdGroupId = event.subject().id();
assertEquals(Group.GroupState.PENDING_ADD,
event.subject().state());
} else if (expectedEvent == GroupEvent.Type.GROUP_UPDATE_FAILED) {
createdGroupId = event.subject().id();
assertEquals(Group.GroupState.PENDING_UPDATE,
event.subject().state());
} else if (expectedEvent == GroupEvent.Type.GROUP_REMOVE_FAILED) {
createdGroupId = event.subject().id();
assertEquals(Group.GroupState.PENDING_DELETE,
event.subject().state());
}
}
public void verifyGroupId(GroupId id) {
assertEquals(createdGroupId, id);
}
}
/**
* Tests group store operations. The following operations are tested:
* a)Tests device group audit completion status change
* b)Tests storeGroup operation
* c)Tests getGroupCount operation
* d)Tests getGroup operation
* e)Tests getGroups operation
* f)Tests addOrUpdateGroupEntry operation from southbound
* g)Tests updateGroupDescription for ADD operation from northbound
* h)Tests updateGroupDescription for REMOVE operation from northbound
* i)Tests deleteGroupDescription operation from northbound
* j)Tests removeGroupEntry operation from southbound
*/
@Test
public void testGroupStoreOperations() {
// Set the Device AUDIT completed in the store
simpleGroupStore.deviceInitialAuditCompleted(D1, true);
// Testing storeGroup operation
GroupKey newKey = new DefaultGroupKey("group1".getBytes());
testStoreAndGetGroup(newKey);
// Testing addOrUpdateGroupEntry operation from southbound
GroupKey currKey = newKey;
testAddGroupEntryFromSB(currKey);
// Testing updateGroupDescription for ADD operation from northbound
newKey = new DefaultGroupKey("group1AddBuckets".getBytes());
testAddBuckets(currKey, newKey);
// Testing updateGroupDescription for REMOVE operation from northbound
currKey = newKey;
newKey = new DefaultGroupKey("group1RemoveBuckets".getBytes());
testRemoveBuckets(currKey, newKey);
// Testing addOrUpdateGroupEntry operation from southbound
currKey = newKey;
testUpdateGroupEntryFromSB(currKey);
// Testing deleteGroupDescription operation from northbound
testDeleteGroup(currKey);
// Testing removeGroupEntry operation from southbound
testRemoveGroupFromSB(currKey);
// Testing removing all groups on the given device
newKey = new DefaultGroupKey("group1".getBytes());
testStoreAndGetGroup(newKey);
testDeleteGroupOnDevice(newKey);
}
// Testing storeGroup operation
private void testStoreAndGetGroup(GroupKey key) {
PortNumber[] ports = {PortNumber.portNumber(31),
PortNumber.portNumber(32)};
List<PortNumber> outPorts = new ArrayList<>();
outPorts.addAll(Arrays.asList(ports));
List<GroupBucket> buckets = new ArrayList<>();
for (PortNumber portNumber: outPorts) {
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
tBuilder.setOutput(portNumber)
.setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
.setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
.pushMpls()
.setMpls(MplsLabel.mplsLabel(106));
buckets.add(DefaultGroupBucket.createSelectGroupBucket(
tBuilder.build()));
}
GroupBuckets groupBuckets = new GroupBuckets(buckets);
GroupDescription groupDesc = new DefaultGroupDescription(
D1,
Group.Type.SELECT,
groupBuckets,
key,
null,
appId);
InternalGroupStoreDelegate checkStoreGroupDelegate =
new InternalGroupStoreDelegate(key,
groupBuckets,
GroupEvent.Type.GROUP_ADD_REQUESTED);
simpleGroupStore.setDelegate(checkStoreGroupDelegate);
// Testing storeGroup operation
simpleGroupStore.storeGroupDescription(groupDesc);
// Testing getGroupCount operation
assertEquals(1, simpleGroupStore.getGroupCount(D1));
// Testing getGroup operation
Group createdGroup = simpleGroupStore.getGroup(D1, key);
checkStoreGroupDelegate.verifyGroupId(createdGroup.id());
// Testing getGroups operation
Iterable<Group> createdGroups = simpleGroupStore.getGroups(D1);
int groupCount = 0;
for (Group group:createdGroups) {
checkStoreGroupDelegate.verifyGroupId(group.id());
groupCount++;
}
assertEquals(1, groupCount);
simpleGroupStore.unsetDelegate(checkStoreGroupDelegate);
}
// Testing addOrUpdateGroupEntry operation from southbound
private void testAddGroupEntryFromSB(GroupKey currKey) {
Group existingGroup = simpleGroupStore.getGroup(D1, currKey);
InternalGroupStoreDelegate addGroupEntryDelegate =
new InternalGroupStoreDelegate(currKey,
existingGroup.buckets(),
GroupEvent.Type.GROUP_ADDED);
simpleGroupStore.setDelegate(addGroupEntryDelegate);
simpleGroupStore.addOrUpdateGroupEntry(existingGroup);
simpleGroupStore.unsetDelegate(addGroupEntryDelegate);
}
// Testing addOrUpdateGroupEntry operation from southbound
private void testUpdateGroupEntryFromSB(GroupKey currKey) {
Group existingGroup = simpleGroupStore.getGroup(D1, currKey);
int totalPkts = 0;
int totalBytes = 0;
List<GroupBucket> newBucketList = new ArrayList<>();
for (GroupBucket bucket:existingGroup.buckets().buckets()) {
StoredGroupBucketEntry newBucket =
(StoredGroupBucketEntry)
DefaultGroupBucket.createSelectGroupBucket(bucket.treatment());
newBucket.setPackets(10);
newBucket.setBytes(10 * 256 * 8);
totalPkts += 10;
totalBytes += 10 * 256 * 8;
newBucketList.add(newBucket);
}
GroupBuckets updatedBuckets = new GroupBuckets(newBucketList);
Group updatedGroup = new DefaultGroup(existingGroup.id(),
existingGroup.deviceId(),
existingGroup.type(),
updatedBuckets);
((StoredGroupEntry) updatedGroup).setPackets(totalPkts);
((StoredGroupEntry) updatedGroup).setBytes(totalBytes);
InternalGroupStoreDelegate updateGroupEntryDelegate =
new InternalGroupStoreDelegate(currKey,
updatedBuckets,
GroupEvent.Type.GROUP_UPDATED);
simpleGroupStore.setDelegate(updateGroupEntryDelegate);
simpleGroupStore.addOrUpdateGroupEntry(updatedGroup);
simpleGroupStore.unsetDelegate(updateGroupEntryDelegate);
}
// Testing updateGroupDescription for ADD operation from northbound
private void testAddBuckets(GroupKey currKey, GroupKey addKey) {
Group existingGroup = simpleGroupStore.getGroup(D1, currKey);
List<GroupBucket> buckets = new ArrayList<>();
buckets.addAll(existingGroup.buckets().buckets());
PortNumber[] newNeighborPorts = {PortNumber.portNumber(41),
PortNumber.portNumber(42)};
List<PortNumber> newOutPorts = new ArrayList<>();
newOutPorts.addAll(Collections.singletonList(newNeighborPorts[0]));
List<GroupBucket> toAddBuckets = new ArrayList<>();
for (PortNumber portNumber: newOutPorts) {
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
tBuilder.setOutput(portNumber)
.setEthDst(MacAddress.valueOf("00:00:00:00:00:03"))
.setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
.pushMpls()
.setMpls(MplsLabel.mplsLabel(106));
toAddBuckets.add(DefaultGroupBucket.createSelectGroupBucket(
tBuilder.build()));
}
GroupBuckets toAddGroupBuckets = new GroupBuckets(toAddBuckets);
buckets.addAll(toAddBuckets);
GroupBuckets updatedGroupBuckets = new GroupBuckets(buckets);
InternalGroupStoreDelegate updateGroupDescDelegate =
new InternalGroupStoreDelegate(addKey,
updatedGroupBuckets,
GroupEvent.Type.GROUP_UPDATE_REQUESTED);
simpleGroupStore.setDelegate(updateGroupDescDelegate);
simpleGroupStore.updateGroupDescription(D1,
currKey,
UpdateType.ADD,
toAddGroupBuckets,
addKey);
simpleGroupStore.unsetDelegate(updateGroupDescDelegate);
}
// Testing updateGroupDescription for REMOVE operation from northbound
private void testRemoveBuckets(GroupKey currKey, GroupKey removeKey) {
Group existingGroup = simpleGroupStore.getGroup(D1, currKey);
List<GroupBucket> buckets = new ArrayList<>();
buckets.addAll(existingGroup.buckets().buckets());
List<GroupBucket> toRemoveBuckets = new ArrayList<>();
// There should be 4 buckets in the current group
toRemoveBuckets.add(buckets.remove(0));
toRemoveBuckets.add(buckets.remove(1));
GroupBuckets toRemoveGroupBuckets = new GroupBuckets(toRemoveBuckets);
GroupBuckets remainingGroupBuckets = new GroupBuckets(buckets);
InternalGroupStoreDelegate removeGroupDescDelegate =
new InternalGroupStoreDelegate(removeKey,
remainingGroupBuckets,
GroupEvent.Type.GROUP_UPDATE_REQUESTED);
simpleGroupStore.setDelegate(removeGroupDescDelegate);
simpleGroupStore.updateGroupDescription(D1,
currKey,
UpdateType.REMOVE,
toRemoveGroupBuckets,
removeKey);
simpleGroupStore.unsetDelegate(removeGroupDescDelegate);
}
// Testing deleteGroupDescription operation from northbound
private void testDeleteGroup(GroupKey currKey) {
Group existingGroup = simpleGroupStore.getGroup(D1, currKey);
InternalGroupStoreDelegate deleteGroupDescDelegate =
new InternalGroupStoreDelegate(currKey,
existingGroup.buckets(),
GroupEvent.Type.GROUP_REMOVE_REQUESTED);
simpleGroupStore.setDelegate(deleteGroupDescDelegate);
simpleGroupStore.deleteGroupDescription(D1, currKey);
simpleGroupStore.unsetDelegate(deleteGroupDescDelegate);
}
// Testing deleteGroupDescription operation from northbound
private void testDeleteGroupOnDevice(GroupKey currKey) {
assertThat(simpleGroupStore.getGroupCount(D1), is(1));
simpleGroupStore.purgeGroupEntry(D1);
assertThat(simpleGroupStore.getGroupCount(D1), is(0));
}
// Testing removeGroupEntry operation from southbound
private void testRemoveGroupFromSB(GroupKey currKey) {
Group existingGroup = simpleGroupStore.getGroup(D1, currKey);
InternalGroupStoreDelegate removeGroupEntryDelegate =
new InternalGroupStoreDelegate(currKey,
existingGroup.buckets(),
GroupEvent.Type.GROUP_REMOVED);
simpleGroupStore.setDelegate(removeGroupEntryDelegate);
simpleGroupStore.removeGroupEntry(existingGroup);
// Testing getGroup operation
existingGroup = simpleGroupStore.getGroup(D1, currKey);
assertEquals(null, existingGroup);
assertEquals(0, Iterables.size(simpleGroupStore.getGroups(D1)));
assertEquals(0, simpleGroupStore.getGroupCount(D1));
simpleGroupStore.unsetDelegate(removeGroupEntryDelegate);
}
@Test
public void testGroupOperationFailure() {
simpleGroupStore.deviceInitialAuditCompleted(D1, true);
ApplicationId appId =
new DefaultApplicationId(2, "org.groupstore.test");
GroupKey key = new DefaultGroupKey("group1".getBytes());
PortNumber[] ports = {PortNumber.portNumber(31),
PortNumber.portNumber(32)};
List<PortNumber> outPorts = new ArrayList<>();
outPorts.add(ports[0]);
outPorts.add(ports[1]);
List<GroupBucket> buckets = new ArrayList<>();
for (PortNumber portNumber: outPorts) {
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
tBuilder.setOutput(portNumber)
.setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
.setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
.pushMpls()
.setMpls(MplsLabel.mplsLabel(106));
buckets.add(DefaultGroupBucket.createSelectGroupBucket(
tBuilder.build()));
}
GroupBuckets groupBuckets = new GroupBuckets(buckets);
GroupDescription groupDesc = new DefaultGroupDescription(
D1,
Group.Type.SELECT,
groupBuckets,
key,
null,
appId);
InternalGroupStoreDelegate checkStoreGroupDelegate =
new InternalGroupStoreDelegate(key,
groupBuckets,
GroupEvent.Type.GROUP_ADD_REQUESTED);
simpleGroupStore.setDelegate(checkStoreGroupDelegate);
// Testing storeGroup operation
simpleGroupStore.storeGroupDescription(groupDesc);
simpleGroupStore.unsetDelegate(checkStoreGroupDelegate);
// Testing Group add operation failure
Group createdGroup = simpleGroupStore.getGroup(D1, key);
checkStoreGroupDelegate.verifyGroupId(createdGroup.id());
GroupOperation groupAddOp = GroupOperation.
createAddGroupOperation(createdGroup.id(),
createdGroup.type(),
createdGroup.buckets());
InternalGroupStoreDelegate checkGroupAddFailureDelegate =
new InternalGroupStoreDelegate(key,
groupBuckets,
GroupEvent.Type.GROUP_ADD_FAILED);
simpleGroupStore.setDelegate(checkGroupAddFailureDelegate);
simpleGroupStore.groupOperationFailed(D1, groupAddOp);
// Testing Group modify operation failure
simpleGroupStore.unsetDelegate(checkGroupAddFailureDelegate);
GroupOperation groupModOp = GroupOperation.
createModifyGroupOperation(createdGroup.id(),
createdGroup.type(),
createdGroup.buckets());
InternalGroupStoreDelegate checkGroupModFailureDelegate =
new InternalGroupStoreDelegate(key,
groupBuckets,
GroupEvent.Type.GROUP_UPDATE_FAILED);
simpleGroupStore.setDelegate(checkGroupModFailureDelegate);
simpleGroupStore.groupOperationFailed(D1, groupModOp);
// Testing Group modify operation failure
simpleGroupStore.unsetDelegate(checkGroupModFailureDelegate);
GroupOperation groupDelOp = GroupOperation.
createDeleteGroupOperation(createdGroup.id(),
createdGroup.type());
InternalGroupStoreDelegate checkGroupDelFailureDelegate =
new InternalGroupStoreDelegate(key,
groupBuckets,
GroupEvent.Type.GROUP_REMOVE_FAILED);
simpleGroupStore.setDelegate(checkGroupDelFailureDelegate);
simpleGroupStore.groupOperationFailed(D1, groupDelOp);
}
}