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
|
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
|
interface is not implemented, virtual-kubelet will periodically check the status
|
||||||
of all pods.
|
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 {
|
func newPodSpec() corev1.PodSpec {
|
||||||
return corev1.PodSpec{
|
return corev1.PodSpec{
|
||||||
Containers: []corev1.Container{
|
Containers: []corev1.Container{
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ func (pc *PodController) processPodStatusUpdate(ctx context.Context, workerID st
|
|||||||
return handleQueueItem(ctx, q, pc.podStatusHandler)
|
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
|
// 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
|
// Providers should implement async update support, even if it just means copying
|
||||||
// something like this in.
|
// something like this in.
|
||||||
|
|||||||
Reference in New Issue
Block a user