FTTH-55780 [UT coverage for VGC upto 47%]

Change-Id: I6503d90643d214ac2fa7e21d5a39a44913019ad7
diff --git a/internal/pkg/application/igmp_test.go b/internal/pkg/application/igmp_test.go
index 8f132bd..1c346aa 100644
--- a/internal/pkg/application/igmp_test.go
+++ b/internal/pkg/application/igmp_test.go
@@ -17,7 +17,9 @@
 
 import (
 	"context"
+	"errors"
 	"net"
+	"sync"
 	"testing"
 	"time"
 	"voltha-go-controller/internal/pkg/of"
@@ -443,46 +445,6 @@
 	}
 }
 
-//func TestIgmpv2QueryPacket(t *testing.T) {
-// 	type args struct {
-// 		mcip    net.IP
-// 		vlan    of.VlanType
-// 		selfip  net.IP
-// 		pbit    uint8
-// 		maxResp uint32
-// 	}
-// 	tests := []struct {
-// 		name    string
-// 		args    args
-// 		want    []byte
-// 		wantErr bool
-// 	}{
-// 		{
-// 			name: "IgmpReportv3Layer",
-// 			args: args{
-// 				vlan:    22,
-// 				selfip:  net.ParseIP("224.0.0.1"),
-// 				pbit:    0,
-// 				maxResp: 1,
-// 				mcip:    net.ParseIP("0.0.0.0"),
-// 			},
-// 			wantErr: true,
-// 		},
-// 	}
-// 	for _, tt := range tests {
-// 		t.Run(tt.name, func(t *testing.T) {
-// 			got, err := Igmpv2QueryPacket(tt.args.mcip, tt.args.vlan, tt.args.selfip, tt.args.pbit, tt.args.maxResp)
-// 			if (err != nil) != tt.wantErr {
-// 				t.Errorf("Igmpv2QueryPacket() error = %v, wantErr %v", err, tt.wantErr)
-// 				return
-// 			}
-// 			if !reflect.DeepEqual(got, tt.want) {
-// 				t.Errorf("Igmpv2QueryPacket() = %v, want %v", got, tt.want)
-// 			}
-// 		})
-// 	}
-// }
-
 func Test_getVersion(t *testing.T) {
 	type args struct {
 		ver string
@@ -552,3 +514,205 @@
 		})
 	}
 }
