Skip to content

Commit

Permalink
Ensure proper code coverage
Browse files Browse the repository at this point in the history
This add new unit-tests to ensure a decent code coverage
for all the different classes under the resource pkg of
buildrun.
  • Loading branch information
qu1queee committed Feb 22, 2021
1 parent 2c071cd commit 015745d
Show file tree
Hide file tree
Showing 12 changed files with 518 additions and 15 deletions.
5 changes: 0 additions & 5 deletions pkg/reconciler/buildrun/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,6 @@ import (
"github.com/shipwright-io/build/pkg/ctxlog"
)

/**
* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller
* business logic. Delete these comments after modifying this file.*
*/

type setOwnerReferenceFunc func(owner, object metav1.Object, scheme *runtime.Scheme) error

// Add creates a new BuildRun Controller and adds it to the Manager. The Manager will set fields on the Controller
Expand Down
5 changes: 1 addition & 4 deletions pkg/reconciler/buildrun/resources/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@ import (

// GetBuildObject retrieves an existing Build based on a name and namespace
func GetBuildObject(ctx context.Context, client client.Client, objectName string, objectNS string, build *buildv1alpha1.Build) error {
if err := client.Get(ctx, types.NamespacedName{Name: objectName, Namespace: objectNS}, build); err != nil {
return err
}
return nil
return client.Get(ctx, types.NamespacedName{Name: objectName, Namespace: objectNS}, build)
}

// IsOwnedByBuild checks if the controllerReferences contains a well known owner Kind
Expand Down
118 changes: 118 additions & 0 deletions pkg/reconciler/buildrun/resources/build_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright The Shipwright Contributors
//
// SPDX-License-Identifier: Apache-2.0

package resources_test

import (
"context"
"errors"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
build "github.com/shipwright-io/build/pkg/apis/build/v1alpha1"
"github.com/shipwright-io/build/pkg/controller/fakes"
"github.com/shipwright-io/build/pkg/reconciler/buildrun/resources"
"github.com/shipwright-io/build/test"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
)

var _ = Describe("Build Resource", func() {

var (
client *fakes.FakeClient
ctl test.Catalog
buildName string
)

Context("Operating on Build resources", func() {
// init vars
buildName = "foobuild"
client = &fakes.FakeClient{}

It("should be able to retrieve a build object if exists", func() {
buildSample := ctl.DefaultBuild(buildName, "foostrategy", build.ClusterBuildStrategyKind)

// stub a GET API call with buildSample contents
getClientStub := func(context context.Context, nn types.NamespacedName, object runtime.Object) error {
switch object := object.(type) {
case *build.Build:
buildSample.DeepCopyInto(object)
return nil
}
return k8serrors.NewNotFound(schema.GroupResource{}, nn.Name)
}

// fake the calls with the above stub definition
client.GetCalls(getClientStub)

build := &build.Build{}
Expect(resources.GetBuildObject(context.TODO(), client, buildName, "default", build)).To(BeNil())
})
It("should not retrieve a missing build object when missing", func() {
// stub a GET API call with buildSample contents that returns "not found"
getClientStub := func(context context.Context, nn types.NamespacedName, object runtime.Object) error {
switch object.(type) {
case *build.Build:
return errors.New("not found")
}
return k8serrors.NewNotFound(schema.GroupResource{}, nn.Name)
}
// fake the calls with the above stub
client.GetCalls(getClientStub)

build := &build.Build{}
Expect(resources.GetBuildObject(context.TODO(), client, buildName, "default", build)).ToNot(BeNil())
})
It("should be able to verify valid ownerships", func() {
managingController := true

buildSample := &build.Build{
TypeMeta: metav1.TypeMeta{
Kind: "fakekind",
},
ObjectMeta: metav1.ObjectMeta{
Name: buildName,
},
}
// fake an instance of OwnerReference with a
// well known fake Kind and Name
fakeOwnerRef := []metav1.OwnerReference{
{
Kind: "fakekind",
Name: buildName,
Controller: &managingController,
},
}
// Assert that our Build is owned by an owner
Expect(resources.IsOwnedByBuild(buildSample, fakeOwnerRef)).To(BeTrue())
})
It("should be able to verify invalid ownerships", func() {
managingController := true

buildSample := &build.Build{
TypeMeta: metav1.TypeMeta{
Kind: "notthatkind",
},
ObjectMeta: metav1.ObjectMeta{
Name: buildName,
},
}
// fake an instance of OwnerReference with a
// well known fake Kind and Name
fakeOwnerRef := []metav1.OwnerReference{
{
Kind: "fakekind",
Name: buildName,
Controller: &managingController,
},
}
// Assert that our Build is not owned by an owner
Expect(resources.IsOwnedByBuild(buildSample, fakeOwnerRef)).To(BeFalse())
})
})
})
2 changes: 1 addition & 1 deletion pkg/reconciler/buildrun/resources/conditions.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func UpdateBuildRunUsingTaskRunCondition(ctx context.Context, client client.Clie
case v1beta1.TaskRunReasonTimedOut:
reason = "BuildRunTimeout"
message = fmt.Sprintf("BuildRun %s failed to finish within %s",
taskRun.GetLabels()[buildv1alpha1.LabelBuildRun],
buildRun.Name,
taskRun.Spec.Timeout.Duration,
)

Expand Down
162 changes: 162 additions & 0 deletions pkg/reconciler/buildrun/resources/conditions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,22 @@
package resources_test

import (
"context"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
build "github.com/shipwright-io/build/pkg/apis/build/v1alpha1"
"github.com/shipwright-io/build/pkg/controller/fakes"
"github.com/shipwright-io/build/pkg/reconciler/buildrun/resources"
"github.com/shipwright-io/build/test"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"knative.dev/pkg/apis"
)

var _ = Describe("Conditions", func() {
Expand Down Expand Up @@ -101,5 +111,157 @@ var _ = Describe("Conditions", func() {
condMsg := br.Status.GetCondition(build.Succeeded).GetMessage()
Expect(condMsg).To(Equal("foobar was updated"))
})

})
Context("Operating with TaskRun Conditions", func() {
var (
client *fakes.FakeClient
ctl test.Catalog
br *build.BuildRun
tr *v1beta1.TaskRun
)

tr = ctl.TaskRunWithStatus("foo", "bar")
br = ctl.DefaultBuildRun("foo", "bar")
client = &fakes.FakeClient{}

It("updates BuildRun condition when TaskRun timeout", func() {

fakeTRCondition := &apis.Condition{
Type: apis.ConditionSucceeded,
Reason: "TaskRunTimeout",
Message: "not relevant",
}

Expect(resources.UpdateBuildRunUsingTaskRunCondition(
context.TODO(),
client,
br,
tr,
fakeTRCondition,
)).To(BeNil())
})

It("updates BuildRun condition when TaskRun fails and pod not found", func() {

// stub a GET API call that fails with not found
getClientStub := func(context context.Context, nn types.NamespacedName, object runtime.Object) error {
switch object.(type) {
case *corev1.Pod:
return k8serrors.NewNotFound(schema.GroupResource{}, nn.Name)
}
return k8serrors.NewNotFound(schema.GroupResource{}, nn.Name)
}
// fake the calls with the above stub
client.GetCalls(getClientStub)

fakeTRCondition := &apis.Condition{
Type: apis.ConditionSucceeded,
Reason: "Failed",
Message: "not relevant",
}

Expect(resources.UpdateBuildRunUsingTaskRunCondition(
context.TODO(),
client,
br,
tr,
fakeTRCondition,
)).To(BeNil())
})

It("updates a BuildRun condition when the related TaskRun fails and pod containers are available", func() {

// generate a pod that have a single container and
// one entry in the ContainerStatuses field, with
// an exitCode
taskRunGeneratedPod := corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "foopod",
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "foobar-container",
},
},
},
Status: corev1.PodStatus{
ContainerStatuses: []corev1.ContainerStatus{
{
Name: "foobar-container",
State: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{
Reason: "foobar",
ExitCode: 1,
},
},
},
},
},
}

// stub a GET API call with taskRunGeneratedPod
getClientStub := func(context context.Context, nn types.NamespacedName, object runtime.Object) error {
switch object := object.(type) {
case *corev1.Pod:
taskRunGeneratedPod.DeepCopyInto(object)
return nil
}
return k8serrors.NewNotFound(schema.GroupResource{}, nn.Name)
}

// fake the calls with the above stub
client.GetCalls(getClientStub)

fakeTRCondition := &apis.Condition{
Type: apis.ConditionSucceeded,
Reason: "Failed",
Message: "not relevant",
}

Expect(resources.UpdateBuildRunUsingTaskRunCondition(
context.TODO(),
client,
br,
tr,
fakeTRCondition,
)).To(BeNil())
})

