diff --git a/test/clusterbuildstrategy_samples.go b/test/clusterbuildstrategy_samples.go index 2fffaf529..40e3d5ce5 100644 --- a/test/clusterbuildstrategy_samples.go +++ b/test/clusterbuildstrategy_samples.go @@ -111,3 +111,138 @@ spec: - name: buildah-images mountPath: /var/lib/containers/storage ` + +// ClusterBuildStrategySingleStepKaniko is a cluster build strategy based on +// Kaniko, which is very close to the actual Kaniko build strategy example in +// the project +const ClusterBuildStrategySingleStepKaniko = ` +apiVersion: build.dev/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: kaniko +spec: + buildSteps: + - name: step-build-and-push + image: gcr.io/kaniko-project/executor:v1.3.0 + workingDir: /workspace/source + securityContext: + runAsUser: 0 + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + - SETFCAP + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + command: + - /kaniko/executor + args: + - --skip-tls-verify=true + - --dockerfile=$(build.dockerfile) + - --context=/workspace/source/$(build.source.contextDir) + - --destination=$(build.output.image) + - --oci-layout-path=/workspace/output/image + - --snapshotMode=redo + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi +` + +// ClusterBuildStrategySingleStepKanikoError is a Kaniko based cluster build +// strategy that has a configuration error (misspelled command flag) so that +// it will fail in Tekton +const ClusterBuildStrategySingleStepKanikoError = ` +apiVersion: build.dev/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: kaniko +spec: + buildSteps: + - name: step-build-and-push + image: gcr.io/kaniko-project/executor:v1.3.0 + workingDir: /workspace/source + securityContext: + runAsUser: 0 + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + - SETFCAP + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + command: + - /kaniko/executor + args: + - --skips-tlss-verifys=true + - --dockerfile=$(build.dockerfile) + - --context=/workspace/source/$(build.source.contextDir) + - --destination=$(build.output.image) + - --oci-layout-path=/workspace/output/image + - --snapshotMode=redo + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi +` + +// ClusterBuildStrategyNoOp is a strategy that does nothing and has no dependencies +const ClusterBuildStrategyNoOp = ` +apiVersion: build.dev/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: noop +spec: + buildSteps: + - name: step-no-and-op + image: alpine:latest + workingDir: /workspace/source + securityContext: + runAsUser: 0 + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + - SETFCAP + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + command: + - "true" + resources: + limits: + cpu: 250m + memory: 128Mi + requests: + cpu: 250m + memory: 128Mi +` diff --git a/test/integration/buildruns_to_taskruns_test.go b/test/integration/buildruns_to_taskruns_test.go index a828b9f08..2ef36dcbc 100644 --- a/test/integration/buildruns_to_taskruns_test.go +++ b/test/integration/buildruns_to_taskruns_test.go @@ -5,14 +5,19 @@ package integration_test import ( + "context" "fmt" + "time" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "knative.dev/pkg/apis" "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" "github.com/shipwright-io/build/test" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/watch" + "knative.dev/pkg/apis" ) var _ = Describe("Integration tests BuildRuns and TaskRuns", func() { @@ -26,7 +31,7 @@ var _ = Describe("Integration tests BuildRuns and TaskRuns", func() { // Load the ClusterBuildStrategies before each test case BeforeEach(func() { - cbsObject, err = tb.Catalog.LoadCBSWithName(STRATEGY+tb.Namespace, []byte(test.ClusterBuildStrategySingleStep)) + cbsObject, err = tb.Catalog.LoadCBSWithName(STRATEGY+tb.Namespace, []byte(test.ClusterBuildStrategySingleStepKaniko)) Expect(err).To(BeNil()) err = tb.CreateClusterBuildStrategy(cbsObject) @@ -59,6 +64,174 @@ var _ = Describe("Integration tests BuildRuns and TaskRuns", func() { } }) + Context("when buildrun uses conditions", func() { + var setupBuildAndBuildRun = func(buildDef []byte, buildRunDef []byte, strategy ...string) (watch.Interface, *v1alpha1.Build, *v1alpha1.BuildRun) { + + var strategyName = STRATEGY + tb.Namespace + if len(strategy) > 0 { + strategyName = strategy[0] + } + + buildRunWitcher, err := tb.BuildClientSet.BuildV1alpha1().BuildRuns(tb.Namespace).Watch(context.TODO(), metav1.ListOptions{}) + Expect(err).To(BeNil()) + + buildObject, err = tb.Catalog.LoadBuildWithNameAndStrategy(BUILD+tb.Namespace, strategyName, buildDef) + Expect(err).To(BeNil()) + Expect(tb.CreateBuild(buildObject)).To(BeNil()) + + buildRunObject, err = tb.Catalog.LoadBRWithNameAndRef(BUILDRUN+tb.Namespace, BUILD+tb.Namespace, buildRunDef) + Expect(err).To(BeNil()) + Expect(tb.CreateBR(buildRunObject)).To(BeNil()) + + //TODO: consider how to deal with buildObject or buildRunObject + return buildRunWitcher, buildObject, buildRunObject + } + + var WithCustomClusterBuildStrategy = func(data []byte, f func()) { + customClusterBuildStrategy, err := tb.Catalog.LoadCBSWithName(STRATEGY+tb.Namespace+"custom", data) + Expect(err).To(BeNil()) + + Expect(tb.CreateClusterBuildStrategy(customClusterBuildStrategy)).To(BeNil()) + f() + Expect(tb.DeleteClusterBuildStrategy(customClusterBuildStrategy.Name)).To(BeNil()) + } + + Context("when condition status unknown", func() { + It("reflects a change from pending to running reason", func() { + buildRunWitcher, _, _ := setupBuildAndBuildRun([]byte(test.BuildCBSMinimal), []byte(test.MinimalBuildRun)) + + var timeout = time.After(tb.TimeOut) + go func() { + <-timeout + buildRunWitcher.Stop() + }() + + var seq = []*v1alpha1.Condition{} + for event := range buildRunWitcher.ResultChan() { + condition := event.Object.(*v1alpha1.BuildRun).Status.GetCondition(v1alpha1.Succeeded) + if condition != nil { + seq = append(seq, condition) + } + + // Pending -> Running + if condition != nil && condition.Reason == "Running" { + buildRunWitcher.Stop() + } + } + + Expect(len(seq)).To(Equal(2)) + Expect(seq[0].Type).To(Equal(v1alpha1.Succeeded)) + Expect(seq[0].Status).To(Equal(corev1.ConditionUnknown)) + Expect(seq[0].Reason).To(Equal("Pending")) + Expect(seq[1].Type).To(Equal(v1alpha1.Succeeded)) + Expect(seq[1].Reason).To(Equal("Running")) + }) + }) + + Context("when condition status is false", func() { + It("reflects a timeout", func() { + buildRunWitcher, build, buildRun := setupBuildAndBuildRun([]byte(test.BuildCBSWithShortTimeOut), []byte(test.MinimalBuildRun)) + + var timeout = time.After(tb.TimeOut) + go func() { + <-timeout + buildRunWitcher.Stop() + }() + + var seq = []*v1alpha1.Condition{} + for event := range buildRunWitcher.ResultChan() { + condition := event.Object.(*v1alpha1.BuildRun).Status.GetCondition(v1alpha1.Succeeded) + if condition != nil { + seq = append(seq, condition) + } + + // Pending -> Running + if condition != nil && condition.Status == corev1.ConditionFalse { + buildRunWitcher.Stop() + } + } + + lastIdx := len(seq) - 1 + Expect(lastIdx).To(BeNumerically(">", 0)) + Expect(seq[lastIdx].Type).To(Equal(v1alpha1.Succeeded)) + Expect(seq[lastIdx].Status).To(Equal(corev1.ConditionFalse)) + Expect(seq[lastIdx].Reason).To(Equal("BuildRunTimeout")) + Expect(seq[lastIdx].Message).To(Equal(fmt.Sprintf("BuildRun %s failed to finish within %v", buildRun.Name, build.Spec.Timeout.Duration))) + }) + + It("reflects a failed reason", func() { + WithCustomClusterBuildStrategy([]byte(test.ClusterBuildStrategySingleStepKanikoError), func() { + buildRunWitcher, _, buildRun := setupBuildAndBuildRun([]byte(test.BuildCBSMinimal), []byte(test.MinimalBuildRun), STRATEGY+tb.Namespace+"custom") + + var timeout = time.After(tb.TimeOut) + go func() { + <-timeout + buildRunWitcher.Stop() + }() + + var seq = []*v1alpha1.Condition{} + for event := range buildRunWitcher.ResultChan() { + condition := event.Object.(*v1alpha1.BuildRun).Status.GetCondition(v1alpha1.Succeeded) + if condition != nil { + seq = append(seq, condition) + } + + if condition != nil && condition.Status == corev1.ConditionFalse { + buildRunWitcher.Stop() + } + } + + buildRun, err = tb.GetBR(buildRun.Name) + Expect(err).ToNot(HaveOccurred()) + Expect(buildRun.Status.CompletionTime).ToNot(BeNil()) + + taskRun, err := tb.GetTaskRunFromBuildRun(buildRun.Name) + Expect(err).ToNot(HaveOccurred()) + + lastIdx := len(seq) - 1 + Expect(lastIdx).To(BeNumerically(">", 0)) + Expect(seq[lastIdx].Type).To(Equal(v1alpha1.Succeeded)) + Expect(seq[lastIdx].Status).To(Equal(corev1.ConditionFalse)) + Expect(seq[lastIdx].Reason).To(Equal("Failed")) + Expect(seq[lastIdx].Message).To(ContainSubstring("buildrun step failed in pod %s", taskRun.Status.PodName)) + }) + }) + }) + + Context("when condition status true", func() { + It("should reflect the taskrun succeeded reason in the buildrun condition", func() { + WithCustomClusterBuildStrategy([]byte(test.ClusterBuildStrategyNoOp), func() { + buildRunWitcher, _, _ := setupBuildAndBuildRun([]byte(test.BuildCBSMinimal), []byte(test.MinimalBuildRun), STRATEGY+tb.Namespace+"custom") + + var timeout = time.After(tb.TimeOut) + go func() { + <-timeout + buildRunWitcher.Stop() + }() + + var seq = []*v1alpha1.Condition{} + for event := range buildRunWitcher.ResultChan() { + condition := event.Object.(*v1alpha1.BuildRun).Status.GetCondition(v1alpha1.Succeeded) + if condition != nil { + seq = append(seq, condition) + } + + if condition != nil && condition.Status == corev1.ConditionTrue { + buildRunWitcher.Stop() + } + } + + lastIdx := len(seq) - 1 + Expect(lastIdx).To(BeNumerically(">", 0)) + Expect(seq[lastIdx].Type).To(Equal(v1alpha1.Succeeded)) + Expect(seq[lastIdx].Status).To(Equal(corev1.ConditionTrue)) + Expect(seq[lastIdx].Reason).To(Equal("Succeeded")) + Expect(seq[lastIdx].Message).To(ContainSubstring("All Steps have completed executing")) + }) + }) + }) + }) + Context("when a buildrun is created", func() { BeforeEach(func() {