github.com/mponton/terratest@v0.44.0/modules/k8s/pod_test.go (about)

     1  //go:build kubeall || kubernetes
     2  // +build kubeall kubernetes
     3  
     4  // NOTE: we have build tags to differentiate kubernetes tests from non-kubernetes tests. This is done because minikube
     5  // is heavy and can interfere with docker related tests in terratest. Specifically, many of the tests start to fail with
     6  // `connection refused` errors from `minikube`. To avoid overloading the system, we run the kubernetes tests and helm
     7  // tests separately from the others. This may not be necessary if you have a sufficiently powerful machine.  We
     8  // recommend at least 4 cores and 16GB of RAM if you want to run all the tests together.
     9  
    10  package k8s
    11  
    12  import (
    13  	"fmt"
    14  	"strings"
    15  	"testing"
    16  	"time"
    17  
    18  	"github.com/stretchr/testify/require"
    19  	corev1 "k8s.io/api/core/v1"
    20  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    21  
    22  	"github.com/mponton/terratest/modules/random"
    23  )
    24  
    25  func TestListPodsReturnsPodsInNamespace(t *testing.T) {
    26  	t.Parallel()
    27  
    28  	uniqueID := strings.ToLower(random.UniqueId())
    29  	options := NewKubectlOptions("", "", uniqueID)
    30  	configData := fmt.Sprintf(EXAMPLE_POD_YAML_TEMPLATE, uniqueID, uniqueID)
    31  	defer KubectlDeleteFromString(t, options, configData)
    32  	KubectlApplyFromString(t, options, configData)
    33  
    34  	pods := ListPods(t, options, metav1.ListOptions{})
    35  	require.Equal(t, len(pods), 1)
    36  	pod := pods[0]
    37  	require.Equal(t, pod.Name, "nginx-pod")
    38  	require.Equal(t, pod.Namespace, uniqueID)
    39  }
    40  
    41  func TestGetPodEReturnsErrorForNonExistantPod(t *testing.T) {
    42  	t.Parallel()
    43  
    44  	options := NewKubectlOptions("", "", "default")
    45  	_, err := GetPodE(t, options, "nginx-pod")
    46  	require.Error(t, err)
    47  }
    48  
    49  func TestGetPodEReturnsCorrectPodInCorrectNamespace(t *testing.T) {
    50  	t.Parallel()
    51  
    52  	uniqueID := strings.ToLower(random.UniqueId())
    53  	options := NewKubectlOptions("", "", uniqueID)
    54  	configData := fmt.Sprintf(EXAMPLE_POD_YAML_TEMPLATE, uniqueID, uniqueID)
    55  	defer KubectlDeleteFromString(t, options, configData)
    56  	KubectlApplyFromString(t, options, configData)
    57  
    58  	pod := GetPod(t, options, "nginx-pod")
    59  	require.Equal(t, pod.Name, "nginx-pod")
    60  	require.Equal(t, pod.Namespace, uniqueID)
    61  }
    62  
    63  func TestWaitUntilNumPodsCreatedReturnsSuccessfully(t *testing.T) {
    64  	t.Parallel()
    65  
    66  	uniqueID := strings.ToLower(random.UniqueId())
    67  	options := NewKubectlOptions("", "", uniqueID)
    68  	configData := fmt.Sprintf(EXAMPLE_POD_YAML_TEMPLATE, uniqueID, uniqueID)
    69  	defer KubectlDeleteFromString(t, options, configData)
    70  	KubectlApplyFromString(t, options, configData)
    71  
    72  	WaitUntilNumPodsCreated(t, options, metav1.ListOptions{}, 1, 60, 1*time.Second)
    73  }
    74  
    75  func TestWaitUntilPodAvailableReturnsSuccessfully(t *testing.T) {
    76  	t.Parallel()
    77  
    78  	uniqueID := strings.ToLower(random.UniqueId())
    79  	options := NewKubectlOptions("", "", uniqueID)
    80  	configData := fmt.Sprintf(EXAMPLE_POD_YAML_TEMPLATE, uniqueID, uniqueID)
    81  	defer KubectlDeleteFromString(t, options, configData)
    82  	KubectlApplyFromString(t, options, configData)
    83  
    84  	WaitUntilPodAvailable(t, options, "nginx-pod", 60, 1*time.Second)
    85  }
    86  
    87  func TestWaitUntilPodWithMultipleContainersAvailableReturnsSuccessfully(t *testing.T) {
    88  	t.Parallel()
    89  
    90  	uniqueID := strings.ToLower(random.UniqueId())
    91  	options := NewKubectlOptions("", "", uniqueID)
    92  	configData := fmt.Sprintf(EXAMPLE_POD_WITH_MULTIPLE_CONTAINERS_YAML_TEMPLATE, uniqueID, uniqueID)
    93  	defer KubectlDeleteFromString(t, options, configData)
    94  	KubectlApplyFromString(t, options, configData)
    95  
    96  	WaitUntilPodAvailable(t, options, "nginx-pod", 60, 1*time.Second)
    97  }
    98  
    99  func TestWaitUntilPodAvailableWithReadinessProbe(t *testing.T) {
   100  	t.Parallel()
   101  
   102  	uniqueID := strings.ToLower(random.UniqueId())
   103  	options := NewKubectlOptions("", "", uniqueID)
   104  	configData := fmt.Sprintf(EXAMPLE_POD_WITH_READINESS_PROBE, uniqueID, uniqueID)
   105  	defer KubectlDeleteFromString(t, options, configData)
   106  	KubectlApplyFromString(t, options, configData)
   107  
   108  	WaitUntilPodAvailable(t, options, "nginx-pod", 60, 1*time.Second)
   109  }
   110  
   111  func TestWaitUntilPodAvailableWithFailingReadinessProbe(t *testing.T) {
   112  	t.Parallel()
   113  
   114  	uniqueID := strings.ToLower(random.UniqueId())
   115  	options := NewKubectlOptions("", "", uniqueID)
   116  	configData := fmt.Sprintf(EXAMPLE_POD_WITH_FAILING_READINESS_PROBE, uniqueID, uniqueID)
   117  	defer KubectlDeleteFromString(t, options, configData)
   118  	KubectlApplyFromString(t, options, configData)
   119  
   120  	err := WaitUntilPodAvailableE(t, options, "nginx-pod", 60, 1*time.Second)
   121  	require.Error(t, err)
   122  }
   123  
   124  const EXAMPLE_POD_YAML_TEMPLATE = `---
   125  apiVersion: v1
   126  kind: Namespace
   127  metadata:
   128    name: %s
   129  ---
   130  apiVersion: v1
   131  kind: Pod
   132  metadata:
   133    name: nginx-pod
   134    namespace: %s
   135  spec:
   136    containers:
   137    - name: nginx
   138      image: nginx:1.15.7
   139      ports:
   140      - containerPort: 80
   141  `
   142  
   143  const EXAMPLE_POD_WITH_MULTIPLE_CONTAINERS_YAML_TEMPLATE = EXAMPLE_POD_YAML_TEMPLATE + `
   144    - name: nginx-two
   145      image: nginx:1.15.7
   146      ports:
   147      - containerPort: 80
   148  `
   149  
   150  const EXAMPLE_POD_WITH_READINESS_PROBE = EXAMPLE_POD_YAML_TEMPLATE + `
   151      readinessProbe:
   152        httpGet:
   153          path: /
   154          port: 80
   155  `
   156  
   157  const EXAMPLE_POD_WITH_FAILING_READINESS_PROBE = EXAMPLE_POD_YAML_TEMPLATE + `
   158      readinessProbe:
   159        httpGet:
   160          path: /not-ready
   161          port: 80
   162        periodSeconds: 1
   163  `
   164  
   165  func TestIsPodAvailable(t *testing.T) {
   166  	t.Parallel()
   167  
   168  	cases := []struct {
   169  		title          string
   170  		pod            *corev1.Pod
   171  		expectedResult bool
   172  	}{
   173  		{
   174  			title: "TestIsPodAvailableStartedButNotReady",
   175  			pod: &corev1.Pod{
   176  				Status: corev1.PodStatus{
   177  					ContainerStatuses: []corev1.ContainerStatus{
   178  						{
   179  							Name:    "container1",
   180  							Ready:   false,
   181  							Started: &[]bool{true}[0],
   182  						},
   183  					},
   184  					Phase: corev1.PodRunning,
   185  				},
   186  			},
   187  			expectedResult: false,
   188  		},
   189  		{
   190  			title: "TestIsPodAvailableStartedAndReady",
   191  			pod: &corev1.Pod{
   192  				Status: corev1.PodStatus{
   193  					ContainerStatuses: []corev1.ContainerStatus{
   194  						{
   195  							Name:    "container1",
   196  							Ready:   true,
   197  							Started: &[]bool{true}[0],
   198  						},
   199  					},
   200  					Phase: corev1.PodRunning,
   201  				},
   202  			},
   203  			expectedResult: true,
   204  		},
   205  	}
   206  	for _, tc := range cases {
   207  		tc := tc
   208  		t.Run(tc.title, func(t *testing.T) {
   209  			t.Parallel()
   210  			actualResult := IsPodAvailable(tc.pod)
   211  			require.Equal(t, tc.expectedResult, actualResult)
   212  		})
   213  	}
   214  }