Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve UT coverage #264

Closed
wants to merge 47 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
a043f34
updated UT
niranjan-n1 Feb 6, 2025
6fa1cb6
increased k8sapi coverage to 8.9%
niranjan-n1 Feb 6, 2025
b359870
improved k8sapi coverage to 18%
niranjan-n1 Feb 7, 2025
b3759ab
increased k8sapi coverage to 40.2%
niranjan-n1 Feb 10, 2025
54d2be3
improved k8sapi coverage to 41.9%
niranjan-n1 Feb 10, 2025
234cebc
increased coverage of csiapi from 7.8 to 37.3
chaganti-rajitha Feb 10, 2025
3ec6084
commented failing test case
chaganti-rajitha Feb 10, 2025
62b14a1
test: Updated unit tests for criapi.go
samihan-dell Feb 11, 2025
2075b33
added utils test files
chaganti-rajitha Feb 11, 2025
334e8dc
test: Increased unit tests for criapi.go from 0% to 40%
samihan-dell Feb 11, 2025
e9c1238
Merge branch 'UT_Coverage' of https://github.com/dell/karavi-resilien…
samihan-dell Feb 11, 2025
25563dd
test: Increased unit tests coverage for criapi.go
samihan-dell Feb 12, 2025
8a2ae62
test: Increased unit tests coverage for criapi.go from 37% to 49%
samihan-dell Feb 12, 2025
e23156f
increased csi UT coverage to 46.2
chaganti-rajitha Feb 12, 2025
9ff3d4f
fixed failing test case
chaganti-rajitha Feb 12, 2025
d18b72f
added unit test for mock.go
niranjan-n1 Feb 14, 2025
9ff927f
update k8scri coverage to 46.4%
niranjan-n1 Feb 17, 2025
749bc79
update k8scri coverage to 46.4%
niranjan-n1 Feb 17, 2025
6dbf691
consolidate mock files in mocks directory
satyakonduri Feb 24, 2025
c14a997
added utils test files
chaganti-rajitha Feb 11, 2025
5b6a2cf
test: Increased unit tests coverage for criapi.go
samihan-dell Feb 12, 2025
82749ee
test: Increased unit tests coverage for criapi.go from 37% to 49%
samihan-dell Feb 12, 2025
4dd9a1c
increased csi UT coverage to 46.2
chaganti-rajitha Feb 12, 2025
bc6dcb3
fixed failing test case
chaganti-rajitha Feb 12, 2025
d866235
added unit test for mock.go
niranjan-n1 Feb 14, 2025
b821c52
update k8scri coverage to 46.4%
niranjan-n1 Feb 17, 2025
301119b
update k8scri coverage to 46.4%
niranjan-n1 Feb 17, 2025
34b57b8
consolidate mock files in mocks directory
satyakonduri Feb 24, 2025
fd9b5c6
Merge branch 'UT_Coverage' of https://github.com/dell/karavi-resilien…
satyakonduri Feb 24, 2025
dcd6466
Merge branch 'UT_Coverage' of https://github.com/dell/karavi-resilien…
satyakonduri Feb 24, 2025
8126be1
Merge branch 'UT_Coverage' of https://github.com/dell/karavi-resilien…
satyakonduri Feb 24, 2025
8ba43f7
added test case in linuxLoopBackDevice.go
chaganti-rajitha Feb 24, 2025
31ea3eb
criapi code coverage
sidharth30060 Feb 25, 2025
cfb8fd6
added test case in k8sapi.go
chaganti-rajitha Feb 25, 2025
cb7c777
Criapi coverage
sidharth30060 Feb 25, 2025
85ae180
added test case on criapi
sidharth30060 Feb 26, 2025
796625c
Fixed linting issues
chaganti-rajitha Feb 27, 2025
dbf52b5
Fixed linting issues in k8api
chaganti-rajitha Feb 27, 2025
bffbcdd
Merge remote-tracking branch 'origin/UT_Coverage' into UT_Coverage
sidharth30060 Feb 27, 2025
3a5e670
Fix lint issues in criapi
sidharth30060 Feb 27, 2025
032ee45
removed and renamed unused parameters
sidharth30060 Feb 27, 2025
7d25d47
Fixed linting issues in csiapi
chaganti-rajitha Feb 27, 2025
27e60a6
fixed linting issue in csi_test.go
chaganti-rajitha Feb 27, 2025
b443e1c
fixed formatting issue in main.go
chaganti-rajitha Feb 27, 2025
d88bee7
fixed formatting issue in main
chaganti-rajitha Feb 27, 2025
1b793c5
fixed formatting issue in main.go
chaganti-rajitha Feb 27, 2025
7d70484
Fix linter errors.
donatwork Feb 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions cmd/podmon/main_steps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"os"
"podmon/internal/csiapi"
"podmon/internal/k8sapi"
"podmon/internal/mocks"
"podmon/internal/monitor"
"strings"
"sync"
Expand All @@ -35,8 +36,8 @@ import (
type mainFeature struct {
// Logrus test hook
loghook *logtest.Hook
k8sapiMock *k8sapi.K8sMock
csiapiMock *csiapi.CSIMock
k8sapiMock *mocks.K8sMock
csiapiMock *mocks.CSIMock
leaderElect *mockLeaderElect
failStartAPIMonitor bool
}
Expand All @@ -53,8 +54,8 @@ func (m *mainFeature) aPodmonInstance() error {
fmt.Printf("loghook last-entry %+v\n", m.loghook.LastEntry())
}
monitor.PodMonitor.CSIExtensionsPresent = false
m.csiapiMock = new(csiapi.CSIMock)
m.k8sapiMock = new(k8sapi.K8sMock)
m.csiapiMock = new(mocks.CSIMock)
m.k8sapiMock = new(mocks.K8sMock)
GetCSIClient = m.mockGetCSIClient
K8sAPI = m.k8sapiMock
m.leaderElect = &mockLeaderElect{}
Expand Down
12 changes: 9 additions & 3 deletions internal/criapi/criapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (

log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
"k8s.io/cri-api/pkg/apis/runtime/v1"
v1 "k8s.io/cri-api/pkg/apis/runtime/v1"
)

// Client represents the client grpc connection to the ContainerRuntimerInterface
Expand All @@ -46,13 +46,17 @@ var CRIMaxConnectionRetry = 3
// CRINewClientTimeout is the timeout for making a new client.
var CRINewClientTimeout = 90 * time.Second

var getGrpcDialContext = func(ctx context.Context, target string, opts ...grpc.DialOption) (conn *grpc.ClientConn, err error) {
return grpc.DialContext(ctx, target, opts...)
}

// NewCRIClient returns a new client connection to the ContainerRuntimeInterface or an error
func NewCRIClient(criSock string, _ ...grpc.DialOption) (*Client, error) {
var err error
ctx, cancel := context.WithTimeout(context.Background(), CRINewClientTimeout)
defer cancel()
for i := 0; i < CRIMaxConnectionRetry; i++ {
CRIClient.CRIConn, err = grpc.DialContext(ctx, criSock, grpc.WithInsecure())
CRIClient.CRIConn, err = getGrpcDialContext(ctx, criSock, grpc.WithInsecure())
if err != nil || CRIClient.CRIConn == nil {
var errMsg string
if err == nil {
Expand Down Expand Up @@ -97,9 +101,11 @@ var knownPaths = [3]string{"/var/run/dockershim.sock", "/run/containerd/containe

// ChooseCRIPath chooses an appropriate unix domain socket path to the CRI interface.
// This is done according to the ordering described for the crictl command.
var osStat = os.Stat

func (cri *Client) ChooseCRIPath() (string, error) {
for _, path := range knownPaths {
_, err := os.Stat(path)
_, err := osStat(path)
if err == nil {
retval := fmt.Sprintf("unix:///%s", path)
return retval, nil
Expand Down
271 changes: 246 additions & 25 deletions internal/criapi/criapi_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
//go:build k8s
// +build k8s

/*
* Copyright (c) 2021-2022 Dell Inc., or its subsidiaries. All Rights Reserved.
*
Expand All @@ -21,41 +18,265 @@ package criapi

import (
"context"
"fmt"
"errors"
"net"
"os"
"testing"
"time"

"github.com/stretchr/testify/assert"
"google.golang.org/grpc"
"google.golang.org/grpc/test/bufconn"
v1 "k8s.io/cri-api/pkg/apis/runtime/v1"
)

func TestListContainers(t *testing.T) {
client, err := NewCRIClient("unix:/var/run/dockershim.sock")
if err != nil {
t.Errorf("NewCRIClient: %s", err)
// Mocking the grpc.DialContext function
var dialContextMock = func(ctx context.Context, target string, _ ...grpc.DialOption) (*grpc.ClientConn, error) {
_ = target // Explicitly ignore the unused parameter
lis := bufconn.Listen(1024 * 1024)
s := grpc.NewServer()
v1.RegisterRuntimeServiceServer(s, &mockRuntimeServiceServer{})
go func() {
if err := s.Serve(lis); err != nil {
panic(err)
}
}()
return grpc.DialContext(ctx, "", grpc.WithContextDialer(bufconnDialer(lis)), grpc.WithInsecure())
}

func bufconnDialer(lis *bufconn.Listener) func(context.Context, string) (net.Conn, error) {
return func(context.Context, string) (net.Conn, error) {
return lis.Dial()
}
req := &v1.ListContainersRequest{}
rep, err := client.ListContainers(context.Background(), req)
if err != nil {
t.Errorf("ListContainers: %s", err)
} else {
for _, cont := range rep.Containers {
fmt.Printf("container Id %s Name %s State %s\n", cont.Id, cont.Metadata.Name, cont.State)
}

type mockRuntimeServiceServer struct {
v1.UnimplementedRuntimeServiceServer
}

func (s *mockRuntimeServiceServer) ListContainers(_ context.Context, _ *v1.ListContainersRequest) (*v1.ListContainersResponse, error) {
// Return a mock response
return &v1.ListContainersResponse{
Containers: []*v1.Container{
{
Id: "test-container-id",
Metadata: &v1.ContainerMetadata{
Name: "test-container",
},
State: v1.ContainerState_CONTAINER_RUNNING,
},
},
}, nil
}

func TestGetGrpcDialContext(t *testing.T) {
// Mock context and target
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
target := "unix:///var/run/dockershim.sock"

// Call the function
conn, err := getGrpcDialContext(ctx, target, grpc.WithInsecure())

// Assertions
assert.NoError(t, err)
assert.NotNil(t, conn)

// Close the connection
err = conn.Close()
assert.NoError(t, err)
}

func TestNewCRIClient_Success(t *testing.T) {
// Override the getGrpcDialContext function with mock
getGrpcDialContext = dialContextMock

client, err := NewCRIClient("unix:///var/run/dockershim.sock")
assert.NoError(t, err)
assert.NotNil(t, client)
assert.NotNil(t, client.CRIConn)
assert.NotNil(t, client.RuntimeServiceClient)
}

func TestNewCRIClient_Failure(t *testing.T) {
// Override the getGrpcDialContext function to simulate failure
getGrpcDialContext = func(_ context.Context, _ string, _ ...grpc.DialOption) (*grpc.ClientConn, error) {
return nil, errors.New("failed to connect")
}

// Reduce retry count and sleep interval for the test
originalRetry := CRIMaxConnectionRetry
originalSleep := CRIClientDialRetry
CRIMaxConnectionRetry = 2
CRIClientDialRetry = 1 * time.Second
defer func() {
CRIMaxConnectionRetry = originalRetry
CRIClientDialRetry = originalSleep
}()

_, err := NewCRIClient("unix:///var/run/dockershim.sock")
assert.Error(t, err)
// assert.Nil(t, client)
}

func TestNewCRIClient_NilConnNoError(t *testing.T) {
// Simulate retries with nil connection and no error
retryCount := 0
getGrpcDialContext = func(_ context.Context, _ string, _ ...grpc.DialOption) (*grpc.ClientConn, error) {
retryCount++
if retryCount < 2 {
return nil, nil
}
return nil, errors.New("failed to connect after retries")
}

// Reduce retry count and sleep interval for the test
originalRetry := CRIMaxConnectionRetry
originalSleep := CRIClientDialRetry
CRIMaxConnectionRetry = 2
CRIClientDialRetry = 1 * time.Second
defer func() {
CRIMaxConnectionRetry = originalRetry
CRIClientDialRetry = originalSleep
}()

_, err := NewCRIClient("unix:///var/run/dockershim.sock")
assert.Error(t, err)
// assert.Nil(t, client)
}

func TestClient_Connected(t *testing.T) {
client := &Client{}

// Test when CRIConn is nil
assert.False(t, client.Connected())

// Test when CRIConn is not nil
client.CRIConn = &grpc.ClientConn{}
assert.True(t, client.Connected())
}

func TestClient_Close(t *testing.T) {
client := &Client{}

// Test when CRIConn is nil
err := client.Close()
assert.NoError(t, err)

// Test when CRIConn is not nil
lis := bufconn.Listen(1024 * 1024)
conn, _ := grpc.DialContext(context.Background(), "", grpc.WithContextDialer(bufconnDialer(lis)), grpc.WithInsecure())
client.CRIConn = conn

err = client.Close()
if err != nil {
t.Errorf("Close: %s", err)
assert.NoError(t, err)
assert.Nil(t, client.CRIConn)
}

func TestClient_ListContainers(t *testing.T) {
// Mocking the grpc.DialContext function
getGrpcDialContext = func(ctx context.Context, _ string, _ ...grpc.DialOption) (*grpc.ClientConn, error) {
lis := bufconn.Listen(1024 * 1024)
s := grpc.NewServer()
v1.RegisterRuntimeServiceServer(s, &mockRuntimeServiceServer{})
go func() {
if err := s.Serve(lis); err != nil {
panic(err)
}
}()
return grpc.DialContext(ctx, "", grpc.WithContextDialer(bufconnDialer(lis)), grpc.WithInsecure())
}

client, err := NewCRIClient("unix:///var/run/dockershim.sock")
assert.NoError(t, err)
assert.NotNil(t, client)

req := &v1.ListContainersRequest{}
resp, err := client.ListContainers(context.Background(), req)
assert.NoError(t, err)
assert.NotNil(t, resp)
assert.Len(t, resp.Containers, 1)
assert.Equal(t, "test-container-id", resp.Containers[0].Id)
assert.Equal(t, "test-container", resp.Containers[0].Metadata.Name)
assert.Equal(t, v1.ContainerState_CONTAINER_RUNNING, resp.Containers[0].State)
}

func TestChooseCRIPath_Success(t *testing.T) {
// Override osStat with mockStat
originalStat := osStat
osStat = mockStat
defer func() { osStat = originalStat }() // Restore original osStat after test

client := &Client{}
path, err := client.ChooseCRIPath()
assert.NoError(t, err)
assert.Equal(t, "unix:////var/run/dockershim.sock", path)
}

func TestGetContainerInfo(t *testing.T) {
infoMap, err := CRIClient.GetContainerInfo(context.Background())
if err != nil {
t.Errorf("GetContainerInfo failed: %s", err)
func TestChooseCRIPath_Failure(t *testing.T) {
// Override osStat with a mock implementation that simulates all paths not existing
originalStat := osStat
osStat = func(_ string) (os.FileInfo, error) {
return nil, os.ErrNotExist
}
for key, value := range infoMap {
if key != value.ID {
t.Error("key != value.ID")
defer func() { osStat = originalStat }() // Restore original osStat after test

client := &Client{}
path, err := client.ChooseCRIPath()
assert.Error(t, err)
assert.Equal(t, "", path)
assert.Equal(t, "Could not find path for CRI runtime from knownPaths", err.Error())
}

var dialContextMockForGetContainerInfo = func(ctx context.Context, _ string, _ ...grpc.DialOption) (*grpc.ClientConn, error) {
lis := bufconn.Listen(1024 * 1024)
s := grpc.NewServer()
v1.RegisterRuntimeServiceServer(s, &mockRuntimeServiceServer{})
go func() {
if err := s.Serve(lis); err != nil {
panic(err)
}
fmt.Printf("ContainerInfo %+v\n", *value)
}()
return grpc.DialContext(ctx, "", grpc.WithContextDialer(bufconnDialer(lis)), grpc.WithInsecure())
}

func mockStat(path string) (os.FileInfo, error) {
if path == "/var/run/dockershim.sock" || path == "/run/containerd/containerd.sock" || path == "/run/crio/crio.sock" {
return nil, nil // Simulate that the file exists
}
return nil, os.ErrNotExist // Simulate that the file does not exist
}

func TestGetContainerInfo_Success(t *testing.T) {
// Override osStat with mockStat
originalStat := osStat
osStat = mockStat
defer func() { osStat = originalStat }() // Restore original osStat after test

// Override the getGrpcDialContext function with our mock
getGrpcDialContext = dialContextMockForGetContainerInfo

client := &Client{}
result, err := client.GetContainerInfo(context.Background())
assert.NoError(t, err)
assert.NotNil(t, result)
assert.Len(t, result, 1)
assert.Equal(t, "test-container-id", result["test-container-id"].ID)
assert.Equal(t, "test-container", result["test-container-id"].Name)
assert.Equal(t, v1.ContainerState_CONTAINER_RUNNING, result["test-container-id"].State)
}

func TestGetContainerInfo_ChooseCRIPathFailure(t *testing.T) {
// Override osStat with a mock implementation that simulates all paths not existing
originalStat := osStat
osStat = func(_ string) (os.FileInfo, error) {
return nil, os.ErrNotExist
}
defer func() { osStat = originalStat }() // Restore original osStat after test

client := &Client{}
result, err := client.GetContainerInfo(context.Background())
assert.Error(t, err)
assert.Equal(t, "Could not find path for CRI runtime from knownPaths", err.Error())
assert.Empty(t, result)
}
6 changes: 5 additions & 1 deletion internal/csiapi/csi.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,16 @@ var CSIClient Client
// CSIClientDialRetry is timeout after failure to connect to the CSI Driver
var CSIClientDialRetry = 30 * time.Second

var getGrpcDialContext = func(ctx context.Context, target string, opts ...grpc.DialOption) (conn *grpc.ClientConn, err error) {
return grpc.DialContext(ctx, target, opts...)
}

// NewCSIClient returns a new CSIApi interface
func NewCSIClient(csiSock string, clientOpts ...grpc.DialOption) (CSIApi, error) {
var err error
for {
// Wait on the driver. It will not open its unix socket until it has become leader.
CSIClient.DriverConn, err = grpc.DialContext(context.Background(), csiSock, clientOpts...)
CSIClient.DriverConn, err = getGrpcDialContext(context.Background(), csiSock, clientOpts...)
log.Debugf("grpc.Dial returned %v %v", CSIClient.DriverConn, err)
if err != nil || CSIClient.DriverConn == nil {
var errMsg string
Expand Down
Loading
Loading