+
+func TestAddToPendingPool(t *testing.T) {
+	type args struct {
+		cntx     context.Context
+		device   string
+		groupKey string
+	}
+
+	group := &IgmpGroup{
+		GroupName:             "test_key",
+		GroupID:               uint32(256),
+		PendingGroupForDevice: make(map[string]time.Time),
+	}
+	tests := []struct {
+		name string
+		args args
+		want bool
+	}{
+		{
+			name: "AddToPendingPool_true",
+			args: args{
+				device:   "SDX6320031",
+				cntx:     context.Background(),
+				groupKey: "test_key",
+			},
+			want: true,
+		},
+		{
+			name: "AddToPendingPool_false",
+			args: args{
+				device:   "SDX6320031",
+				cntx:     context.Background(),
+				groupKey: "test_key",
+			},
+			want: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			switch tt.name {
+			case "AddToPendingPool_true":
+				va := GetApplication()
+				va.IgmpGroups.Store("test_key", group)
+				dbintf := mocks.NewMockDBIntf(gomock.NewController(t))
+				db = dbintf
+				dbintf.EXPECT().PutIgmpGroup(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).Times(1)
+				if got := AddToPendingPool(tt.args.cntx, tt.args.device, tt.args.groupKey); got != tt.want {
+					t.Errorf("AddToPendingPool() = %v, want %v", got, tt.want)
+				}
+			case "AddToPendingPool_false":
+				va := GetApplication()
+				va.IgmpGroups.Store("test_key", group)
+				dbintf := mocks.NewMockDBIntf(gomock.NewController(t))
+				db = dbintf
+				dbintf.EXPECT().PutIgmpGroup(gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.New("failed")).Times(1)
+				if got := AddToPendingPool(tt.args.cntx, tt.args.device, tt.args.groupKey); got != tt.want {
+					t.Errorf("AddToPendingPool() = %v, want %v", got, tt.want)
+				}
+			}
+		})
+	}
+}
+
+func TestGetMcastServiceForSubAlarm(t *testing.T) {
+	type args struct {
+		uniPort *VoltPort
+		mvp     *MvlanProfile
+	}
+	mvp := &MvlanProfile{
+		Name: "mvlan_test",
+	}
+	voltPort := &VoltPort{
+		Name:   "16777472",
+		Device: "SDX6320031",
+		ID:     16777472,
+		State:  PortStateUp,
+	}
+	voltServ := &VoltService{
+		VoltServiceOper: VoltServiceOper{
+			Device: "SDX6320031",
+		},
+		VoltServiceCfg: VoltServiceCfg{
+			IgmpEnabled:      true,
+			MvlanProfileName: "mvlan_test",
+			Name:             "SDX6320031-1_SDX6320031-1-4096-2310-4096-65",
+		},
+	}
+	voltPortVnets := make([]*VoltPortVnet, 0)
+	voltPortVnet := &VoltPortVnet{
+		Device:      "SDX6320031",
+		Port:        "16777472",
+		IgmpEnabled: true,
+		services:    sync.Map{},
+	}
+	tests := []struct {
+		name string
+		args args
+		want string
+	}{
+		{
+			name: "GetMcastServiceForSubAlarm",
+			args: args{
+				uniPort: voltPort,
+				mvp:     mvp,
+			},
+			want: "SDX6320031-1_SDX6320031-1-4096-2310-4096-65",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			switch tt.name {
+			case "GetMcastServiceForSubAlarm":
+				va := GetApplication()
+				voltPortVnets = append(voltPortVnets, voltPortVnet)
+				voltPortVnet.services.Store("SDX6320031-1_SDX6320031-1-4096-2310-4096-65", voltServ)
+				va.VnetsByPort.Store("16777472", voltPortVnets)
+				if got := GetMcastServiceForSubAlarm(tt.args.uniPort, tt.args.mvp); got != tt.want {
+					t.Errorf("GetMcastServiceForSubAlarm() = %v, want %v", got, tt.want)
+				}
+			}
+		})
+	}
+}
+
+func TestSendQueryExpiredEventGroupSpecific(t *testing.T) {
+	type args struct {
+		portKey string
+		igd     *IgmpGroupDevice
+		igc     *IgmpGroupChannel
+	}
+	mvp := &MvlanProfile{
+		Name: "mvlan_test",
+	}
+	voltServ := &VoltService{
+		VoltServiceOper: VoltServiceOper{
+			Device: "SDX6320031",
+		},
+		VoltServiceCfg: VoltServiceCfg{
+			IgmpEnabled:      true,
+			MvlanProfileName: "mvlan_test",
+			Name:             "SDX6320031-1_SDX6320031-1-4096-2310-4096-65",
+		},
+	}
+	voltPortVnets := make([]*VoltPortVnet, 0)
+	voltPortVnet := &VoltPortVnet{
+		Device:      "SDX6320031",
+		Port:        "16777472",
+		IgmpEnabled: true,
+		services:    sync.Map{},
+	}
+	tests := []struct {
+		name string
+		args args
+	}{
+		{
+			name: "SendQueryExpiredEventGroupSpecific",
+			args: args{
+				portKey: "16777472",
+				igd: &IgmpGroupDevice{
+					Mvlan: of.VlanAny,
+				},
+				igc: &IgmpGroupChannel{},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			va := GetApplication()
+			voltPortVnets = append(voltPortVnets, voltPortVnet)
+			voltPortVnet.services.Store("SDX6320031-1_SDX6320031-1-4096-2310-4096-65", voltServ)
+			va.VnetsByPort.Store("16777472", voltPortVnets)
+			va.MvlanProfilesByTag.Store(of.VlanAny, mvp)
+			SendQueryExpiredEventGroupSpecific(tt.args.portKey, tt.args.igd, tt.args.igc)
+		})
+	}
+}
+
+func TestVoltApplication_GetPonPortID(t *testing.T) {
+	type args struct {
+		device    string
+		uniPortID string
+	}
+	tests := []struct {
+		name string
+		args args
+		want uint32
+	}{
+		{
+			name: "RestoreIgmpGroupsFromDb",
+			args: args{},
+			want: uint32(255),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			va := &VoltApplication{}
+			if got := va.GetPonPortID(tt.args.device, tt.args.uniPortID); got != tt.want {
+				t.Errorf("VoltApplication.GetPonPortID() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/internal/pkg/application/igmpgroup_test.go b/internal/pkg/application/igmpgroup_test.go
new file mode 100644
index 0000000..aec7f45
--- /dev/null
+++ b/internal/pkg/application/igmpgroup_test.go
@@ -0,0 +1,253 @@
+/*
+* Copyright 2022-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 application
+
+import (
+	"context"
+	"net"
+	"reflect"
+	"testing"
+	"time"
+	"voltha-go-controller/internal/pkg/of"
+	"voltha-go-controller/internal/test/mocks"
+
+	"github.com/golang/mock/gomock"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestNewIgmpGroup(t *testing.T) {
+	type args struct {
+		name string
+		vlan of.VlanType
+	}
+	group := &IgmpGroup{
+		GroupName: "test_key",
+	}
+	tests := []struct {
+		name string
+		args args
+		want *IgmpGroup
+	}{
+		{
+			name: "NewIgmpGroup",
+			args: args{
+				name: "test_key",
+			},
+			want: group,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := NewIgmpGroup(tt.args.name, tt.args.vlan)
+			assert.NotNil(t, got)
+		})
+	}
+}
+
+func TestIgmpGroup_IgmpGroupInit(t *testing.T) {
+	type args struct {
+		name string
+		gip  net.IP
+		mvp  *MvlanProfile
+	}
+	grp := make(map[string]*MvlanGroup)
+	grp["test_key"] = &MvlanGroup{
+		Name:     "test_key",
+		IsStatic: true,
+	}
+	tests := []struct {
+		name string
+		args args
+	}{
+		{
+			name: "IgmpGroupInit",
+			args: args{
+				name: "test_key",
+				gip:  AllSystemsMulticastGroupIP,
+				mvp: &MvlanProfile{
+					Version: "test_version",
+					Name:    "test_key",
+					Groups:  grp,
+				},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			ig := &IgmpGroup{}
+			ig.IgmpGroupInit(tt.args.name, tt.args.gip, tt.args.mvp)
+		})
+	}
+}
+
+func TestIgmpGroup_IgmpGroupReInit(t *testing.T) {
+	type args struct {
+		cntx context.Context
+		name string
+		gip  net.IP
+	}
+	tests := []struct {
+		name string
+		args args
+	}{
+		{
+			name: "IgmpGroupInit",
+			args: args{
+				cntx: context.Background(),
+				name: "test_key",
+				gip:  AllSystemsMulticastGroupIP,
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			ig := &IgmpGroup{}
+			ig.IgmpGroupReInit(tt.args.cntx, tt.args.name, tt.args.gip)
+		})
+	}
+}
+
+func TestIgmpGroup_DeleteIgmpGroupDevice(t *testing.T) {
+	type args struct {
+		cntx   context.Context
+		device string
+	}
+	devices := map[string]*IgmpGroupDevice{}
+	igmpDevice := &IgmpGroupDevice{
+		Device:    "SDX6320031",
+		SerialNo:  "SDX6320031",
+		GroupName: "group1",
+		Mvlan:     of.VlanAny,
+	}
+	devices["SDX6320031"] = igmpDevice
+	tests := []struct {
+		name string
+		args args
+	}{
+		{
+			name: "DeleteIgmpGroupDevice",
+			args: args{
+				cntx:   context.Background(),
+				device: "SDX6320031",
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			ig := &IgmpGroup{
+				Devices: devices,
+			}
+			dbintf := mocks.NewMockDBIntf(gomock.NewController(t))
+			db = dbintf
+			dbintf.EXPECT().DelIgmpDevice(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
+			ig.DeleteIgmpGroupDevice(tt.args.cntx, tt.args.device)
+		})
+	}
+}
+
+func TestIgmpGroup_removeExpiredGroupFromDevice(t *testing.T) {
+	type args struct {
+		cntx context.Context
+	}
+	PendingGroupForDevice := make(map[string]time.Time)
+	PendingGroupForDevice["SDX6320031"] = time.Now().Add(time.Duration(GroupExpiryTime) * time.Minute)
+	tests := []struct {
+		name string
+		args args
+	}{
+		{
+			name: "DeleteIgmpGroupDevice",
+			args: args{
+				cntx: context.Background(),
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			ig := &IgmpGroup{
+				PendingGroupForDevice: PendingGroupForDevice,
+			}
+			ig.removeExpiredGroupFromDevice(tt.args.cntx)
+		})
+	}
+}
+
+func TestIgmpGroup_GetAllIgmpChannel(t *testing.T) {
+	devices := map[string]*IgmpGroupDevice{}
+	igmpDevice := &IgmpGroupDevice{
+		Device:    "SDX6320031",
+		SerialNo:  "SDX6320031",
+		GroupName: "group1",
+		Mvlan:     of.VlanAny,
+	}
+	devices["SDX6320031"] = igmpDevice
+	tests := []struct {
+		name string
+		want map[string]string
+	}{
+		{
+			name: "GetAllIgmpChannel",
+			want: make(map[string]string),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			ig := &IgmpGroup{
+				Devices: devices,
+			}
+			if got := ig.GetAllIgmpChannel(); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("IgmpGroup.GetAllIgmpChannel() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestIgmpGroup_GetAllIgmpChannelForDevice(t *testing.T) {
+	type args struct {
+		deviceID string
+	}
+	devices := map[string]*IgmpGroupDevice{}
+	igmpDevice := &IgmpGroupDevice{
+		Device:    "SDX6320031",
+		SerialNo:  "SDX6320031",
+		GroupName: "group1",
+		Mvlan:     of.VlanAny,
+	}
+	devices["SDX6320031"] = igmpDevice
+	tests := []struct {
+		name string
+		args args
+		want map[string]string
+	}{
+		{
+			name: "GetAllIgmpChannelForDevice",
+			args: args{
+				deviceID: "SDX6320031",
+			},
+			want: make(map[string]string),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			ig := &IgmpGroup{
+				Devices: devices,
+			}
+			if got := ig.GetAllIgmpChannelForDevice(tt.args.deviceID); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("IgmpGroup.GetAllIgmpChannelForDevice() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/internal/pkg/application/igmpport_test.go b/internal/pkg/application/igmpport_test.go
new file mode 100644
index 0000000..7ff2459
--- /dev/null
+++ b/internal/pkg/application/igmpport_test.go
@@ -0,0 +1,131 @@
+/*
+* Copyright 2022-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 application
+
+import (
+	"net"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestNewIgmpGroupPort(t *testing.T) {
+	type args struct {
+		port      string
+		cvlan     uint16
+		pbit      uint8
+		version   uint8
+		incl      bool
+		ponPortID uint32
+	}
+	tests := []struct {
+		name string
+		args args
+		want *IgmpGroupPort
+	}{
+		{
+			name: "NewIgmpGroupPort",
+			args: args{
+				port:      "256",
+				cvlan:     AnyVlan,
+				pbit:      0,
+				version:   uint8(12),
+				incl:      true,
+				ponPortID: uint32(256),
+			},
+			want: &IgmpGroupPort{},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := NewIgmpGroupPort(tt.args.port, tt.args.cvlan, tt.args.pbit, tt.args.version, tt.args.incl, tt.args.ponPortID)
+			assert.NotNil(t, got)
+		})
+	}
+}
+
+func TestIgmpGroupPort_DelExclSource(t *testing.T) {
+	type args struct {
+		src net.IP
+	}
+	tests := []struct {
+		name string
+		args args
+	}{
+		{
+			name: "DelExclSource",
+			args: args{
+				src: AllSystemsMulticastGroupIP,
+			},
+		},
+		{
+			name: "AddExclSource",
+			args: args{
+				src: AllSystemsMulticastGroupIP,
+			},
+		},
+		{
+			name: "DelInclSource",
+			args: args{
+				src: AllSystemsMulticastGroupIP,
+			},
+		},
+		{
+			name: "AddInclSource",
+			args: args{
+				src: AllSystemsMulticastGroupIP,
+			},
+		},
+		{
+			name: "InclSourceIsIn",
+			args: args{
+				src: AllSystemsMulticastGroupIP,
+			},
+		},
+		{
+			name: "ExclSourceIsIn",
+			args: args{
+				src: AllSystemsMulticastGroupIP,
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			igp := &IgmpGroupPort{
+				ExcludeList: []net.IP{
+					AllSystemsMulticastGroupIP,
+				},
+				IncludeList: []net.IP{
+					AllSystemsMulticastGroupIP,
+				},
+			}
+			switch tt.name {
+			case "DelExclSource":
+				igp.DelExclSource(tt.args.src)
+			case "AddExclSource":
+				igp.AddExclSource(tt.args.src)
+			case "DelInclSource":
+				igp.DelInclSource(tt.args.src)
+			case "AddInclSource":
+				igp.AddInclSource(tt.args.src)
+			case "InclSourceIsIn":
+				igp.InclSourceIsIn(tt.args.src)
+			case "ExclSourceIsIn":
+				igp.ExclSourceIsIn(tt.args.src)
+			}
+		})
+	}
+}
diff --git a/internal/pkg/application/igmpprofiles_test.go b/internal/pkg/application/igmpprofiles_test.go
new file mode 100644
index 0000000..e3b7328
--- /dev/null
+++ b/internal/pkg/application/igmpprofiles_test.go
@@ -0,0 +1,755 @@
+/*
+* Copyright 2022-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 application
+
+import (
+	"context"
+	"net"
+	"reflect"
+	"sync"
+	"testing"
+	"voltha-go-controller/internal/pkg/controller"
+	"voltha-go-controller/internal/pkg/of"
+	common "voltha-go-controller/internal/pkg/types"
+	"voltha-go-controller/internal/pkg/util"
+	"voltha-go-controller/internal/test/mocks"
+
+	"github.com/golang/mock/gomock"
+	"github.com/stretchr/testify/assert"
+)
+
+func Test_newIgmpProfile(t *testing.T) {
+	type args struct {
+		igmpProfileConfig *common.IGMPConfig
+	}
+	b := true
+	tests := []struct {
+		name string
+		args args
+		want *IgmpProfile
+	}{
+		{
+			name: "DelExclSource",
+			args: args{
+				igmpProfileConfig: &common.IGMPConfig{
+					FastLeave:      &b,
+					PeriodicQuery:  &b,
+					WithRAUpLink:   &b,
+					WithRADownLink: &b,
+				},
+			},
+			want: &IgmpProfile{},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := newIgmpProfile(tt.args.igmpProfileConfig)
+			assert.NotNil(t, got)
+		})
+	}
+}
+
+func TestNewMvlanProfile(t *testing.T) {
+	type args struct {
+		name                string
+		mvlan               of.VlanType
+		ponVlan             of.VlanType
+		isChannelBasedGroup bool
+		OLTSerialNums       []string
+		actChannelPerPon    uint32
+	}
+	tests := []struct {
+		name string
+		args args
+		want *MvlanProfile
+	}{
+		{
+			name: "DelExclSource",
+			args: args{
+				name: "test_mvlan",
+			},
+			want: &MvlanProfile{},
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := NewMvlanProfile(tt.args.name, tt.args.mvlan, tt.args.ponVlan, tt.args.isChannelBasedGroup, tt.args.OLTSerialNums, tt.args.actChannelPerPon)
+			assert.NotNil(t, got)
+		})
+	}
+}
+
+func TestMvlanProfile_AddMvlanProxy(t *testing.T) {
+	proxy := map[string]*MCGroupProxy{}
+	proxy["test_key"] = &MCGroupProxy{
+		Mode: common.Exclude,
+	}
+	grp := make(map[string]*MvlanGroup)
+	grp["test_key"] = &MvlanGroup{
+		Name:     "test_key",
+		IsStatic: true,
+	}
+	type args struct {
+		name      string
+		proxyInfo common.MulticastGroupProxy
+	}
+	tests := []struct {
+		name string
+		args args
+	}{
+		{
+			name: "AddMvlanProxy",
+			args: args{
+				name: "test_key",
+				proxyInfo: common.MulticastGroupProxy{
+					IsStatic: common.IsStaticYes,
+				},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			mvp := &MvlanProfile{
+				Proxy:  proxy,
+				Groups: grp,
+			}
+			mvp.AddMvlanProxy(tt.args.name, tt.args.proxyInfo)
+		})
+	}
+}
+
+func TestMvlanProfile_AddMvlanGroup(t *testing.T) {
+	type args struct {
+		name string
+		ips  []string
+	}
+	grp := make(map[string]*MvlanGroup)
+	grp["test_key"] = &MvlanGroup{
+		Name:     "test_key",
+		IsStatic: true,
+	}
+	tests := []struct {
+		name string
+		args args
+	}{
+		{
+			name: "AddMvlanProxy",
+			args: args{
+				name: "test_key",
+				ips: []string{
+					"0.0.0.0",
+				},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			mvp := &MvlanProfile{
+				Groups: grp,
+			}
+			mvp.AddMvlanGroup(tt.args.name, tt.args.ips)
+		})
+	}
+}
+
+func TestMvlanProfile_GetUsMatchVlan(t *testing.T) {
+	tests := []struct {
+		name string
+		want of.VlanType
+	}{
+		{
+			name: "GetUsMatchVlan",
+			want: of.VlanAny,
+		},
+		{
+			name: "GetUsMatchVlan_IsPonVlanPresent",
+			want: of.VlanAny,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			mvp := &MvlanProfile{
+				PonVlan: of.VlanAny,
+				Mvlan:   of.VlanAny,
+			}
+			switch tt.name {
+			case "GetUsMatchVlan":
+				mvp.IsPonVlanPresent = true
+				if got := mvp.GetUsMatchVlan(); !reflect.DeepEqual(got, tt.want) {
+					t.Errorf("MvlanProfile.GetUsMatchVlan() = %v, want %v", got, tt.want)
+				}
+			case "GetUsMatchVlan_IsPonVlanPresent":
+				if got := mvp.GetUsMatchVlan(); !reflect.DeepEqual(got, tt.want) {
+					t.Errorf("MvlanProfile.GetUsMatchVlan() = %v, want %v", got, tt.want)
+				}
+			}
+		})
+	}
+}
+
+func TestMvlanProfile_isChannelStatic(t *testing.T) {
+	type args struct {
+		channel net.IP
+	}
+	grp := make(map[string]*MvlanGroup)
+	grp["test_key"] = &MvlanGroup{
+		Name:     "test_key",
+		IsStatic: true,
+		McIPs: []string{
+			"224.0.0.1",
+		},
+	}
+	tests := []struct {
+		name string
+		args args
+		want bool
+	}{
+		{
+			name: "isChannelStatic",
+			args: args{
+				channel: AllSystemsMulticastGroupIP,
+			},
+			want: true,
+		},
+		{
+			name: "isChannelStatic_false",
+			want: false,
+		},
+		{
+			name: "containsStaticChannels",
+			want: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			mvp := &MvlanProfile{
+				Groups: grp,
+			}
+			switch tt.name {
+			case "isChannelStatic", "isChannelStatic_false":
+				if got := mvp.isChannelStatic(tt.args.channel); got != tt.want {
+					t.Errorf("MvlanProfile.isChannelStatic() = %v, want %v", got, tt.want)
+				}
+
+			case "containsStaticChannels":
+				if got := mvp.containsStaticChannels(); got != tt.want {
+					t.Errorf("MvlanProfile.isChannelStatic() = %v, want %v", got, tt.want)
+				}
+			}
+		})
+	}
+}
+
+func TestMvlanProfile_getAllStaticChannels(t *testing.T) {
+	grp := make(map[string]*MvlanGroup)
+	grp["test_key"] = &MvlanGroup{
+		Name:     "test_key",
+		IsStatic: true,
+		McIPs: []string{
+			"224.0.0.1",
+		},
+	}
+	tests := []struct {
+		name  string
+		want  []net.IP
+		want1 bool
+	}{
+		{
+			name: "getAllStaticChannels",
+			want: []net.IP{
+				AllSystemsMulticastGroupIP,
+			},
+			want1: true,
+		},
+		{
+			name: "getAllOldGroupStaticChannels",
+			want: []net.IP{
+				AllSystemsMulticastGroupIP,
+			},
+			want1: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			mvp := &MvlanProfile{
+				Groups:    grp,
+				oldGroups: grp,
+			}
+			switch tt.name {
+			case "getAllStaticChannels":
+				got, got1 := mvp.getAllStaticChannels()
+				if !reflect.DeepEqual(got, tt.want) {
+					t.Errorf("MvlanProfile.getAllStaticChannels() got = %v, want %v", got, tt.want)
+				}
+				if got1 != tt.want1 {
+					t.Errorf("MvlanProfile.getAllStaticChannels() got1 = %v, want %v", got1, tt.want1)
+				}
+			case "getAllOldGroupStaticChannels":
+				got, got1 := mvp.getAllOldGroupStaticChannels()
+				if !reflect.DeepEqual(got, tt.want) {
+					t.Errorf("MvlanProfile.getAllStaticChannels() got = %v, want %v", got, tt.want)
+				}
+				if got1 != tt.want1 {
+					t.Errorf("MvlanProfile.getAllStaticChannels() got1 = %v, want %v", got1, tt.want1)
+				}
+			}
+		})
+	}
+}
+
+func TestMvlanProfile_DelFlows(t *testing.T) {
+	type args struct {
+		cntx   context.Context
+		device *VoltDevice
+		flow   *of.VoltFlow
+	}
+	appMock := mocks.NewMockApp(gomock.NewController(t))
+	controller.NewController(ctx, appMock)
+	pendingDeleteFlow := map[string]map[string]bool{}
+	delFlow := map[string]bool{}
+	delFlow["SDX6320031"] = true
+	pendingDeleteFlow["SDX6320031"] = delFlow
+	voltDev := &VoltDevice{
+		Name:            "SDX6320031",
+		SerialNum:       "SDX6320031",
+		FlowDelEventMap: util.NewConcurrentMap(),
+	}
+	subFlows := map[uint64]*of.VoltSubFlow{}
+	vltSubFlow := &of.VoltSubFlow{
+		Cookie: 103112802816,
+		State:  of.FlowAddSuccess,
+	}
+	subFlows[0] = vltSubFlow
+	flow := &of.VoltFlow{
+		PortName: "SDX6320031-1",
+		SubFlows: subFlows,
+	}
+	tests := []struct {
+		name    string
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "getAllStaticChannels",
+			args: args{
+				cntx:   context.Background(),
+				device: voltDev,
+				flow:   flow,
+			},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			mvp := &MvlanProfile{
+				PendingDeleteFlow: pendingDeleteFlow,
+			}
+			dbintf := mocks.NewMockDBIntf(gomock.NewController(t))
+			db = dbintf
+			dbintf.EXPECT().PutMvlan(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).Times(1)
+			if err := mvp.DelFlows(tt.args.cntx, tt.args.device, tt.args.flow); (err != nil) != tt.wantErr {
+				t.Errorf("MvlanProfile.DelFlows() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func TestMvlanProfile_generateGroupKey(t *testing.T) {
+	type args struct {
+		name   string
+		ipAddr string
+	}
+	tests := []struct {
+		name string
+		args args
+		want string
+	}{
+		{
+			name: "generateGroupKey",
+			args: args{
+				name:   "test-key",
+				ipAddr: "0.0.0.0",
+			},
+			want: "0_test-key",
+		},
+		{
+			name: "generateGroupKey_IsChannelBasedGroup",
+			args: args{
+				name:   "test-key",
+				ipAddr: "0.0.0.0",
+			},
+			want: "0_0.0.0.0",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			mvp := &MvlanProfile{}
+			switch tt.name {
+			case "generateGroupKey":
+				if got := mvp.generateGroupKey(tt.args.name, tt.args.ipAddr); got != tt.want {
+					t.Errorf("MvlanProfile.generateGroupKey() = %v, want %v", got, tt.want)
+				}
+			case "generateGroupKey_IsChannelBasedGroup":
+				mvp.IsChannelBasedGroup = true
+				if got := mvp.generateGroupKey(tt.args.name, tt.args.ipAddr); got != tt.want {
+					t.Errorf("MvlanProfile.generateGroupKey() = %v, want %v", got, tt.want)
+				}
+			}
+		})
+	}
+}
+
+func TestMvlanProfile_GetStaticGroupName(t *testing.T) {
+	type args struct {
+		gip net.IP
+	}
+	grp := make(map[string]*MvlanGroup)
+	grp["test_key"] = &MvlanGroup{
+		Name:     "test_key",
+		IsStatic: true,
+		McIPs: []string{
+			"224.0.0.1",
+		},
+	}
+	tests := []struct {
+		name string
+		args args
+		want string
+	}{
+		{
+			name: "GetStaticGroupName",
+			args: args{
+				gip: AllSystemsMulticastGroupIP,
+			},
+			want: "test_key",
+		},
+		{
+			name: "GetStaticGroupName",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			mvp := &MvlanProfile{
+				Groups: grp,
+			}
+			if got := mvp.GetStaticGroupName(tt.args.gip); got != tt.want {
+				t.Errorf("MvlanProfile.GetStaticGroupName() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestMvlanProfile_pushIgmpMcastFlows(t *testing.T) {
+	type args struct {
+		cntx         context.Context
+		OLTSerialNum string
+	}
+	grp := make(map[string]*MvlanGroup)
+	grp["test_key"] = &MvlanGroup{
+		Name:     "test_key",
+		IsStatic: true,
+		McIPs: []string{
+			"224.0.0.1",
+		},
+	}
+	devicesList := make(map[string]OperInProgress)
+	devicesList["SDX6320031"] = opt82
+	va := GetApplication()
+	d := &VoltDevice{
+		Name:      "SDX6320031",
+		SerialNum: "SDX6320031",
+		Ports:     sync.Map{},
+		NniPort:   "16777472",
+	}
+	voltPort := &VoltPort{
+		Name:                     "16777472",
+		Device:                   "SDX6320031",
+		ID:                       16777472,
+		State:                    PortStateUp,
+		ChannelPerSubAlarmRaised: false,
+		Type:                     VoltPortTypeNni,
+	}
+	d.Ports.Store("16777472", voltPort)
+	va.DevicesDisc.Store("SDX6320031", d)
+	mvp := &MvlanProfile{
+		Name: "mvlan_test",
+	}
+	va.MvlanProfilesByTag.Store(of.VlanAny, mvp)
+	tests := []struct {
+		name string
+		args args
+	}{
+		{
+			name: "GetStaticGroupName",
+			args: args{
+				cntx:         context.Background(),
+				OLTSerialNum: "SDX6320031",
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			mvp := &MvlanProfile{
+				DevicesList: devicesList,
+				Groups:      grp,
+				Mvlan:       of.VlanAny,
+			}
+			mvp.pushIgmpMcastFlows(tt.args.cntx, tt.args.OLTSerialNum)
+		})
+	}
+}
+
+func TestMvlanProfile_updateStaticGroups(t *testing.T) {
+	type args struct {
+		cntx     context.Context
+		deviceID string
+		added    []net.IP
+		removed  []net.IP
+	}
+	devicesList := make(map[string]OperInProgress)
+	devicesList["SDX6320031"] = opt82
+	va := GetApplication()
+	d := &VoltDevice{
+		Name:            "SDX6320031",
+		SerialNum:       "SDX6320031",
+		Ports:           sync.Map{},
+		NniPort:         "16777472",
+		FlowDelEventMap: util.NewConcurrentMap(),
+	}
+	va.DevicesDisc.Store("SDX6320031", d)
+	tests := []struct {
+		name string
+		args args
+	}{
+		{
+			name: "updateStaticGroups",
+			args: args{
+				cntx:     context.Background(),
+				deviceID: "SDX6320031",
+				added:    []net.IP{AllSystemsMulticastGroupIP},
+				removed:  []net.IP{AllSystemsMulticastGroupIP},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			mvp := &MvlanProfile{
+				Name:        "mvlan_test",
+				DevicesList: devicesList,
+				Mvlan:       of.VlanAny,
+			}
+			va.MvlanProfilesByTag.Store(of.VlanAny, mvp)
+			va.MvlanProfilesByName.Store("mvlan_test", mvp)
+			mvp.updateStaticGroups(tt.args.cntx, tt.args.deviceID, tt.args.added, tt.args.removed)
+		})
+	}
+}
+func TestMvlanProfile_updateDynamicGroups(t *testing.T) {
+	type args struct {
+		cntx     context.Context
+		deviceID string
+		added    []net.IP
+		removed  []net.IP
+	}
+	grp := make(map[string]*MvlanGroup)
+	grp["test_key"] = &MvlanGroup{
+		Name:     "test_key",
+		IsStatic: true,
+		McIPs: []string{
+			"224.0.0.1",
+		},
+	}
+	devicesList := make(map[string]OperInProgress)
+	devicesList["SDX6320031"] = opt82
+	va := GetApplication()
+	d := &VoltDevice{
+		Name:            "SDX6320031",
+		SerialNum:       "SDX6320031",
+		Ports:           sync.Map{},
+		NniPort:         "16777472",
+		FlowDelEventMap: util.NewConcurrentMap(),
+	}
+	va.DevicesDisc.Store("SDX6320031", d)
+	devices := map[string]*IgmpGroupDevice{}
+	igmpDevice := &IgmpGroupDevice{
+		Device:        "SDX6320031",
+		SerialNo:      "SDX6320031",
+		GroupName:     "4096_test_key",
+		Mvlan:         of.VlanAny,
+		GroupChannels: sync.Map{},
+		GroupAddr:     AllSystemsMulticastGroupIP,
+	}
+	devices["SDX6320031"] = igmpDevice
+	group := &IgmpGroup{
+		GroupName: "4096_test_key",
+		GroupID:   uint32(256),
+		Mvlan:     of.VlanAny,
+		Devices:   devices,
+	}
+	va.IgmpGroups.Store("4096_test_key", group)
+	newReceivers := map[string]*IgmpGroupPort{}
+	igp := &IgmpGroupPort{
+		Port: "16777470",
+	}
+	newReceivers["16777472"] = igp
+	b := IgmpVersion2
+	igmpChanel := &IgmpGroupChannel{
+		GroupAddr:    AllSystemsMulticastGroupIP,
+		GroupName:    "test_key",
+		NewReceivers: newReceivers,
+		Version:      IgmpVersion2,
+		ServVersion:  &b,
+	}
+	igmpDevice.GroupChannels.Store(AllSystemsMulticastGroupIP.String(), igmpChanel)
+	proxy := map[string]*MCGroupProxy{}
+	mgGroupProxy := &MCGroupProxy{
+		Mode: common.Include,
+		SourceList: []net.IP{
+			AllSystemsMulticastGroupIP,
+		},
+	}
+	proxy[igmpChanel.GroupName] = mgGroupProxy
+	tests := []struct {
+		name string
+		args args
+	}{
+		{
+			name: "updateDynamicGroups",
+			args: args{
+				cntx:     context.Background(),
+				deviceID: "SDX6320031",
+				added:    []net.IP{AllSystemsMulticastGroupIP},
+				removed:  []net.IP{AllSystemsMulticastGroupIP},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			mvp := &MvlanProfile{
+				Name:        "test_key",
+				DevicesList: devicesList,
+				Mvlan:       of.VlanAny,
+				Groups:      grp,
+				Proxy:       proxy,
+			}
+			va.MvlanProfilesByTag.Store(of.VlanAny, mvp)
+			va.MvlanProfilesByName.Store("test_key", mvp)
+			dbintf := mocks.NewMockDBIntf(gomock.NewController(t))
+			db = dbintf
+			dbintf.EXPECT().PutIgmpRcvr(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).Times(1)
+			dbintf.EXPECT().PutIgmpChannel(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).Times(1)
+			mvp.updateDynamicGroups(tt.args.cntx, tt.args.deviceID, tt.args.added, tt.args.removed)
+		})
+	}
+}
+
+func TestMvlanProfile_checkStaticGrpSSMProxyDiff(t *testing.T) {
+	type args struct {
+		oldProxy *MCGroupProxy
+		newProxy *MCGroupProxy
+	}
+	tests := []struct {
+		name string
+		args args
+		want bool
+	}{
+		{
+			name: "updateDynamicGroups",
+			args: args{
+				oldProxy: &MCGroupProxy{
+					Mode: common.Exclude,
+					SourceList: []net.IP{
+						AllSystemsMulticastGroupIP,
+					},
+				},
+				newProxy: &MCGroupProxy{
+					Mode: common.Exclude,
+					SourceList: []net.IP{
+						AllSystemsMulticastGroupIP,
+					},
+				},
+			},
+		},
+		{
+			name: "updateDynamicGroups_true",
+			args: args{
+				newProxy: &MCGroupProxy{},
+			},
+			want: true,
+		},
+		{
+			name: "updateDynamicGroups_nil",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			mvp := &MvlanProfile{}
+			if got := mvp.checkStaticGrpSSMProxyDiff(tt.args.oldProxy, tt.args.newProxy); got != tt.want {
+				t.Errorf("MvlanProfile.checkStaticGrpSSMProxyDiff() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestMvlanProfile_UpdateActiveChannelSubscriberAlarm(t *testing.T) {
+	devicesList := make(map[string]OperInProgress)
+	devicesList["SDX6320031"] = opt82
+	voltDev := &VoltDevice{
+		Name:            "SDX6320031",
+		SerialNum:       "SDX6320031",
+		FlowDelEventMap: util.NewConcurrentMap(),
+		Ports:           sync.Map{},
+	}
+	va := GetApplication()
+	va.DevicesDisc.Store("SDX6320031", voltDev)
+	voltPort := &VoltPort{
+		Name:                     "16777472",
+		Device:                   "SDX6320031",
+		ID:                       16777472,
+		State:                    PortStateUp,
+		ChannelPerSubAlarmRaised: true,
+		Type:                     VoltPortTypeAccess,
+		ActiveChannels:           uint32(2),
+	}
+	voltDev.Ports.Store("16777472", voltPort)
+	tests := []struct {
+		name string
+	}{
+		{
+			name: "UpdateActiveChannelSubscriberAlarm",
+		},
+		{
+			name: "UpdateActiveChannelSubscriberAlarm_else",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			mvp := &MvlanProfile{
+				DevicesList:       devicesList,
+				MaxActiveChannels: uint32(5),
+			}
+			switch tt.name {
+			case "UpdateActiveChannelSubscriberAlarm":
+				mvp.UpdateActiveChannelSubscriberAlarm()
+			case "UpdateActiveChannelSubscriberAlarm_else":
+				voltPort.ActiveChannels = uint32(6)
+				voltPort.ChannelPerSubAlarmRaised = false
+				mvp.UpdateActiveChannelSubscriberAlarm()
+			}
+		})
+	}
+}