Skip to content

Commit

Permalink
test: added tests for the Service analyzer (#1011)
Browse files Browse the repository at this point in the history
* Added new tests for the `Service` analyzer defined in the
  `pkg/analyzer` package.

* The addition of these new tests has increased the code coverage of the
  service.go file to over 97%.

* Additionally addressed some flaky tests related to the `ReplicaSet`and
  `PersisentVolumeClaim` analyzers.

Partially addresses: #889

Signed-off-by: VaibhavMalik4187 <vaibhavmalik2018@gmail.com>
Co-authored-by: Aris Boutselis <arisboutselis08@gmail.com>
  • Loading branch information
VaibhavMalik4187 and arbreezy committed Mar 14, 2024
1 parent 28e19a9 commit 531f0bc
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 86 deletions.
7 changes: 7 additions & 0 deletions pkg/analyzer/pvc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package analyzer

import (
"context"
"sort"
"testing"

"github.com/k8sgpt-ai/k8sgpt/pkg/common"
Expand Down Expand Up @@ -205,6 +206,12 @@ func TestPersistentVolumeClaimAnalyzer(t *testing.T) {
if tt.expectations == nil {
require.Equal(t, 0, len(results))
} else {
sort.Slice(results, func(i, j int) bool {
return results[i].Name < results[j].Name
})

require.Equal(t, len(tt.expectations), len(results))

for i, expectation := range tt.expectations {
require.Equal(t, expectation, results[i].Name)
for _, failure := range results[i].Error {
Expand Down
2 changes: 2 additions & 0 deletions pkg/analyzer/rs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ func TestReplicaSetAnalyzer(t *testing.T) {
},
}

require.Equal(t, len(expectations), len(results))

for i, expectation := range expectations {
require.Equal(t, expectation.name, results[i].Name)
for j, failure := range results[i].Error {
Expand Down
16 changes: 9 additions & 7 deletions pkg/analyzer/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,17 @@ func (ServiceAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
count++
pods = append(pods, addresses.TargetRef.Kind+"/"+addresses.TargetRef.Name)
}
}
}

doc := apiDoc.GetApiDocV2("subsets.notReadyAddresses")
if count > 0 {
doc := apiDoc.GetApiDocV2("subsets.notReadyAddresses")

failures = append(failures, common.Failure{
Text: fmt.Sprintf("Service has not ready endpoints, pods: %s, expected %d", pods, count),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{},
})
}
failures = append(failures, common.Failure{
Text: fmt.Sprintf("Service has not ready endpoints, pods: %s, expected %d", pods, count),
KubernetesDoc: doc,
Sensitive: []common.Sensitive{},
})
}
}

Expand Down
210 changes: 131 additions & 79 deletions pkg/analyzer/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,108 +15,160 @@ package analyzer

import (
"context"
"sort"
"testing"

"github.com/k8sgpt-ai/k8sgpt/pkg/common"
"github.com/k8sgpt-ai/k8sgpt/pkg/kubernetes"
"github.com/magiconair/properties/assert"
"github.com/stretchr/testify/require"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/tools/leaderelection/resourcelock"
)

func TestServiceAnalyzer(t *testing.T) {

clientset := fake.NewSimpleClientset(&v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
Name: "example",
Namespace: "default",
Annotations: map[string]string{},
},
},
&v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "example",
Namespace: "default",
Annotations: map[string]string{},
},
Spec: v1.ServiceSpec{
Selector: map[string]string{
"app": "example",
},
}})

config := common.Analyzer{
Client: &kubernetes.Client{
Client: clientset,
Client: fake.NewSimpleClientset(
&v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
Name: "Endpoint1",
Namespace: "test",
},
// Endpoint with non-zero subsets.
Subsets: []v1.EndpointSubset{
{
// These not ready end points will contribute to failures.
NotReadyAddresses: []v1.EndpointAddress{
{
TargetRef: &v1.ObjectReference{
Kind: "test-reference",
Name: "reference1",
},
},
{
TargetRef: &v1.ObjectReference{
Kind: "test-reference",
Name: "reference2",
},
},
},
},
{
// These not ready end points will contribute to failures.
NotReadyAddresses: []v1.EndpointAddress{
{
TargetRef: &v1.ObjectReference{
Kind: "test-reference",
Name: "reference3",
},
},
},
},
},
},
&v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
Name: "Endpoint2",
Namespace: "test",
Annotations: map[string]string{
// Leader election record annotation key defined.
resourcelock.LeaderElectionRecordAnnotationKey: "this is okay",
},
},
// Endpoint with zero subsets.
},
&v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
// This won't contribute to any failures.
Name: "non-existent-service",
Namespace: "test",
Annotations: map[string]string{},
},
// Endpoint with zero subsets.
},
&v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
Name: "Service1",
Namespace: "test",
Annotations: map[string]string{},
},
// Endpoint with zero subsets.
},
&v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "Service1",
Namespace: "test",
},
Spec: v1.ServiceSpec{
Selector: map[string]string{
"app1": "test-app1",
"app2": "test-app2",
},
},
},
&v1.Service{
ObjectMeta: metav1.ObjectMeta{
// This service won't be discovered.
Name: "Service2",
Namespace: "default",
},
Spec: v1.ServiceSpec{
Selector: map[string]string{
"app1": "test-app1",
"app2": "test-app2",
},
},
},
&v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "Service3",
Namespace: "test",
},
Spec: v1.ServiceSpec{
// No Spec Selector
},
},
),
},
Context: context.Background(),
Namespace: "default",
Namespace: "test",
}

serviceAnalyzer := ServiceAnalyzer{}
analysisResults, err := serviceAnalyzer.Analyze(config)
if err != nil {
t.Error(err)
}
assert.Equal(t, len(analysisResults), 1)
}
sAnalyzer := ServiceAnalyzer{}
results, err := sAnalyzer.Analyze(config)
require.NoError(t, err)

func TestServiceAnalyzerNamespaceFiltering(t *testing.T) {
sort.Slice(results, func(i, j int) bool {
return results[i].Name < results[j].Name
})

clientset := fake.NewSimpleClientset(
&v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
Name: "example",
Namespace: "default",
Annotations: map[string]string{},
expectations := []struct {
name string
failuresText []string
}{
{
name: "test/Endpoint1",
failuresText: []string{
"Service has not ready endpoints, pods",
},
},
&v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "example",
Namespace: "default",
Annotations: map[string]string{},
},
Spec: v1.ServiceSpec{
Selector: map[string]string{
"app": "example",
},
},
},
&v1.Endpoints{
ObjectMeta: metav1.ObjectMeta{
Name: "example",
Namespace: "other-namespace",
Annotations: map[string]string{},
},
},
&v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "example",
Namespace: "other-namespace",
Annotations: map[string]string{},
},
Spec: v1.ServiceSpec{
Selector: map[string]string{
"app": "example",
},
{
name: "test/Service1",
failuresText: []string{
"Service has no endpoints, expected label",
"Service has no endpoints, expected label",
},
},
)

config := common.Analyzer{
Client: &kubernetes.Client{
Client: clientset,
},
Context: context.Background(),
Namespace: "default",
}

serviceAnalyzer := ServiceAnalyzer{}
analysisResults, err := serviceAnalyzer.Analyze(config)
if err != nil {
t.Error(err)
require.Equal(t, len(expectations), len(results))

for i, result := range results {
require.Equal(t, expectations[i].name, result.Name)
for j, failure := range result.Error {
require.Contains(t, failure.Text, expectations[i].failuresText[j])
}
}
assert.Equal(t, len(analysisResults), 1)
}

0 comments on commit 531f0bc

Please sign in to comment.