Skip to content

Commit

Permalink
Tests for Custom Scheduler Name on Build and BuildRun objects
Browse files Browse the repository at this point in the history
Signed-off-by: Dylan Orzel <dorzel@redhat.com>
  • Loading branch information
dorzel committed Feb 12, 2025
1 parent ba0f291 commit f16ee49
Show file tree
Hide file tree
Showing 12 changed files with 649 additions and 3 deletions.
15 changes: 15 additions & 0 deletions pkg/reconciler/build/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -645,5 +645,20 @@ var _ = Describe("Reconcile Build", func() {
Expect(statusWriter.UpdateCallCount()).To(Equal(1))
})
})

Context("when SchedulerName is specified", func() {
It("should fail to validate when the SchedulerName is invalid", func() {
// set SchedulerName to be invalid
buildSample.Spec.SchedulerName = strings.Repeat("s", 64)
buildSample.Spec.Output.PushSecret = nil

statusCall := ctl.StubFunc(corev1.ConditionFalse, build.SchedulerNameNotValid, "Scheduler name not valid: name part "+validation.MaxLenError(63))
statusWriter.UpdateCalls(statusCall)

_, err := reconciler.Reconcile(context.TODO(), request)
Expect(err).To(BeNil())
Expect(statusWriter.UpdateCallCount()).To(Equal(1))
})
})
})
})
59 changes: 59 additions & 0 deletions pkg/reconciler/buildrun/buildrun_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1660,5 +1660,64 @@ var _ = Describe("Reconcile BuildRun", func() {
Expect(statusWriter.UpdateCallCount()).To(Equal(1))
})
})

Context("when SchedulerName is specified", func() {
It("should fail to validate when the SchedulerName is invalid", func() {
// set SchedulerName to be invalid
buildRunSample.Spec.SchedulerName = strings.Repeat("s", 64)

statusCall := ctl.StubFunc(corev1.ConditionFalse, build.SchedulerNameNotValid, validation.MaxLenError(64))
statusWriter.UpdateCalls(statusCall)

_, err := reconciler.Reconcile(context.TODO(), buildRunRequest)
Expect(err).To(BeNil())
Expect(statusWriter.UpdateCallCount()).To(Equal(1))
})
})

Context("when a buildrun has a buildSpec defined and overrides nodeSelector", func() {
BeforeEach(func() {
buildRunSample = ctl.BuildRunWithNodeSelectorOverride(buildRunName, buildName, map[string]string{"Key": "testkey", "Value": "testvalue"})
})

It("should fail to register", func() {
statusCall := ctl.StubFunc(corev1.ConditionFalse, build.BuildReason(resources.BuildRunBuildFieldOverrideForbidden), "cannot use 'nodeSelector' override and 'buildSpec' simultaneously")
statusWriter.UpdateCalls(statusCall)

_, err := reconciler.Reconcile(context.TODO(), buildRunRequest)
Expect(err).To(BeNil())
Expect(statusWriter.UpdateCallCount()).To(Equal(1))
})
})

Context("when a buildrun has a buildSpec defined and overrides Tolerations", func() {
BeforeEach(func() {
buildRunSample = ctl.BuildRunWithTolerationsOverride(buildRunName, buildName, []corev1.Toleration{{Key: "testkey", Value: "testvalue", Operator: corev1.TolerationOpEqual, Effect: corev1.TaintEffectNoSchedule}})
})

It("should fail to register", func() {
statusCall := ctl.StubFunc(corev1.ConditionFalse, build.BuildReason(resources.BuildRunBuildFieldOverrideForbidden), "cannot use 'tolerations' override and 'buildSpec' simultaneously")
statusWriter.UpdateCalls(statusCall)

_, err := reconciler.Reconcile(context.TODO(), buildRunRequest)
Expect(err).To(BeNil())
Expect(statusWriter.UpdateCallCount()).To(Equal(1))
})
})

