Skip to content

Commit

Permalink
Deflake e2e test for startupProbe
Browse files Browse the repository at this point in the history
  • Loading branch information
matthyx authored and 0robustus1 committed Mar 24, 2021
1 parent d93339e commit 5ed7095
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 12 deletions.
24 changes: 12 additions & 12 deletions test/e2e/common/container_probe.go
Expand Up @@ -358,10 +358,9 @@ var _ = framework.KubeDescribe("Probing container", func() {
Description: A Pod is created with startup and readiness probes. The Container is started by creating /tmp/startup after 45 seconds, delaying the ready state by this amount of time. This is similar to the "Pod readiness probe, with initial delay" test.
*/
ginkgo.It("should be ready immediately after startupProbe succeeds", func() {
sleepBeforeStarted := time.Duration(45)
cmd := []string{"/bin/sh", "-c", fmt.Sprintf("sleep %d; echo ok >/tmp/startup; sleep 600", sleepBeforeStarted)}
cmd := []string{"/bin/sh", "-c", "echo ok >/tmp/health; sleep 10; echo ok >/tmp/startup; sleep 600"}
readinessProbe := &v1.Probe{
Handler: execHandler([]string{"/bin/true"}),
Handler: execHandler([]string{"/bin/cat", "/tmp/health"}),
InitialDelaySeconds: 0,
PeriodSeconds: 60,
}
Expand All @@ -375,7 +374,15 @@ var _ = framework.KubeDescribe("Probing container", func() {
p, err := podClient.Get(context.TODO(), p.Name, metav1.GetOptions{})
framework.ExpectNoError(err)

e2epod.WaitTimeoutForPodReadyInNamespace(f.ClientSet, p.Name, f.Namespace.Name, framework.PodStartTimeout)
err = e2epod.WaitForPodContainerStarted(f.ClientSet, f.Namespace.Name, p.Name, 0, framework.PodStartTimeout)
framework.ExpectNoError(err)
startedTime := time.Now()

// We assume the pod became ready when the container became ready. This
// is true for a single container pod.
err = e2epod.WaitTimeoutForPodReadyInNamespace(f.ClientSet, p.Name, f.Namespace.Name, framework.PodStartTimeout)
framework.ExpectNoError(err)
readyTime := time.Now()

p, err = podClient.Get(context.TODO(), p.Name, metav1.GetOptions{})
framework.ExpectNoError(err)
Expand All @@ -384,14 +391,7 @@ var _ = framework.KubeDescribe("Probing container", func() {
framework.ExpectNoError(err)
framework.ExpectEqual(isReady, true, "pod should be ready")

// We assume the pod became ready when the container became ready. This
// is true for a single container pod.
readyTime, err := GetTransitionTimeForReadyCondition(p)
framework.ExpectNoError(err)
startedTime, err := GetContainerStartedTime(p, "busybox")
framework.ExpectNoError(err)

readyIn := readyTime.Sub(startedTime) - sleepBeforeStarted*time.Second
readyIn := readyTime.Sub(startedTime)
framework.Logf("Container started at %v, pod became ready at %v, %v after startupProbe succeeded", startedTime, readyTime, readyIn)
if readyIn < 0 {
framework.Failf("Pod became ready before startupProbe succeeded")
Expand Down
37 changes: 37 additions & 0 deletions test/e2e/framework/pod/resource.go
Expand Up @@ -298,6 +298,43 @@ func podsRunning(c clientset.Interface, pods *v1.PodList) []error {
return e
}

func podContainerFailed(c clientset.Interface, namespace, podName string, containerIndex int, reason string) wait.ConditionFunc {
return func() (bool, error) {
pod, err := c.CoreV1().Pods(namespace).Get(context.TODO(), podName, metav1.GetOptions{})
if err != nil {
return false, err
}
switch pod.Status.Phase {
case v1.PodPending:
if len(pod.Status.ContainerStatuses) == 0 {
return false, nil
}
containerStatus := pod.Status.ContainerStatuses[containerIndex]
if containerStatus.State.Waiting != nil && containerStatus.State.Waiting.Reason == reason {
return true, nil
}
return false, nil
case v1.PodFailed, v1.PodRunning, v1.PodSucceeded:
return false, fmt.Errorf("pod was expected to be pending, but it is in the state: %s", pod.Status.Phase)
}
return false, nil
}
}

func podContainerStarted(c clientset.Interface, namespace, podName string, containerIndex int) wait.ConditionFunc {
return func() (bool, error) {
pod, err := c.CoreV1().Pods(namespace).Get(context.TODO(), podName, metav1.GetOptions{})
if err != nil {
return false, err
}
if containerIndex > len(pod.Status.ContainerStatuses)-1 {
return false, nil
}
containerStatus := pod.Status.ContainerStatuses[containerIndex]
return *containerStatus.Started, nil
}
}

// LogPodStates logs basic info of provided pods for debugging.
func LogPodStates(pods []v1.Pod) {
// Find maximum widths for pod, node, and phase strings for column printing.
Expand Down
12 changes: 12 additions & 0 deletions test/e2e/framework/pod/wait.go
Expand Up @@ -537,3 +537,15 @@ func WaitForNRestartablePods(ps *testutils.PodStore, expect int, timeout time.Du
}
return podNames, nil
}

// WaitForPodContainerToFail waits for the given Pod container to fail with the given reason, specifically due to
// invalid container configuration. In this case, the container will remain in a waiting state with a specific
// reason set, which should match the given reason.
func WaitForPodContainerToFail(c clientset.Interface, namespace, podName string, containerIndex int, reason string, timeout time.Duration) error {
return wait.PollImmediate(poll, timeout, podContainerFailed(c, namespace, podName, containerIndex, reason))
}

// WaitForPodContainerStarted waits for the given Pod container to start, after a successful run of the startupProbe.
func WaitForPodContainerStarted(c clientset.Interface, namespace, podName string, containerIndex int, timeout time.Duration) error {
return wait.PollImmediate(poll, timeout, podContainerStarted(c, namespace, podName, containerIndex))
}

0 comments on commit 5ed7095

Please sign in to comment.