Skip to content

Commit

Permalink
Adds e2e tests for oci tekton cache
Browse files Browse the repository at this point in the history
Signed-off-by: PuneetPunamiya <[email protected]>
  • Loading branch information
PuneetPunamiya committed Oct 17, 2024
1 parent 028702e commit 83cc28f
Show file tree
Hide file tree
Showing 6 changed files with 348 additions and 88 deletions.
21 changes: 21 additions & 0 deletions tests/client/setup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package client

import (
"testing"

tektonv1client "github.com/tektoncd/pipeline/pkg/client/clientset/versioned/typed/pipeline/v1"
"k8s.io/client-go/tools/clientcmd"
)

func TektonClient(t *testing.T) *tektonv1client.TektonV1Client {
t.Helper()

rules := clientcmd.NewDefaultClientConfigLoadingRules()
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(rules, &clientcmd.ConfigOverrides{})
config, err := clientConfig.ClientConfig()
if err != nil {
t.Fatalf("Error creating client config: %v", err)
}

return tektonv1client.NewForConfigOrDie(config)
}
92 changes: 7 additions & 85 deletions tests/e2e_gcs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,95 +5,17 @@ package tests

import (
"context"
"fmt"
"log"
"os"
"testing"
"time"

"github.com/openshift-pipelines/tekton-caches/tests/client"
"github.com/openshift-pipelines/tekton-caches/tests/resources"
tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
tektonv1client "github.com/tektoncd/pipeline/pkg/client/clientset/versioned/typed/pipeline/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/clientcmd"

"sigs.k8s.io/yaml"

corev1 "k8s.io/api/core/v1"
"knative.dev/pkg/apis"
)

// ConditionAccessorFn is a condition function used polling functions.
type ConditionAccessorFn func(ca apis.ConditionAccessor) (bool, error)

const (
defaultNamespace = "default"
waitInterval = 10 * time.Minute
tickerDuration = 10 * time.Second
)

var deletePolicy = metav1.DeletePropagationForeground

func tektonClient(t *testing.T) *tektonv1client.TektonV1Client {
t.Helper()

rules := clientcmd.NewDefaultClientConfigLoadingRules()
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(rules, &clientcmd.ConfigOverrides{})
config, err := clientConfig.ClientConfig()
if err != nil {
t.Fatalf("Error creating client config: %v", err)
}

return tektonv1client.NewForConfigOrDie(config)
}

// Succeed provides a poll condition function that checks if the ConditionAccessor
// resource has successfully completed or not.
func Succeed(name string) ConditionAccessorFn {
return func(ca apis.ConditionAccessor) (bool, error) {
c := ca.GetCondition(apis.ConditionSucceeded)
if c != nil {
if c.Status == corev1.ConditionTrue {
return true, nil
} else if c.Status == corev1.ConditionFalse {
return true, fmt.Errorf("%q failed", name)
}
}
return false, nil
}
}

func waitForPipelineRun(ctx context.Context, tc *tektonv1client.TektonV1Client, pr *tektonv1.PipelineRun, cond ConditionAccessorFn, duration time.Duration) error {
ticker := time.NewTicker(tickerDuration)
defer ticker.Stop()
stop := make(chan bool)
done := func() {
stop <- true
}
go func() {
time.Sleep(duration)
done()
}()
for {
select {
case <-stop:
return fmt.Errorf("timeout waiting for PipelineRun %s to complete", pr.Name)
case <-ticker.C:
pr, err := tc.PipelineRuns(defaultNamespace).Get(ctx, pr.Name, metav1.GetOptions{})
if err != nil {
return err
}
log.Printf("PipelineRun %s is %v", pr.Name, pr.Status.GetCondition(apis.ConditionSucceeded))
if val, err := cond(&pr.Status); val && err != nil {
go done()
return fmt.Errorf("PipelineRun %s failed: %s", pr.Name, err.Error())
} else if !val {
continue
}
return nil
}
}
}

