@Override
    public void pushGroupMetrics(DeviceId deviceId,
                                 Collection<Group> groupEntries) {
        boolean deviceInitialAuditStatus =
                deviceInitialAuditStatus(deviceId);
        Set<Group> southboundGroupEntries =
                Sets.newHashSet(groupEntries);
        Set<StoredGroupEntry> storedGroupEntries =
                Sets.newHashSet(getStoredGroups(deviceId));
        Set<Group> extraneousStoredEntries =
                Sets.newHashSet(getExtraneousGroups(deviceId));
        NodeId master;

        if (log.isTraceEnabled()) {
            log.trace("pushGroupMetrics: Displaying all ({}) southboundGroupEntries for device {}",
                    southboundGroupEntries.size(),
                    deviceId);
            for (Group group : southboundGroupEntries) {
                log.trace("Group {} in device {}", group, deviceId);
            }

            log.trace("Displaying all ({}) stored group entries for device {}",
                    storedGroupEntries.size(),
                    deviceId);
            for (StoredGroupEntry group : storedGroupEntries) {
                log.trace("Stored Group {} for device {}", group, deviceId);
            }
        }

        garbageCollect(deviceId, southboundGroupEntries, storedGroupEntries);

        // update stats
        for (Iterator<Group> it2 = southboundGroupEntries.iterator(); it2.hasNext();) {
            // Mastership change can occur during this iteration
            if (!shouldHandle(deviceId)) {
                log.warn("Tried to update the group stats while the node was not the master" +
                        " or the device {} was not available", deviceId);
                return;
            }
            Group group = it2.next();
            if (storedGroupEntries.remove(group)) {
                // we both have the group, let's update some info then.
                log.trace("Group AUDIT: group {} exists in both planes for device {}",
                          group.id(), deviceId);

                groupAdded(group);
                it2.remove();
            }
        }

        // extraneous groups in the dataplane
        for (Group group : southboundGroupEntries) {
            if (getGroup(group.deviceId(), group.id()) != null) {
                // There is a group existing with the same id
                // It is possible that group update is
                // in progress while we got a stale info from switch
                if (!storedGroupEntries.remove(getGroup(
                        group.deviceId(), group.id()))) {
                    log.warn("Group AUDIT: Inconsistent state:"
                                     + "Group exists in ID based table while "
                                     + "not present in key based table");
                }
            } else {
                // Mastership change can occur during this iteration
                if (!shouldHandle(deviceId)) {
                    log.warn("Tried to process extraneous groups while the node was not the master" +
                            " or the device {} was not available", deviceId);
                    return;
                }
                // there are groups in the switch that aren't in the store
                log.debug("Group AUDIT: extraneous group {} exists in data plane for device {}",
                          group.id(), deviceId);
                extraneousStoredEntries.remove(group);
                if (allowExtraneousGroups) {
                    extraneousGroup(group);
                } else {
                    notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_REQUESTED, group));
                }
            }
        }

        // missing groups in the dataplane
        for (StoredGroupEntry group : storedGroupEntries) {
            // Mastership change can occur during this iteration
            if (!shouldHandle(deviceId)) {
                log.warn("Tried to process missing groups while the node was not the master" +
                        " or the device {} was not available", deviceId);
                return;
            }
            // there are groups in the store that aren't in the switch
            log.debug("Group AUDIT: group {} missing in data plane for device {}",
                      group.id(), deviceId);
            groupMissing(group);
        }

        // extraneous groups in the store
        for (Group group : extraneousStoredEntries) {
            // Mastership change can occur during this iteration
            if (!shouldHandle(deviceId)) {
                log.warn("Tried to process node extraneous groups while the node was not the master" +
                        " or the device {} was not available", deviceId);
                return;
            }
            // there are groups in the extraneous store that
            // aren't in the switch
            log.debug("Group AUDIT: clearing extraneous group {} from store for device {}",
                      group.id(), deviceId);
            removeExtraneousGroupEntry(group);
        }

        if (!deviceInitialAuditStatus) {
            log.info("Group AUDIT: Setting device {} initial AUDIT completed",
                     deviceId);
            deviceInitialAuditCompleted(deviceId, true);
        }
    }
@Test
    public void testPushGroupMetrics() {
        groupStore.deviceInitialAuditCompleted(deviceId1, true);
        groupStore.deviceInitialAuditCompleted(deviceId2, true);

        GroupDescription groupDescription3 = new DefaultGroupDescription(
                deviceId1,
                ALL,
                allGroupBuckets,
                new DefaultGroupKey("aaa".getBytes()),
                null,
                APP_ID);

        groupStore.storeGroupDescription(groupDescription1);
        groupStore.storeGroupDescription(groupDescription2);
        groupStore.storeGroupDescription(groupDescription3);
        Group group1 = groupStore.getGroup(deviceId1, groupId1);

        assertThat(group1, instanceOf(DefaultGroup.class));
        DefaultGroup defaultGroup1 = (DefaultGroup) group1;
        defaultGroup1.setPackets(55L);
        defaultGroup1.setBytes(66L);
        groupStore.pushGroupMetrics(deviceId1, ImmutableList.of(group1));

        // Make sure the group was updated.

        Group requeryGroup1 = groupStore.getGroup(deviceId1, groupId1);
        assertThat(requeryGroup1.packets(), is(55L));
        assertThat(requeryGroup1.bytes(), is(66L));

    }