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

test: added unit test for cleanupDanglingPods #516

Merged
merged 10 commits into from
Apr 6, 2023
105 changes: 105 additions & 0 deletions pkg/provider/podsTracker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package provider

import (
"context"
"fmt"
"strings"
"testing"
"time"
Expand All @@ -14,6 +15,7 @@ import (
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
)

func TestUpdatePodStatus(t *testing.T) {
Expand Down Expand Up @@ -158,3 +160,106 @@ func TestProcessPodUpdates(t *testing.T) {
})
}
}

func TestCleanupDanglingPods(t *testing.T) {
podName1 := "pod-" + uuid.New().String()
podName2 := "pod-" + uuid.New().String()
danglingPodName := "pod-" + uuid.New().String()
podNamespace := "ns-" + uuid.New().String()

podsNames := []string{podName1, podName2}
k8sPods := testsutil.CreatePodsList(podsNames, podNamespace)

activePods := testsutil.CreatePodsList([]string{danglingPodName}, podNamespace)
activePods = append(activePods, k8sPods[0], k8sPods[1])

cg1 := testsutil.CreateContainerGroupObj(podName1, podNamespace, "Succeeded",
testsutil.CreateACIContainersListObj(runningState, "Initializing",
testsutil.CgCreationTime.Add(time.Second*2),
testsutil.CgCreationTime.Add(time.Second*3),
false, false, false), "Succeeded")

cg2 := testsutil.CreateContainerGroupObj(podName2, podNamespace, "Succeeded",
testsutil.CreateACIContainersListObj(runningState, "Initializing",
testsutil.CgCreationTime.Add(time.Second*2),
testsutil.CgCreationTime.Add(time.Second*3),
false, false, false), "Succeeded")

cg3 := testsutil.CreateContainerGroupObj(danglingPodName, podNamespace, "Succeeded",
testsutil.CreateACIContainersListObj(runningState, "Initializing",
testsutil.CgCreationTime.Add(time.Second*2),
testsutil.CgCreationTime.Add(time.Second*3),
false, false, false), "Succeeded")

mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()

aciMocks := createNewACIMock()

aciMocks.MockGetContainerGroupList = func(ctx context.Context, resourceGroup string) ([]*azaciv2.ContainerGroup, error) {
var result []*azaciv2.ContainerGroup
result = append(result, cg1, cg2, cg3)
return result, nil
}

aciMocks.MockGetContainerGroup = func(ctx context.Context, resourceGroup, containerGroupName string) (*azaciv2.ContainerGroup, error) {
switch containerGroupName {
case podName1:
return cg1, nil
case podName2:
return cg2, nil
case danglingPodName:
return cg3, nil
default:
return nil, nil
}
}

aciMocks.MockDeleteContainerGroup = func(ctx context.Context, resourceGroup, cgName string) error {
updatedActivePods := make([]*v1.Pod, 0)

for i := range activePods {
podCgName := fmt.Sprintf("%s-%s", activePods[i].Namespace, activePods[i].Name)
if podCgName != cgName {
updatedActivePods = append(updatedActivePods, activePods[i])
}
}

activePods = updatedActivePods
return nil
}

activePodsLister := NewMockPodLister(mockCtrl)
k8sPodsLister := NewMockPodLister(mockCtrl)
mockPodsNamespaceLister := NewMockPodNamespaceLister(mockCtrl)

aciProvider, err := createTestProvider(aciMocks, NewMockConfigMapLister(mockCtrl),
NewMockSecretLister(mockCtrl), activePodsLister)
if err != nil {
t.Fatal("failed to create the test provider", err)
}

podsTracker := &PodsTracker{
pods: k8sPodsLister,
updateCb: func(updatedPod *v1.Pod) {
},
handler: aciProvider,
}

k8sPodsLister.EXPECT().List(gomock.Any()).Return(k8sPods, nil).AnyTimes()

activePodsLister.EXPECT().Pods(podNamespace).Return(mockPodsNamespaceLister).AnyTimes()
mockPodsNamespaceLister.EXPECT().Get(danglingPodName).Return(activePods[0], nil)
mockPodsNamespaceLister.EXPECT().Get(podName1).Return(activePods[1], nil)
mockPodsNamespaceLister.EXPECT().Get(podName2).Return(activePods[2], nil)

aciProvider.tracker = podsTracker
podsTracker.cleanupDanglingPods(context.Background())

assert.Equal(t, len(activePods), 2, "The dangling pod should be deleted from activePods")
for i := range activePods {
if !equality.Semantic.DeepEqual(activePods[i], k8sPods[i]) {
t.Errorf("activePods and k8sPods should be in sync. Expected %#v, got %#v", k8sPods[i], activePods[i])
}
}
}
102 changes: 51 additions & 51 deletions pkg/tests/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
azaciv2 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerinstance/armcontainerinstance/v2"
"github.com/google/uuid"
"github.com/virtual-kubelet/azure-aci/pkg/util"
v12 "k8s.io/api/core/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
Expand Down Expand Up @@ -183,54 +183,54 @@ func CreateCGProbeObj(hasHTTPGet, hasExec bool) *azaciv2.ContainerProbe {
}
}