It("updates a BuildRun condition when the related TaskRun fails and pod containers are not available", func() {

taskRunGeneratedPod := corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "foobar",
},
}

// stub a GET API call with the above taskRunGeneratedPod spec
getClientStub := func(context context.Context, nn types.NamespacedName, object runtime.Object) error {
switch object := object.(type) {
case *corev1.Pod:
taskRunGeneratedPod.DeepCopyInto(object)
return nil
}
return k8serrors.NewNotFound(schema.GroupResource{}, nn.Name)
}
// fake the calls with the above stub
client.GetCalls(getClientStub)

fakeTRCondition := &apis.Condition{
Type: apis.ConditionSucceeded,
Reason: "Failed",
Message: "not relevant",
}

Expect(resources.UpdateBuildRunUsingTaskRunCondition(
context.TODO(),
client,
br,
tr,
fakeTRCondition,
)).To(BeNil())
})
})
})
26 changes: 26 additions & 0 deletions pkg/reconciler/buildrun/resources/errors_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright The Shipwright Contributors
//
// SPDX-License-Identifier: Apache-2.0

package resources_test

import (
"errors"
"fmt"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/shipwright-io/build/pkg/reconciler/buildrun/resources"
)

var _ = Describe("Multiple errors", func() {
Context("Dealing with multiple errors", func() {
It("should handle multiple errors", func() {
error01 := errors.New("error01")
error02 := errors.New("error02")
msg := "handling multiple errors"
customError := resources.HandleError(msg, error01, error02)
Expect(customError).To(Equal(fmt.Errorf("errors: %s, %s, msg: %s", error01, error02, msg)))
})
})
})
3 changes: 3 additions & 0 deletions pkg/reconciler/buildrun/resources/resources_suite_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Copyright The Shipwright Contributors
//
// SPDX-License-Identifier: Apache-2.0
package resources_test

import (
Expand Down
4 changes: 3 additions & 1 deletion pkg/reconciler/buildrun/resources/service_accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ func IsGeneratedServiceAccountUsed(buildRun *buildv1alpha1.BuildRun) bool {
return buildRun.Spec.ServiceAccount != nil && buildRun.Spec.ServiceAccount.Generate
}

// RetrieveServiceAccount ...
// RetrieveServiceAccount provides either a default sa with a referenced secret or it will generate a new sa on the fly.
// When not using the generate feature, it will modify and return the default sa from a k8s namespace, which is "default"
// or the default sa inside an openshift namespace, which is "pipeline".
func RetrieveServiceAccount(ctx context.Context, client client.Client, build *buildv1alpha1.Build, buildRun *buildv1alpha1.BuildRun) (*corev1.ServiceAccount, error) {
serviceAccount := &corev1.ServiceAccount{}

Expand Down
Loading

0 comments on commit 015745d

Please sign in to comment.