github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/manager/resources/job/job_test.go (about)

     1  /*
     2   * Copyright contributors to the Hyperledger Fabric Operator project
     3   *
     4   * SPDX-License-Identifier: Apache-2.0
     5   *
     6   * Licensed under the Apache License, Version 2.0 (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at:
     9   *
    10   * 	  http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   * Unless required by applicable law or agreed to in writing, software
    13   * distributed under the License is distributed on an "AS IS" BASIS,
    14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15   * See the License for the specific language governing permissions and
    16   * limitations under the License.
    17   */
    18  
    19  package job_test
    20  
    21  import (
    22  	"context"
    23  	"errors"
    24  	"time"
    25  
    26  	. "github.com/onsi/ginkgo/v2"
    27  	. "github.com/onsi/gomega"
    28  
    29  	"github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/container"
    30  	"github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/job"
    31  	"github.com/IBM-Blockchain/fabric-operator/pkg/manager/resources/job/mocks"
    32  
    33  	v1 "k8s.io/api/batch/v1"
    34  	corev1 "k8s.io/api/core/v1"
    35  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    36  	"k8s.io/apimachinery/pkg/types"
    37  
    38  	k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
    39  )
    40  
    41  var _ = Describe("Job", func() {
    42  	var (
    43  		k8sJob  *v1.Job
    44  		testJob *job.Job
    45  	)
    46  
    47  	BeforeEach(func() {
    48  		k8sJob = &v1.Job{
    49  			ObjectMeta: metav1.ObjectMeta{
    50  				Name:      "k8sJob",
    51  				Namespace: "default",
    52  			},
    53  		}
    54  		testJob = &job.Job{
    55  			Job: k8sJob,
    56  		}
    57  	})
    58  
    59  	It("creates job with defaults", func() {
    60  		testJob = job.NewWithDefaults(k8sJob)
    61  		Expect(testJob.Timeouts).To(Equal(&job.Timeouts{
    62  			WaitUntilActive:   60 * time.Second,
    63  			WaitUntilFinished: 60 * time.Second,
    64  		}))
    65  
    66  		By("adding unique id to job name", func() {
    67  			Expect(testJob.Name).To(ContainSubstring("k8sJob-"))
    68  		})
    69  	})
    70  
    71  	It("adds container", func() {
    72  		cont := container.Container{
    73  			Container: &corev1.Container{
    74  				Name: "test-cont",
    75  			},
    76  		}
    77  
    78  		testJob.AddContainer(cont)
    79  		Expect(len(testJob.Spec.Template.Spec.Containers)).To(Equal(1))
    80  		Expect(testJob.Spec.Template.Spec.Containers[0]).To(Equal(*cont.Container))
    81  	})
    82  
    83  	Context("volumes", func() {
    84  		BeforeEach(func() {
    85  			testJob.Spec.Template.Spec.Volumes = []corev1.Volume{
    86  				{
    87  					Name: "test-volume",
    88  				},
    89  			}
    90  		})
    91  
    92  		It("appends volume if missing", func() {
    93  			testJob.AppendVolumeIfMissing(corev1.Volume{Name: "test-volume"})
    94  			testJob.AppendVolumeIfMissing(corev1.Volume{Name: "test-volume2"})
    95  
    96  			Expect(len(testJob.Spec.Template.Spec.Volumes)).To(Equal(2))
    97  			Expect(testJob.Spec.Template.Spec.Volumes[1]).To(Equal(corev1.Volume{Name: "test-volume2"}))
    98  		})
    99  	})
   100  
   101  	Context("image pull secrets", func() {
   102  		BeforeEach(func() {
   103  			testJob.Spec.Template.Spec.ImagePullSecrets = []corev1.LocalObjectReference{
   104  				{
   105  					Name: "pullsecret",
   106  				},
   107  			}
   108  		})
   109  
   110  		It("appends volume if missing", func() {
   111  			testJob.AppendPullSecret(corev1.LocalObjectReference{Name: "pullsecret"})
   112  			testJob.AppendPullSecret(corev1.LocalObjectReference{Name: "pullsecret2"})
   113  
   114  			Expect(len(testJob.Spec.Template.Spec.ImagePullSecrets)).To(Equal(2))
   115  			Expect(testJob.Spec.Template.Spec.ImagePullSecrets[1]).To(
   116  				Equal(corev1.LocalObjectReference{Name: "pullsecret2"}),
   117  			)
   118  		})
   119  	})
   120  
   121  	Context("events", func() {
   122  		var (
   123  			client *mocks.Client
   124  		)
   125  
   126  		BeforeEach(func() {
   127  			client = &mocks.Client{}
   128  
   129  		})
   130  
   131  		Context("status", func() {
   132  			Context("failures", func() {
   133  				Context("job", func() {
   134  					When("getting job from API server fails", func() {
   135  						BeforeEach(func() {
   136  							client.GetStub = func(ctx context.Context, nn types.NamespacedName, obj k8sclient.Object) error {
   137  								return errors.New("failed to get job")
   138  							}
   139  						})
   140  
   141  						It("returns error and UNKNOWN status", func() {
   142  							status, err := testJob.Status(client)
   143  							Expect(err).To(HaveOccurred())
   144  							Expect(status).To(Equal(job.UNKNOWN))
   145  						})
   146  					})
   147  
   148  					When("job has failed", func() {
   149  						BeforeEach(func() {
   150  							client.GetStub = func(ctx context.Context, nn types.NamespacedName, obj k8sclient.Object) error {
   151  								j := obj.(*v1.Job)
   152  								j.Status = v1.JobStatus{
   153  									Failed: int32(1),
   154  								}
   155  								return nil
   156  							}
   157  						})
   158  
   159  						It("returns FAILED status", func() {
   160  							status, err := testJob.Status(client)
   161  							Expect(err).NotTo(HaveOccurred())
   162  							Expect(status).To(Equal(job.FAILED))
   163  						})
   164  					})
   165  				})
   166  
   167  				Context("pods", func() {
   168  					When("getting pods from API server fails", func() {
   169  						BeforeEach(func() {
   170  							client.ListStub = func(ctx context.Context, list k8sclient.ObjectList, opts ...k8sclient.ListOption) error {
   171  								return errors.New("failed to list pods")
   172  							}
   173  						})
   174  
   175  						It("returns error and UNKNOWN status", func() {
   176  							status, err := testJob.Status(client)
   177  							Expect(err).To(HaveOccurred())
   178  							Expect(status).To(Equal(job.UNKNOWN))
   179  						})
   180  					})
   181  
   182  					When("job has failed", func() {
   183  						BeforeEach(func() {
   184  							client.ListStub = func(ctx context.Context, list k8sclient.ObjectList, opts ...k8sclient.ListOption) error {
   185  								pods := list.(*corev1.PodList)
   186  								pods.Items = []corev1.Pod{
   187  									{
   188  										Status: corev1.PodStatus{
   189  											Phase: corev1.PodFailed,
   190  										},
   191  									},
   192  								}
   193  								return nil
   194  							}
   195  						})
   196  
   197  						It("returns FAILED status", func() {
   198  							status, err := testJob.Status(client)
   199  							Expect(err).NotTo(HaveOccurred())
   200  							Expect(status).To(Equal(job.FAILED))
   201  						})
   202  					})
   203  				})
   204  			})
   205  
   206  			It("returns COMPLETED state", func() {
   207  				status, err := testJob.Status(client)
   208  				Expect(err).NotTo(HaveOccurred())
   209  				Expect(status).To(Equal(job.COMPLETED))
   210  			})
   211  		})
   212  
   213  		Context("wait until active", func() {
   214  			BeforeEach(func() {
   215  				testJob.Timeouts = &job.Timeouts{
   216  					WaitUntilActive: time.Second,
   217  				}
   218  
   219  				client.GetStub = func(ctx context.Context, nn types.NamespacedName, obj k8sclient.Object) error {
   220  					j := obj.(*v1.Job)
   221  					j.Status = v1.JobStatus{
   222  						Active: int32(1),
   223  					}
   224  					return nil
   225  				}
   226  			})
   227  
   228  			It("returns before timeout with no errors", func() {
   229  				err := testJob.WaitUntilActive(client)
   230  				Expect(err).NotTo(HaveOccurred())
   231  			})
   232  		})
   233  
   234  		Context("wait until finished", func() {
   235  			BeforeEach(func() {
   236  				testJob.Timeouts = &job.Timeouts{
   237  					WaitUntilFinished: time.Second,
   238  				}
   239  
   240  				client.ListStub = func(ctx context.Context, list k8sclient.ObjectList, opts ...k8sclient.ListOption) error {
   241  					pods := list.(*corev1.PodList)
   242  					pods.Items = []corev1.Pod{
   243  						{
   244  							Status: corev1.PodStatus{
   245  								ContainerStatuses: []corev1.ContainerStatus{
   246  									{
   247  										State: corev1.ContainerState{
   248  											Terminated: &corev1.ContainerStateTerminated{},
   249  										},
   250  									},
   251  								},
   252  							},
   253  						},
   254  					}
   255  					return nil
   256  				}
   257  			})
   258  
   259  			It("returns before timeout with no errors", func() {
   260  				err := testJob.WaitUntilFinished(client)
   261  				Expect(err).NotTo(HaveOccurred())
   262  			})
   263  		})
   264  	})
   265  })