// Test initial AUDIT process with pending group requests
  private void testInitialAuditWithPendingGroupRequests(DeviceId deviceId) {
    PortNumber[] ports1 = {PortNumber.portNumber(31), PortNumber.portNumber(32)};
    PortNumber[] ports2 = {PortNumber.portNumber(41), PortNumber.portNumber(42)};
    GroupId gId1 = new DefaultGroupId(1);
    Group group1 = createSouthboundGroupEntry(gId1, Arrays.asList(ports1), 0, deviceId);
    GroupId gId2 = new DefaultGroupId(2);
    // Non zero reference count will make the group manager to queue
    // the extraneous groups until reference count is zero.
    Group group2 = createSouthboundGroupEntry(gId2, Arrays.asList(ports2), 2, deviceId);
    List<Group> groupEntries = Arrays.asList(group1, group2);
    providerService.pushGroupMetrics(deviceId, groupEntries);
    // First group metrics would trigger the device audit completion
    // post which all pending group requests are also executed.
    GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
    Group createdGroup = groupService.getGroup(deviceId, key);
    int createdGroupId = createdGroup.id().id();
    assertNotEquals(gId1.id(), createdGroupId);
    assertNotEquals(gId2.id(), createdGroupId);

    List<GroupOperation> expectedGroupOps =
        Arrays.asList(
            GroupOperation.createDeleteGroupOperation(gId1, Group.Type.SELECT),
            GroupOperation.createAddGroupOperation(
                createdGroup.id(), Group.Type.SELECT, createdGroup.buckets()));
    if (deviceId.equals(DID)) {
      internalProvider.validate(deviceId, expectedGroupOps);
    } else {
      this.validate(deviceId, expectedGroupOps);
    }
  }
 // Test group remove operations
 private void testRemoveGroup(DeviceId deviceId) {
   GroupKey currKey = new DefaultGroupKey("group1RemoveBuckets".getBytes());
   Group existingGroup = groupService.getGroup(deviceId, currKey);
   groupService.removeGroup(deviceId, currKey, appId);
   List<GroupOperation> expectedGroupOps =
       Collections.singletonList(
           GroupOperation.createDeleteGroupOperation(existingGroup.id(), Group.Type.SELECT));
   if (deviceId.equals(DID)) {
     internalProvider.validate(deviceId, expectedGroupOps);
   } else {
     this.validate(deviceId, expectedGroupOps);
   }
   List<Group> groupEntries = Collections.emptyList();
   providerService.pushGroupMetrics(deviceId, groupEntries);
   internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_REMOVED));
 }
  // Test group add bucket operations
  private void testAddBuckets(DeviceId deviceId) {
    GroupKey addKey = new DefaultGroupKey("group1AddBuckets".getBytes());

    GroupKey prevKey = new DefaultGroupKey("group1BeforeAudit".getBytes());
    Group createdGroup = groupService.getGroup(deviceId, prevKey);
    List<GroupBucket> buckets = new ArrayList<>();
    buckets.addAll(createdGroup.buckets().buckets());

    PortNumber[] addPorts = {PortNumber.portNumber(51), PortNumber.portNumber(52)};
    List<PortNumber> outPorts;
    outPorts = new ArrayList<>();
    outPorts.addAll(Arrays.asList(addPorts));
    List<GroupBucket> addBuckets;
    addBuckets = 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));
      addBuckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build()));
      buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build()));
    }
    GroupBuckets groupAddBuckets = new GroupBuckets(addBuckets);
    groupService.addBucketsToGroup(deviceId, prevKey, groupAddBuckets, addKey, appId);
    GroupBuckets updatedBuckets = new GroupBuckets(buckets);
    List<GroupOperation> expectedGroupOps =
        Collections.singletonList(
            GroupOperation.createModifyGroupOperation(
                createdGroup.id(), Group.Type.SELECT, updatedBuckets));
    if (deviceId.equals(DID)) {
      internalProvider.validate(deviceId, expectedGroupOps);
    } else {
      this.validate(deviceId, expectedGroupOps);
    }
    Group existingGroup = groupService.getGroup(deviceId, addKey);
    List<Group> groupEntries = Collections.singletonList(existingGroup);
    providerService.pushGroupMetrics(deviceId, groupEntries);
    internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_UPDATED));
  }
 // Test AUDIT process with extraneous groups and missing groups
 private void testAuditWithExtraneousMissingGroups(DeviceId deviceId) {
   PortNumber[] ports1 = {PortNumber.portNumber(31), PortNumber.portNumber(32)};
   PortNumber[] ports2 = {PortNumber.portNumber(41), PortNumber.portNumber(42)};
   GroupId gId1 = new DefaultGroupId(1);
   Group group1 = createSouthboundGroupEntry(gId1, Arrays.asList(ports1), 0, deviceId);
   GroupId gId2 = new DefaultGroupId(2);
   Group group2 = createSouthboundGroupEntry(gId2, Arrays.asList(ports2), 0, deviceId);
   List<Group> groupEntries = Arrays.asList(group1, group2);
   providerService.pushGroupMetrics(deviceId, groupEntries);
   GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
   Group createdGroup = groupService.getGroup(deviceId, key);
   List<GroupOperation> expectedGroupOps =
       Arrays.asList(
           GroupOperation.createDeleteGroupOperation(gId1, Group.Type.SELECT),
           GroupOperation.createDeleteGroupOperation(gId2, Group.Type.SELECT),
           GroupOperation.createAddGroupOperation(
               createdGroup.id(), Group.Type.SELECT, createdGroup.buckets()));
   if (deviceId.equals(DID)) {
     internalProvider.validate(deviceId, expectedGroupOps);
   } else {
     this.validate(deviceId, expectedGroupOps);
   }
 }