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

chore(test): improve tests for job collector #432

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
49 changes: 45 additions & 4 deletions pkg/jobs/collector_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package jobs

import (
"context"
"reflect"
"testing"

trivy_checks "github.com/aquasecurity/trivy-checks"
"github.com/stretchr/testify/assert"

"github.com/aquasecurity/trivy-kubernetes/pkg/k8s"
)

func TestLoadCheckFilesByID(t *testing.T) {
Expand Down Expand Up @@ -177,8 +180,8 @@
}
}

func TestFilterCommandsByPlatform(t *testing.T) {
commandsK8s := []any{
var (
commandsK8s = []any{
map[string]interface{}{
"id": "CMD-0001",
"title": "kubelet.conf file permissions",
Expand All @@ -204,7 +207,7 @@
"platforms": []interface{}{"k8s"},
},
}
commandsRKE2 := []any{
commandsRKE2 = []any{
map[string]interface{}{
"id": "CMD-0001",
"title": "kubelet.conf file permissions",
Expand All @@ -222,11 +225,13 @@
"platforms": []interface{}{"k8s", "rke2"},
},
}
commandsMap := map[string][]any{
commandsMap = map[string][]any{
"k8s": commandsK8s,
"rke2": commandsRKE2,
}
)

func TestFilterCommandsByPlatform(t *testing.T) {
tests := []struct {
name string
platform string
Expand Down Expand Up @@ -273,3 +278,39 @@
})
}
}

func TestJobCollector_ApplyAndCollect(t *testing.T) {
nss := []string{"default", "kube-system"}

tests := []struct {
name string
nodeName string
err error
want string
}{
{
"success",
"node1",
nil,
"",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
nsResource := k8s.NewMockNamespaceableResourceInterface(nss, test.err)
mockCluster := k8s.NewMockCluster(k8s.NewMockClusterDynamicClient(nsResource))
mockCollector := NewCollector(mockCluster,

Check failure on line 303 in pkg/jobs/collector_test.go

View workflow job for this annotation

GitHub Actions / Verify code

cannot use mockCluster (variable of type *k8s.MockCluster) as k8s.Cluster value in argument to NewCollector: *k8s.MockCluster does not implement k8s.Cluster (wrong type for method GetK8sClientSet)

Check failure on line 303 in pkg/jobs/collector_test.go

View workflow job for this annotation

GitHub Actions / Run unit tests

cannot use mockCluster (variable of type *k8s.MockCluster) as k8s.Cluster value in argument to NewCollector: *k8s.MockCluster does not implement k8s.Cluster (wrong type for method GetK8sClientSet)
WithEmbeddedCommandFileSystem(trivy_checks.EmbeddedK8sCommandsFileSystem),
WithEmbeddedNodeConfigFilesystem(trivy_checks.EmbeddedConfigCommandsFileSystem))
// gotCmd, gotCfg := getEmbeddedCommands(trivy_checks.EmbeddedK8sCommandsFileSystem, trivy_checks.EmbeddedConfigCommandsFileSystem, AddChecksByCheckId)

got, err := mockCollector.ApplyAndCollect(context.TODO(), test.nodeName)
if err != test.err {
t.Errorf("expected error %v, got %v", test.err, err)
}
assert.Equal(t, got, test.want)
})
}

}
138 changes: 138 additions & 0 deletions pkg/k8s/mocks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package k8s

import (
"context"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/fake"

"github.com/aquasecurity/trivy-kubernetes/pkg/bom"
"github.com/aquasecurity/trivy-kubernetes/pkg/k8s/docker"
)

type MockClusterDynamicClient struct {
resource dynamic.NamespaceableResourceInterface
}

func NewMockClusterDynamicClient(resource dynamic.NamespaceableResourceInterface) *MockClusterDynamicClient {
return &MockClusterDynamicClient{
resource: resource,
}
}
func (m MockClusterDynamicClient) Resource(schema.GroupVersionResource) dynamic.NamespaceableResourceInterface {
return m.resource

}

type MockNamespaceableResourceInterface struct {
err error
namespaces []string
}

func NewMockNamespaceableResourceInterface(namespaces []string, err error) *MockNamespaceableResourceInterface {
return &MockNamespaceableResourceInterface{
err: err,
namespaces: namespaces,
}
}

func (m MockNamespaceableResourceInterface) Namespace(s string) dynamic.ResourceInterface {
return nil
}

func (m MockNamespaceableResourceInterface) Create(ctx context.Context, obj *unstructured.Unstructured, options metav1.CreateOptions, subresources ...string) (*unstructured.Unstructured, error) {
return &unstructured.Unstructured{}, nil
}

func (m MockNamespaceableResourceInterface) Update(ctx context.Context, obj *unstructured.Unstructured, options metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) {
return &unstructured.Unstructured{}, nil
}

func (m MockNamespaceableResourceInterface) UpdateStatus(ctx context.Context, obj *unstructured.Unstructured, options metav1.UpdateOptions) (*unstructured.Unstructured, error) {
return &unstructured.Unstructured{}, nil
}

func (m MockNamespaceableResourceInterface) Delete(ctx context.Context, name string, options metav1.DeleteOptions, subresources ...string) error {
return nil
}

func (m MockNamespaceableResourceInterface) DeleteCollection(ctx context.Context, options metav1.DeleteOptions, listOptions metav1.ListOptions) error {
return nil
}

func (m MockNamespaceableResourceInterface) Get(ctx context.Context, name string, options metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) {
return &unstructured.Unstructured{}, nil
}

func (m MockNamespaceableResourceInterface) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
return nil, nil
}

