diff --git a/executor/linux/build_test.go b/executor/linux/build_test.go index af0ad5d3..ce5934d4 100644 --- a/executor/linux/build_test.go +++ b/executor/linux/build_test.go @@ -1545,6 +1545,36 @@ func TestLinux_ExecBuild(t *testing.T) { if err != nil { t.Errorf("Kubernetes runtime SetupMock returned err: %v", err) } + + _runtime.(kubernetes.MockKubernetesRuntime).StartPodTracker(context.Background()) + + go func() { + _runtime.(kubernetes.MockKubernetesRuntime).SimulateResync(nil) + + var stepsRunningCount int + + percents := []int{0, 0, 50, 100} + lastIndex := len(percents) - 1 + for index, stepsCompletedPercent := range percents { + if index == 0 || index == lastIndex { + stepsRunningCount = 0 + } else { + stepsRunningCount = 1 + } + + err := _runtime.(kubernetes.MockKubernetesRuntime).SimulateStatusUpdate(_pod, + testContainerStatuses( + _pipeline, true, stepsRunningCount, stepsCompletedPercent, + ), + ) + if err != nil { + t.Errorf("%s - failed to simulate pod update: %s", test.name, err) + } + + // simulate exec build duration + time.Sleep(100 * time.Microsecond) + } + }() } err = _engine.ExecBuild(context.Background()) @@ -1910,6 +1940,9 @@ func TestLinux_StreamBuild(t *testing.T) { if err != nil { t.Errorf("Kubernetes runtime SetupMock returned err: %v", err) } + + // Runtime.StreamBuild calls PodTracker.Start after the PodTracker is marked Ready + _runtime.(kubernetes.MockKubernetesRuntime).MarkPodTrackerReady() } if test.earlyBuildDone { diff --git a/executor/linux/secret_test.go b/executor/linux/secret_test.go index 2891d6a7..0043872c 100644 --- a/executor/linux/secret_test.go +++ b/executor/linux/secret_test.go @@ -365,6 +365,8 @@ func TestLinux_Secret_exec(t *testing.T) { if err != nil { t.Errorf("Kubernetes runtime SetupMock returned err: %v", err) } + + go _runtime.(kubernetes.MockKubernetesRuntime).SimulateResync(nil) } err = _engine.secret.exec(context.Background(), &p.Secrets) diff --git a/runtime/kubernetes/build.go b/runtime/kubernetes/build.go index ad94681f..a72c3b24 100644 --- a/runtime/kubernetes/build.go +++ b/runtime/kubernetes/build.go @@ -212,7 +212,7 @@ func (c *client) AssembleBuild(ctx context.Context, b *pipeline.Build) error { } } - // setup containerTeachers now that all containers are defined. + // setup containerTrackers now that all containers are defined. c.PodTracker.TrackContainers(c.Pod.Spec.Containers) // send signal to StreamBuild now that PodTracker is ready to be started. diff --git a/runtime/kubernetes/mock.go b/runtime/kubernetes/mock.go index 077d52eb..6c2ec36f 100644 --- a/runtime/kubernetes/mock.go +++ b/runtime/kubernetes/mock.go @@ -8,6 +8,8 @@ package kubernetes // It is exported for use in tests of other packages. import ( + "context" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/fake" @@ -84,7 +86,8 @@ func NewMock(_pod *v1.Pod, opts ...ClientOpt) (*client, error) { c.PodTracker = tracker - // The test is responsible for calling c.PodTracker.Start() if needed + // The test is responsible for calling c.PodTracker.Start(ctx) if needed. + // In some cases it is more convenient to call c.(MockKubernetesRuntime).StartPodTracker(ctx) return c, nil } @@ -95,7 +98,9 @@ func NewMock(_pod *v1.Pod, opts ...ClientOpt) (*client, error) { type MockKubernetesRuntime interface { SetupMock() error MarkPodTrackerReady() + StartPodTracker(context.Context) SimulateResync(*v1.Pod) + SimulateStatusUpdate(*v1.Pod, []v1.ContainerStatus) error } // SetupMock allows the Kubernetes runtime to perform additional Mock-related config. @@ -114,6 +119,13 @@ func (c *client) MarkPodTrackerReady() { close(c.PodTracker.Ready) } +// StartPodTracker tells the podTracker it can start populating the cache. +// +// This function is intended for running tests only. +func (c *client) StartPodTracker(ctx context.Context) { + c.PodTracker.Start(ctx) +} + // 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. // @@ -129,3 +141,22 @@ func (c *client) SimulateResync(oldPod *v1.Pod) { // simulate a re-sync/PodUpdate event c.PodTracker.HandlePodUpdate(oldPod, c.Pod) } + +// SimulateUpdate simulates an update event from the k8s API. +// +// This function is intended for running tests only. +func (c *client) SimulateStatusUpdate(pod *v1.Pod, containerStatuses []v1.ContainerStatus) error { + // We have to have a full copy here because the k8s client Mock + // replaces the pod it is storing, it does not just update the status. + updatedPod := pod.DeepCopy() + updatedPod.Status.ContainerStatuses = containerStatuses + + _, err := c.Kubernetes.CoreV1().Pods(pod.GetNamespace()). + UpdateStatus( + context.Background(), + updatedPod, + metav1.UpdateOptions{}, + ) + + return err +}