Context("when a buildrun has a buildSpec defined and overrides schedulerName", func() {
BeforeEach(func() {
buildRunSample = ctl.BuildRunWithSchedulerNameOverride(buildRunName, buildName, "testSchedulerName")
})

It("should fail to register", func() {
statusCall := ctl.StubFunc(corev1.ConditionFalse, build.BuildReason(resources.BuildRunBuildFieldOverrideForbidden), "cannot use 'schedulerName' override and 'buildSpec' simultaneously")
statusWriter.UpdateCalls(statusCall)

_, err := reconciler.Reconcile(context.TODO(), buildRunRequest)
Expect(err).To(BeNil())
Expect(statusWriter.UpdateCallCount()).To(Equal(1))
})
})
})
})
22 changes: 22 additions & 0 deletions pkg/reconciler/buildrun/resources/taskrun_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -678,5 +678,27 @@ var _ = Describe("GenerateTaskrun", func() {
Expect(got.Spec.PodTemplate.Tolerations[0].Value).To(Equal(buildRun.Spec.Tolerations[0].Value))
})
})

Context("when the build and buildrun both specify a SchedulerName", func() {
BeforeEach(func() {
build, err = ctl.LoadBuildYAML([]byte(test.MinimalBuildWithSchedulerName))
Expect(err).To(BeNil())

buildRun, err = ctl.LoadBuildRunFromBytes([]byte(test.MinimalBuildRunWithSchedulerName))
Expect(err).To(BeNil())

buildStrategy, err = ctl.LoadBuildStrategyFromBytes([]byte(test.ClusterBuildStrategyNoOp))
Expect(err).To(BeNil())
})

JustBeforeEach(func() {
got, err = resources.GenerateTaskRun(config.NewDefaultConfig(), build, buildRun, serviceAccountName, buildStrategy)
Expect(err).To(BeNil())
})

It("should give precedence to the SchedulerName value specified in the buildRun", func() {
Expect(got.Spec.PodTemplate.SchedulerName).To(Equal(buildRun.Spec.SchedulerName))
})
})
})
})
88 changes: 88 additions & 0 deletions pkg/validate/nodeselector_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright The Shipwright Contributors
//
// SPDX-License-Identifier: Apache-2.0

package validate_test

import (
"context"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

corev1 "k8s.io/apimachinery/pkg/apis/meta/v1"

. "github.com/shipwright-io/build/pkg/apis/build/v1beta1"
"github.com/shipwright-io/build/pkg/validate"
)

var _ = Describe("ValidateNodeSelector", func() {
var ctx context.Context

BeforeEach(func() {
ctx = context.TODO()
})

var validate = func(build *Build) {
GinkgoHelper()

var validator = &validate.NodeSelectorRef{Build: build}
Expect(validator.ValidatePath(ctx)).To(Succeed())
}

var sampleBuild = func(key string, value string) *Build {
return &Build{
ObjectMeta: corev1.ObjectMeta{
Namespace: "foo",
Name: "bar",
},
Spec: BuildSpec{
NodeSelector: map[string]string{key: value},
},
}
}

Context("when node selector is specified", func() {
It("should pass an empty key and value", func() {
build := sampleBuild("", "")
validate(build)
Expect(build.Status.Reason).To(BeNil())
Expect(build.Status.Message).To(BeNil())
})

It("should pass a valid key and valid value", func() {
build := sampleBuild("validkey", "validvalue")
validate(build)
Expect(build.Status.Reason).To(BeNil())
Expect(build.Status.Message).To(BeNil())
})

It("should pass an empty key and valid value", func() {
build := sampleBuild("", "validvalue")
validate(build)
Expect(build.Status.Reason).To(BeNil())
Expect(build.Status.Message).To(BeNil())
})

It("should fail an empty key and invalid value", func() {
build := sampleBuild("", "invalidvalue!")
validate(build)
Expect(*build.Status.Reason).To(Equal(NodeSelectorNotValid))
Expect(*build.Status.Message).To(ContainSubstring("Node selector value not valid"))
})

It("should fail an invalid key and empty value", func() {
build := sampleBuild("invalidkey!", "")
validate(build)
Expect(*build.Status.Reason).To(Equal(NodeSelectorNotValid))
Expect(*build.Status.Message).To(ContainSubstring("Node selector key not valid"))
})

It("should fail both an invalid key and invalid value", func() {
build := sampleBuild("invalidkey!", "invalidvalue!")
validate(build)
Expect(*build.Status.Reason).To(Equal(NodeSelectorNotValid))
Expect(*build.Status.Message).To(ContainSubstring("Node selector key not valid"))
})
})
})
60 changes: 60 additions & 0 deletions pkg/validate/scheduler_name_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright The Shipwright Contributors
//
// SPDX-License-Identifier: Apache-2.0