func (m MockNamespaceableResourceInterface) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, options metav1.PatchOptions, subresources ...string) (*unstructured.Unstructured, error) {
return &unstructured.Unstructured{}, nil
}

func (m MockNamespaceableResourceInterface) Apply(ctx context.Context, name string, obj *unstructured.Unstructured, options metav1.ApplyOptions, subresources ...string) (*unstructured.Unstructured, error) {
return &unstructured.Unstructured{}, nil
}

func (m MockNamespaceableResourceInterface) ApplyStatus(ctx context.Context, name string, obj *unstructured.Unstructured, options metav1.ApplyOptions) (*unstructured.Unstructured, error) {
return &unstructured.Unstructured{}, nil
}

func (m MockNamespaceableResourceInterface) List(ctx context.Context, opts metav1.ListOptions) (*unstructured.UnstructuredList, error) {
if m.err != nil {
return nil, m.err
}
result := &unstructured.UnstructuredList{}
for _, namespace := range m.namespaces {
result.Items = append(result.Items, unstructured.Unstructured{
Object: map[string]interface{}{
"metadata": map[string]interface{}{
"name": namespace,
},
},
})
}
return result, nil
}

type MockCluster struct {
dynamicClient dynamic.Interface
}

func NewMockCluster(dynamicClient dynamic.Interface) *MockCluster {
return &MockCluster{
dynamicClient: dynamicClient,
}
}

// GetDynamicClient returns dynamic.Interface
func (m *MockCluster) GetDynamicClient() dynamic.Interface {
return m.dynamicClient
}

// Stub methods to satisfy the Cluster interface
func (m *MockCluster) GetCurrentContext() string { return "" }
func (m *MockCluster) GetCurrentNamespace() string { return "" }
func (m *MockCluster) GetK8sClientSet() kubernetes.Interface {
return fake.NewClientset()
}
func (m *MockCluster) GetGVRs(bool, []string) ([]schema.GroupVersionResource, error) { return nil, nil }
func (m *MockCluster) GetGVR(string) (schema.GroupVersionResource, error) {
return schema.GroupVersionResource{}, nil
}
func (m *MockCluster) CreateClusterBom(ctx context.Context) (*bom.Result, error) { return nil, nil }
func (m *MockCluster) GetClusterVersion() string { return "" }
func (m *MockCluster) AuthByResource(resource unstructured.Unstructured) (map[string]docker.Auth, error) {
return nil, nil
}
func (m *MockCluster) Platform() Platform {
return Platform{Name: "k8s", Version: "1.23.0"}
}
126 changes: 4 additions & 122 deletions pkg/trivyk8s/trivyk8s_test.go
Original file line number Diff line number Diff line change
@@ -1,132 +1,17 @@
package trivyk8s

import (
"context"
"fmt"
"testing"

"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"

"github.com/stretchr/testify/assert"

"github.com/aquasecurity/trivy-kubernetes/pkg/artifacts"
"github.com/aquasecurity/trivy-kubernetes/pkg/bom"
"github.com/aquasecurity/trivy-kubernetes/pkg/k8s"
"github.com/aquasecurity/trivy-kubernetes/pkg/k8s/docker"
)

type MockClusterDynamicClient struct {
resource dynamic.NamespaceableResourceInterface
}

func (m MockClusterDynamicClient) Resource(schema.GroupVersionResource) dynamic.NamespaceableResourceInterface {
return m.resource

}

type MockNamespaceableResourceInterface struct {
err error
namespaces []string
}

func (m MockNamespaceableResourceInterface) Namespace(s string) dynamic.ResourceInterface {
return nil
}

func (m MockNamespaceableResourceInterface) Create(ctx context.Context, obj *unstructured.Unstructured, options metav1.CreateOptions, subresources ...string) (*unstructured.Unstructured, error) {
return &unstructured.Unstructured{}, nil
}

func (m MockNamespaceableResourceInterface) Update(ctx context.Context, obj *unstructured.Unstructured, options metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) {
return &unstructured.Unstructured{}, nil
}

