Skip to content

Commit

Permalink
Unit test for code coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
harshitap26 committed Sep 17, 2024
1 parent 0dbd6ab commit 23f98f5
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 29 deletions.
14 changes: 0 additions & 14 deletions k8sutils/k8sutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,3 @@ func LeaderElection(clientset *kubernetes.Interface, lockName string, namespace
os.Exit(1)
}
}

// ReturnKubeClientSet - Returns the KubeClient Set
func ReturnKubeClientSet() (kubernetes.Interface, error) {
config, err := rest.InClusterConfig()
if err != nil {
return nil, err
}

clientSet, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, err
}
return clientSet, nil
}
12 changes: 12 additions & 0 deletions service/features/controller_publish_unpublish.feature
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ Feature: VxFlex OS CSI interface
And I call UnpublishVolume nfs
And no error was received
Then a valid UnpublishVolumeResponse is returned

Scenario: a Basic NFS controller Publish and unpublish no error with SDC dependency
Given a VxFlexOS service
When I specify CreateVolumeMountRequest "nfs"
And I call CreateVolume "volume1"
Then a valid CreateVolumeResponse is returned
And I induce SDC dependency
And I call NFS PublishVolume with "single-writer"
Then a valid PublishVolumeResponse is returned
And I call UnpublishVolume nfs
And no error was received
Then a valid UnpublishVolumeResponse is returned

Scenario: a Basic NFS controller Publish and unpublish NFS export not found error
Given a VxFlexOS service
Expand Down
13 changes: 13 additions & 0 deletions service/features/service.feature
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ Feature: VxFlex OS CSI interface
Then configMap is updated
Then a valid GetPlugInfoResponse is returned

Scenario Outline: Identity GetPluginInfo bad call
Given a VxFlexOS service
When I call GetPluginInfo
When I call BeforeServe
And I induce error <error>
Then configMap is updated
Then a valid GetPlugInfoResponse is returned
Examples:
| error |
| "UpdateConfigMapUnmarshalError" |
| "GetIPAddressByInterfaceError" |
| "UpdateConfigK8sClientError" |

Scenario Outline: Dynamic log config change
Given a VxFlexOS service
When I call DynamicLogChange <file>
Expand Down
32 changes: 24 additions & 8 deletions service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ type Service interface {
ProcessMapSecretChange() error
}

type NetworkInterface interface {
InterfaceByName(name string) (*net.Interface, error)
Addrs(interfaceObj *net.Interface) ([]net.Addr, error)
}

