Merge pull request #743 from chewong/pod-status-nil-pointer
Add unit tests for #584
This commit is contained in:
@@ -179,7 +179,7 @@ type PodLifecycleHandler interface {
|
||||
```
|
||||
|
||||
There is also an optional interface `PodNotifier` which enables the provider to
|
||||
asyncronously notify the virtual-kubelet about pod status changes. If this
|
||||
asynchronously notify the virtual-kubelet about pod status changes. If this
|
||||
interface is not implemented, virtual-kubelet will periodically check the status
|
||||
of all pods.
|
||||
|
||||
|
||||
103
node/pod_test.go
103
node/pod_test.go
@@ -225,6 +225,109 @@ func TestPodDelete(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchPodStatusFromProvider(t *testing.T) {
|
||||
startedAt := metav1.NewTime(time.Now())
|
||||
finishedAt := metav1.NewTime(startedAt.Add(time.Second * 10))
|
||||
containerStateRunning := &corev1.ContainerStateRunning{StartedAt: startedAt}
|
||||
containerStateTerminated := &corev1.ContainerStateTerminated{StartedAt: startedAt, FinishedAt: finishedAt}
|
||||
containerStateWaiting := &corev1.ContainerStateWaiting{}
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
running *corev1.ContainerStateRunning
|
||||
terminated *corev1.ContainerStateTerminated
|
||||
waiting *corev1.ContainerStateWaiting
|
||||
expectedStartedAt metav1.Time
|
||||
expectedFinishedAt metav1.Time
|
||||
}{
|
||||
{desc: "container in running state", running: containerStateRunning, expectedStartedAt: startedAt},
|
||||
{desc: "container in terminated state", terminated: containerStateTerminated, expectedStartedAt: startedAt, expectedFinishedAt: finishedAt},
|
||||
{desc: "container in waiting state", waiting: containerStateWaiting},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
c := newTestController()
|
||||
pod := &corev1.Pod{}
|
||||
pod.ObjectMeta.Namespace = "default"
|
||||
pod.ObjectMeta.Name = "nginx"
|
||||
pod.Status.Phase = corev1.PodRunning
|
||||
containerStatus := corev1.ContainerStatus{}
|
||||
if tc.running != nil {
|
||||
containerStatus.State.Running = tc.running
|
||||
} else if tc.terminated != nil {
|
||||
containerStatus.State.Terminated = tc.terminated
|
||||
} else if tc.waiting != nil {
|
||||
containerStatus.State.Waiting = tc.waiting
|
||||
}
|
||||
pod.Status.ContainerStatuses = []corev1.ContainerStatus{containerStatus}
|
||||
|
||||
pc := c.client.CoreV1().Pods("default")
|
||||
p, err := pc.Create(pod)
|
||||
assert.NilError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
updatedPod, err := c.fetchPodStatusFromProvider(ctx, nil, p)
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Equal(t, updatedPod.Status.Phase, corev1.PodFailed)
|
||||
assert.Assert(t, is.Len(updatedPod.Status.ContainerStatuses, 1))
|
||||
assert.Assert(t, updatedPod.Status.ContainerStatuses[0].State.Running == nil)
|
||||
|
||||
// Test cases for running and terminated container state
|
||||
if tc.running != nil || tc.terminated != nil {
|
||||
// Ensure that the container is in terminated state and other states are nil
|
||||
assert.Assert(t, updatedPod.Status.ContainerStatuses[0].State.Terminated != nil)
|
||||
assert.Assert(t, updatedPod.Status.ContainerStatuses[0].State.Waiting == nil)
|
||||
|
||||
terminated := updatedPod.Status.ContainerStatuses[0].State.Terminated
|
||||
assert.Equal(t, terminated.StartedAt, tc.expectedStartedAt)
|
||||
assert.Assert(t, terminated.StartedAt.Before(&terminated.FinishedAt))
|
||||
if tc.terminated != nil {
|
||||
assert.Equal(t, terminated.FinishedAt, tc.expectedFinishedAt)
|
||||
}
|
||||
} else {
|
||||
// Test case for waiting container state
|
||||
assert.Assert(t, updatedPod.Status.ContainerStatuses[0].State.Terminated == nil)
|
||||
assert.Assert(t, updatedPod.Status.ContainerStatuses[0].State.Waiting != nil)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchPodStatusFromProviderWithExpiredPod(t *testing.T) {
|
||||
c := newTestController()
|
||||
pod := &corev1.Pod{}
|
||||
pod.ObjectMeta.Namespace = "default"
|
||||
pod.ObjectMeta.Name = "nginx"
|
||||
pod.Status.Phase = corev1.PodRunning
|
||||
containerStatus := corev1.ContainerStatus{}
|
||||
|
||||
// We should terminate containters in a pod that has not provided pod status update for more than a minute
|
||||
startedAt := time.Now().Add(-(time.Minute + time.Second))
|
||||
containerStatus.State.Running = &corev1.ContainerStateRunning{StartedAt: metav1.NewTime(startedAt)}
|
||||
pod.ObjectMeta.CreationTimestamp.Time = startedAt
|
||||
pod.Status.ContainerStatuses = []corev1.ContainerStatus{containerStatus}
|
||||
|
||||
pc := c.client.CoreV1().Pods("default")
|
||||
p, err := pc.Create(pod)
|
||||
assert.NilError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
updatedPod, err := c.fetchPodStatusFromProvider(ctx, nil, p)
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Equal(t, updatedPod.Status.Phase, corev1.PodFailed)
|
||||
assert.Assert(t, is.Len(updatedPod.Status.ContainerStatuses, 1))
|
||||
assert.Assert(t, updatedPod.Status.ContainerStatuses[0].State.Running == nil)
|
||||
assert.Assert(t, updatedPod.Status.ContainerStatuses[0].State.Terminated != nil)
|
||||
assert.Assert(t, updatedPod.Status.ContainerStatuses[0].State.Waiting == nil)
|
||||
|
||||
terminated := updatedPod.Status.ContainerStatuses[0].State.Terminated
|
||||
assert.Equal(t, terminated.StartedAt, metav1.NewTime(startedAt))
|
||||
assert.Assert(t, terminated.StartedAt.Before(&terminated.FinishedAt))
|
||||
}
|
||||
|
||||
func newPodSpec() corev1.PodSpec {
|
||||
return corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
|
||||
@@ -116,7 +116,7 @@ func (pc *PodController) processPodStatusUpdate(ctx context.Context, workerID st
|
||||
return handleQueueItem(ctx, q, pc.podStatusHandler)
|
||||
}
|
||||
|
||||
// providerSyncLoop syncronizes pod states from the provider back to kubernetes
|
||||
// providerSyncLoop synchronizes pod states from the provider back to kubernetes
|
||||
// Deprecated: This is only used when the provider does not support async updates
|
||||
// Providers should implement async update support, even if it just means copying
|
||||
// something like this in.
|
||||
|
||||
Reference in New Issue
Block a user