func (m MockNamespaceableResourceInterface) UpdateStatus(ctx context.Context, obj *unstructured.Unstructured, options metav1.UpdateOptions) (*unstructured.Unstructured, error) {
return &unstructured.Unstructured{}, nil
}

func (m MockNamespaceableResourceInterface) Delete(ctx context.Context, name string, options metav1.DeleteOptions, subresources ...string) error {
return nil
}

func (m MockNamespaceableResourceInterface) DeleteCollection(ctx context.Context, options metav1.DeleteOptions, listOptions metav1.ListOptions) error {
return nil
}

func (m MockNamespaceableResourceInterface) Get(ctx context.Context, name string, options metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) {
return &unstructured.Unstructured{}, nil
}

func (m MockNamespaceableResourceInterface) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
return nil, nil
}

func (m MockNamespaceableResourceInterface) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, options metav1.PatchOptions, subresources ...string) (*unstructured.Unstructured, error) {
return &unstructured.Unstructured{}, nil
}

func (m MockNamespaceableResourceInterface) Apply(ctx context.Context, name string, obj *unstructured.Unstructured, options metav1.ApplyOptions, subresources ...string) (*unstructured.Unstructured, error) {
return &unstructured.Unstructured{}, nil
}

func (m MockNamespaceableResourceInterface) ApplyStatus(ctx context.Context, name string, obj *unstructured.Unstructured, options metav1.ApplyOptions) (*unstructured.Unstructured, error) {
return &unstructured.Unstructured{}, nil
}

func (m MockNamespaceableResourceInterface) List(ctx context.Context, opts metav1.ListOptions) (*unstructured.UnstructuredList, error) {
if m.err != nil {
return nil, m.err
}
result := &unstructured.UnstructuredList{}
for _, namespace := range m.namespaces {
result.Items = append(result.Items, unstructured.Unstructured{
Object: map[string]interface{}{
"metadata": map[string]interface{}{
"name": namespace,
},
},
})
}
return result, nil
}

type MockCluster struct {
dynamicClient dynamic.Interface
}

func newMockCluster(dynamicClient dynamic.Interface) *MockCluster {
return &MockCluster{
dynamicClient: dynamicClient,
}
}

// GetDynamicClient returns dynamic.Interface
func (m *MockCluster) GetDynamicClient() dynamic.Interface {
return m.dynamicClient
}

// Stub methods to satisfy the Cluster interface
func (m *MockCluster) GetCurrentContext() string { return "" }
func (m *MockCluster) GetCurrentNamespace() string { return "" }
func (m *MockCluster) GetK8sClientSet() *kubernetes.Clientset { return nil }
func (m *MockCluster) GetGVRs(bool, []string) ([]schema.GroupVersionResource, error) { return nil, nil }
func (m *MockCluster) GetGVR(string) (schema.GroupVersionResource, error) {
return schema.GroupVersionResource{}, nil
}
func (m *MockCluster) CreateClusterBom(ctx context.Context) (*bom.Result, error) { return nil, nil }
func (m *MockCluster) GetClusterVersion() string { return "" }
func (m *MockCluster) AuthByResource(resource unstructured.Unstructured) (map[string]docker.Auth, error) {
return nil, nil
}
func (m *MockCluster) Platform() k8s.Platform { return k8s.Platform{} }

func TestGetNamespaces(t *testing.T) {
tests := []struct {
name string
Expand Down Expand Up @@ -192,15 +77,12 @@

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
nsResource := k8s.NewMockNamespaceableResourceInterface(tt.mockNamespaces, tt.mockError)

client := &client{
includeNamespaces: tt.includeNamespaces,
excludeNamespaces: tt.excludeNamespaces,
cluster: newMockCluster(MockClusterDynamicClient{
resource: MockNamespaceableResourceInterface{
err: tt.mockError,
namespaces: tt.mockNamespaces,
},
}),
cluster: k8s.NewMockCluster(k8s.NewMockClusterDynamicClient(nsResource)),

Check failure on line 85 in pkg/trivyk8s/trivyk8s_test.go

View workflow job for this annotation

GitHub Actions / Verify code

cannot use k8s.NewMockCluster(k8s.NewMockClusterDynamicClient(nsResource)) (value of type *k8s.MockCluster) as k8s.Cluster value in struct literal: *k8s.MockCluster does not implement k8s.Cluster (wrong type for method GetK8sClientSet)

Check failure on line 85 in pkg/trivyk8s/trivyk8s_test.go

View workflow job for this annotation

GitHub Actions / Run unit tests

cannot use k8s.NewMockCluster(k8s.NewMockClusterDynamicClient(nsResource)) (value of type *k8s.MockCluster) as k8s.Cluster value in struct literal: *k8s.MockCluster does not implement k8s.Cluster (wrong type for method GetK8sClientSet)
}

// Run the test
Expand Down
Loading