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

🏃 Add unit tests for health check function #2472

Merged
Merged
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
188 changes: 188 additions & 0 deletions controlplane/kubeadm/internal/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ package internal

import (
"context"
"errors"
"fmt"
"strings"
"testing"

corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -242,3 +244,189 @@ func (f *fakeClient) List(_ context.Context, list runtime.Object, _ ...client.Li
}
return nil
}

func TestManagementCluster_healthCheck_NoError(t *testing.T) {
tests := []struct {
name string
machineList *clusterv1.MachineList
check healthCheck
clusterKey types.NamespacedName
controlPlaneName string
}{
{
name: "simple",
machineList: &clusterv1.MachineList{
Items: []clusterv1.Machine{
controlPlaneMachine("one"),
controlPlaneMachine("two"),
controlPlaneMachine("three"),
},
},
check: func(ctx context.Context) (healthCheckResult, error) {
return healthCheckResult{
"one": nil,
"two": nil,
"three": nil,
}, nil
},
clusterKey: types.NamespacedName{Namespace: "default", Name: "cluster-name"},
controlPlaneName: "control-plane-name",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
m := &ManagementCluster{
Client: &fakeClient{list: tt.machineList},
}
if err := m.healthCheck(ctx, tt.check, tt.clusterKey, tt.controlPlaneName); err != nil {
t.Fatal("did not expect an error?")
}
})
}
}

func TestManagementCluster_healthCheck_Errors(t *testing.T) {
tests := []struct {
name string
machineList *clusterv1.MachineList
check healthCheck
clusterKey types.NamespacedName
controlPlaneName string
// expected errors will ensure the error contains this list of strings.
// If not supplied, no check on the error's value will occur.
expectedErrors []string
}{
{
name: "machine's node was not checked for health",
machineList: &clusterv1.MachineList{
Items: []clusterv1.Machine{
controlPlaneMachine("one"),
controlPlaneMachine("two"),
controlPlaneMachine("three"),
},
},
check: func(ctx context.Context) (healthCheckResult, error) {
return healthCheckResult{
"one": nil,
}, nil
},
},
{
name: "health check returns an error not related to the nodes health",
machineList: &clusterv1.MachineList{
Items: []clusterv1.Machine{
controlPlaneMachine("one"),
controlPlaneMachine("two"),
controlPlaneMachine("three"),
},
},
check: func(ctx context.Context) (healthCheckResult, error) {
return healthCheckResult{
"one": nil,
"two": errors.New("two"),
"three": errors.New("three"),
}, errors.New("meta")
},
expectedErrors: []string{"two", "three", "meta"},
},
{
name: "two nodes error on the check but no overall error occurred",
machineList: &clusterv1.MachineList{
Items: []clusterv1.Machine{
controlPlaneMachine("one"),
controlPlaneMachine("two"),
controlPlaneMachine("three"),
},
},
check: func(ctx context.Context) (healthCheckResult, error) {
return healthCheckResult{
"one": nil,
"two": errors.New("two"),
"three": errors.New("three"),
}, nil
},
expectedErrors: []string{"two", "three"},
},
{
name: "more nodes than machines were checked (out of band control plane nodes)",
machineList: &clusterv1.MachineList{
Items: []clusterv1.Machine{
controlPlaneMachine("one"),
},
},
check: func(ctx context.Context) (healthCheckResult, error) {
return healthCheckResult{
"one": nil,
"two": nil,
"three": nil,
}, nil
},
},
{
name: "a machine that has a nil node reference",
machineList: &clusterv1.MachineList{
Items: []clusterv1.Machine{
controlPlaneMachine("one"),
controlPlaneMachine("two"),
nilNodeRef(controlPlaneMachine("three")),
},
},
check: func(ctx context.Context) (healthCheckResult, error) {
return healthCheckResult{
"one": nil,
"two": nil,
"three": nil,
}, nil
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
clusterKey := types.NamespacedName{Namespace: "default", Name: "cluster-name"}
controlPlaneName := "control-plane-name"

m := &ManagementCluster{
Client: &fakeClient{list: tt.machineList},
}
err := m.healthCheck(ctx, tt.check, clusterKey, controlPlaneName)
if err == nil {
t.Fatal("Expected an error")
}
for _, expectedError := range tt.expectedErrors {
if !strings.Contains(err.Error(), expectedError) {
t.Fatalf("Expected %q to contain %q", err.Error(), expectedError)
}
}
})
}
}

func controlPlaneMachine(name string) clusterv1.Machine {
t := true
return clusterv1.Machine{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: name,
Labels: ControlPlaneLabelsForCluster("cluster-name"),
OwnerReferences: []metav1.OwnerReference{
{
Kind: "KubeadmControlPlane",
Name: "control-plane-name",
Controller: &t,
},
},
},
Status: clusterv1.MachineStatus{
NodeRef: &corev1.ObjectReference{
Name: name,
},
},
}
}

func nilNodeRef(machine clusterv1.Machine) clusterv1.Machine {
machine.Status.NodeRef = nil
return machine
}