func GetPodConditions(creationTime, readyConditionTime v1.Time, readyConditionStatus v12.ConditionStatus) []v12.PodCondition {
return []v12.PodCondition{
func GetPodConditions(creationTime, readyConditionTime v1.Time, readyConditionStatus corev1.ConditionStatus) []corev1.PodCondition {
return []corev1.PodCondition{
{
Type: v12.PodReady,
Type: corev1.PodReady,
Status: readyConditionStatus,
LastTransitionTime: readyConditionTime,
}, {
Type: v12.PodInitialized,
Status: v12.ConditionTrue,
Type: corev1.PodInitialized,
Status: corev1.ConditionTrue,
LastTransitionTime: creationTime,
}, {
Type: v12.PodScheduled,
Status: v12.ConditionTrue,
Type: corev1.PodScheduled,
Status: corev1.ConditionTrue,
LastTransitionTime: creationTime,
},
}
}

func CreatePodObj(podName, podNamespace string) *v12.Pod {
return &v12.Pod{
func CreatePodObj(podName, podNamespace string) *corev1.Pod {
return &corev1.Pod{
ObjectMeta: v1.ObjectMeta{
Name: podName,
Namespace: podNamespace,
},
Spec: v12.PodSpec{
Containers: []v12.Container{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "nginx",
Ports: []v12.ContainerPort{
Ports: []corev1.ContainerPort{
{
Name: "http",
ContainerPort: 8080,
},
},
Resources: v12.ResourceRequirements{
Requests: v12.ResourceList{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
"cpu": resource.MustParse("0.99"),
"memory": resource.MustParse("1.5G"),
},
Limits: v12.ResourceList{
Limits: corev1.ResourceList{
"cpu": resource.MustParse("3999m"),
"memory": resource.MustParse("8010M"),
},
},

LivenessProbe: &v12.Probe{
ProbeHandler: v12.ProbeHandler{
HTTPGet: &v12.HTTPGetAction{
LivenessProbe: &corev1.Probe{
ProbeHandler: corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{
Port: intstr.FromString("http"),
Path: "/",
},
Expand All @@ -241,9 +241,9 @@ func CreatePodObj(podName, podNamespace string) *v12.Pod {
SuccessThreshold: 3,
FailureThreshold: 5,
},
ReadinessProbe: &v12.Probe{
ProbeHandler: v12.ProbeHandler{
HTTPGet: &v12.HTTPGetAction{
ReadinessProbe: &corev1.Probe{
ProbeHandler: corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{
Port: intstr.FromInt(8080),
Path: "/",
},
Expand All @@ -260,19 +260,19 @@ func CreatePodObj(podName, podNamespace string) *v12.Pod {
}
}

func CreatePodProbeObj(hasHTTPGet, hasExec bool) *v12.Probe {
var httpGet *v12.HTTPGetAction
var exec *v12.ExecAction
func CreatePodProbeObj(hasHTTPGet, hasExec bool) *corev1.Probe {
var httpGet *corev1.HTTPGetAction
var exec *corev1.ExecAction

if hasHTTPGet {
httpGet = &v12.HTTPGetAction{
httpGet = &corev1.HTTPGetAction{
Port: intstr.FromString("http"),
Path: "/",
Scheme: "http",
}
}
if hasExec {
exec = &v12.ExecAction{
exec = &corev1.ExecAction{
Command: []string{
"/bin/sh",
"-c",
Expand All @@ -281,54 +281,54 @@ func CreatePodProbeObj(hasHTTPGet, hasExec bool) *v12.Probe {
}
}

return &v12.Probe{
ProbeHandler: v12.ProbeHandler{
return &corev1.Probe{
ProbeHandler: corev1.ProbeHandler{
HTTPGet: httpGet,
Exec: exec,
},
}
}

func CreateContainerPortObj(portName string, containerPort int32) []v12.ContainerPort {
return []v12.ContainerPort{
func CreateContainerPortObj(portName string, containerPort int32) []corev1.ContainerPort {
return []corev1.ContainerPort{
{
Name: portName,
ContainerPort: containerPort,
},
}
}

func CreatePodVolumeObj(azureFileVolumeName string, fakeSecretName string, projectedVolumeName string) []v12.Volume {
func CreatePodVolumeObj(azureFileVolumeName string, fakeSecretName string, projectedVolumeName string) []corev1.Volume {
emptyVolumeName := "emptyVolumeName"
fakeShareName1 := "aksshare1"

return []v12.Volume{
return []corev1.Volume{
{
Name: emptyVolumeName,
VolumeSource: v12.VolumeSource{
EmptyDir: &v12.EmptyDirVolumeSource{},
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
},
{
Name: azureFileVolumeName,
VolumeSource: v12.VolumeSource{
AzureFile: &v12.AzureFileVolumeSource{
VolumeSource: corev1.VolumeSource{
AzureFile: &corev1.AzureFileVolumeSource{
ShareName: fakeShareName1,
SecretName: fakeSecretName,
ReadOnly: true,
},
},
}, {
Name: projectedVolumeName,
VolumeSource: v12.VolumeSource{
Projected: &v12.ProjectedVolumeSource{
Sources: []v12.VolumeProjection{
VolumeSource: corev1.VolumeSource{
Projected: &corev1.ProjectedVolumeSource{
Sources: []corev1.VolumeProjection{
{
ConfigMap: &v12.ConfigMapProjection{
LocalObjectReference: v12.LocalObjectReference{
ConfigMap: &corev1.ConfigMapProjection{
LocalObjectReference: corev1.LocalObjectReference{
Name: "kube-root-ca.crt",
},
Items: []v12.KeyToPath{
Items: []corev1.KeyToPath{
{
Key: "ca.crt",
Path: "ca.crt",
Expand All @@ -343,22 +343,22 @@ func CreatePodVolumeObj(azureFileVolumeName string, fakeSecretName string, proje
}
}

func CreatePodsList(podNames []string, podNameSpace string) []*v12.Pod {
result := make([]*v12.Pod, 0, len(podNames))
func CreatePodsList(podNames []string, podNameSpace string) []*corev1.Pod {
result := make([]*corev1.Pod, 0, len(podNames))
for _, podName := range podNames {
pod := &v12.Pod{
pod := &corev1.Pod{
ObjectMeta: v1.ObjectMeta{
Name: podName,
Namespace: podNameSpace,
CreationTimestamp: v1.NewTime(time.Now()),
UID: types.UID(uuid.New().String()),
},
Status: v12.PodStatus{
Phase: v12.PodRunning,
ContainerStatuses: []v12.ContainerStatus {
Status: corev1.PodStatus{
Phase: corev1.PodRunning,
ContainerStatuses: []corev1.ContainerStatus{
{
State: v12.ContainerState {
Running: &v12.ContainerStateRunning{
State: corev1.ContainerState{
Running: &corev1.ContainerStateRunning{
StartedAt: v1.NewTime(time.Now()),
},
},
Expand Down