Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b28f5db
Issue 40: Unit-test for CRD
mrajagopal Aug 14, 2024
b1f649c
Issue 40: Unit-test for CRD
mrajagopal Aug 20, 2024
ee263e6
Merge branch 'main' into mrajagopal-unit-tests
mrajagopal Aug 15, 2025
7bb7833
feat: Create unit tests for NIC, NIM, NGF, and NGX
mrajagopal Sep 3, 2025
29de4ac
Merge branch 'main' into mrajagopal-unit-tests
mrajagopal Sep 3, 2025
33dabbd
Chore: Update to reflect changes in return parameters
mrajagopal Sep 3, 2025
d53e7ff
chore: replace deprecated routine filepath.HasPrefix with strings.Has…
mrajagopal Sep 3, 2025
2d9225d
Update pkg/jobs/ngf_job_list_test.go
mrajagopal Sep 4, 2025
ecb3c62
Update pkg/jobs/ngf_job_list_test.go
mrajagopal Sep 4, 2025
6d7b09d
Update pkg/data_collector/data_collector.go
mrajagopal Sep 4, 2025
6ef2f3e
Update pkg/jobs/nic_job_list_test.go
mrajagopal Sep 4, 2025
e124a26
Update pkg/jobs/job_test.go
mrajagopal Sep 4, 2025
1922e67
Update pkg/jobs/nic_job_list_test.go
mrajagopal Sep 4, 2025
2c2bd5c
Update pkg/jobs/common_job_list_test.go
mrajagopal Sep 4, 2025
3170f31
Fix: Address issues from common_job_list tests
mrajagopal Sep 15, 2025
d954b2e
Fix: Implement a mock data_collector
mrajagopal Sep 15, 2025
5e2bd87
Fix: Use the mock data_collector in various tests
mrajagopal Sep 15, 2025
6eef435
Fix merge-conflicts from main onto branch
mrajagopal Oct 13, 2025
625c0be
Fix: merge conflict from main
mrajagopal Oct 13, 2025
8e5c792
Fix: incorporate test coverage report
mrajagopal Oct 13, 2025
ba84c4e
Fix: Use library function for a pointer
mrajagopal Oct 13, 2025
0f1c9e6
Review fixes
mrajagopal Oct 14, 2025
7beddf9
Merge branch 'main' into mrajagopal-unit-tests
mrajagopal Oct 16, 2025
043d54d
Update pkg/mock/mock_data_collector.go
mrajagopal Oct 16, 2025
9e5a541
Update pkg/mock/mock_data_collector.go
mrajagopal Oct 16, 2025
eda9364
Review: Read mock CRD objects via a YAML declaration
mrajagopal Oct 17, 2025
7757474
Review: Read mock objects via a YAML declaration
mrajagopal Oct 17, 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
82 changes: 82 additions & 0 deletions pkg/crds/crd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package crds

import (
"reflect"
"testing"
)

