Skip to content

Commit

Permalink
enhance(executor tests): Manage k8s mocks for Executor AssembleBuild …
Browse files Browse the repository at this point in the history
…test (#432)

* test: Fix kubernetes tests for executor AssembleBuild

Adds some new WaitForPod* test helpers.

* sort imports in runtime/kubernetes/kubernetes.go

* test: add pause to simulate step execution

* AssembleBuild test does not need to mark steps running
  • Loading branch information
cognifloyd authored Feb 27, 2023
1 parent a73da0f commit 95f4223
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 3 deletions.
27 changes: 25 additions & 2 deletions executor/linux/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1305,8 +1305,7 @@ func TestLinux_AssembleBuild(t *testing.T) {

switch test.runtime {
case constants.DriverKubernetes:
_pod := testPodFor(_pipeline)
_runtime, err = kubernetes.NewMock(_pod)
_runtime, err = kubernetes.NewMock(&v1.Pod{}) // do not use _pod here! AssembleBuild will load it.
if err != nil {
t.Errorf("unable to create kubernetes runtime engine: %v", err)
}
Expand Down Expand Up @@ -1337,6 +1336,30 @@ func TestLinux_AssembleBuild(t *testing.T) {
t.Errorf("unable to create build: %v", err)
}

// Kubernetes runtime needs to set up the Mock after CreateBuild is called
if test.runtime == constants.DriverKubernetes {
go func() {
_mockRuntime := _runtime.(kubernetes.MockKubernetesRuntime)
// This handles waiting until runtime.AssembleBuild has prepared the PodTracker.
_mockRuntime.WaitForPodTrackerReady()
// Normally, runtime.StreamBuild (which runs in a goroutine) calls PodTracker.Start.
_mockRuntime.StartPodTracker(context.Background())

_pod := testPodFor(_pipeline)

// Now wait until the pod is created at the end of runtime.AssembleBuild.
_mockRuntime.WaitForPodCreate(_pod.GetNamespace(), _pod.GetName())

// Mark services running and secrets as completed, but no steps have started.
err := _mockRuntime.SimulateStatusUpdate(_pod,
testContainerStatuses(_pipeline, true, 0, 0),
)
if err != nil {
t.Errorf("%s - failed to simulate pod update: %s", test.name, err)
}
}()
}

err = _engine.AssembleBuild(context.Background())

if test.failure {
Expand Down
2 changes: 1 addition & 1 deletion runtime/kubernetes/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
package kubernetes

import (
"github.com/sirupsen/logrus"
v1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"

velav1alpha1 "github.com/go-vela/worker/runtime/kubernetes/apis/vela/v1alpha1"
velaK8sClient "github.com/go-vela/worker/runtime/kubernetes/generated/clientset/versioned"
"github.com/sirupsen/logrus"
)

type config struct {
Expand Down
44 changes: 44 additions & 0 deletions runtime/kubernetes/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/tools/cache"

velav1alpha1 "github.com/go-vela/worker/runtime/kubernetes/apis/vela/v1alpha1"
fakeVelaK8sClient "github.com/go-vela/worker/runtime/kubernetes/generated/clientset/versioned/fake"
Expand Down Expand Up @@ -99,6 +100,8 @@ type MockKubernetesRuntime interface {
SetupMock() error
MarkPodTrackerReady()
StartPodTracker(context.Context)
WaitForPodTrackerReady()
WaitForPodCreate(string, string)
SimulateResync(*v1.Pod)
SimulateStatusUpdate(*v1.Pod, []v1.ContainerStatus) error
}
Expand Down Expand Up @@ -126,6 +129,47 @@ func (c *client) StartPodTracker(ctx context.Context) {
c.PodTracker.Start(ctx)
}

// WaitForPodTrackerReady waits for PodTracker.Ready to be closed (which happens in AssembleBuild).
//
// This function is intended for running tests only.
func (c *client) WaitForPodTrackerReady() {
<-c.PodTracker.Ready
}

// WaitForPodCreate waits for PodTracker.Ready to be closed (which happens in AssembleBuild).
//
// This function is intended for running tests only.
func (c *client) WaitForPodCreate(namespace, name string) {
created := make(chan struct{})

c.PodTracker.podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
select {
case <-created:
// not interested in any other create events.
return
default:
break
}

var (
pod *v1.Pod
ok bool
)

if pod, ok = obj.(*v1.Pod); !ok {
return
}

if pod.GetNamespace() == namespace && pod.GetName() == name {
close(created)
}
},
})

<-created
}

// SimulateResync simulates an resync where the PodTracker refreshes its cache.
// This resync is from oldPod to runtime.Pod. If nil, oldPod defaults to runtime.Pod.
//
Expand Down

0 comments on commit 95f4223

Please sign in to comment.