package validate_test

import (
"context"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

corev1 "k8s.io/apimachinery/pkg/apis/meta/v1"

. "github.com/shipwright-io/build/pkg/apis/build/v1beta1"
"github.com/shipwright-io/build/pkg/validate"
)

var _ = Describe("ValidateSchedulerName", func() {
var ctx context.Context

BeforeEach(func() {
ctx = context.TODO()
})

var validate = func(build *Build) {
GinkgoHelper()

var validator = &validate.SchedulerNameRef{Build: build}
Expect(validator.ValidatePath(ctx)).To(Succeed())
}

var sampleBuild = func(schedulerName string) *Build {
return &Build{
ObjectMeta: corev1.ObjectMeta{
Namespace: "foo",
Name: "bar",
},
Spec: BuildSpec{
SchedulerName: schedulerName,
},
}
}

Context("when schedulerName is specified", func() {
It("should pass an empty name", func() {
build := sampleBuild("")
validate(build)
Expect(build.Status.Reason).To(BeNil())
Expect(build.Status.Message).To(BeNil())
})

It("should fail an invalid name", func() {
build := sampleBuild("invalidname!")
validate(build)
Expect(*build.Status.Reason).To(Equal(SchedulerNameNotValid))
Expect(*build.Status.Message).To(ContainSubstring("Scheduler name not valid"))
})
})
})
127 changes: 127 additions & 0 deletions pkg/validate/tolerations_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright The Shipwright Contributors
//
// SPDX-License-Identifier: Apache-2.0

package validate_test

import (
"context"
"fmt"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

v1 "k8s.io/api/core/v1"
corev1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/utils/ptr"

. "github.com/shipwright-io/build/pkg/apis/build/v1beta1"
"github.com/shipwright-io/build/pkg/validate"
)

