Refactors IGMPProxy application in API and APP bundles

Change-Id: I465d6c0f49079804ae8e0a1f464581c25c6d2300
diff --git a/app/src/test/java/org/opencord/igmpproxy/impl/IgmpStatisticsTest.java b/app/src/test/java/org/opencord/igmpproxy/impl/IgmpStatisticsTest.java
new file mode 100644
index 0000000..2677511
--- /dev/null
+++ b/app/src/test/java/org/opencord/igmpproxy/impl/IgmpStatisticsTest.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2017-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.igmpproxy.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.onlab.junit.TestTools.assertAfter;
+
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.junit.TestUtils;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.Ip4Address;
+import org.onosproject.core.CoreServiceAdapter;
+import org.onosproject.net.flow.FlowRuleServiceAdapter;
+import org.onosproject.net.flowobjective.FlowObjectiveServiceAdapter;
+
+import org.opencord.igmpproxy.IgmpStatisticsEvent;
+
+import com.google.common.collect.Lists;
+import org.opencord.igmpproxy.IgmpStatisticsEventListener;
+
+/**
+ * Set of tests of the ONOS application component for IGMP Statistics.
+ */
+public class IgmpStatisticsTest extends IgmpManagerBase {
+
+    private static final int WAIT_TIMEOUT = 500;
+
+    private IgmpManager igmpManager;
+
+    private IgmpStatisticsManager igmpStatisticsManager;
+
+    private MockIgmpStatisticsEventListener mockListener = new MockIgmpStatisticsEventListener();
+
+    // Set up the IGMP application.
+    @Before
+    public void setUp() {
+        igmpManager = new IgmpManager();
+        igmpManager.coreService = new CoreServiceAdapter();
+        igmpManager.mastershipService = new MockMastershipService();
+        igmpManager.flowObjectiveService = new FlowObjectiveServiceAdapter();
+        igmpManager.deviceService = new MockDeviceService();
+        igmpManager.packetService = new MockPacketService();
+        igmpManager.flowRuleService = new FlowRuleServiceAdapter();
+        igmpManager.multicastService = new TestMulticastRouteService();
+        igmpManager.sadisService = new MockSadisService();
+        igmpStatisticsManager = new IgmpStatisticsManager();
+        igmpStatisticsManager.cfgService = new MockCfgService();
+        igmpStatisticsManager.addListener(mockListener);
+        TestUtils.setField(igmpStatisticsManager, "eventDispatcher", new TestEventDispatcher());
+        igmpStatisticsManager.activate(new MockComponentContext());
+        igmpManager.igmpStatisticsManager = this.igmpStatisticsManager;
+        // By default - we send query messages
+        SingleStateMachine.sendQuery = true;
+    }
+
+    // Tear Down the IGMP application.
+    @After
+    public void tearDown() {
+        igmpStatisticsManager.removeListener(mockListener);
+        igmpStatisticsManager.deactivate();
+        IgmpManager.groupMemberMap.clear();
+        StateMachine.clearMap();
+    }
+
+    //Test Igmp Statistics.
+    @Test
+    public void testIgmpStatistics() throws InterruptedException {
+        SingleStateMachine.sendQuery = false;
+        igmpManager.networkConfig = new TestNetworkConfigRegistry(false);
+        igmpManager.activate();
+
+        //IGMPv3 Join
+        flagForPacket = false;
+        Ethernet igmpv3MembershipReportPkt = IgmpSender.getInstance().buildIgmpV3Join(GROUP_IP, SOURCE_IP_OF_A);
+        sendPacket(igmpv3MembershipReportPkt);
+        synchronized (savedPackets) {
+            savedPackets.wait(WAIT_TIMEOUT);
+        }
+        //Leave
+        flagForPacket = false;
+        Ethernet igmpv3LeavePkt = IgmpSender.getInstance().buildIgmpV3Leave(GROUP_IP, SOURCE_IP_OF_A);
+        sendPacket(igmpv3LeavePkt);
+        synchronized (savedPackets) {
+            savedPackets.wait(WAIT_TIMEOUT);
+        }
+
+        assertAfter(WAIT_TIMEOUT, WAIT_TIMEOUT * 2, () ->
+            assertEquals((long) 2, igmpStatisticsManager.getIgmpStats().getTotalMsgReceived().longValue()));
+        assertEquals((long) 1, igmpStatisticsManager.getIgmpStats().getIgmpJoinReq().longValue());
+        assertEquals((long) 2, igmpStatisticsManager.getIgmpStats().getIgmpv3MembershipReport().longValue());
+        assertEquals((long) 1, igmpStatisticsManager.getIgmpStats().getIgmpSuccessJoinRejoinReq().longValue());
+        assertEquals((long) 1, igmpStatisticsManager.getIgmpStats().getUnconfiguredGroupCounter().longValue());
+        assertEquals((long) 2, igmpStatisticsManager.getIgmpStats().getValidIgmpPacketCounter().longValue());
+        assertEquals((long) 1, igmpStatisticsManager.getIgmpStats().getIgmpChannelJoinCounter().longValue());
+        assertEquals((long) 1, igmpStatisticsManager.getIgmpStats().getIgmpLeaveReq().longValue());
+        assertEquals((long) 2, igmpStatisticsManager.getIgmpStats().getIgmpMsgReceived().longValue());
+        assertEquals((long) 2, igmpStatisticsManager.getIgmpStats().getIgmpValidChecksumCounter().longValue());
+
+    }
+
+    //Test packet with Unknown Multicast IpAddress
+    @Test
+    public void testIgmpUnknownMulticastIpAddress() throws InterruptedException {
+        SingleStateMachine.sendQuery = false;
+
+        igmpManager.networkConfig = new TestNetworkConfigRegistry(false);
+        igmpManager.activate();
+
+        Ethernet firstPacket =
+             IgmpSender.getInstance().buildIgmpV3Join(UNKNOWN_GRP_IP, SOURCE_IP_OF_A);
+        // Sending first packet
+        sendPacket(firstPacket);
+        assertAfter(WAIT_TIMEOUT, WAIT_TIMEOUT * 2, () ->
+        assertEquals((long) 1,
+             igmpStatisticsManager.getIgmpStats().getFailJoinReqUnknownMulticastIpCounter().longValue()));
+    }
+
+    //Test Igmp Query Statistics.
+    @Test
+    public void testIgmpQueryStatistics() throws InterruptedException {
+        igmpManager.networkConfig = new TestNetworkConfigRegistry(false);
+        igmpManager.activate();
+
+        flagForQueryPacket = true;
+        //IGMPV3 Group Specific Membership Query packet
+        Ethernet igmpv3MembershipQueryPkt = IgmpSender.getInstance().buildIgmpV3Query(GROUP_IP, SOURCE_IP_OF_A);
+        sendPacket(igmpv3MembershipQueryPkt);
+
+        //IGMPV3 General Membership Query packet
+        Ethernet igmpv3MembershipQueryPkt1 =
+              IgmpSender.getInstance().buildIgmpV3Query(Ip4Address.valueOf(0), SOURCE_IP_OF_A);
+        sendPacket(igmpv3MembershipQueryPkt1);
+        assertAfter(WAIT_TIMEOUT, WAIT_TIMEOUT * 2, () ->
+        assertEquals(igmpStatisticsManager.getIgmpStats()
+            .getIgmpGrpAndSrcSpecificMembershipQuery().longValue(), 1));
+        assertEquals(igmpStatisticsManager.getIgmpStats()
+            .getIgmpGeneralMembershipQuery().longValue(), 1);
+        assertEquals(igmpStatisticsManager.getIgmpStats()
+             .getCurrentGrpNumCounter().longValue(), 1);
+    }
+
+    //Test Events
+    @Test
+    public void testIgmpStatisticsEvent() {
+        final int waitEventGeneration = igmpStatisticsManager.statisticsGenerationPeriodInSeconds * 1000;
+        //assert that event listened as the app activates
+        assertAfter(WAIT_TIMEOUT, WAIT_TIMEOUT * 2, () ->
+            assertEquals(mockListener.events.size(), 1));
+
+        assertAfter(waitEventGeneration / 2, waitEventGeneration, () ->
+            assertEquals(mockListener.events.size(), 2));
+
+        for (IgmpStatisticsEvent event : mockListener.events) {
+            assertEquals(event.type(), IgmpStatisticsEvent.Type.STATS_UPDATE);
+        }
+    }
+
+    //Test packet with Unknown Wrong Membership mode
+    @Test
+    public void testWrongIgmpPacket() throws InterruptedException {
+        SingleStateMachine.sendQuery = false;
+
+        igmpManager.networkConfig = new TestNetworkConfigRegistry(false);
+        igmpManager.activate();
+
+        Ethernet firstPacket = buildWrongIgmpPacket(GROUP_IP, SOURCE_IP_OF_A);
+        // Sending first packet
+        sendPacket(firstPacket);
+        assertAfter(WAIT_TIMEOUT, WAIT_TIMEOUT * 2, () ->
+        assertEquals((long) 1,
+            igmpStatisticsManager.getIgmpStats().getReportsRxWithWrongModeCounter().longValue()));
+    }
+
+    //Test packet with Unknown IGMP type.
+    @Test
+    public void testUnknownIgmpPacket() throws InterruptedException {
+        SingleStateMachine.sendQuery = false;
+
+        igmpManager.networkConfig = new TestNetworkConfigRegistry(false);
+        igmpManager.activate();
+
+        Ethernet firstPacket = buildUnknownIgmpPacket(GROUP_IP, SOURCE_IP_OF_A);
+        // Sending first packet
+        sendPacket(firstPacket);
+        assertAfter(WAIT_TIMEOUT, WAIT_TIMEOUT * 2, () ->
+        assertEquals((long) 1,
+            igmpStatisticsManager.getIgmpStats().getUnknownIgmpTypePacketsRxCounter().longValue()));
+    }
+
+    //Test packet with Insufficient Permission.
+    @Test
+    public void testSufficientPermission() throws InterruptedException {
+        SingleStateMachine.sendQuery = false;
+
+        flagForPermission = true;
+        igmpManager.networkConfig = new TestNetworkConfigRegistry(false);
+        igmpManager.activate();
+
+        Ethernet firstPacket = IgmpSender.getInstance().buildIgmpV3Join(GROUP_IP, SOURCE_IP_OF_A);
+        // Sending first packet
+        sendPacket(firstPacket);
+        assertAfter(WAIT_TIMEOUT, WAIT_TIMEOUT * 2, () ->
+        assertEquals((long) 1,
+            igmpStatisticsManager.getIgmpStats().getFailJoinReqInsuffPermissionAccessCounter().longValue()));
+    }
+
+    public class MockIgmpStatisticsEventListener implements IgmpStatisticsEventListener {
+        protected List<IgmpStatisticsEvent> events = Lists.newArrayList();
+
+        @Override
+        public void event(IgmpStatisticsEvent event) {
+            events.add(event);
+        }
+
+    }
+}