mirror of https://github.com/knative/func.git
test: integration test for tekton on cluster build (#1789)
* test: integration tests for Tekton builds Signed-off-by: Matej Vasek <mvasek@redhat.com> * fixup: disable s2i integration test for now Signed-off-by: Matej Vasek <mvasek@redhat.com> --------- Signed-off-by: Matej Vasek <mvasek@redhat.com>
This commit is contained in:
parent
5034bd31d2
commit
6b97fb5a3c
|
@ -24,10 +24,13 @@ jobs:
|
|||
run: ./hack/registry.sh
|
||||
- name: Allocate Cluster
|
||||
run: ./hack/allocate.sh
|
||||
- name: Patch S2I Task
|
||||
run: ./hack/patch-s2i-task.sh
|
||||
- name: Install Tekton
|
||||
run: ./hack/tekton.sh
|
||||
- name: Set up environment variables
|
||||
run: |
|
||||
echo "TEKTON_TESTS_ENABLED=1" >> "$GITHUB_ENV"
|
||||
echo "GITLAB_TESTS_ENABLED=1" >> "$GITHUB_ENV"
|
||||
echo "GITLAB_HOSTNAME=gitlab.127.0.0.1.sslip.io" >> "$GITHUB_ENV"
|
||||
echo "GITLAB_ROOT_PASSWORD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32})" >> "$GITHUB_ENV"
|
||||
|
|
|
@ -71,6 +71,8 @@ containerdConfigPatches:
|
|||
- |-
|
||||
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:50000"]
|
||||
endpoint = ["http://func-registry:5000"]
|
||||
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.default.svc.cluster.local:5000"]
|
||||
endpoint = ["http://func-registry:5000"]
|
||||
EOF
|
||||
sleep 10
|
||||
kubectl wait pod --for=condition=Ready -l '!job-name' -n kube-system --timeout=5m
|
||||
|
@ -206,6 +208,19 @@ data:
|
|||
host: "localhost:50000"
|
||||
help: "https://kind.sigs.k8s.io/docs/user/local-registry/"
|
||||
EOF
|
||||
|
||||
# Make the registry available in cluster under registry.default.svc.cluster.local:5000.
|
||||
# This is useful since for "*.local" registries HTTP (not HTTPS) is used by default by some applications.
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: registry
|
||||
namespace: default
|
||||
spec:
|
||||
type: ExternalName
|
||||
externalName: func-registry
|
||||
EOF
|
||||
}
|
||||
|
||||
namespace() {
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# This script patches the s2i Tekton task, so it recognizes registry.default.svc.cluster.local:5000 as insecure.
|
||||
|
||||
echo "Patching s2i Tekton task to use 'registry.default.svc.cluster.local:5000' as an insecure registry."
|
||||
|
||||
patch pkg/pipelines/resources/tekton/task/func-s2i/0.1/func-s2i.yaml <<EOF
|
||||
diff --git a/pkg/pipelines/resources/tekton/task/func-s2i/0.1/func-s2i.yaml b/pkg/pipelines/resources/tekton/task/func-s2i/0.1/func-s2i.yaml
|
||||
index a6973d70..f2bdb5d6 100644
|
||||
--- a/pkg/pipelines/resources/tekton/task/func-s2i/0.1/func-s2i.yaml
|
||||
+++ b/pkg/pipelines/resources/tekton/task/func-s2i/0.1/func-s2i.yaml
|
||||
@@ -102,6 +102,8 @@ spec:
|
||||
image: quay.io/buildah/stable:v1.27.0
|
||||
workingDir: /gen-source
|
||||
script: |
|
||||
+ export BUILD_REGISTRY_SOURCES='{"insecureRegistries": ["registry.default.svc.cluster.local:5000"]}'
|
||||
+
|
||||
TLS_VERIFY_FLAG=""
|
||||
if [ "\$(params.TLSVERIFY)" = "false" ] || [ "\$(params.TLSVERIFY)" = "0" ]; then
|
||||
TLS_VERIFY_FLAG="--tls-verify=false"
|
||||
EOF
|
|
@ -102,15 +102,20 @@ spec:
|
|||
image: quay.io/buildah/stable:v1.27.0
|
||||
workingDir: /gen-source
|
||||
script: |
|
||||
TLS_VERIFY_FLAG=""
|
||||
if [ "$(params.TLSVERIFY)" = "false" ] || [ "$(params.TLSVERIFY)" = "0" ]; then
|
||||
TLS_VERIFY_FLAG="--tls-verify=false"
|
||||
fi
|
||||
|
||||
[[ "$(workspaces.sslcertdir.bound)" == "true" ]] && CERT_DIR_FLAG="--cert-dir $(workspaces.sslcertdir.path)"
|
||||
ARTIFACTS_CACHE_PATH="$(workspaces.cache.path)/mvn-artifacts"
|
||||
[ -d "${ARTIFACTS_CACHE_PATH}" ] || mkdir "${ARTIFACTS_CACHE_PATH}"
|
||||
buildah ${CERT_DIR_FLAG} bud --storage-driver=vfs --tls-verify=$(params.TLSVERIFY) --layers \
|
||||
buildah ${CERT_DIR_FLAG} bud --storage-driver=vfs ${TLS_VERIFY_FLAG} --layers \
|
||||
-v "${ARTIFACTS_CACHE_PATH}:/tmp/artifacts/:rw,z,U" \
|
||||
-f /gen-source/Dockerfile.gen -t $(params.IMAGE) .
|
||||
|
||||
[[ "$(workspaces.dockerconfig.bound)" == "true" ]] && export DOCKER_CONFIG="$(workspaces.dockerconfig.path)"
|
||||
buildah ${CERT_DIR_FLAG} push --storage-driver=vfs --tls-verify=$(params.TLSVERIFY) --digestfile $(workspaces.source.path)/image-digest \
|
||||
buildah ${CERT_DIR_FLAG} push --storage-driver=vfs ${TLS_VERIFY_FLAG} --digestfile $(workspaces.source.path)/image-digest \
|
||||
$(params.IMAGE) docker://$(params.IMAGE)
|
||||
|
||||
cat $(workspaces.source.path)/image-digest | tee /tekton/results/IMAGE_DIGEST
|
||||
|
|
|
@ -0,0 +1,228 @@
|
|||
//go:build integration
|
||||
// +build integration
|
||||
|
||||
package tekton_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"knative.dev/func/pkg/docker"
|
||||
fn "knative.dev/func/pkg/functions"
|
||||
"knative.dev/func/pkg/pipelines/tekton"
|
||||
"knative.dev/func/pkg/random"
|
||||
)
|
||||
|
||||
func TestOnClusterBuild(t *testing.T) {
|
||||
checkTestEnabled(t)
|
||||
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||
defer cancel()
|
||||
|
||||
ns := "default"
|
||||
|
||||
credentialsProvider := func(ctx context.Context, image string) (docker.Credentials, error) {
|
||||
return docker.Credentials{
|
||||
Username: "",
|
||||
Password: "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
Builder string
|
||||
}{
|
||||
{Builder: "s2i"},
|
||||
{Builder: "pack"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.Builder, func(t *testing.T) {
|
||||
if test.Builder == "s2i" {
|
||||
t.Skip("Skipping because this causes 'no space left on device' in GH Action.")
|
||||
}
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
urlChan := make(chan string, 1)
|
||||
|
||||
pp := tekton.NewPipelinesProvider(
|
||||
tekton.WithCredentialsProvider(credentialsProvider),
|
||||
tekton.WithNamespace(ns),
|
||||
tekton.WithProgressListener(pl{urlChan: urlChan}))
|
||||
|
||||
f := createSimpleGoProject(t, ns)
|
||||
f.Build.Builder = test.Builder
|
||||
|
||||
go func() {
|
||||
err := pp.Run(ctx, f)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
cancel()
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case u := <-urlChan:
|
||||
resp, err := http.Get(u)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
_ = resp.Body.Close()
|
||||
if resp.StatusCode != 200 {
|
||||
t.Error("bad HTTP response code")
|
||||
return
|
||||
}
|
||||
t.Log("call to knative service successful")
|
||||
case <-time.After(time.Minute * 10):
|
||||
t.Error("timeout while waiting for service to start")
|
||||
case <-ctx.Done():
|
||||
t.Error("cancelled")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func checkTestEnabled(t *testing.T) {
|
||||
val := os.Getenv("TEKTON_TESTS_ENABLED")
|
||||
enabled, _ := strconv.ParseBool(val)
|
||||
if !enabled {
|
||||
t.Skip("tekton tests are not enabled")
|
||||
}
|
||||
}
|
||||
|
||||
type pl struct {
|
||||
urlChan chan<- string
|
||||
}
|
||||
|
||||
func (p pl) log(args ...any) {
|
||||
_, file, line, ok := runtime.Caller(2)
|
||||
if ok {
|
||||
prefix := fmt.Sprintf("%s:%d", filepath.Base(file), line)
|
||||
args = append([]any{prefix}, args...)
|
||||
}
|
||||
fmt.Fprintln(os.Stderr, args...)
|
||||
}
|
||||
|
||||
func (p pl) SetTotal(i int) {
|
||||
p.log("ProgressListener::SetTotal: ", i)
|
||||
}
|
||||
|
||||
func (p pl) Increment(message string) {
|
||||
p.log("ProgressListener::Increment: ", message)
|
||||
if strings.Contains(message, "URL:") {
|
||||
parts := strings.Split(message, "URL:")
|
||||
if len(parts) < 2 {
|
||||
p.log("bad output message: %q", message)
|
||||
return
|
||||
}
|
||||
u := strings.TrimSpace(parts[1])
|
||||
p.urlChan <- u
|
||||
}
|
||||
}
|
||||
|
||||
func (p pl) Complete(message string) {
|
||||
p.log("ProgressListener::Complete: ", message)
|
||||
}
|
||||
|
||||
func (p pl) Stopping() {
|
||||
p.log("ProgressListener::Stopping")
|
||||
}
|
||||
|
||||
func (p pl) Done() {
|
||||
p.log("ProgressListener::Done")
|
||||
}
|
||||
|
||||
func createSimpleGoProject(t *testing.T, ns string) fn.Function {
|
||||
var err error
|
||||
|
||||
funcName := "fn-" + strings.ToLower(random.AlphaString(5))
|
||||
|
||||
projDir := filepath.Join(t.TempDir(), funcName)
|
||||
err = os.Mkdir(projDir, 0755)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = os.WriteFile(filepath.Join(projDir, "main.go"), []byte(simpleGOSvc), 0644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = os.WriteFile(filepath.Join(projDir, "go.mod"), []byte("module web\n\ngo 1.20\n"), 0644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
f := fn.Function{
|
||||
Root: projDir,
|
||||
Name: funcName,
|
||||
Runtime: "none",
|
||||
Template: "none",
|
||||
Image: "registry.default.svc.cluster.local:5000/" + funcName,
|
||||
Created: time.Now(),
|
||||
Invoke: "none",
|
||||
Build: fn.BuildSpec{
|
||||
BuilderImages: map[string]string{
|
||||
"pack": "docker.io/paketobuildpacks/builder:base",
|
||||
"s2i": "registry.access.redhat.com/ubi8/go-toolset",
|
||||
},
|
||||
},
|
||||
Deploy: fn.DeploySpec{
|
||||
Namespace: ns,
|
||||
},
|
||||
}
|
||||
f = fn.NewFunctionWith(f)
|
||||
err = f.Write()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
const simpleGOSvc = `package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sigs := make(chan os.Signal, 5)
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
s := http.Server{
|
||||
Handler: http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
resp.Header().Add("Content-Type", "text/plain")
|
||||
resp.WriteHeader(200)
|
||||
_, _ = resp.Write([]byte("OK"))
|
||||
}),
|
||||
}
|
||||
go func() {
|
||||
<-sigs
|
||||
_ = s.Shutdown(context.Background())
|
||||
}()
|
||||
port := "8080"
|
||||
if p, ok := os.LookupEnv("PORT"); ok {
|
||||
port = p
|
||||
}
|
||||
l, err := net.Listen("tcp4", ":"+port)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_ = s.Serve(l)
|
||||
}
|
||||
`
|
Loading…
Reference in New Issue