diff --git a/test/e2e/scheduling/preemption.go b/test/e2e/scheduling/preemption.go index 03481a7d69a..92c15d7f642 100644 --- a/test/e2e/scheduling/preemption.go +++ b/test/e2e/scheduling/preemption.go @@ -461,12 +461,12 @@ var _ = SIGDescribe("SchedulerPreemption [Serial]", func() { ginkgo.AfterEach(func() { // print out additional info if tests failed if ginkgo.CurrentGinkgoTestDescription().Failed { - // list existing priorities + // List existing PriorityClasses. priorityList, err := cs.SchedulingV1().PriorityClasses().List(context.TODO(), metav1.ListOptions{}) if err != nil { - framework.Logf("Unable to list priorities: %v", err) + framework.Logf("Unable to list PriorityClasses: %v", err) } else { - framework.Logf("List existing priorities:") + framework.Logf("List existing PriorityClasses:") for _, p := range priorityList.Items { framework.Logf("%v/%v created at %v", p.Name, p.Value, p.CreationTimestamp) } @@ -518,8 +518,7 @@ var _ = SIGDescribe("SchedulerPreemption [Serial]", func() { priorityPairs = append(priorityPairs, priorityPair{name: priorityName, value: priorityVal}) _, err := cs.SchedulingV1().PriorityClasses().Create(context.TODO(), &schedulingv1.PriorityClass{ObjectMeta: metav1.ObjectMeta{Name: priorityName}, Value: priorityVal}, metav1.CreateOptions{}) if err != nil { - framework.Logf("Failed to create priority '%v/%v': %v", priorityName, priorityVal, err) - framework.Logf("Reason: %v. Msg: %v", apierrors.ReasonForError(err), err) + framework.Logf("Failed to create priority '%v/%v'. Reason: %v. Msg: %v", priorityName, priorityVal, apierrors.ReasonForError(err), err) } framework.ExpectEqual(err == nil || apierrors.IsAlreadyExists(err), true) } @@ -669,6 +668,87 @@ var _ = SIGDescribe("SchedulerPreemption [Serial]", func() { } }) }) + + ginkgo.Context("PriorityClass endpoints", func() { + var cs clientset.Interface + f := framework.NewDefaultFramework("sched-preemption-path") + var pcs []*schedulingv1.PriorityClass + + ginkgo.BeforeEach(func() { + cs = f.ClientSet + // Create 2 PriorityClass: p1, p2. + for i := 1; i <= 2; i++ { + name, val := fmt.Sprintf("p%d", i), int32(i) + pc, err := cs.SchedulingV1().PriorityClasses().Create(context.TODO(), &schedulingv1.PriorityClass{ObjectMeta: metav1.ObjectMeta{Name: name}, Value: val}, metav1.CreateOptions{}) + if err != nil { + framework.Logf("Failed to create priority '%v/%v'. Reason: %v. Msg: %v", name, val, apierrors.ReasonForError(err), err) + } + framework.ExpectEqual(err == nil || apierrors.IsAlreadyExists(err), true) + pcs = append(pcs, pc) + } + }) + + ginkgo.AfterEach(func() { + // Print out additional info if tests failed. + if ginkgo.CurrentGinkgoTestDescription().Failed { + // List existing PriorityClasses. + priorityList, err := cs.SchedulingV1().PriorityClasses().List(context.TODO(), metav1.ListOptions{}) + if err != nil { + framework.Logf("Unable to list PriorityClasses: %v", err) + } else { + framework.Logf("List existing PriorityClasses:") + for _, p := range priorityList.Items { + framework.Logf("%v/%v created at %v", p.Name, p.Value, p.CreationTimestamp) + } + } + } + + // Cannot run collection deletion which would delete all system level priority classes. + for _, pc := range pcs { + err := cs.SchedulingV1().PriorityClasses().Delete(context.TODO(), pc.Name, *metav1.NewDeleteOptions(0)) + framework.ExpectNoError(err) + } + }) + + ginkgo.It("verify PriorityClass endpoints can be operated with different HTTP methods", func() { + // 1. Patch/Update on immutable fields will fail. + pcCopy := pcs[0].DeepCopy() + pcCopy.Value = pcCopy.Value * 10 + err := patchPriorityClass(cs, pcs[0], pcCopy) + framework.ExpectError(err, "expect a patch error on an immutable field") + framework.Logf("%v", err) + + pcCopy = pcs[1].DeepCopy() + pcCopy.Value = pcCopy.Value * 10 + _, err = cs.SchedulingV1().PriorityClasses().Update(context.TODO(), pcCopy, metav1.UpdateOptions{}) + framework.ExpectError(err, "expect an update error on an immutable field") + framework.Logf("%v", err) + + // 2. Patch/Update on mutable fields will succeed. + newDesc := "updated description" + pcCopy = pcs[0].DeepCopy() + pcCopy.Description = newDesc + err = patchPriorityClass(cs, pcs[0], pcCopy) + framework.ExpectNoError(err) + + pcCopy = pcs[1].DeepCopy() + pcCopy.Description = newDesc + _, err = cs.SchedulingV1().PriorityClasses().Update(context.TODO(), pcCopy, metav1.UpdateOptions{}) + framework.ExpectNoError(err) + + // 3. List existing PriorityClasses. + _, err = cs.SchedulingV1().PriorityClasses().List(context.TODO(), metav1.ListOptions{}) + framework.ExpectNoError(err) + + // 4. Verify fields of updated PriorityClasses. + for _, pc := range pcs { + livePC, err := cs.SchedulingV1().PriorityClasses().Get(context.TODO(), pc.Name, metav1.GetOptions{}) + framework.ExpectNoError(err) + framework.ExpectEqual(livePC.Value, pc.Value) + framework.ExpectEqual(livePC.Description, newDesc) + } + }) + }) }) type pauseRSConfig struct { @@ -756,3 +836,21 @@ func patchNode(client clientset.Interface, old *v1.Node, new *v1.Node) error { _, err = client.CoreV1().Nodes().Patch(context.TODO(), old.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}, "status") return err } + +func patchPriorityClass(cs clientset.Interface, old, new *schedulingv1.PriorityClass) error { + oldData, err := json.Marshal(old) + if err != nil { + return err + } + + newData, err := json.Marshal(new) + if err != nil { + return err + } + patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, &schedulingv1.PriorityClass{}) + if err != nil { + return fmt.Errorf("failed to create merge patch for PriorityClass %q: %v", old.Name, err) + } + _, err = cs.SchedulingV1().PriorityClasses().Patch(context.TODO(), old.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}) + return err +}