Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhance(executor tests): Manage k8s mocks for Executor exec tests #431

Merged
merged 6 commits into from
Feb 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions executor/linux/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions executor/linux/secret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion runtime/kubernetes/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
wass3r marked this conversation as resolved.
Show resolved Hide resolved
c.PodTracker.TrackContainers(c.Pod.Spec.Containers)

// send signal to StreamBuild now that PodTracker is ready to be started.
Expand Down
33 changes: 32 additions & 1 deletion runtime/kubernetes/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}
Expand All @@ -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.
Expand All @@ -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.
//
Expand All @@ -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
}