/*
 * Copyright 2016-present Open Networking Foundation
 *
 * 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.opencord.cordmcast.impl;

import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;

import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.junit.TestUtils;
import org.onlab.packet.IpAddress;
import org.onlab.packet.VlanId;
import org.onosproject.cfg.ComponentConfigAdapter;
import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.cluster.ClusterServiceAdapter;
import org.onosproject.mcast.api.McastEvent;
import org.onosproject.mcast.api.McastRoute;
import org.onosproject.mcast.api.McastRouteUpdate;
import org.onosproject.mcast.api.MulticastRouteService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.HostId;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.IPCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
import org.onosproject.net.flowobjective.Objective;
import org.onosproject.store.service.StorageServiceAdapter;
import org.onosproject.store.service.TestConsistentMap;
import org.opencord.cordmcast.CordMcastStatistics;
import org.opencord.cordmcast.CordMcastStatisticsEvent;
import org.osgi.service.component.ComponentContext;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;

import java.util.Dictionary;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;
import java.util.Map;
import java.util.Arrays;
import java.util.Collection;

import static org.junit.Assert.*;
import static org.onlab.junit.TestTools.assertAfter;

public class McastTest extends McastTestBase {

  private CordMcast cordMcast;
  private CordMcastStatisticsManager cordMcastStatisticsManager;

  private MockCordMcastStatisticsEventListener mockListener = new MockCordMcastStatisticsEventListener();

  private static final int WAIT_TIMEOUT = 1000;
  private static final int WAIT = 250;
  McastRouteUpdate previousSubject, currentSubject;

  @Before
  public void setUp() {
        //setup operation is handled by init() method in each test
   }

    @After
    public void tearDown() {
      cordMcast.deactivate();
      forwardMap.clear();
      nextMap.clear();
    }

    private void init(boolean vlanEnabled, VlanId egressVlan, VlanId egressInnerVlan) {
        cordMcast = new CordMcast();
        cordMcastStatisticsManager = new CordMcastStatisticsManager();
        cordMcastStatisticsManager.clusterService = new ClusterServiceAdapter();
        cordMcastStatisticsManager.leadershipService = new LeadershipServiceMcastAdapter();
        cordMcast.coreService = new MockCoreService();

        TestNetworkConfigRegistry testNetworkConfigRegistry = new TestNetworkConfigRegistry();
        testNetworkConfigRegistry.setEgressVlan(egressVlan);
        testNetworkConfigRegistry.setEgressInnerVlan(egressInnerVlan);
        cordMcast.networkConfig = testNetworkConfigRegistry;

        cordMcast.flowObjectiveService = new MockFlowObjectiveService();
        cordMcast.mastershipService = new TestMastershipService();
        cordMcast.deviceService = new MockDeviceService();
        cordMcast.componentConfigService = new ComponentConfigAdapter();
        cordMcastStatisticsManager.componentConfigService = new ComponentConfigAdapter();
        cordMcastStatisticsManager.addListener(mockListener);
        cordMcast.sadisService = new MockSadisService();
        cordMcast.cordMcastStatisticsService = cordMcastStatisticsManager;

        cordMcast.storageService = EasyMock.createMock(StorageServiceAdapter.class);
        expect(cordMcast.storageService.consistentMapBuilder()).andReturn(new TestConsistentMap.Builder<>());
        replay(cordMcast.storageService);

        Dictionary<String, Object> cfgDict = new Hashtable<String, Object>();
        cfgDict.put("vlanEnabled", vlanEnabled);
        cfgDict.put("eventGenerationPeriodInSeconds", EVENT_GENERATION_PERIOD);

        cordMcast.componentConfigService = EasyMock.createNiceMock(ComponentConfigService.class);
        replay(cordMcast.componentConfigService);

        Set<McastRoute> route1Set = new HashSet<McastRoute>();
        route1Set.add(route1);

        cordMcast.mcastService = EasyMock.createNiceMock(MulticastRouteService.class);
        expect(cordMcast.mcastService.getRoutes()).andReturn(Sets.newHashSet());
        replay(cordMcast.mcastService);

        cordMcastStatisticsManager.mcastService = EasyMock.createNiceMock(MulticastRouteService.class);
        expect(cordMcastStatisticsManager.mcastService.getRoutes()).andReturn(route1Set).times(2);
        replay(cordMcastStatisticsManager.mcastService);

        TestUtils.setField(cordMcastStatisticsManager, "eventDispatcher", new TestEventDispatcher());

        ComponentContext componentContext = EasyMock.createMock(ComponentContext.class);
        expect(componentContext.getProperties()).andReturn(cfgDict).times(2);
        replay(componentContext);
        cordMcast.cordMcastStatisticsService = cordMcastStatisticsManager;
        cordMcastStatisticsManager.activate(componentContext);

        cordMcast.activate(componentContext);
    }

    @Test
    public void testAddingSinkEvent() throws InterruptedException {
      init(false, null, null);

      Set<ConnectPoint> sinks2Cp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_B));
      Map<HostId, Set<ConnectPoint>> sinks2 = ImmutableMap.of(HOST_ID_NONE, sinks2Cp);

      //Adding the details to create different routes
      previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
      currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks2);
      // Creating new mcast event for adding sink
      McastEvent event = new McastEvent(McastEvent.Type.SINKS_ADDED, previousSubject, currentSubject);
      cordMcast.listener.event(event);
      synchronized (forwardMap) {
        forwardMap.wait(WAIT_TIMEOUT);
      }

      // ForwardMap will contain the operation "Add" in the flowObjective. None -> CP_B
      assertNotNull(forwardMap.get(DEVICE_ID_OF_A));
      assertEquals(forwardMap.get(DEVICE_ID_OF_A).op(), Objective.Operation.ADD);

      // Output port number will be PORT_B i.e. 16
      Collection<TrafficTreatment> traffictreatMentCollection =
           nextMap.get(DEVICE_ID_OF_A).next();
      assertEquals(1, traffictreatMentCollection.size());
      OutputInstruction output = null;
      for (TrafficTreatment trafficTreatment : traffictreatMentCollection) {
         output = outputPort(trafficTreatment);
      }
      assertNotNull(output);
      assertEquals(PORT_B, output.port());
      // Checking the group ip address
      TrafficSelector trafficSelector = forwardMap.get(DEVICE_ID_OF_A).selector();
      IPCriterion ipCriterion = ipAddress(trafficSelector);
      assertNotNull(ipCriterion);
      assertEquals(MULTICAST_IP, ipCriterion.ip().address());
      //checking the vlan criterion
      TrafficSelector meta = forwardMap.get(DEVICE_ID_OF_A).meta();
      VlanIdCriterion vlanId = vlanId(meta, Criterion.Type.VLAN_VID);
      assertNull(vlanId); //since vlanEnabled flag is false
      VlanIdCriterion innerVlanIdCriterion = vlanId(meta, Criterion.Type.INNER_VLAN_VID);
      assertNull(innerVlanIdCriterion);
    }

    @Test
    public void testAddingSinkEventVlanEnabled() throws InterruptedException {
        // vlanEnabled is set to true and just egressVlan is set
        init(true, VlanId.vlanId("4000"), null);

        Set<ConnectPoint> sinks2Cp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_B));
        Map<HostId, Set<ConnectPoint>> sinks2 = ImmutableMap.of(HOST_ID_NONE, sinks2Cp);

        //Adding the details to create different routes
        previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
        currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks2);
        // Creating new mcast event for adding sink
        McastEvent event = new McastEvent(McastEvent.Type.SINKS_ADDED, previousSubject, currentSubject);
        cordMcast.listener.event(event);
        synchronized (forwardMap) {
            forwardMap.wait(WAIT_TIMEOUT);
        }
        // ForwardMap will contain the operation "Add" in the flowObjective. None -> CP_B
        assertNotNull(forwardMap.get(DEVICE_ID_OF_A));
        assertEquals(forwardMap.get(DEVICE_ID_OF_A).op(), Objective.Operation.ADD);

        // Output port number will be PORT_B i.e. 16
        Collection<TrafficTreatment> traffictreatMentCollection =
                nextMap.get(DEVICE_ID_OF_A).next();
        assertEquals(1, traffictreatMentCollection.size());
        OutputInstruction output = null;
        for (TrafficTreatment trafficTreatment : traffictreatMentCollection) {
            output = outputPort(trafficTreatment);
        }
        assertNotNull(output);
        assertEquals(PORT_B, output.port());
        // Checking the group ip address
        TrafficSelector trafficSelector = forwardMap.get(DEVICE_ID_OF_A).selector();
        IPCriterion ipCriterion = ipAddress(trafficSelector);
        assertNotNull(ipCriterion);
        assertEquals(MULTICAST_IP, ipCriterion.ip().address());
        //checking the vlan criteria
        TrafficSelector meta = forwardMap.get(DEVICE_ID_OF_A).meta();
        VlanIdCriterion vlanIdCriterion = vlanId(meta, Criterion.Type.VLAN_VID);
        assertNotNull(vlanIdCriterion); //since vlanEnabled flag is true
        assertEquals(cordMcast.assignedVlan(), vlanIdCriterion.vlanId());
        VlanIdCriterion innerVlanIdCriterion = vlanId(meta, Criterion.Type.INNER_VLAN_VID);
        assertNull(innerVlanIdCriterion);
    }

    @Test
    public void testAddingSinkEventInnerVlanEnabled() throws InterruptedException {
        // vlanEnabled is set to true and egressVlan & egressInnerVlan are set
        init(true, VlanId.vlanId("4000"), VlanId.vlanId("1000"));

        Set<ConnectPoint> sinks2Cp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_B));
        Map<HostId, Set<ConnectPoint>> sinks2 = ImmutableMap.of(HOST_ID_NONE, sinks2Cp);

        //Adding the details to create different routes
        previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
        currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks2);
        // Creating new mcast event for adding sink
        McastEvent event = new McastEvent(McastEvent.Type.SINKS_ADDED, previousSubject, currentSubject);
        cordMcast.listener.event(event);
        synchronized (forwardMap) {
            forwardMap.wait(WAIT_TIMEOUT);
        }

        // ForwardMap will contain the operation "Add" in the flowObjective. None -> CP_B
        assertNotNull(forwardMap.get(DEVICE_ID_OF_A));
        assertEquals(forwardMap.get(DEVICE_ID_OF_A).op(), Objective.Operation.ADD);

        // Output port number will be PORT_B i.e. 16
        Collection<TrafficTreatment> traffictreatMentCollection =
                nextMap.get(DEVICE_ID_OF_A).next();
        assertEquals(1, traffictreatMentCollection.size());
        OutputInstruction output = null;
        for (TrafficTreatment trafficTreatment : traffictreatMentCollection) {
            output = outputPort(trafficTreatment);
        }
        assertNotNull(output);
        assertEquals(PORT_B, output.port());
        // Checking the group ip address
        TrafficSelector trafficSelector = forwardMap.get(DEVICE_ID_OF_A).selector();
        IPCriterion ipCriterion = ipAddress(trafficSelector);
        assertNotNull(ipCriterion);
        assertEquals(MULTICAST_IP, ipCriterion.ip().address());
        //checking the vlan criteria
        TrafficSelector meta = forwardMap.get(DEVICE_ID_OF_A).meta();
        VlanIdCriterion vlanIdCriterion = vlanId(meta, Criterion.Type.VLAN_VID);
        assertNotNull(vlanIdCriterion); //since vlanEnabled flag is true
        assertEquals(cordMcast.assignedVlan(), vlanIdCriterion.vlanId());
        VlanIdCriterion innerVlanIdCriterion = vlanId(meta, Criterion.Type.INNER_VLAN_VID);
        assertNotNull(innerVlanIdCriterion);
        assertEquals(cordMcast.assignedInnerVlan(), innerVlanIdCriterion.vlanId());
    }

    @Test
    public void testAddToExistingSinkEvent() throws InterruptedException {
      init(false, null, null);
       // Adding first sink (none --> CP_B)
       testAddingSinkEvent();

       Set<ConnectPoint> sinksCp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_B));
       Map<HostId, Set<ConnectPoint>> sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
       previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
       sinksCp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_B, CONNECT_POINT_C));
       sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
       currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
       // Again listening the mcast event with different output port ( none --> CP_B, CP_C)
       McastEvent event = new McastEvent(McastEvent.Type.SINKS_ADDED, previousSubject, currentSubject);
       cordMcast.listener.event(event);

       // NextMap will contain the operation "ADD_TO_EXISTING" in the DefaultNextObjective.
       assertAfter(WAIT_TIMEOUT, WAIT_TIMEOUT * 2, () ->
       assertEquals(nextMap.get(DEVICE_ID_OF_A).op(), Objective.Operation.ADD_TO_EXISTING));
       // Output port number will be changed to 24 i.e. PORT_C
       Collection<TrafficTreatment> traffictreatMentCollection = nextMap.get(DEVICE_ID_OF_A).next();
       assertEquals(1, traffictreatMentCollection.size());
       OutputInstruction output = null;
       for (TrafficTreatment trafficTreatment : traffictreatMentCollection) {
          output = outputPort(trafficTreatment);
       }
       assertNotNull(output);
       assertEquals(PORT_C, output.port());
    }

    @Test
    public void testRemoveSinkEvent() throws InterruptedException {
       init(false, null, null);
       testAddToExistingSinkEvent();
       // Handling the mcast event for removing sink.
       Set<ConnectPoint> sinksCp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_B, CONNECT_POINT_C));
       Map<HostId, Set<ConnectPoint>> sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
       previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
       sinksCp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_C));
       sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
       currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
       McastEvent event = new McastEvent(McastEvent.Type.SINKS_REMOVED, previousSubject, currentSubject);
       cordMcast.listener.event(event);
       // Operation will be REMOVE_FROM_EXISTING and nextMap will be updated. ( None --> CP_C)
       assertAfter(WAIT_TIMEOUT, WAIT_TIMEOUT * 2, () ->
       assertEquals(nextMap.get(DEVICE_ID_OF_A).op(), Objective.Operation.REMOVE_FROM_EXISTING));

       // Output port number will be PORT_B i.e. 16
       // Port_B is removed from the group.
       Collection<TrafficTreatment> traffictreatMentCollection =
            nextMap.get(DEVICE_ID_OF_A).next();
       assertEquals(1, traffictreatMentCollection.size());
       OutputInstruction output = null;
       for (TrafficTreatment trafficTreatment : traffictreatMentCollection) {
          output = outputPort(trafficTreatment);
       }
       assertNotNull(output);
       assertEquals(PORT_B, output.port());

    }

    @Test
    public void testRemoveLastSinkEvent() throws InterruptedException {
        init(false, null, null);
       testRemoveSinkEvent();
       // Handling the mcast event for removing sink.
       Set<ConnectPoint> sinksCp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_C));
       Map<HostId, Set<ConnectPoint>> sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
       previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
       sinksCp = new HashSet<ConnectPoint>(Arrays.asList());
       sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
       currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
       McastEvent event = new McastEvent(McastEvent.Type.SINKS_REMOVED, previousSubject, currentSubject);
       cordMcast.listener.event(event);

       // Operation will be REMOVE and nextMap will be updated.  None --> { }
       assertAfter(WAIT_TIMEOUT, WAIT_TIMEOUT * 2, () ->
       assertEquals(nextMap.get(DEVICE_ID_OF_A).op(), Objective.Operation.REMOVE));
  }

  @Test
  public void testUnkownOltDevice() throws InterruptedException {
       init(false, null, null);
       // Configuration of mcast event for unknown olt device
       final DeviceId deviceIdOfB = DeviceId.deviceId("of:1");

       ConnectPoint connectPointA = new ConnectPoint(deviceIdOfB, PORT_A);
       ConnectPoint connectPointB = new ConnectPoint(deviceIdOfB, PORT_B);
       Set<ConnectPoint> sourcesCp = new HashSet<ConnectPoint>(Arrays.asList(connectPointA));
       Set<ConnectPoint> sinksCp = new HashSet<ConnectPoint>(Arrays.asList());
       Set<ConnectPoint> sinks2Cp = new HashSet<ConnectPoint>(Arrays.asList(connectPointB));
       Map<HostId, Set<ConnectPoint>> sources = ImmutableMap.of(HOST_ID_NONE, sourcesCp);

       Map<HostId, Set<ConnectPoint>> sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
       Map<HostId, Set<ConnectPoint>> sinks2 = ImmutableMap.of(HOST_ID_NONE, sinks2Cp);
       //Adding the details to create different routes
       McastRouteUpdate previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
       McastRouteUpdate currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks2);
       // Creating new mcast event for adding sink
       McastEvent event = new McastEvent(McastEvent.Type.SINKS_ADDED, previousSubject, currentSubject);
       cordMcast.listener.event(event);
       // OltInfo flag is set to true when olt device is unkown
       assertAfter(WAIT, WAIT * 2, () -> assertTrue(knownOltFlag));
       assertEquals(0, forwardMap.size());
       assertEquals(0, nextMap.size());

  }

  @Test
  public void testRouteAddedEvent() throws InterruptedException {
      init(false, null, null);
      //Adding the details to create different routes
      previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, emptySource, sinks);
      currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, emptySource, sinks);
      // Creating new mcast event for route adding
      McastEvent event = new McastEvent(McastEvent.Type.ROUTE_ADDED, previousSubject, currentSubject);
      cordMcast.listener.event(event);
      // There will be no forwarding objective
      assertAfter(WAIT, WAIT * 2, () -> assertEquals(0, forwardMap.size()));
      assertEquals(0, nextMap.size());

   }


  @Test
  public void testRouteRemovedEvent() throws InterruptedException {
      init(false, null, null);
      testRouteAddedEvent();

      //Adding the details to create different routes
      previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, emptySource, sinks);
      currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, emptySource, sinks);
      // Creating new mcast event for route removing
      McastEvent event = new McastEvent(McastEvent.Type.ROUTE_REMOVED, previousSubject, currentSubject);
      cordMcast.listener.event(event);
      // There will be no forwarding objective
      assertAfter(WAIT, WAIT * 2, () -> assertEquals(0, forwardMap.size()));
      assertEquals(0, nextMap.size());

   }

  @Test
  public void testSourceAddedEvent() throws InterruptedException {
      init(false, null, null);
      // Adding route before adding source.
      testRouteAddedEvent();

      //Adding the details to create different routes
      previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, emptySource, sinks);
      currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
      // Creating new mcast event for source adding
      McastEvent event = new McastEvent(McastEvent.Type.SOURCES_ADDED, previousSubject, currentSubject);
      cordMcast.listener.event(event);
      // There will be no forwarding objective
      assertAfter(WAIT, WAIT * 2, () -> assertEquals(0, forwardMap.size()));
      assertEquals(0, nextMap.size());

   }

  @Test
  public void testSourcesRemovedEvent() throws InterruptedException {
      init(false, null, null);
      testSourceAddedEvent();

      //Adding the details to create different routes
      previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
      currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, emptySource, sinks);
      // Creating new mcast event for removing source
      // Warning message of unknown event will be displayed.
      McastEvent event = new McastEvent(McastEvent.Type.SOURCES_REMOVED, previousSubject, currentSubject);
      cordMcast.listener.event(event);
      assertAfter(WAIT, WAIT * 2, () -> assertEquals(0, forwardMap.size()));
      assertEquals(0, nextMap.size());
   }

    @Test
    public void mcastTestEventGeneration() throws InterruptedException {
      init(false, VlanId.vlanId("4000"), VlanId.NONE);
      //fetching route details used to push CordMcastStatisticsEvent.
      IpAddress testGroup = route1.group();
      String testSource = route1.source().isEmpty() ? "*" : route1.source().get().toString();
      VlanId testVlan = cordMcast.assignedVlan();

      // Thread is scheduled without any delay
      assertAfter(WAIT, WAIT * 2, () ->
              assertEquals(1, mockListener.mcastEventList.size()));

      for (CordMcastStatisticsEvent event: mockListener.mcastEventList) {
           assertEquals(event.type(), CordMcastStatisticsEvent.Type.STATUS_UPDATE);
      }

      CordMcastStatistics cordMcastStatistics = mockListener.mcastEventList.get(0).subject().get(0);
      assertEquals(VlanId.NONE, cordMcastStatistics.getVlanId());
      assertEquals(testVlan, cordMcastStatistics.getVlanId());
      assertEquals(testSource, cordMcastStatistics.getSourceAddress());
      assertEquals(testGroup, cordMcastStatistics.getGroupAddress());

      // Test for vlanEnabled
      Dictionary<String, Object> cfgDict = new Hashtable<>();
      cfgDict.put("vlanEnabled", true);

      ComponentContext componentContext = EasyMock.createMock(ComponentContext.class);
      expect(componentContext.getProperties()).andReturn(cfgDict);
      replay(componentContext);
      cordMcast.modified(componentContext);
      testVlan = cordMcast.assignedVlan();

      assertAfter(EVENT_GENERATION_PERIOD, EVENT_GENERATION_PERIOD * 1000, () ->
              assertEquals(2, mockListener.mcastEventList.size()));

      for (CordMcastStatisticsEvent event: mockListener.mcastEventList) {
          assertEquals(event.type(), CordMcastStatisticsEvent.Type.STATUS_UPDATE);
      }

      cordMcastStatistics = mockListener.mcastEventList.get(1).subject().get(0);
      assertNotEquals(VlanId.NONE, cordMcastStatistics.getVlanId());
      assertEquals(testVlan, cordMcastStatistics.getVlanId());
      assertEquals(testSource, cordMcastStatistics.getSourceAddress());
      assertEquals(testGroup, cordMcastStatistics.getGroupAddress());
    }
}