func TestCacheGCS(t *testing.T) {
ctx := context.Background()
pr := new(tektonv1.PipelineRun)
Expand All @@ -105,17 +27,17 @@ func TestCacheGCS(t *testing.T) {
t.Fatalf("Error unmarshalling: %v", err)
}

tc := tektonClient(t)
tc := client.TektonClient(t)

_ = tc.PipelineRuns(defaultNamespace).Delete(ctx, pr.GetName(), metav1.DeleteOptions{
PropagationPolicy: &deletePolicy,
_ = tc.PipelineRuns(resources.DefaultNamespace).Delete(ctx, pr.GetName(), metav1.DeleteOptions{
PropagationPolicy: &resources.DeletePolicy,
})

if _, err = tc.PipelineRuns(defaultNamespace).Create(ctx, pr, metav1.CreateOptions{}); err != nil {
if _, err = tc.PipelineRuns(resources.DefaultNamespace).Create(ctx, pr, metav1.CreateOptions{}); err != nil {
t.Fatalf("Error creating PipelineRun: %v", err)
}

if err := waitForPipelineRun(ctx, tc, pr, Succeed(pr.Name), waitInterval); err != nil {
if err := resources.WaitForPipelineRun(ctx, tc, pr, resources.Succeed(pr.Name), resources.WaitInterval); err != nil {
t.Fatalf("Error waiting for PipelineRun to complete: %v", err)
}
}
73 changes: 70 additions & 3 deletions tests/oci_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
//go:build e2e
// +build e2e

package tests

import (
Expand All @@ -12,9 +9,14 @@ import (
"github.com/openshift-pipelines/tekton-caches/internal/fetch"
"github.com/openshift-pipelines/tekton-caches/internal/hash"
"github.com/openshift-pipelines/tekton-caches/internal/upload"
"github.com/openshift-pipelines/tekton-caches/tests/client"
"github.com/openshift-pipelines/tekton-caches/tests/resources"
tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
"gotest.tools/v3/assert"
"gotest.tools/v3/env"
"gotest.tools/v3/fs"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"
)

const (
Expand All @@ -41,3 +43,68 @@ func TestOCIUpload(t *testing.T) {
assert.NilError(t, fetch.Fetch(ctx, hash, regTarget, tmpdir.Path(), false))
assert.NilError(t, fetch.Fetch(ctx, "unknown", regTarget, tmpdir.Path(), false)) // should not error on unknown hash
}

func TestCacheOCI(t *testing.T) {
ctx := context.Background()
p := new(tektonv1.Pipeline)
pr := new(tektonv1.PipelineRun)

// Get the pipeline yaml
pipeline, err := os.ReadFile("test-pipelineruns/test-pipeline-oci.yaml")
if err != nil {
t.Fatalf("Error reading file: %v", err)
}
if err := yaml.UnmarshalStrict(pipeline, p); err != nil {
t.Fatalf("Error unmarshalling: %v", err)
}

// Get the pipelineRun yaml
pipelineRun, err := os.ReadFile("test-pipelineruns/test-pipelinerun-oci.yaml")
if err != nil {
t.Fatalf("Error reading file: %v", err)
}
if err := yaml.UnmarshalStrict(pipelineRun, pr); err != nil {
t.Fatalf("Error unmarshalling: %v", err)
}

tc := client.TektonClient(t)

// Install the pipeline example
if _, err := tc.Pipelines(resources.DefaultNamespace).Create(ctx, p, metav1.CreateOptions{}); err != nil {
t.Fatalf("Error creating Pipeline: %v", err)
}

_ = tc.PipelineRuns(resources.DefaultNamespace).Delete(ctx, pr.GetName(), metav1.DeleteOptions{
PropagationPolicy: &resources.DeletePolicy,
})

// Install the pipelineRun example
if _, err = tc.PipelineRuns(resources.DefaultNamespace).Create(ctx, pr, metav1.CreateOptions{}); err != nil {
t.Fatalf("Error creating PipelineRun: %v", err)
}

if err := resources.WaitForPipelineRun(ctx, tc, pr, resources.Succeed(pr.Name), resources.WaitInterval); err != nil {
t.Fatalf("Error waiting for PipelineRun to complete: %v", err)
}

// Get the taskrun
tr, err := tc.TaskRuns(resources.DefaultNamespace).Get(ctx, "pipelinerun-oci-test-build-task", metav1.GetOptions{})
if err != nil {
t.Fatalf("Error creating PipelineRun: %v", err)
}

// Assert the result which was produced by stepAction and stored as result in taskrun
assert.Equal(t, tr.Status.Results[0].Value.StringVal, "true")

// Delete the pipelinerun
err = tc.PipelineRuns(resources.DefaultNamespace).Delete(ctx, pr.GetName(), metav1.DeleteOptions{})
if err != nil {
t.Fatalf("Error deleting pipelinerun")
}

// Delete the pipeline
err = tc.Pipelines(resources.DefaultNamespace).Delete(ctx, p.GetName(), metav1.DeleteOptions{})
if err != nil {
t.Fatalf("Error deleting pipelinerun")
}
}
74 changes: 74 additions & 0 deletions tests/resources/pipelines.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package resources

import (
"context"
"fmt"
"log"
"time"

tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
tektonv1client "github.com/tektoncd/pipeline/pkg/client/clientset/versioned/typed/pipeline/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

corev1 "k8s.io/api/core/v1"
"knative.dev/pkg/apis"
)

// ConditionAccessorFn is a condition function used polling functions.
type ConditionAccessorFn func(ca apis.ConditionAccessor) (bool, error)

const (
DefaultNamespace = "default"
WaitInterval = 10 * time.Minute
TickerDuration = 10 * time.Second
)

var DeletePolicy = metav1.DeletePropagationForeground

// Succeed provides a poll condition function that checks if the ConditionAccessor
// resource has successfully completed or not.
func Succeed(name string) ConditionAccessorFn {
return func(ca apis.ConditionAccessor) (bool, error) {
c := ca.GetCondition(apis.ConditionSucceeded)
if c != nil {
if c.Status == corev1.ConditionTrue {
return true, nil
} else if c.Status == corev1.ConditionFalse {
return true, fmt.Errorf("%q failed", name)
}
}
return false, nil
}
}

func WaitForPipelineRun(ctx context.Context, tc *tektonv1client.TektonV1Client, pr *tektonv1.PipelineRun, cond ConditionAccessorFn, duration time.Duration) error {
ticker := time.NewTicker(TickerDuration)
defer ticker.Stop()
stop := make(chan bool)
done := func() {
stop <- true
}
go func() {
time.Sleep(duration)
done()
}()
for {
select {
case <-stop:
return fmt.Errorf("timeout waiting for PipelineRun %s to complete", pr.Name)
case <-ticker.C:
pr, err := tc.PipelineRuns(DefaultNamespace).Get(ctx, pr.Name, metav1.GetOptions{})
if err != nil {
return err
}
log.Printf("PipelineRun %s is %v", pr.Name, pr.Status.GetCondition(apis.ConditionSucceeded))
if val, err := cond(&pr.Status); val && err != nil {
go done()
return fmt.Errorf("PipelineRun %s failed: %s", pr.Name, err.Error())
} else if !val {
continue
}
return nil
}
}
}
Loading

0 comments on commit 83cc28f

Please sign in to comment.