// Opts defines service configuration options.
type Opts struct {
// map from system name to ArrayConnectionData
Expand Down Expand Up @@ -185,7 +190,15 @@ type Config struct {
InterfaceNames map[string]string `yaml:"interfaceNames"`
}

type GetIPAddressByInterfacefunc func(string) (string, error)
type GetIPAddressByInterfacefunc func(string, NetworkInterface) (string, error)

func (s *service) InterfaceByName(name string) (*net.Interface, error) {
return net.InterfaceByName(name)
}

func (s *service) Addrs(interfaceObj *net.Interface) ([]net.Addr, error) {
return interfaceObj.Addrs()
}

// Process dynamic changes to configMap or Secret.
func (s *service) ProcessMapSecretChange() error {
Expand Down Expand Up @@ -529,7 +542,7 @@ func (s *service) updateConfigMap(getIPAddressByInterfacefunc GetIPAddressByInte
interfaceName = strings.TrimSpace(interfaceName)

// Find the IP of the Interfaces
ipAddress, err := getIPAddressByInterfacefunc(interfaceName)
ipAddress, err := getIPAddressByInterfacefunc(interfaceName, &service{})
if err != nil {
Log.Printf("Error while getting IP address for interface %s: %v\n", interfaceName, err)
continue
Expand Down Expand Up @@ -563,7 +576,8 @@ func (s *service) updateConfigMap(getIPAddressByInterfacefunc GetIPAddressByInte

err := yaml.Unmarshal([]byte(existingYaml), &configData)
if err != nil {
panic(fmt.Sprintf("Failed to parse ConfigMap data: %v", err))
Log.Errorf("Failed to parse ConfigMap data: %v", err)
return
}

// Check and update Interfaces with the IPs
Expand All @@ -572,12 +586,14 @@ func (s *service) updateConfigMap(getIPAddressByInterfacefunc GetIPAddressByInte
interfaceNames[node] = ipAddressList
}
} else {
panic("interfaceNames key missing or not in expected format")
Log.Errorf("interfaceNames key missing or not in expected format")
return
}

updatedYaml, err := yaml.Marshal(configData)
if err != nil {
panic(fmt.Sprintf("Failed to marshal updated data: %v", err))
Log.Errorf("Failed to marshal updated data: %v", err)
return
}
cm.Data["driver-config-params.yaml"] = string(updatedYaml)
}
Expand All @@ -592,13 +608,13 @@ func (s *service) updateConfigMap(getIPAddressByInterfacefunc GetIPAddressByInte
fmt.Println("ConfigMap updated successfully")
}

func (s *service) getIPAddressByInterface(interfaceName string) (string, error) {
interfaceObj, err := net.InterfaceByName(interfaceName)
func (s *service) getIPAddressByInterface(interfaceName string, networkInterface NetworkInterface) (string, error) {
interfaceObj, err := networkInterface.InterfaceByName(interfaceName)
if err != nil {
return "", err
}

addrs, err := interfaceObj.Addrs()
addrs, err := networkInterface.Addrs(interfaceObj)
if err != nil {
return "", err
}
Expand Down
143 changes: 143 additions & 0 deletions service/service_unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,50 @@
package service

import (
"context"
"errors"
"fmt"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/fake"
"net"
"testing"

csi "github.com/container-storage-interface/spec/lib/go/csi"
siotypes "github.com/dell/goscaleio/types/v1"
"github.com/stretchr/testify/assert"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
)

type mockService struct {
}

func (s *mockService) InterfaceByName(interfaceName string) (*net.Interface, error) {

if interfaceName == "" {
return nil, fmt.Errorf("invalid interface name")

} else if interfaceName != "eth0" {
return nil, nil
}
return &net.Interface{
Name: interfaceName},
nil
}

func (s *mockService) Addrs(interfaceObj *net.Interface) ([]net.Addr, error) {

if interfaceObj == nil {
return nil, fmt.Errorf("invalid interface object")
}
return []net.Addr{
&net.IPNet{
IP: net.IPv4(10, 0, 0, 1),
},
}, nil
}

func TestGetVolSize(t *testing.T) {
tests := []struct {
cr *csi.CapacityRange
Expand Down Expand Up @@ -446,3 +481,111 @@ func TestValidateQoSParameters(t *testing.T) {
})
}
}

func TestGetIPAddressByInterface(t *testing.T) {

tests := []struct {
name string
interfaceName string
expectedIP string
expectedError error
}{
{
name: "Valid Interface Name",
interfaceName: "eth0",
expectedIP: "10.0.0.1",
expectedError: nil,
},
{
name: "Wrong Interface Name",
interfaceName: "eth1",
expectedIP: "",
expectedError: fmt.Errorf("invalid interface object"),
},
{
name: "Empty Interface Name",
interfaceName: "",
expectedIP: "",
expectedError: fmt.Errorf("invalid interface name"),
},
}

for _, tt := range tests {
s := &service{}
t.Run(tt.name, func(t *testing.T) {
interfaceIP, err := s.getIPAddressByInterface(tt.interfaceName, &mockService{})
assert.Equal(t, err, tt.expectedError)
assert.Equal(t, interfaceIP, tt.expectedIP)
})
}
}

func TestFindNetworkInterfaceIPs(t *testing.T) {
tests := []struct {
name string
expectedError error
client kubernetes.Interface
configMapData map[string]string
createConfigMap func(map[string]string, kubernetes.Interface)
}{
{
name: "Error getting K8sClient",
expectedError: fmt.Errorf("unable to load in-cluster configuration, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined"),
client: nil,
configMapData: nil,
createConfigMap: func(map[string]string, kubernetes.Interface) {
},
},
{
name: "Error getting ConfigMap",
expectedError: &k8serrors.StatusError{
ErrStatus: metav1.Status{
Status: metav1.StatusFailure,
Message: "configmaps \"vxflexos-config-params\" not found",
Reason: metav1.StatusReasonNotFound,
Details: &metav1.StatusDetails{
Name: "vxflexos-config-params",
Kind: "configmaps",
},
Code: 404,
}},
client: fake.NewSimpleClientset(),
configMapData: nil,
createConfigMap: func(map[string]string, kubernetes.Interface) {
},
},
{
name: "No Error",
expectedError: nil,
client: fake.NewSimpleClientset(),
configMapData: map[string]string{
"driver-config-params.yaml": `interfaceNames:
worker1: 127.1.1.12`,
},
createConfigMap: func(data map[string]string, clientSet kubernetes.Interface) {
configMap := &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: DriverConfigMap,
Namespace: DriverNamespace,
},
Data: data,
}
// Create a ConfigMap using fake ClientSet
_, err := clientSet.CoreV1().ConfigMaps(DriverNamespace).Create(context.TODO(), configMap, metav1.CreateOptions{})
if err != nil {
Log.Fatalf("failed to create configMaps: %v", err)
}
},
},
}

for _, tt := range tests {
s := &service{}
t.Run(tt.name, func(t *testing.T) {
K8sClientset = tt.client
tt.createConfigMap(tt.configMapData, tt.client)
_, err := s.findNetworkInterfaceIPs()
assert.Equal(t, err, tt.expectedError)
})
}
}
37 changes: 36 additions & 1 deletion service/step_defs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1340,12 +1340,23 @@ func (f *feature) iInduceError(errtype string) error {
f.service.adminClients[arrayID2] = nil
f.service.systems[arrayID2] = nil
stepHandlersErrors.PodmonControllerProbeError = true
case "UpdateConfigMapUnmarshalError":
stepHandlersErrors.UpdateConfigMapUnmarshalError = true
case "GetIPAddressByInterfaceError":
stepHandlersErrors.GetIPAddressByInterfaceError = true
case "UpdateConfigK8sClientError":
stepHandlersErrors.UpdateConfigK8sClientError = true
default:
fmt.Println("Ensure that the error is handled in the handlers section.")
}
return nil
}

func (f *feature) iInduceSDCDependency() error {
sdcDependencyOnNFS = true
return nil
}

func (f *feature) getControllerPublishVolumeRequest(accessType string) *csi.ControllerPublishVolumeRequest {
capability := new(csi.VolumeCapability)
block := new(csi.VolumeCapability_Block)
Expand Down Expand Up @@ -1646,6 +1657,12 @@ func (f *feature) iCallPublishVolumeWithNFS(arg1 string) error {
"driver-config-params.yaml": `interfaceNames:
worker1: 127.1.1.11`,
}

if sdcDependencyOnNFS {
configMapData = map[string]string{}
K8sClientset = nil
}

configMap := &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: DriverConfigMap,
Expand Down Expand Up @@ -1812,6 +1829,12 @@ func (f *feature) iCallUnpublishVolumeNFS() error {
"driver-config-params.yaml": `interfaceNames:
worker1: 127.1.1.12`,
}

if sdcDependencyOnNFS {
configMapData = map[string]string{}
K8sClientset = nil
}

configMap := &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: DriverConfigMap,
Expand Down Expand Up @@ -3084,11 +3107,17 @@ func (f *feature) theConfigMapIsUpdated() error {
// Initializing a fake Kubernetes ClientSet
clientSet := fake.NewSimpleClientset()
K8sClientset = clientSet
if stepHandlersErrors.UpdateConfigK8sClientError {
K8sClientset = nil
}

data := `interfaceNames:
worker1: "eth1"
worker2: "eth2"`

if stepHandlersErrors.UpdateConfigMapUnmarshalError {
data = `interfaceName:`
}
configMapData := map[string]string{
"driver-config-params.yaml": data,
}
Expand Down Expand Up @@ -3116,9 +3145,14 @@ func (f *feature) theConfigMapIsUpdated() error {
}

// Mocking the GetIPAddressByInterface function
GetIPAddressByInterface := func(interfaceName string) (string, error) {
GetIPAddressByInterface := func(interfaceName string, networkInterface NetworkInterface) (string, error) {

Check failure on line 3148 in service/step_defs_test.go

View workflow job for this annotation

GitHub Actions / Golang Validation / Lint golang code

unused-parameter: parameter 'interfaceName' seems to be unused, consider removing or renaming it as _ (revive)

Check failure on line 3148 in service/step_defs_test.go

View workflow job for this annotation

GitHub Actions / Golang Validation / Lint golang code

unused-parameter: parameter 'networkInterface' seems to be unused, consider removing or renaming it as _ (revive)
return "10.0.0.1", nil
}
if stepHandlersErrors.GetIPAddressByInterfaceError {
GetIPAddressByInterface = func(interfaceName string, networkInterface NetworkInterface) (string, error) {

Check failure on line 3152 in service/step_defs_test.go

View workflow job for this annotation

GitHub Actions / Golang Validation / Lint golang code

unused-parameter: parameter 'interfaceName' seems to be unused, consider removing or renaming it as _ (revive)

Check failure on line 3152 in service/step_defs_test.go

View workflow job for this annotation

GitHub Actions / Golang Validation / Lint golang code

unused-parameter: parameter 'networkInterface' seems to be unused, consider removing or renaming it as _ (revive)
return "", fmt.Errorf("error geting the IP address of the interface")
}
}

s := &service{}
s.opts.KubeNodeName = "worker1"
Expand Down Expand Up @@ -4668,6 +4702,7 @@ func FeatureContext(s *godog.ScenarioContext) {
s.Step(`^there are no remaining mounts$`, f.thereAreNoRemainingMounts)
s.Step(`^I call BeforeServe$`, f.iCallBeforeServe)
s.Step(`^configMap is updated$`, f.theConfigMapIsUpdated)
s.Step(`^I induce SDC dependency$`, f.iInduceSDCDependency)
s.Step(`^I call NodeStageVolume$`, f.iCallNodeStageVolume)
s.Step(`^I call NodeUnstageVolume with "([^"]*)"$`, f.iCallNodeUnstageVolumeWith)
s.Step(`^I call NodeGetCapabilities "([^"]*)"$`, f.iCallNodeGetCapabilities)
Expand Down
Loading

0 comments on commit 23f98f5

Please sign in to comment.