func TestGetNICCRDList(t *testing.T) {
tests := []struct {
name string
want []Crd
}{
{
name: "Correct CRD list",
want: []Crd{
{
Resource: "apdoslogconfs",
Group: "appprotectdos.f5.com",
Version: "v1beta1",
},
{
Resource: "apdospolicies",
Group: "appprotectdos.f5.com",
Version: "v1beta1",
},
{
Resource: "dosprotectedresources",
Group: "appprotectdos.f5.com",
Version: "v1beta1",
},
{
Resource: "aplogconfs",
Group: "appprotect.f5.com",
Version: "v1beta1",
},
{
Resource: "appolicies",
Group: "appprotect.f5.com",
Version: "v1beta1",
},
{
Resource: "apusersigs",
Group: "appprotect.f5.com",
Version: "v1beta1",
},
{
Resource: "globalconfigurations",
Group: "k8s.nginx.org",
Version: "v1",
},
{
Resource: "policies",
Group: "k8s.nginx.org",
Version: "v1",
},
{
Resource: "transportservers",
Group: "k8s.nginx.org",
Version: "v1",
},
{
Resource: "virtualserverroutes",
Group: "k8s.nginx.org",
Version: "v1",
},
{
Resource: "virtualservers",
Group: "k8s.nginx.org",
Version: "v1",
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetNICCRDList(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetNICCRDList() = %v, want %v", got, tt.want)
}
})
}
}
10 changes: 7 additions & 3 deletions pkg/data_collector/data_collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,14 @@ type DataCollector struct {
Logger *log.Logger
LogFile *os.File
K8sRestConfig *rest.Config
K8sCoreClientSet *kubernetes.Clientset
K8sCoreClientSet kubernetes.Interface
K8sCrdClientSet *crdClient.Clientset
K8sMetricsClientSet *metricsClient.Clientset
K8sHelmClientSet map[string]helmClient.Client
ExcludeDBData bool
ExcludeTimeSeriesData bool
PodExecutor func(namespace, pod, container string, command []string, ctx context.Context) ([]byte, error)
QueryCRD func(crd crds.Crd, namespace string, ctx context.Context) ([]byte, error)
}

type Manifest struct {
Expand Down Expand Up @@ -147,6 +149,8 @@ func NewDataCollector(collector *DataCollector) error {
collector.LogFile = logFile
collector.Logger = log.New(logFile, "", log.LstdFlags|log.LUTC|log.Lmicroseconds|log.Lshortfile)
collector.K8sHelmClientSet = make(map[string]helmClient.Client)
collector.PodExecutor = collector.RealPodExecutor
collector.QueryCRD = collector.RealQueryCRD

//Initialize clients
collector.K8sRestConfig = config
Expand Down Expand Up @@ -259,7 +263,7 @@ func (c *DataCollector) WrapUp(product string) (string, error) {
return tarballName, nil
}

func (c *DataCollector) PodExecutor(namespace string, pod string, container string, command []string, ctx context.Context) ([]byte, error) {
func (c *DataCollector) RealPodExecutor(namespace string, pod string, container string, command []string, ctx context.Context) ([]byte, error) {
req := c.K8sCoreClientSet.CoreV1().RESTClient().Post().
Namespace(namespace).
Resource("pods").
Expand Down Expand Up @@ -292,7 +296,7 @@ func (c *DataCollector) PodExecutor(namespace string, pod string, container stri
}
}

func (c *DataCollector) QueryCRD(crd crds.Crd, namespace string, ctx context.Context) ([]byte, error) {
func (c *DataCollector) RealQueryCRD(crd crds.Crd, namespace string, ctx context.Context) ([]byte, error) {

schemeGroupVersion := schema.GroupVersion{Group: crd.Group, Version: crd.Version}
negotiatedSerializer := scheme.Codecs.WithoutConversion()
Expand Down
133 changes: 133 additions & 0 deletions pkg/data_collector/data_collector_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package data_collector

import (
"bytes"
"context"
"io"
"log"
"os"
"path/filepath"
"testing"

"github.com/nginxinc/nginx-k8s-supportpkg/pkg/crds"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/rest"
)

func TestNewDataCollector_Success(t *testing.T) {
dc := &DataCollector{Namespaces: []string{"default"}}
err := NewDataCollector(dc)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if dc.BaseDir == "" {
t.Error("BaseDir should be set")
}
if dc.Logger == nil {
t.Error("Logger should be set")
}
if dc.LogFile == nil {
t.Error("LogFile should be set")
}
if dc.K8sCoreClientSet == nil {
t.Error("K8sCoreClientSet should be set")
}
if dc.K8sCrdClientSet == nil {
t.Error("K8sCrdClientSet should be set")
}
if dc.K8sMetricsClientSet == nil {
t.Error("K8sMetricsClientSet should be set")
}
if dc.K8sHelmClientSet == nil {
t.Error("K8sHelmClientSet should be set")
}
}

func TestWrapUp_CreatesTarball(t *testing.T) {
tmpDir := t.TempDir()
logFile, _ := os.Create(filepath.Join(tmpDir, "supportpkg.log"))
dc := &DataCollector{
BaseDir: tmpDir,
LogFile: logFile,
Logger: log.New(io.Discard, "", 0),
}
product := "nginx"
tarball, err := dc.WrapUp(product)
if err != nil {
t.Fatalf("WrapUp failed: %v", err)
}
if _, err := os.Stat(tarball); err != nil {
t.Errorf("tarball not created: %v", err)
}
_ = os.Remove(tarball)
}

func TestRealPodExecutor_ReturnsOutput(t *testing.T) {
dc := &DataCollector{
K8sCoreClientSet: fake.NewSimpleClientset(),
K8sRestConfig: &rest.Config{},
}
// Replace RealPodExecutor with a mock for testing
dc.PodExecutor = func(namespace, pod, container string, command []string, ctx context.Context) ([]byte, error) {
return []byte("output"), nil
}
out, err := dc.PodExecutor("default", "pod", "container", []string{"echo", "hello"}, context.TODO())
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if !bytes.Contains(out, []byte("output")) {
t.Errorf("expected output, got %s", string(out))
}
}

func TestRealQueryCRD_ReturnsErrorOnInvalidConfig(t *testing.T) {
dc := &DataCollector{
K8sRestConfig: &rest.Config{},
}
crd := crds.Crd{Group: "test", Version: "v1", Resource: "foos"}
_, err := dc.RealQueryCRD(crd, "default", context.TODO())
if err == nil {
t.Error("expected error for invalid config")
}
}

func TestAllNamespacesExist_AllExist(t *testing.T) {
client := fake.NewSimpleClientset(&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "default"}})
dc := &DataCollector{
Namespaces: []string{"default"},
K8sCoreClientSet: client,
Logger: log.New(io.Discard, "", 0),
}
if !dc.AllNamespacesExist() {
t.Error("expected all namespaces to exist")
}
}

func TestAllNamespacesExist_NotExist(t *testing.T) {
client := fake.NewSimpleClientset()
dc := &DataCollector{
Namespaces: []string{"missing"},
K8sCoreClientSet: client,
Logger: log.New(io.Discard, "", 0),
}
if dc.AllNamespacesExist() {
t.Error("expected namespaces to not exist")
}
}

func TestWrapUp_ErrorOnLogFileClose(t *testing.T) {
tmpDir := t.TempDir()
logFile, _ := os.Create(filepath.Join(tmpDir, "supportpkg.log"))
logFile.Close() // Already closed
dc := &DataCollector{
BaseDir: tmpDir,
LogFile: logFile,
Logger: log.New(io.Discard, "", 0),
}
_, err := dc.WrapUp("nginx")
if err == nil {
t.Error("expected error on closing already closed log file")
}
}
6 changes: 3 additions & 3 deletions pkg/jobs/common_job_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func CommonJobList() []Job {
Execute: func(dc *data_collector.DataCollector, ctx context.Context, ch chan JobResult) {
jobResult := JobResult{Files: make(map[string][]byte), Error: nil}
for _, namespace := range dc.Namespaces {
result, err := dc.K8sCoreClientSet.DiscoveryClient.ServerPreferredResources()
result, err := dc.K8sCoreClientSet.Discovery().ServerPreferredResources()
if err != nil {
dc.Logger.Printf("\tCould not retrieve API resources list %s: %v\n", namespace, err)
} else {
Expand All @@ -163,7 +163,7 @@ func CommonJobList() []Job {
Execute: func(dc *data_collector.DataCollector, ctx context.Context, ch chan JobResult) {
jobResult := JobResult{Files: make(map[string][]byte), Error: nil}
for _, namespace := range dc.Namespaces {
result, err := dc.K8sCoreClientSet.DiscoveryClient.ServerGroups()
result, err := dc.K8sCoreClientSet.Discovery().ServerGroups()
if err != nil {
dc.Logger.Printf("\tCould not retrieve API versions list %s: %v\n", namespace, err)
} else {
Expand Down Expand Up @@ -367,7 +367,7 @@ func CommonJobList() []Job {
Timeout: time.Second * 10,
Execute: func(dc *data_collector.DataCollector, ctx context.Context, ch chan JobResult) {
jobResult := JobResult{Files: make(map[string][]byte), Error: nil}
result, err := dc.K8sCoreClientSet.ServerVersion()
result, err := dc.K8sCoreClientSet.Discovery().ServerVersion()
if err != nil {
dc.Logger.Printf("\tCould not retrieve server version: %v\n", err)
} else {
Expand Down
Loading
Loading