var _ = Describe("ValidateTolerations", func() {
var ctx context.Context

BeforeEach(func() {
ctx = context.TODO()
})

var validate = func(build *Build) {
GinkgoHelper()

var validator = &validate.TolerationsRef{Build: build}
Expect(validator.ValidatePath(ctx)).To(Succeed())
}

var sampleBuild = func(toleration v1.Toleration) *Build {
return &Build{
ObjectMeta: corev1.ObjectMeta{
Namespace: "foo",
Name: "bar",
},
Spec: BuildSpec{
Tolerations: []v1.Toleration{toleration},
},
}
}

Context("when tolerations is specified", func() {
It("should fail an empty key and empty value", func() {
build := sampleBuild(v1.Toleration{Key: "", Value: "", Operator: v1.TolerationOpEqual, Effect: v1.TaintEffectNoSchedule})
validate(build)
Expect(*build.Status.Reason).To(Equal(TolerationNotValid))
Expect(*build.Status.Message).To(ContainSubstring(validation.EmptyError()))
})

It("should pass a valid key and valid value", func() {
build := sampleBuild(v1.Toleration{Key: "validkey", Value: "validvalue", Operator: v1.TolerationOpEqual, Effect: v1.TaintEffectNoSchedule})
validate(build)
Expect(build.Status.Reason).To(BeNil())
Expect(build.Status.Message).To(BeNil())
})

It("should pass a valid key and empty value", func() {
build := sampleBuild(v1.Toleration{Key: "validkey", Value: "", Operator: v1.TolerationOpEqual, Effect: v1.TaintEffectNoSchedule})
validate(build)
Expect(build.Status.Reason).To(BeNil())
Expect(build.Status.Message).To(BeNil())
})

It("should fail an invalid key and empty value", func() {
build := sampleBuild(v1.Toleration{Key: "invalidkey!", Value: "", Operator: v1.TolerationOpEqual, Effect: v1.TaintEffectNoSchedule})
validate(build)
Expect(*build.Status.Reason).To(Equal(TolerationNotValid))
Expect(*build.Status.Message).To(ContainSubstring("Toleration key not valid"))
})

It("should fail an invalid key and invalid value", func() {
build := sampleBuild(v1.Toleration{Key: "invalidkey!", Value: "invalidvalue!", Operator: v1.TolerationOpEqual, Effect: v1.TaintEffectNoSchedule})
validate(build)
Expect(*build.Status.Reason).To(Equal(TolerationNotValid))
Expect(*build.Status.Message).To(ContainSubstring("Toleration key not valid"))
})

It("should fail a valid key and invalid value", func() {
build := sampleBuild(v1.Toleration{Key: "validkey", Value: "invalidvalue!", Operator: v1.TolerationOpEqual, Effect: v1.TaintEffectNoSchedule})
validate(build)
Expect(*build.Status.Reason).To(Equal(TolerationNotValid))
Expect(*build.Status.Message).To(ContainSubstring("Toleration value not valid"))
})

It("should fail an invalid operator", func() {
build := sampleBuild(v1.Toleration{Key: "validkey", Value: "validvalue", Operator: "invalidoperator", Effect: v1.TaintEffectNoSchedule})
validate(build)
Expect(*build.Status.Reason).To(Equal(TolerationNotValid))
Expect(*build.Status.Message).To(ContainSubstring("Toleration operator not valid"))
})

It("should pass an empty taint effect", func() {
build := sampleBuild(v1.Toleration{Key: "validkey", Value: "validvalue", Operator: v1.TolerationOpEqual, Effect: ""})
validate(build)
Expect(build.Status.Reason).To(BeNil())
Expect(build.Status.Message).To(BeNil())
})

It("should pass a taint effect of NoSchedule", func() {
build := sampleBuild(v1.Toleration{Key: "validkey", Value: "validvalue", Operator: v1.TolerationOpEqual, Effect: v1.TaintEffectNoSchedule})
validate(build)
Expect(build.Status.Reason).To(BeNil())
Expect(build.Status.Message).To(BeNil())
})

It("should fail an invalid taint effect", func() {
build := sampleBuild(v1.Toleration{Key: "validkey", Value: "validvalue", Operator: v1.TolerationOpEqual, Effect: v1.TaintEffectNoExecute})
validate(build)
Expect(*build.Status.Reason).To(Equal(TolerationNotValid))
Expect(*build.Status.Message).To(ContainSubstring(fmt.Sprintf("Only the '%v' toleration effect is supported.", v1.TaintEffectNoSchedule)))
})

It("should fail specifying tolerationSeconds", func() {
build := sampleBuild(v1.Toleration{Key: "validkey", Value: "validvalue", Operator: v1.TolerationOpEqual, Effect: v1.TaintEffectNoSchedule, TolerationSeconds: ptr.To(int64(10))})
validate(build)
Expect(*build.Status.Reason).To(Equal(TolerationNotValid))
Expect(*build.Status.Message).To(ContainSubstring("Specifying TolerationSeconds is not supported"))
})
})
})
Loading

0 comments on commit f16ee49

Please sign in to comment.