github.com/iter8-tools/iter8@v1.1.2/base/readiness_test.go (about)

     1  package base
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  
    11  	"helm.sh/helm/v3/pkg/cli"
    12  
    13  	corev1 "k8s.io/api/core/v1"
    14  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    15  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    16  	"k8s.io/apimachinery/pkg/runtime"
    17  	"k8s.io/apimachinery/pkg/runtime/schema"
    18  )
    19  
    20  // TestNoObject tests that task fails if the object is not present
    21  func TestNoObject(t *testing.T) {
    22  	_ = os.Chdir(t.TempDir())
    23  	ns, nm := "default", "test-pod"
    24  	pod := newPod(ns, nm).withCondition("Ready", "True").build()
    25  	rTask := newReadinessTask("non-existent-pod").withVersion("v1").withResource("pods").withNamespace(ns).withCondition("Ready").build()
    26  	runTaskTest(t, rTask, false, ns, pod)
    27  }
    28  
    29  // TestWithoutCondition tests the task succeeds when there are no conditions on the object
    30  // It should be successful
    31  // Also validates parsing of timeout
    32  // Also validates setting of default namespace
    33  func TestWithoutConditions(t *testing.T) {
    34  	_ = os.Chdir(t.TempDir())
    35  	ns, nm := "default", "test-pod"
    36  	pod := newPod(ns, nm).build()
    37  	rTask := newReadinessTask(nm).withVersion("v1").withResource("pods").withTimeout("20s").build()
    38  	runTaskTest(t, rTask, true, ns, pod)
    39  }
    40  
    41  // TestWithCondition tests that the task succeeds when the condition is present and True
    42  func TestWithCondition(t *testing.T) {
    43  	_ = os.Chdir(t.TempDir())
    44  	ns, nm := "default", "test-pod"
    45  	pod := newPod(ns, nm).withCondition("Ready", "True").build()
    46  	rTask := newReadinessTask(nm).withVersion("v1").withResource("pods").withNamespace(ns).withCondition("Ready").build()
    47  	runTaskTest(t, rTask, true, ns, pod)
    48  }
    49  
    50  // TestWithFalseCondition tests that the task fails when the condition is present and not True
    51  func TestWithFalseCondition(t *testing.T) {
    52  	_ = os.Chdir(t.TempDir())
    53  	ns, nm := "default", "test-pod"
    54  	pod := newPod(ns, nm).withCondition("Ready", "False").build()
    55  	rTask := newReadinessTask(nm).withVersion("v1").withResource("pods").withNamespace(ns).withCondition("Ready").build()
    56  	runTaskTest(t, rTask, false, ns, pod)
    57  }
    58  
    59  // TestConditionNotPresent tests that the task fails when the condition is not present (but others are)
    60  func TestConditionNotPresent(t *testing.T) {
    61  	_ = os.Chdir(t.TempDir())
    62  	ns, nm := "default", "test-pod"
    63  	pod := newPod(ns, nm).build()
    64  	rTask := newReadinessTask(nm).withVersion("v1").withResource("pods").withNamespace(ns).withCondition("NotPresent").build()
    65  	runTaskTest(t, rTask, false, ns, pod)
    66  }
    67  
    68  // TestInvalidTimeout tests that the task fails when the specified timeout is invalid (not parseable)
    69  func TestInvalidTimeout(t *testing.T) {
    70  	_ = os.Chdir(t.TempDir())
    71  	ns, nm := "default", "test-pod"
    72  	pod := newPod(ns, nm).withCondition("Ready", "True").build()
    73  	rTask := newReadinessTask(nm).withVersion("v1").withResource("pods").withNamespace(ns).withTimeout("timeout").build()
    74  	runTaskTest(t, rTask, false, ns, pod)
    75  }
    76  
    77  // UTILITY METHODS for all tests
    78  
    79  // runTaskTest creates fake cluster with pod and runs rTask
    80  func runTaskTest(t *testing.T, rTask *readinessTask, success bool, ns string, pod *unstructured.Unstructured) {
    81  	*kd = *NewFakeKubeDriver(cli.New())
    82  	rs := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
    83  	_, err := kd.dynamicClient.Resource(rs).Namespace(ns).Create(context.Background(), pod, metav1.CreateOptions{})
    84  	assert.NoError(t, err, "get failed")
    85  
    86  	err = rTask.run(&Experiment{
    87  		Spec:   []Task{rTask},
    88  		Result: &ExperimentResult{},
    89  	})
    90  	if success {
    91  		assert.NoError(t, err)
    92  	} else {
    93  		assert.Error(t, err)
    94  	}
    95  }
    96  
    97  type podBuilder corev1.Pod
    98  
    99  func newPod(ns string, nm string) *podBuilder {
   100  	pod := &corev1.Pod{
   101  		TypeMeta: metav1.TypeMeta{
   102  			APIVersion: "v1",
   103  			Kind:       "Pod",
   104  		},
   105  		ObjectMeta: metav1.ObjectMeta{
   106  			Name:      nm,
   107  			Namespace: ns,
   108  		},
   109  	}
   110  	return (*podBuilder)(pod)
   111  }
   112  
   113  func (p *podBuilder) build() *unstructured.Unstructured {
   114  	o, err := runtime.DefaultUnstructuredConverter.ToUnstructured((*corev1.Pod)(p))
   115  	if err != nil {
   116  		return nil
   117  	}
   118  	return &unstructured.Unstructured{Object: o}
   119  }
   120  
   121  func (p *podBuilder) withCondition(typ string, value string) *podBuilder {
   122  	c := corev1.PodCondition{Type: (corev1.PodConditionType(typ))}
   123  	switch strings.ToLower(value) {
   124  	case "true":
   125  		c.Status = corev1.ConditionTrue
   126  	case "false":
   127  		c.Status = corev1.ConditionFalse
   128  	default:
   129  		c.Status = corev1.ConditionUnknown
   130  	}
   131  	p.Status.Conditions = append(p.Status.Conditions, c)
   132  
   133  	return p
   134  }
   135  
   136  type readinessTaskBuilder readinessTask
   137  
   138  func newReadinessTask(name string) *readinessTaskBuilder {
   139  	rTask := &readinessTask{
   140  		TaskMeta: TaskMeta{
   141  			Task: StringPointer(ReadinessTaskName),
   142  		},
   143  		With: readinessInputs{
   144  			Name: name,
   145  		},
   146  	}
   147  
   148  	return (*readinessTaskBuilder)(rTask)
   149  }
   150  
   151  //	func (t *readinessTaskBuilder) withGroup(group string) *readinessTaskBuilder {
   152  //		t.With.Group = group
   153  //		return t
   154  //	}
   155  func (t *readinessTaskBuilder) withVersion(version string) *readinessTaskBuilder {
   156  	t.With.Version = version
   157  	return t
   158  }
   159  
   160  func (t *readinessTaskBuilder) withResource(resource string) *readinessTaskBuilder {
   161  	t.With.Resource = resource
   162  	return t
   163  }
   164  
   165  func (t *readinessTaskBuilder) withNamespace(ns string) *readinessTaskBuilder {
   166  	t.With.Namespace = StringPointer(ns)
   167  	return t
   168  }
   169  
   170  func (t *readinessTaskBuilder) withTimeout(timeout string) *readinessTaskBuilder {
   171  	t.With.Timeout = StringPointer(timeout)
   172  	return t
   173  }
   174  
   175  func (t *readinessTaskBuilder) withCondition(condition string) *readinessTaskBuilder {
   176  	t.With.Conditions = append(t.With.Conditions, condition)
   177  	return t
   178  }
   179  
   180  func (t *readinessTaskBuilder) build() *readinessTask {
   181  	return (*readinessTask)(t)
   182  }