...

Source file src/k8s.io/kubernetes/test/e2e/framework/pod/wait_test.go

Documentation: k8s.io/kubernetes/test/e2e/framework/pod

     1  /*
     2  Copyright 2022 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package pod_test
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"regexp"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/onsi/ginkgo/v2"
    27  	"github.com/onsi/ginkgo/v2/reporters"
    28  	"github.com/onsi/gomega"
    29  
    30  	v1 "k8s.io/api/core/v1"
    31  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    32  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    33  	"k8s.io/client-go/kubernetes/fake"
    34  	"k8s.io/kubernetes/test/e2e/framework"
    35  	"k8s.io/kubernetes/test/e2e/framework/internal/output"
    36  	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
    37  	_ "k8s.io/kubernetes/test/utils/format" // activate YAML object dumps
    38  )
    39  
    40  // The line number of the following code is checked in TestFailureOutput below.
    41  // Be careful when moving it around or changing the import statements above.
    42  // Here are some intentionally blank lines that can be removed to compensate
    43  // for future additional import statements.
    44  //
    45  //
    46  //
    47  //
    48  //
    49  //
    50  // This must be line #50.
    51  
    52  var _ = ginkgo.Describe("pod", func() {
    53  	ginkgo.It("not found, must exist", func(ctx context.Context) {
    54  		gomega.Eventually(ctx, framework.HandleRetry(getNoSuchPod)).WithTimeout(timeout).Should(e2epod.BeInPhase(v1.PodRunning))
    55  	})
    56  
    57  	ginkgo.It("not found, retry", func(ctx context.Context) {
    58  		framework.ExpectNoError(e2epod.WaitTimeoutForPodRunningInNamespace(ctx, clientSet, "no-such-pod", "default", timeout))
    59  	})
    60  
    61  	ginkgo.It("not found, retry with wrappers", func(ctx context.Context) {
    62  		gomega.Eventually(ctx, framework.RetryNotFound(framework.HandleRetry(getNoSuchPod))).WithTimeout(timeout).Should(e2epod.BeInPhase(v1.PodRunning))
    63  	})
    64  
    65  	ginkgo.It("not found, retry with inverted wrappers", func(ctx context.Context) {
    66  		gomega.Eventually(ctx, framework.HandleRetry(framework.RetryNotFound(getNoSuchPod))).WithTimeout(timeout).Should(e2epod.BeInPhase(v1.PodRunning))
    67  	})
    68  
    69  	ginkgo.It("not running", func(ctx context.Context) {
    70  		ginkgo.By(fmt.Sprintf("waiting for pod %s to run", podName))
    71  		framework.ExpectNoError(e2epod.WaitTimeoutForPodRunningInNamespace(ctx, clientSet, podName, podNamespace, timeout))
    72  	})
    73  
    74  	ginkgo.It("failed", func(ctx context.Context) {
    75  		framework.ExpectNoError(e2epod.WaitTimeoutForPodRunningInNamespace(ctx, clientSet, failedPodName, podNamespace, timeout))
    76  	})
    77  
    78  	ginkgo.It("gets reported with API error", func(ctx context.Context) {
    79  		called := false
    80  		getPod := func(ctx context.Context) (*v1.Pod, error) {
    81  			if called {
    82  				ginkgo.By("returning fake API error")
    83  				return nil, apierrors.NewTooManyRequests("fake API error", 10)
    84  			}
    85  			called = true
    86  			pod, err := clientSet.CoreV1().Pods(podNamespace).Get(ctx, podName, metav1.GetOptions{})
    87  			if err != nil {
    88  				return nil, err
    89  			}
    90  			ginkgo.By("returning pod")
    91  			return pod, err
    92  		}
    93  		gomega.Eventually(ctx, framework.HandleRetry(getPod)).WithTimeout(5 * timeout).Should(e2epod.BeInPhase(v1.PodRunning))
    94  	})
    95  })
    96  
    97  func getNoSuchPod(ctx context.Context) (*v1.Pod, error) {
    98  	return clientSet.CoreV1().Pods("default").Get(ctx, "no-such-pod", metav1.GetOptions{})
    99  }
   100  
   101  const (
   102  	podName       = "pending-pod"
   103  	podNamespace  = "default"
   104  	failedPodName = "failed-pod"
   105  	timeout       = time.Second
   106  )
   107  
   108  var (
   109  	clientSet = fake.NewSimpleClientset(
   110  		&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: podName, Namespace: podNamespace}, Status: v1.PodStatus{Phase: v1.PodPending}},
   111  		&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: failedPodName, Namespace: podNamespace}, Status: v1.PodStatus{Phase: v1.PodFailed}},
   112  	)
   113  )
   114  
   115  func TestFailureOutput(t *testing.T) {
   116  
   117  	expected := output.TestResult{
   118  		NormalizeOutput: func(in string) string {
   119  			return regexp.MustCompile(`wait.go:[[:digit:]]*`).ReplaceAllString(in, `wait.go`)
   120  		},
   121  		Suite: reporters.JUnitTestSuite{
   122  			Tests:    7,
   123  			Failures: 7,
   124  			Errors:   0,
   125  			Disabled: 0,
   126  			Skipped:  0,
   127  			TestCases: []reporters.JUnitTestCase{
   128  				{
   129  					Name:   "[It] pod not found, must exist",
   130  					Status: "failed",
   131  					Failure: &reporters.JUnitFailure{
   132  						Type: "failed",
   133  						Description: `[FAILED] Told to stop trying after <after>.
   134  Unexpected final error while getting *v1.Pod: pods "no-such-pod" not found
   135  In [It] at: wait_test.go:54 <time>
   136  `,
   137  					},
   138  					SystemErr: `> Enter [It] not found, must exist - wait_test.go:53 <time>
   139  [FAILED] Told to stop trying after <after>.
   140  Unexpected final error while getting *v1.Pod: pods "no-such-pod" not found
   141  In [It] at: wait_test.go:54 <time>
   142  < Exit [It] not found, must exist - wait_test.go:53 <time>
   143  `,
   144  				},
   145  				{
   146  					Name:   "[It] pod not found, retry",
   147  					Status: "failed",
   148  					Failure: &reporters.JUnitFailure{
   149  						Type: "failed",
   150  						Description: `[FAILED] Timed out after <after>.
   151  The function passed to Eventually returned the following error:
   152      <framework.transientError>: 
   153      pods "no-such-pod" not found
   154      {
   155          error: <*errors.StatusError>{
   156              ErrStatus: {
   157                  TypeMeta: {Kind: "", APIVersion: ""},
   158                  ListMeta: {
   159                      SelfLink: "",
   160                      ResourceVersion: "",
   161                      Continue: "",
   162                      RemainingItemCount: nil,
   163                  },
   164                  Status: "Failure",
   165                  Message: "pods \"no-such-pod\" not found",
   166                  Reason: "NotFound",
   167                  Details: {Name: "no-such-pod", Group: "", Kind: "pods", UID: "", Causes: nil, RetryAfterSeconds: 0},
   168                  Code: 404,
   169              },
   170          },
   171      }
   172  In [It] at: wait_test.go:58 <time>
   173  `,
   174  					},
   175  					SystemErr: `> Enter [It] not found, retry - wait_test.go:57 <time>
   176  <klog> wait_test.go:58] Failed inside E2E framework:
   177      k8s.io/kubernetes/test/e2e/framework/pod.WaitTimeoutForPodRunningInNamespace()
   178      	wait.go
   179      k8s.io/kubernetes/test/e2e/framework/pod_test.glob..func1.2()
   180      	wait_test.go:58
   181  [FAILED] Timed out after <after>.
   182  The function passed to Eventually returned the following error:
   183      <framework.transientError>: 
   184      pods "no-such-pod" not found
   185      {
   186          error: <*errors.StatusError>{
   187              ErrStatus: {
   188                  TypeMeta: {Kind: "", APIVersion: ""},
   189                  ListMeta: {
   190                      SelfLink: "",
   191                      ResourceVersion: "",
   192                      Continue: "",
   193                      RemainingItemCount: nil,
   194                  },
   195                  Status: "Failure",
   196                  Message: "pods \"no-such-pod\" not found",
   197                  Reason: "NotFound",
   198                  Details: {Name: "no-such-pod", Group: "", Kind: "pods", UID: "", Causes: nil, RetryAfterSeconds: 0},
   199                  Code: 404,
   200              },
   201          },
   202      }
   203  In [It] at: wait_test.go:58 <time>
   204  < Exit [It] not found, retry - wait_test.go:57 <time>
   205  `,
   206  				},
   207  				{
   208  					Name:   "[It] pod not found, retry with wrappers",
   209  					Status: "failed",
   210  					Failure: &reporters.JUnitFailure{
   211  						Type: "failed",
   212  						Description: `[FAILED] Timed out after <after>.
   213  The function passed to Eventually returned the following error:
   214      <framework.transientError>: 
   215      pods "no-such-pod" not found
   216      {
   217          error: <*errors.StatusError>{
   218              ErrStatus: {
   219                  TypeMeta: {Kind: "", APIVersion: ""},
   220                  ListMeta: {
   221                      SelfLink: "",
   222                      ResourceVersion: "",
   223                      Continue: "",
   224                      RemainingItemCount: nil,
   225                  },
   226                  Status: "Failure",
   227                  Message: "pods \"no-such-pod\" not found",
   228                  Reason: "NotFound",
   229                  Details: {Name: "no-such-pod", Group: "", Kind: "pods", UID: "", Causes: nil, RetryAfterSeconds: 0},
   230                  Code: 404,
   231              },
   232          },
   233      }
   234  In [It] at: wait_test.go:62 <time>
   235  `,
   236  					},
   237  					SystemErr: `> Enter [It] not found, retry with wrappers - wait_test.go:61 <time>
   238  [FAILED] Timed out after <after>.
   239  The function passed to Eventually returned the following error:
   240      <framework.transientError>: 
   241      pods "no-such-pod" not found
   242      {
   243          error: <*errors.StatusError>{
   244              ErrStatus: {
   245                  TypeMeta: {Kind: "", APIVersion: ""},
   246                  ListMeta: {
   247                      SelfLink: "",
   248                      ResourceVersion: "",
   249                      Continue: "",
   250                      RemainingItemCount: nil,
   251                  },
   252                  Status: "Failure",
   253                  Message: "pods \"no-such-pod\" not found",
   254                  Reason: "NotFound",
   255                  Details: {Name: "no-such-pod", Group: "", Kind: "pods", UID: "", Causes: nil, RetryAfterSeconds: 0},
   256                  Code: 404,
   257              },
   258          },
   259      }
   260  In [It] at: wait_test.go:62 <time>
   261  < Exit [It] not found, retry with wrappers - wait_test.go:61 <time>
   262  `,
   263  				},
   264  				{
   265  					Name:   "[It] pod not found, retry with inverted wrappers",
   266  					Status: "failed",
   267  					Failure: &reporters.JUnitFailure{
   268  						Type: "failed",
   269  						Description: `[FAILED] Timed out after <after>.
   270  The function passed to Eventually returned the following error:
   271      <framework.transientError>: 
   272      pods "no-such-pod" not found
   273      {
   274          error: <*errors.StatusError>{
   275              ErrStatus: {
   276                  TypeMeta: {Kind: "", APIVersion: ""},
   277                  ListMeta: {
   278                      SelfLink: "",
   279                      ResourceVersion: "",
   280                      Continue: "",
   281                      RemainingItemCount: nil,
   282                  },
   283                  Status: "Failure",
   284                  Message: "pods \"no-such-pod\" not found",
   285                  Reason: "NotFound",
   286                  Details: {Name: "no-such-pod", Group: "", Kind: "pods", UID: "", Causes: nil, RetryAfterSeconds: 0},
   287                  Code: 404,
   288              },
   289          },
   290      }
   291  In [It] at: wait_test.go:66 <time>
   292  `,
   293  					},
   294  					SystemErr: `> Enter [It] not found, retry with inverted wrappers - wait_test.go:65 <time>
   295  [FAILED] Timed out after <after>.
   296  The function passed to Eventually returned the following error:
   297      <framework.transientError>: 
   298      pods "no-such-pod" not found
   299      {
   300          error: <*errors.StatusError>{
   301              ErrStatus: {
   302                  TypeMeta: {Kind: "", APIVersion: ""},
   303                  ListMeta: {
   304                      SelfLink: "",
   305                      ResourceVersion: "",
   306                      Continue: "",
   307                      RemainingItemCount: nil,
   308                  },
   309                  Status: "Failure",
   310                  Message: "pods \"no-such-pod\" not found",
   311                  Reason: "NotFound",
   312                  Details: {Name: "no-such-pod", Group: "", Kind: "pods", UID: "", Causes: nil, RetryAfterSeconds: 0},
   313                  Code: 404,
   314              },
   315          },
   316      }
   317  In [It] at: wait_test.go:66 <time>
   318  < Exit [It] not found, retry with inverted wrappers - wait_test.go:65 <time>
   319  `,
   320  				},
   321  				{
   322  					Name:   "[It] pod not running",
   323  					Status: "failed",
   324  					Failure: &reporters.JUnitFailure{
   325  						Description: `[FAILED] Timed out after <after>.
   326  Expected Pod to be in <v1.PodPhase>: "Running"
   327  Got instead:
   328      <*v1.Pod>: 
   329          metadata:
   330            creationTimestamp: null
   331            name: pending-pod
   332            namespace: default
   333          spec:
   334            containers: null
   335          status:
   336            phase: Pending
   337  In [It] at: wait_test.go:71 <time>
   338  `,
   339  						Type: "failed",
   340  					},
   341  					SystemErr: `> Enter [It] not running - wait_test.go:69 <time>
   342  STEP: waiting for pod pending-pod to run - wait_test.go:70 <time>
   343  <klog> wait_test.go:71] Failed inside E2E framework:
   344      k8s.io/kubernetes/test/e2e/framework/pod.WaitTimeoutForPodRunningInNamespace()
   345      	wait.go
   346      k8s.io/kubernetes/test/e2e/framework/pod_test.glob..func1.5()
   347      	wait_test.go:71
   348  [FAILED] Timed out after <after>.
   349  Expected Pod to be in <v1.PodPhase>: "Running"
   350  Got instead:
   351      <*v1.Pod>: 
   352          metadata:
   353            creationTimestamp: null
   354            name: pending-pod
   355            namespace: default
   356          spec:
   357            containers: null
   358          status:
   359            phase: Pending
   360  In [It] at: wait_test.go:71 <time>
   361  < Exit [It] not running - wait_test.go:69 <time>
   362  `,
   363  				},
   364  				{
   365  					Name:   "[It] pod failed",
   366  					Status: "failed",
   367  					Failure: &reporters.JUnitFailure{
   368  						Description: `[FAILED] Told to stop trying after <after>.
   369  Expected pod to reach phase "Running", got final phase "Failed" instead:
   370      <*v1.Pod>: 
   371          metadata:
   372            creationTimestamp: null
   373            name: failed-pod
   374            namespace: default
   375          spec:
   376            containers: null
   377          status:
   378            phase: Failed
   379  In [It] at: wait_test.go:75 <time>
   380  `,
   381  						Type: "failed",
   382  					},
   383  					SystemErr: `> Enter [It] failed - wait_test.go:74 <time>
   384  <klog> wait_test.go:75] Failed inside E2E framework:
   385      k8s.io/kubernetes/test/e2e/framework/pod.WaitTimeoutForPodRunningInNamespace()
   386      	wait.go
   387      k8s.io/kubernetes/test/e2e/framework/pod_test.glob..func1.6()
   388      	wait_test.go:75
   389  [FAILED] Told to stop trying after <after>.
   390  Expected pod to reach phase "Running", got final phase "Failed" instead:
   391      <*v1.Pod>: 
   392          metadata:
   393            creationTimestamp: null
   394            name: failed-pod
   395            namespace: default
   396          spec:
   397            containers: null
   398          status:
   399            phase: Failed
   400  In [It] at: wait_test.go:75 <time>
   401  < Exit [It] failed - wait_test.go:74 <time>
   402  `,
   403  				},
   404  				{
   405  					Name:   "[It] pod gets reported with API error",
   406  					Status: "failed",
   407  					Failure: &reporters.JUnitFailure{
   408  						Description: `[FAILED] Timed out after <after>.
   409  The function passed to Eventually returned the following error:
   410      <*errors.StatusError>: 
   411      fake API error
   412      {
   413          ErrStatus: 
   414              code: 429
   415              details:
   416                retryAfterSeconds: 10
   417              message: fake API error
   418              metadata: {}
   419              reason: TooManyRequests
   420              status: Failure,
   421      }
   422  At one point, however, the function did return successfully.
   423  Yet, Eventually failed because the matcher was not satisfied:
   424  Expected Pod to be in <v1.PodPhase>: "Running"
   425  Got instead:
   426      <*v1.Pod>: 
   427          metadata:
   428            creationTimestamp: null
   429            name: pending-pod
   430            namespace: default
   431          spec:
   432            containers: null
   433          status:
   434            phase: Pending
   435  In [It] at: wait_test.go:93 <time>
   436  `,
   437  						Type: "failed",
   438  					},
   439  					SystemErr: `> Enter [It] gets reported with API error - wait_test.go:78 <time>
   440  STEP: returning pod - wait_test.go:90 <time>
   441  STEP: returning fake API error - wait_test.go:82 <time>
   442  [FAILED] Timed out after <after>.
   443  The function passed to Eventually returned the following error:
   444      <*errors.StatusError>: 
   445      fake API error
   446      {
   447          ErrStatus: 
   448              code: 429
   449              details:
   450                retryAfterSeconds: 10
   451              message: fake API error
   452              metadata: {}
   453              reason: TooManyRequests
   454              status: Failure,
   455      }
   456  At one point, however, the function did return successfully.
   457  Yet, Eventually failed because the matcher was not satisfied:
   458  Expected Pod to be in <v1.PodPhase>: "Running"
   459  Got instead:
   460      <*v1.Pod>: 
   461          metadata:
   462            creationTimestamp: null
   463            name: pending-pod
   464            namespace: default
   465          spec:
   466            containers: null
   467          status:
   468            phase: Pending
   469  In [It] at: wait_test.go:93 <time>
   470  < Exit [It] gets reported with API error - wait_test.go:78 <time>
   471  `,
   472  				},
   473  			},
   474  		},
   475  	}
   476  	output.TestGinkgoOutput(t, expected)
   477  }
   478  

View as plain text