mirror of https://github.com/knative/func.git
test: oncluster build initial e2e set of tests (#1193)
This commit is contained in:
parent
ae75e5e803
commit
4041d609dd
|
@ -0,0 +1,29 @@
|
|||
name: Func E2E OnCluster RT Test
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: On Cluster RT Test
|
||||
strategy:
|
||||
matrix:
|
||||
go: [1.17.x]
|
||||
os: ["ubuntu-latest"]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
- name: Install Binaries
|
||||
run: ./hack/binaries.sh
|
||||
- name: Allocate Cluster
|
||||
run: ./hack/allocate.sh
|
||||
- name: Deploy Tekton
|
||||
run: ./hack/tekton.sh
|
||||
- name: Deploy Test Git Server
|
||||
run: ./test/gitserver.sh
|
||||
- name: E2E On Cluster Test (Runtimes)
|
||||
env:
|
||||
TEST_TAGS: runtime
|
||||
run: make && make test-e2e-on-cluster
|
|
@ -0,0 +1,29 @@
|
|||
name: Func E2E OnCluster Test
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: On Cluster Test
|
||||
strategy:
|
||||
matrix:
|
||||
go: [1.17.x]
|
||||
os: ["ubuntu-latest"]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
- name: Install Binaries
|
||||
run: ./hack/binaries.sh
|
||||
- name: Allocate Cluster
|
||||
run: ./hack/allocate.sh
|
||||
- name: Deploy Tekton
|
||||
run: ./hack/tekton.sh
|
||||
- name: Deploy Test Git Server
|
||||
run: ./test/gitserver.sh
|
||||
- name: E2E On Cluster Test
|
||||
env:
|
||||
E2E_RUNTIMES: ""
|
||||
run: make && make test-e2e-on-cluster
|
3
Makefile
3
Makefile
|
@ -149,6 +149,9 @@ test-e2e: ## Run end-to-end tests using an available cluster.
|
|||
test-e2e-runtime: ## Run end-to-end lifecycle tests using an available cluster for a single runtime.
|
||||
./test/e2e_lifecycle_tests.sh $(runtime)
|
||||
|
||||
test-e2e-on-cluster: ## Run end-to-end on-cluster build tests using an available cluster.
|
||||
./test/e2e_oncluster_tests.sh
|
||||
|
||||
######################
|
||||
##@ Release Artifacts
|
||||
######################
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
#
|
||||
# Install Tekton and required tasks in the cluster
|
||||
#
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
export TERM="${TERM:-dumb}"
|
||||
|
||||
tekton_release="previous/v0.38.3"
|
||||
git_clone_release="0.4"
|
||||
source_path="https://raw.githubusercontent.com/knative-sandbox/kn-plugin-func/main"
|
||||
namespace="${NAMESPACE:-default}"
|
||||
|
||||
tekton() {
|
||||
echo "Installing Tekton..."
|
||||
kubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/${tekton_release}/release.yaml
|
||||
sleep 10
|
||||
kubectl wait pod --for=condition=Ready --timeout=180s -n tekton-pipelines -l "app=tekton-pipelines-controller"
|
||||
|
||||
kubectl create clusterrolebinding ${namespace}:knative-serving-namespaced-admin \
|
||||
--clusterrole=knative-serving-namespaced-admin --serviceaccount=${namespace}:default
|
||||
}
|
||||
|
||||
tekton_tasks() {
|
||||
echo "Creating Pipeline tasks..."
|
||||
kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/master/task/git-clone/${git_clone_release}/git-clone.yaml
|
||||
kubectl apply -f ${source_path}/pipelines/resources/tekton/task/func-buildpacks/0.1/func-buildpacks.yaml
|
||||
kubectl apply -f ${source_path}/pipelines/resources/tekton/task/func-deploy/0.1/func-deploy.yaml
|
||||
}
|
||||
|
||||
tekton
|
||||
tekton_tasks
|
||||
|
||||
echo Done
|
|
@ -17,7 +17,7 @@ podman_pid=$!
|
|||
|
||||
DOCKER_HOST="unix://$(podman info -f '{{.Host.RemoteSocket.Path}}' 2> /dev/null)"
|
||||
export DOCKER_HOST
|
||||
go test -tags integration ./... -v
|
||||
go test -test.timeout=15m -tags integration ./... -v
|
||||
e=$?
|
||||
|
||||
kill -TERM "$podman_pid" > /dev/null 2>&1
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
# Functions E2E Test
|
||||
|
||||
## Lifecycle tests
|
||||
|
||||
Lifecycle tests exercises the most important phases of a function lifecycle starting from
|
||||
creation, going thru to build, deployment, execution and then deletion (CRUD operations).
|
||||
It runs func commands such as `create`, `deploy`, `list` and `delete` for a language
|
||||
runtime using both default `http` and `cloudevents` templates.
|
||||
|
||||
## Extended tests
|
||||
|
||||
Extended tests performs additional tests on `func` such as templates, config envs, volumes, labels and
|
||||
other scenarios.
|
||||
|
||||
## On Cluster Builds tests
|
||||
|
||||
On cluster builds e2e tests exercises functions built directly on cluster.
|
||||
The tests are organized per scenarios under `./_oncluster` folder.
|
||||
|
||||
### Pre-requisites
|
||||
|
||||
Prior to run On Cluster builds e2e tests ensure you are connected to
|
||||
a Kubernetes Cluster with the following deployed:
|
||||
|
||||
- Knative Serving
|
||||
- Tekton
|
||||
- Tekton Tasks listed [here](../docs/reference/on_cluster_build.md)
|
||||
- Embedded Git Server (`func-git`) used by tests
|
||||
|
||||
For your convenience you can run the following script to setup Tekton and required Tasks:
|
||||
```
|
||||
$ ../hack/tekton.sh
|
||||
```
|
||||
|
||||
To install the Git Server required by tests, run:
|
||||
```
|
||||
$ ./gitserver.sh
|
||||
```
|
||||
|
||||
#### Running all the Tests on KinD
|
||||
|
||||
The below instructions will run all the tests on KinD using an **ephemeral** container registry.
|
||||
```
|
||||
# Pre-Reqs
|
||||
./hack/allocate.sh
|
||||
./hack/tekton.sh
|
||||
./test/gitserver.sh
|
||||
make build
|
||||
|
||||
# Run tests
|
||||
./test/e2e_oncluter_tests.sh
|
||||
```
|
||||
|
||||
#### Running "runtime" only scenario
|
||||
|
||||
You can run only e2e tests to exercise a given language/runtime, for example *python*
|
||||
|
||||
```
|
||||
env E2E_RUNTIMES=python TEST_TAGS=runtime ./test/e2e_oncluster_test.sh
|
||||
```
|
||||
|
||||
#### Running tests except "runtime" ones
|
||||
|
||||
You can run most of on cluster builds e2e scenarios, except the language/runtime specific
|
||||
ones, by running:
|
||||
```
|
||||
env E2E_RUNTIMES="" ./test/e2e_oncluster_test.sh
|
||||
```
|
|
@ -0,0 +1,115 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type TestExecCmd struct {
|
||||
|
||||
// binary to invoke
|
||||
// Example: "func", "kn", "kubectl", "/usr/bin/sh"
|
||||
Binary string
|
||||
|
||||
// Binary args to append before actual args. Examples:
|
||||
// when 'kn' binary binaryArgs should be ["func"]
|
||||
BinaryArgs []string
|
||||
|
||||
// Run commands from Dir
|
||||
SourceDir string
|
||||
|
||||
// Indicates shell should dump command line args during execution
|
||||
ShouldDumpCmdLine bool
|
||||
|
||||
// Indicates shell should dump
|
||||
ShouldDumpOnSuccess bool
|
||||
|
||||
// Fail Test on Error
|
||||
ShouldFailOnError bool
|
||||
|
||||
// Environment variable to be used with the command
|
||||
Env []string
|
||||
|
||||
// Optional function to be used to dump stdout command results
|
||||
DumpLogger func(out string)
|
||||
|
||||
// Boolean
|
||||
T *testing.T
|
||||
}
|
||||
|
||||
// TestExecCmdResult stored command result
|
||||
type TestExecCmdResult struct {
|
||||
Stdout string
|
||||
Stderr string
|
||||
Error error
|
||||
}
|
||||
|
||||
func (f *TestExecCmd) WithEnv(envKey string, envValue string) *TestExecCmd {
|
||||
env := envKey + "=" + envValue
|
||||
f.Env = append(f.Env, env)
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *TestExecCmd) FromDir(dir string) *TestExecCmd {
|
||||
f.SourceDir = dir
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *TestExecCmd) Run(oneArgs string) TestExecCmdResult {
|
||||
args := strings.Split(oneArgs, " ")
|
||||
return f.Exec(args...)
|
||||
}
|
||||
|
||||
// Exec invokes go exec library and runs a shell command combining the binary args with args from method signature
|
||||
func (f *TestExecCmd) Exec(args ...string) TestExecCmdResult {
|
||||
finalArgs := f.BinaryArgs
|
||||
if finalArgs == nil {
|
||||
finalArgs = args
|
||||
} else if args != nil {
|
||||
finalArgs = append(finalArgs, args...)
|
||||
}
|
||||
|
||||
if f.ShouldDumpCmdLine {
|
||||
f.T.Log(f.Binary, strings.Join(finalArgs, " "))
|
||||
}
|
||||
|
||||
var stderr bytes.Buffer
|
||||
var stdout bytes.Buffer
|
||||
|
||||
cmd := exec.Command(f.Binary, finalArgs...)
|
||||
cmd.Stderr = &stderr
|
||||
cmd.Stdout = &stdout
|
||||
if f.SourceDir != "" {
|
||||
cmd.Dir = f.SourceDir
|
||||
}
|
||||
cmd.Env = append(os.Environ(), f.Env...)
|
||||
err := cmd.Run()
|
||||
|
||||
result := TestExecCmdResult{
|
||||
Stdout: stdout.String(),
|
||||
Stderr: stderr.String(),
|
||||
Error: err,
|
||||
}
|
||||
|
||||
if err == nil && f.ShouldDumpOnSuccess {
|
||||
if result.Stdout != "" {
|
||||
if f.DumpLogger != nil {
|
||||
f.DumpLogger(result.Stdout)
|
||||
} else {
|
||||
f.T.Logf("%v", result.Stdout)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
f.T.Log(err.Error())
|
||||
f.T.Log(result.Stderr)
|
||||
if f.ShouldFailOnError {
|
||||
f.T.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"knative.dev/kn-plugin-func/k8s"
|
||||
e2e "knative.dev/kn-plugin-func/test/_e2e"
|
||||
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
func GetGitServer(T *testing.T) GitProvider {
|
||||
gitTestServer := GitTestServerProvider{}
|
||||
gitTestServer.Init(T)
|
||||
return &gitTestServer
|
||||
}
|
||||
|
||||
type GitRemoteRepo struct {
|
||||
RepoName string
|
||||
ExternalCloneURL string
|
||||
ClusterCloneURL string
|
||||
}
|
||||
|
||||
type GitProvider interface {
|
||||
Init(T *testing.T)
|
||||
CreateRepository(repoName string) *GitRemoteRepo
|
||||
DeleteRepository(repoName string)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Git Server on Kubernetes as Knative Service (func-git)
|
||||
// ------------------------------------------------------
|
||||
|
||||
type GitTestServerProvider struct {
|
||||
PodName string
|
||||
ServiceUrl string
|
||||
Kubectl *TestExecCmd
|
||||
t *testing.T
|
||||
}
|
||||
|
||||
func (g *GitTestServerProvider) Init(T *testing.T) {
|
||||
|
||||
g.t = T
|
||||
if g.PodName == "" {
|
||||
config, err := k8s.GetClientConfig().ClientConfig()
|
||||
if err != nil {
|
||||
T.Fatal(err.Error())
|
||||
}
|
||||
clientSet, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
T.Fatal(err.Error())
|
||||
}
|
||||
ctx := context.Background()
|
||||
|
||||
namespace, _, _ := k8s.GetClientConfig().Namespace()
|
||||
podList, err := clientSet.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{
|
||||
LabelSelector: "serving.knative.dev/service=func-git",
|
||||
})
|
||||
if err != nil {
|
||||
T.Fatal(err.Error())
|
||||
}
|
||||
for _, pod := range podList.Items {
|
||||
g.PodName = pod.Name
|
||||
}
|
||||
}
|
||||
|
||||
if g.ServiceUrl == "" {
|
||||
// Get Route Name
|
||||
g.ServiceUrl = e2e.GetKnativeServiceUrl(T, "func-git")
|
||||
}
|
||||
|
||||
if g.Kubectl == nil {
|
||||
g.Kubectl = &TestExecCmd{
|
||||
Binary: "kubectl",
|
||||
ShouldDumpCmdLine: true,
|
||||
ShouldDumpOnSuccess: true,
|
||||
T: T,
|
||||
}
|
||||
}
|
||||
T.Logf("Initialized HTTP Func Git Server: Server URL = %v Pod Name = %v\n", g.ServiceUrl, g.PodName)
|
||||
}
|
||||
|
||||
func (g *GitTestServerProvider) CreateRepository(repoName string) *GitRemoteRepo {
|
||||
// kubectl exec $podname -c user-container -- git-repo create $reponame
|
||||
cmdResult := g.Kubectl.Exec("exec", g.PodName, "-c", "user-container", "--", "git-repo", "create", repoName)
|
||||
if !strings.Contains(cmdResult.Stdout, "created") {
|
||||
g.t.Fatal("unable to create git bare repository " + repoName)
|
||||
}
|
||||
gitRepo := &GitRemoteRepo{
|
||||
RepoName: repoName,
|
||||
ExternalCloneURL: g.ServiceUrl + "/" + repoName + ".git",
|
||||
ClusterCloneURL: "http://func-git.default.svc.cluster.local/" + repoName + ".git",
|
||||
}
|
||||
return gitRepo
|
||||
}
|
||||
|
||||
func (g *GitTestServerProvider) DeleteRepository(repoName string) {
|
||||
cmdResult := g.Kubectl.Exec("exec", g.PodName, "-c", "user-container", "--", "git-repo", "delete", repoName)
|
||||
if !strings.Contains(cmdResult.Stdout, "deleted") {
|
||||
g.t.Fatal("unable to delete git bare repository " + repoName)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
e2e "knative.dev/kn-plugin-func/test/_e2e"
|
||||
)
|
||||
|
||||
func NewKnFuncShellCli(t *testing.T) *TestExecCmd {
|
||||
knFunc := TestExecCmd{}
|
||||
knFunc.T = t
|
||||
|
||||
if e2e.IsUseKnFunc() {
|
||||
knFunc.Binary = "kn"
|
||||
knFunc.BinaryArgs = []string{"func"}
|
||||
} else {
|
||||
knFunc.Binary = e2e.GetFuncBinaryPath()
|
||||
if knFunc.Binary == "" {
|
||||
t.Log("'func' binary not defined. Please set E2E_FUNC_BIN_PATH environment variable prior to running tests")
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
cmd := knFunc.Exec()
|
||||
if cmd.Error != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
knFunc.ShouldDumpCmdLine = true
|
||||
knFunc.ShouldFailOnError = true
|
||||
return &knFunc
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func NewShellCmd(t *testing.T, fromDirectory string) *TestExecCmd {
|
||||
|
||||
shellCmd := TestExecCmd{
|
||||
Binary: "sh",
|
||||
BinaryArgs: []string{"-c"},
|
||||
SourceDir: fromDirectory,
|
||||
ShouldDumpCmdLine: true,
|
||||
ShouldDumpOnSuccess: true,
|
||||
T: t,
|
||||
}
|
||||
return &shellCmd
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package e2e
|
||||
|
||||
import "strings"
|
||||
|
||||
// CleanOutput Some commands, such as deploy command, spans spinner chars and cursor shifts at output which are captured and merged
|
||||
// regular output messages. This functions is meant to remove these chars in order to facilitate tests assertions and data extraction from output
|
||||
func CleanOutput(stdOutput string) string {
|
||||
toRemove := []string{
|
||||
"🕛 ",
|
||||
"🕐 ",
|
||||
"🕑 ",
|
||||
"🕒 ",
|
||||
"🕓 ",
|
||||
"🕔 ",
|
||||
"🕕 ",
|
||||
"🕖 ",
|
||||
"🕗 ",
|
||||
"🕘 ",
|
||||
"🕙 ",
|
||||
"🕚 ",
|
||||
"\033[1A",
|
||||
"\033[1B",
|
||||
"\033[K",
|
||||
}
|
||||
for _, c := range toRemove {
|
||||
stdOutput = strings.ReplaceAll(stdOutput, c, "")
|
||||
}
|
||||
return stdOutput
|
||||
}
|
|
@ -41,29 +41,3 @@ func Deploy(t *testing.T, knFunc *TestShellCmdRunner, project *FunctionTestProje
|
|||
project.IsDeployed = true
|
||||
|
||||
}
|
||||
|
||||
// CleanOutput Some commands, such as deploy command, spans spinner chars and cursor shifts at output which are captured and merged
|
||||
// regular output messages. This functions is meant to remove these chars in order to facilitate tests assertions and data extraction from output
|
||||
func CleanOutput(deployOutput string) string {
|
||||
toRemove := []string{
|
||||
"🕛 ",
|
||||
"🕐 ",
|
||||
"🕑 ",
|
||||
"🕒 ",
|
||||
"🕓 ",
|
||||
"🕔 ",
|
||||
"🕕 ",
|
||||
"🕖 ",
|
||||
"🕗 ",
|
||||
"🕘 ",
|
||||
"🕙 ",
|
||||
"🕚 ",
|
||||
"\033[1A",
|
||||
"\033[1B",
|
||||
"\033[K",
|
||||
}
|
||||
for _, c := range toRemove {
|
||||
deployOutput = strings.ReplaceAll(deployOutput, c, "")
|
||||
}
|
||||
return deployOutput
|
||||
}
|
||||
|
|
|
@ -39,10 +39,18 @@ func RetrieveKnativeServiceResource(t *testing.T, serviceName string) *unstructu
|
|||
}
|
||||
|
||||
// GetCurrentServiceRevision retrieves current revision name for the deployed function
|
||||
func GetCurrentServiceRevision(t *testing.T, project *FunctionTestProject) string {
|
||||
resource := RetrieveKnativeServiceResource(t, project.FunctionName)
|
||||
func GetCurrentServiceRevision(t *testing.T, serviceName string) string {
|
||||
resource := RetrieveKnativeServiceResource(t, serviceName)
|
||||
rootMap := resource.UnstructuredContent()
|
||||
statusMap := rootMap["status"].(map[string]interface{})
|
||||
latestReadyRevision := statusMap["latestReadyRevisionName"].(string)
|
||||
return latestReadyRevision
|
||||
}
|
||||
|
||||
func GetKnativeServiceUrl(t *testing.T, functionName string) string {
|
||||
resource := RetrieveKnativeServiceResource(t, functionName)
|
||||
rootMap := resource.UnstructuredContent()
|
||||
statusMap := rootMap["status"].(map[string]interface{})
|
||||
url := statusMap["url"].(string)
|
||||
return url
|
||||
}
|
||||
|
|
|
@ -22,9 +22,9 @@ func ReadyCheck(t *testing.T, knFunc *TestShellCmdRunner, project FunctionTestPr
|
|||
}
|
||||
|
||||
// NewRevisionCheck waits for a new revision to report as ready
|
||||
func NewRevisionCheck(t *testing.T, previousRevision string, project *FunctionTestProject) (newRevision string) {
|
||||
func NewRevisionCheck(t *testing.T, previousRevision string, serviceName string) (newRevision string) {
|
||||
err := wait.PollImmediate(5*time.Second, 1*time.Minute, func() (done bool, err error) {
|
||||
newRevision = GetCurrentServiceRevision(t, project)
|
||||
newRevision = GetCurrentServiceRevision(t, serviceName)
|
||||
t.Logf("Waiting for new revision deployment (previous revision [%v], current revision [%v])", previousRevision, newRevision)
|
||||
return newRevision != "" && newRevision != previousRevision, nil
|
||||
})
|
|
@ -33,13 +33,13 @@ func Update(t *testing.T, knFunc *TestShellCmdRunner, project *FunctionTestProje
|
|||
t.Fatal("an error has occurred while updating project folder with new sources.", err.Error())
|
||||
}
|
||||
|
||||
previousRevision := GetCurrentServiceRevision(t, project)
|
||||
previousRevision := GetCurrentServiceRevision(t, project.FunctionName)
|
||||
|
||||
// Redeploy function
|
||||
Deploy(t, knFunc, project)
|
||||
|
||||
// Waits New Revision to become ready
|
||||
NewRevisionCheck(t, previousRevision, project)
|
||||
NewRevisionCheck(t, previousRevision, project.FunctionName)
|
||||
|
||||
// Indicates new project (from update templates) is in use
|
||||
project.IsNewRevision = true
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package oncluster
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
// AssertNoError ensure err is nil otherwise fails testing
|
||||
func AssertNoError(t *testing.T, err error) {
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// AssertThatTektonPipelineRunSucceed verifies the pipeline and pipelinerun were actually created
|
||||
// on the cluster and ensure all the Tasks of the pipelinerun executed successfully
|
||||
// Also it logs a brief summary of execution of the pipeline for potential debug purposes
|
||||
func AssertThatTektonPipelineRunSucceed(t *testing.T, functionName string) {
|
||||
assert.Assert(t, TektonPipelineExists(t, functionName), "tekton pipeline not found on cluster")
|
||||
RunSummary := TektonPipelineLastRunSummary(t, functionName)
|
||||
t.Logf("Tekton Run Summary:\n %v", RunSummary.ToString())
|
||||
assert.Assert(t, RunSummary.IsSucceed(), "expected pipeline run was not succeeded")
|
||||
}
|
||||
|
||||
// AssertThatTektonPipelineResourcesNotExists is intended to check the pipeline and pipelinerun resources
|
||||
// do not exists. This is meant to be called after a `func delete` to ensure everything is cleaned
|
||||
func AssertThatTektonPipelineResourcesNotExists(t *testing.T, functionName string) {
|
||||
if !t.Failed() {
|
||||
t.Log("Checking resources got cleaned")
|
||||
assert.Assert(t, !TektonPipelineExists(t, functionName), "tekton pipeline was found but it should not exist")
|
||||
assert.Assert(t, !TektonPipelineRunExists(t, functionName), "tekton pipelinerun was found but it should not exist")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package oncluster
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
common "knative.dev/kn-plugin-func/test/_common"
|
||||
)
|
||||
|
||||
type Git struct {
|
||||
URL string
|
||||
Revision string
|
||||
ContextDir string
|
||||
}
|
||||
|
||||
// UpdateFuncYamlGit update func.yaml file by setting build to git as well as git fields.
|
||||
func UpdateFuncYamlGit(t *testing.T, projectDir string, git Git) {
|
||||
|
||||
funcYamlPath := projectDir + "/func.yaml"
|
||||
data, err := os.ReadFile(funcYamlPath)
|
||||
AssertNoError(t, err)
|
||||
|
||||
m := make(map[interface{}]interface{})
|
||||
err = yaml.Unmarshal([]byte(data), &m)
|
||||
AssertNoError(t, err)
|
||||
|
||||
gitMap := make(map[interface{}]interface{})
|
||||
m["build"] = "git"
|
||||
m["git"] = gitMap
|
||||
|
||||
changeLog := fmt.Sprintln("build:", "git")
|
||||
updateGitField := func(targetField string, targetValue string) {
|
||||
if targetValue != "" {
|
||||
gitMap[targetField] = targetValue
|
||||
changeLog += fmt.Sprintln("git.", targetField, ":", targetValue)
|
||||
}
|
||||
}
|
||||
updateGitField("url", git.URL)
|
||||
updateGitField("revision", git.Revision)
|
||||
updateGitField("contextDir", git.ContextDir)
|
||||
|
||||
outData, _ := yaml.Marshal(m)
|
||||
err = os.WriteFile(funcYamlPath, outData, 0644)
|
||||
AssertNoError(t, err)
|
||||
t.Logf("func.yaml changed:\n%v", changeLog)
|
||||
}
|
||||
|
||||
// GitInitialCommitAndPush Runs repeatable git commands used on every initial repository setup
|
||||
// such as `git init`, `git config user`, `git add .`, `git remote add ...` and `git push`
|
||||
func GitInitialCommitAndPush(t *testing.T, gitProjectPath string, originCloneURL string) (sh *common.TestExecCmd) {
|
||||
|
||||
sh = common.NewShellCmd(t, gitProjectPath)
|
||||
sh.ShouldFailOnError = true
|
||||
sh.ShouldDumpOnSuccess = true
|
||||
sh.Exec(`git init`)
|
||||
sh.Exec(`git branch -M main`)
|
||||
sh.Exec(`git add .`)
|
||||
sh.Exec(`git config user.name "John Smith"`)
|
||||
sh.Exec(`git config user.email "john.smith@example.com"`)
|
||||
sh.Exec(`git commit -m "initial commit"`)
|
||||
sh.Exec(`git remote add origin ` + originCloneURL)
|
||||
sh.Exec(`git push -u origin main`)
|
||||
return sh
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package oncluster
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// WriteNewSimpleIndexJS is used to replace the content of "index.js" of a Node JS function created by a test case.
|
||||
// File content will cause the deployed function to, when invoked, return the value specified on `withBodyReturning`
|
||||
// params, which is handy for test assertions.
|
||||
func WriteNewSimpleIndexJS(t *testing.T, nodeJsFuncProjectDir string, withBodyReturning string) {
|
||||
indexJsContent := fmt.Sprintf(`
|
||||
function invoke(context) {
|
||||
return { body: '%v' }
|
||||
}
|
||||
module.exports = invoke;
|
||||
`, withBodyReturning)
|
||||
|
||||
err := os.WriteFile(filepath.Join(nodeJsFuncProjectDir, "index.js"), []byte(indexJsContent), 0644)
|
||||
AssertNoError(t, err)
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
//go:build oncluster
|
||||
// +build oncluster
|
||||
|
||||
package oncluster
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
common "knative.dev/kn-plugin-func/test/_common"
|
||||
e2e "knative.dev/kn-plugin-func/test/_e2e"
|
||||
)
|
||||
|
||||
// TestDefault covers basic test scenario that ensure on cluster build from a "default branch" and
|
||||
// code changes (new commits) will be properly built and deployed on new revision
|
||||
func TestBasicDefault(t *testing.T) {
|
||||
|
||||
var funcName = "test-func-basic"
|
||||
var funcPath = filepath.Join(os.TempDir(), funcName)
|
||||
|
||||
func() {
|
||||
gitServer := common.GitTestServerProvider{}
|
||||
gitServer.Init(t)
|
||||
remoteRepo := gitServer.CreateRepository(funcName)
|
||||
defer gitServer.DeleteRepository(funcName)
|
||||
|
||||
knFunc := common.NewKnFuncShellCli(t)
|
||||
knFunc.Exec("create", "-l", "node", funcPath)
|
||||
defer os.RemoveAll(funcPath)
|
||||
|
||||
// Write an `index.js` that make node func to return 'first revision'
|
||||
WriteNewSimpleIndexJS(t, funcPath, "first revision")
|
||||
|
||||
sh := GitInitialCommitAndPush(t, funcPath, remoteRepo.ExternalCloneURL)
|
||||
|
||||
// Update func.yaml build as git + url + context-dir
|
||||
UpdateFuncYamlGit(t, funcPath, Git{URL: remoteRepo.ClusterCloneURL})
|
||||
|
||||
// Deploy it
|
||||
knFunc.Exec("deploy", "-r", e2e.GetRegistry(), "-p", funcPath)
|
||||
defer knFunc.Exec("delete", "-p", funcPath)
|
||||
|
||||
// Assert "first revision" is returned
|
||||
result := knFunc.Exec("invoke", "-p", funcPath)
|
||||
assert.Assert(t, strings.Contains(result.Stdout, "first revision"), "Func body does not contain 'first revision'")
|
||||
|
||||
previousServiceRevision := e2e.GetCurrentServiceRevision(t, funcName)
|
||||
|
||||
// Update index.js to force node func to return 'new revision'
|
||||
WriteNewSimpleIndexJS(t, funcPath, "new revision")
|
||||
sh.Exec(`git add index.js`)
|
||||
sh.Exec(`git commit -m "revision 2"`)
|
||||
sh.Exec(`git push`)
|
||||
|
||||
// Re-Deploy Func
|
||||
knFunc.Exec("deploy", "-r", e2e.GetRegistry(), "-p", funcPath)
|
||||
e2e.NewRevisionCheck(t, previousServiceRevision, funcName) // Wait New Service Revision
|
||||
|
||||
// -- Assertions --
|
||||
result = knFunc.Exec("invoke", "-p", funcPath)
|
||||
assert.Assert(t, strings.Contains(result.Stdout, "new revision"), "Func body does not contain 'new revision'")
|
||||
AssertThatTektonPipelineRunSucceed(t, funcName)
|
||||
|
||||
}()
|
||||
|
||||
AssertThatTektonPipelineResourcesNotExists(t, funcName)
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
//go:build oncluster
|
||||
// +build oncluster
|
||||
|
||||
package oncluster
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
common "knative.dev/kn-plugin-func/test/_common"
|
||||
e2e "knative.dev/kn-plugin-func/test/_e2e"
|
||||
)
|
||||
|
||||
// TestContextDirFunc tests the following use case:
|
||||
// - As a Developer I want my function located in a specific directory on my project, hosted on my
|
||||
// public git repository from the main branch, to get deployed on my cluster
|
||||
func TestContextDirFunc(t *testing.T) {
|
||||
|
||||
var gitProjectName = "test-project"
|
||||
var gitProjectPath = filepath.Join(os.TempDir(), gitProjectName)
|
||||
var funcName = "test-func-context-dir"
|
||||
var funcContextDir = filepath.Join("functions", funcName)
|
||||
var funcPath = filepath.Join(gitProjectPath, funcContextDir)
|
||||
|
||||
func() {
|
||||
|
||||
gitServer := common.GitTestServerProvider{}
|
||||
gitServer.Init(t)
|
||||
remoteRepo := gitServer.CreateRepository(gitProjectName)
|
||||
defer gitServer.DeleteRepository(gitProjectName)
|
||||
|
||||
knFunc := common.NewKnFuncShellCli(t)
|
||||
knFunc.Exec("create", "-l", "node", funcPath)
|
||||
|
||||
WriteNewSimpleIndexJS(t, funcPath, "hello dir")
|
||||
|
||||
defer os.RemoveAll(gitProjectPath)
|
||||
|
||||
// Initial commit to repository: git init + commit + push
|
||||
GitInitialCommitAndPush(t, gitProjectPath, remoteRepo.ExternalCloneURL)
|
||||
|
||||
// Update func.yaml build as git + url + context-dir
|
||||
UpdateFuncYamlGit(t, funcPath, Git{URL: remoteRepo.ClusterCloneURL, ContextDir: funcContextDir})
|
||||
|
||||
knFunc.Exec("deploy", "-r", e2e.GetRegistry(), "-p", funcPath)
|
||||
defer knFunc.Exec("delete", "-p", funcPath)
|
||||
|
||||
// -- Assertions --
|
||||
result := knFunc.Exec("invoke", "-p", funcPath)
|
||||
assert.Assert(t, strings.Contains(result.Stdout, "hello dir"), "Func body does not contain 'hello dir'")
|
||||
AssertThatTektonPipelineRunSucceed(t, funcName)
|
||||
|
||||
}()
|
||||
|
||||
AssertThatTektonPipelineResourcesNotExists(t, funcName)
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
//go:build oncluster
|
||||
// +build oncluster
|
||||
|
||||
package oncluster
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
common "knative.dev/kn-plugin-func/test/_common"
|
||||
e2e "knative.dev/kn-plugin-func/test/_e2e"
|
||||
)
|
||||
|
||||
// TestFromCliBuildLocal tests the scenario which func.yaml indicates that builds should be on cluster
|
||||
// but users wants to run a local build on its machine
|
||||
func TestFromCliBuildLocal(t *testing.T) {
|
||||
|
||||
var funcName = "test-func-cli-local"
|
||||
var funcPath = filepath.Join(os.TempDir(), funcName)
|
||||
|
||||
knFunc := common.NewKnFuncShellCli(t)
|
||||
knFunc.Exec("create", "-l", "node", funcPath)
|
||||
defer os.RemoveAll(funcPath)
|
||||
|
||||
// Update func.yaml build as local + some fake url (it should not call it anyway)
|
||||
UpdateFuncYamlGit(t, funcPath, Git{URL: "http://fake-repo/repo.git"})
|
||||
|
||||
knFunc.Exec("deploy", "-r", e2e.GetRegistry(), "-p", funcPath, "--build", "local")
|
||||
defer knFunc.Exec("delete", "-p", funcPath)
|
||||
|
||||
// -- Assertions --
|
||||
knFunc.Exec("invoke", "-p", funcPath)
|
||||
AssertThatTektonPipelineResourcesNotExists(t, funcName)
|
||||
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
//go:build oncluster
|
||||
// +build oncluster
|
||||
|
||||
package oncluster
|
||||
|
||||
/*
|
||||
Tests on this file covers the scenarios when func.yaml is not modified (build: local)
|
||||
and git build strategy is specified thru CLI.
|
||||
|
||||
A) Default Branch Test
|
||||
func deploy --build=git --git-url=http://gitserver/myfunc.git
|
||||
|
||||
b) Feature Branch Test
|
||||
func deploy --build=git --git-url=http://gitserver/myfunc.git --git-branch=feature/my-branch
|
||||
|
||||
c) Context Dir test
|
||||
func deploy --build=git --git-url=http://gitserver/myfunc.git --git-dir=functions/myfunc
|
||||
*/
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
common "knative.dev/kn-plugin-func/test/_common"
|
||||
e2e "knative.dev/kn-plugin-func/test/_e2e"
|
||||
)
|
||||
|
||||
// TestFromCliDefaultBranch triggers a default branch test by using CLI flags
|
||||
func TestFromCliDefaultBranch(t *testing.T) {
|
||||
|
||||
var gitProjectName = "test-func-yaml-build-local"
|
||||
var gitProjectPath = filepath.Join(os.TempDir(), gitProjectName)
|
||||
var funcName = gitProjectName
|
||||
var funcPath = gitProjectPath
|
||||
|
||||
gitServer := common.GitTestServerProvider{}
|
||||
gitServer.Init(t)
|
||||
remoteRepo := gitServer.CreateRepository(gitProjectName)
|
||||
defer gitServer.DeleteRepository(gitProjectName)
|
||||
|
||||
knFunc := common.NewKnFuncShellCli(t)
|
||||
knFunc.Exec("create", "-l", "node", funcPath)
|
||||
defer os.RemoveAll(gitProjectPath)
|
||||
|
||||
GitInitialCommitAndPush(t, gitProjectPath, remoteRepo.ExternalCloneURL)
|
||||
|
||||
knFunc.Exec("deploy",
|
||||
"-r", e2e.GetRegistry(),
|
||||
"-p", funcPath,
|
||||
"--build", "git",
|
||||
"--git-url", remoteRepo.ClusterCloneURL)
|
||||
|
||||
defer knFunc.Exec("delete", "-p", funcPath)
|
||||
|
||||
// ## ASSERTIONS
|
||||
result := knFunc.Exec("invoke", "-p", funcPath)
|
||||
assert.Assert(t, strings.Contains(result.Stdout, "Hello"), "Func body does not contain 'Hello'")
|
||||
AssertThatTektonPipelineRunSucceed(t, funcName)
|
||||
|
||||
}
|
||||
|
||||
// TestFromCliFeatureBranch trigger a feature branch test by using CLI flags
|
||||
func TestFromCliFeatureBranch(t *testing.T) {
|
||||
|
||||
var funcName = "test-func-cli-feature-branch"
|
||||
var funcPath = filepath.Join(os.TempDir(), funcName)
|
||||
|
||||
gitServer := common.GitTestServerProvider{}
|
||||
gitServer.Init(t)
|
||||
remoteRepo := gitServer.CreateRepository(funcName)
|
||||
defer gitServer.DeleteRepository(funcName)
|
||||
|
||||
knFunc := common.NewKnFuncShellCli(t)
|
||||
knFunc.Exec("create", "-l", "node", funcPath)
|
||||
defer os.RemoveAll(funcPath)
|
||||
|
||||
GitInitialCommitAndPush(t, funcPath, remoteRepo.ExternalCloneURL)
|
||||
|
||||
WriteNewSimpleIndexJS(t, funcPath, "hello branch")
|
||||
|
||||
sh := common.NewShellCmd(t, funcPath)
|
||||
sh.ShouldFailOnError = true
|
||||
sh.Exec("git checkout -b feature/branch")
|
||||
sh.Exec("git add index.js")
|
||||
sh.Exec(`git commit -m "feature branch change"`)
|
||||
sh.Exec("git push -u origin feature/branch")
|
||||
|
||||
knFunc.Exec("deploy",
|
||||
"-r", e2e.GetRegistry(),
|
||||
"-p", funcPath,
|
||||
"--build", "git",
|
||||
"--git-url", remoteRepo.ClusterCloneURL,
|
||||
"--git-branch", "feature/branch")
|
||||
|
||||
defer knFunc.Exec("delete", "-p", funcPath)
|
||||
|
||||
// ## ASSERTIONS
|
||||
result := knFunc.Exec("invoke", "-p", funcPath)
|
||||
assert.Assert(t, strings.Contains(result.Stdout, "hello branch"), "Func body does not contain 'hello branch'")
|
||||
AssertThatTektonPipelineRunSucceed(t, funcName)
|
||||
|
||||
}
|
||||
|
||||
// TestFromCliContextDirFunc triggers a context dir test by using CLI flags
|
||||
func TestFromCliContextDirFunc(t *testing.T) {
|
||||
|
||||
var gitProjectName = "test-project"
|
||||
var gitProjectPath = filepath.Join(os.TempDir(), gitProjectName)
|
||||
var funcName = "test-func-context-dir"
|
||||
var funcContextDir = filepath.Join("functions", funcName)
|
||||
var funcPath = filepath.Join(gitProjectPath, funcContextDir)
|
||||
|
||||
gitServer := common.GitTestServerProvider{}
|
||||
gitServer.Init(t)
|
||||
remoteRepo := gitServer.CreateRepository(gitProjectName)
|
||||
defer gitServer.DeleteRepository(gitProjectName)
|
||||
|
||||
knFunc := common.NewKnFuncShellCli(t)
|
||||
knFunc.Exec("create", "-l", "node", funcPath)
|
||||
defer os.RemoveAll(gitProjectPath)
|
||||
|
||||
WriteNewSimpleIndexJS(t, funcPath, "hello dir")
|
||||
|
||||
GitInitialCommitAndPush(t, gitProjectPath, remoteRepo.ExternalCloneURL)
|
||||
|
||||
knFunc.Exec("deploy",
|
||||
"-r", e2e.GetRegistry(),
|
||||
"-p", funcPath,
|
||||
"--build", "git",
|
||||
"--git-url", remoteRepo.ClusterCloneURL,
|
||||
"--git-dir", funcContextDir)
|
||||
|
||||
defer knFunc.Exec("delete", "-p", funcPath)
|
||||
|
||||
// -- Assertions --
|
||||
result := knFunc.Exec("invoke", "-p", funcPath)
|
||||
assert.Assert(t, strings.Contains(result.Stdout, "hello dir"), "Func body does not contain 'hello dir'")
|
||||
AssertThatTektonPipelineRunSucceed(t, funcName)
|
||||
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
//go:build oncluster
|
||||
// +build oncluster
|
||||
|
||||
package oncluster
|
||||
|
||||
/*
|
||||
Tests on this file covers "on cluster build" use cases:
|
||||
|
||||
A) I want my function hosted on my public git repository from a FEATURE BRANCH to get built deployed
|
||||
b) I want my function hosted on my public git repository from a specific GIT TAG to get built and deployed
|
||||
c) I want my function hosted on my public git repository from a specific COMMIT HASH to get built and deployed
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
common "knative.dev/kn-plugin-func/test/_common"
|
||||
e2e "knative.dev/kn-plugin-func/test/_e2e"
|
||||
)
|
||||
|
||||
func TestFromFeatureBranch(t *testing.T) {
|
||||
|
||||
setupCodeFn := func(sh *common.TestExecCmd, funcProjectPath string, clusterCloneUrl string) {
|
||||
|
||||
WriteNewSimpleIndexJS(t, funcProjectPath, "hello branch")
|
||||
sh.Exec("git checkout -b feature/branch")
|
||||
sh.Exec("git add index.js")
|
||||
sh.Exec(`git commit -m "feature branch change"`)
|
||||
sh.Exec("git push -u origin feature/branch")
|
||||
UpdateFuncYamlGit(t, funcProjectPath, Git{URL: clusterCloneUrl, Revision: "feature/branch"})
|
||||
|
||||
}
|
||||
assertBodyFn := func(response string) bool {
|
||||
return strings.Contains(response, "hello branch")
|
||||
}
|
||||
GitRevisionCheck(t, "test-func-feature-branch", setupCodeFn, assertBodyFn)
|
||||
}
|
||||
|
||||
func TestFromRevisionTag(t *testing.T) {
|
||||
|
||||
setupCodeFn := func(sh *common.TestExecCmd, funcProjectPath string, clusterCloneUrl string) {
|
||||
|
||||
WriteNewSimpleIndexJS(t, funcProjectPath, "hello v1")
|
||||
sh.Exec("git add index.js")
|
||||
sh.Exec(`git commit -m "version 1"`)
|
||||
sh.Exec("git push origin main")
|
||||
sh.Exec("git tag tag-v1")
|
||||
sh.Exec("git push origin tag-v1")
|
||||
WriteNewSimpleIndexJS(t, funcProjectPath, "hello v2")
|
||||
sh.Exec("git add index.js")
|
||||
sh.Exec(`git commit -m "version 2"`)
|
||||
sh.Exec("git push origin main")
|
||||
UpdateFuncYamlGit(t, funcProjectPath, Git{URL: clusterCloneUrl, Revision: "tag-v1"})
|
||||
|
||||
}
|
||||
assertBodyFn := func(response string) bool {
|
||||
return strings.Contains(response, "hello v1")
|
||||
}
|
||||
GitRevisionCheck(t, "test-func-tag", setupCodeFn, assertBodyFn)
|
||||
}
|
||||
|
||||
func TestFromCommitHash(t *testing.T) {
|
||||
|
||||
setupCodeFn := func(sh *common.TestExecCmd, funcProjectPath string, clusterCloneUrl string) {
|
||||
|
||||
WriteNewSimpleIndexJS(t, funcProjectPath, "hello v1")
|
||||
sh.Exec("git add index.js")
|
||||
sh.Exec(`git commit -m "version 1"`)
|
||||
sh.Exec("git push origin main")
|
||||
gitRevParse := sh.Exec("git rev-parse HEAD")
|
||||
WriteNewSimpleIndexJS(t, funcProjectPath, "hello v2")
|
||||
sh.Exec("git add index.js")
|
||||
sh.Exec(`git commit -m "version 2"`)
|
||||
sh.Exec("git push origin main")
|
||||
commitHash := strings.TrimSpace(gitRevParse.Stdout)
|
||||
UpdateFuncYamlGit(t, funcProjectPath, Git{URL: clusterCloneUrl, Revision: commitHash})
|
||||
|
||||
t.Logf("Revision Check: commit hash resolved to [%v]", commitHash)
|
||||
}
|
||||
assertBodyFn := func(response string) bool {
|
||||
return strings.Contains(response, "hello v1")
|
||||
}
|
||||
GitRevisionCheck(t, "test-func-commit", setupCodeFn, assertBodyFn)
|
||||
}
|
||||
|
||||
func GitRevisionCheck(
|
||||
t *testing.T,
|
||||
funcName string,
|
||||
setupCodeFn func(shell *common.TestExecCmd, funcProjectPath string, clusterCloneUrl string),
|
||||
assertBodyFn func(response string) bool) {
|
||||
|
||||
var funcPath = filepath.Join(os.TempDir(), funcName)
|
||||
|
||||
gitServer := common.GitTestServerProvider{}
|
||||
gitServer.Init(t)
|
||||
remoteRepo := gitServer.CreateRepository(funcName)
|
||||
defer gitServer.DeleteRepository(funcName)
|
||||
|
||||
knFunc := common.NewKnFuncShellCli(t)
|
||||
knFunc.Exec("create", "-l", "node", funcPath)
|
||||
defer os.RemoveAll(funcPath)
|
||||
|
||||
sh := GitInitialCommitAndPush(t, funcPath, remoteRepo.ExternalCloneURL)
|
||||
|
||||
// Setup specific code
|
||||
setupCodeFn(sh, funcPath, remoteRepo.ClusterCloneURL)
|
||||
|
||||
knFunc.Exec("deploy", "-r", e2e.GetRegistry(), "-p", funcPath)
|
||||
defer knFunc.Exec("delete", "-p", funcPath)
|
||||
|
||||
// -- Assertions --
|
||||
result := knFunc.Exec("invoke", "-p", funcPath)
|
||||
if !assertBodyFn(result.Stdout) {
|
||||
t.Error("Func Body does not contains expected expression")
|
||||
}
|
||||
AssertThatTektonPipelineRunSucceed(t, funcName)
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
//go:build oncluster || runtime
|
||||
// +build oncluster runtime
|
||||
|
||||
package oncluster
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
common "knative.dev/kn-plugin-func/test/_common"
|
||||
e2e "knative.dev/kn-plugin-func/test/_e2e"
|
||||
)
|
||||
|
||||
// TestRuntime will invoke a language runtime test against (by default) to all runtimes.
|
||||
// The Environment Variable E2E_RUNTIMES can be used to select the languages/runtimes to be tested
|
||||
func TestRuntime(t *testing.T) {
|
||||
|
||||
var runtimeList = []string{}
|
||||
runtimes, present := os.LookupEnv("E2E_RUNTIMES")
|
||||
|
||||
if present {
|
||||
if runtimes != "" {
|
||||
runtimeList = strings.Split(runtimes, " ")
|
||||
}
|
||||
} else {
|
||||
runtimeList = []string{"node", "python", "quarkus", "springboot", "typescript"} // "go" and "rust" pending support
|
||||
}
|
||||
for _, lang := range runtimeList {
|
||||
t.Run(lang+"_test", func(t *testing.T) {
|
||||
runtimeImpl(t, lang)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func runtimeImpl(t *testing.T, lang string) {
|
||||
|
||||
var gitProjectName = "test-func-lang-" + lang
|
||||
var gitProjectPath = filepath.Join(os.TempDir(), gitProjectName)
|
||||
var funcName = gitProjectName
|
||||
var funcPath = gitProjectPath
|
||||
|
||||
gitServer := common.GitTestServerProvider{}
|
||||
gitServer.Init(t)
|
||||
remoteRepo := gitServer.CreateRepository(gitProjectName)
|
||||
defer gitServer.DeleteRepository(gitProjectName)
|
||||
|
||||
knFunc := common.NewKnFuncShellCli(t)
|
||||
knFunc.Exec("create", "-l", lang, funcPath)
|
||||
defer os.RemoveAll(gitProjectPath)
|
||||
|
||||
GitInitialCommitAndPush(t, gitProjectPath, remoteRepo.ExternalCloneURL)
|
||||
|
||||
knFunc.Exec("deploy",
|
||||
"-r", e2e.GetRegistry(),
|
||||
"-p", funcPath,
|
||||
"--build", "git",
|
||||
"--git-url", remoteRepo.ClusterCloneURL)
|
||||
|
||||
defer knFunc.Exec("delete", "-p", funcPath)
|
||||
|
||||
// -- Assertions --
|
||||
result := knFunc.Exec("invoke", "-p", funcPath)
|
||||
t.Log(result)
|
||||
AssertThatTektonPipelineRunSucceed(t, funcName)
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package oncluster
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"knative.dev/kn-plugin-func/k8s"
|
||||
"knative.dev/kn-plugin-func/pipelines/tekton"
|
||||
)
|
||||
|
||||
// TektonPipelineExists verifies pipeline with a given prefix exists on cluster
|
||||
func TektonPipelineExists(t *testing.T, pipelinePrefix string) bool {
|
||||
namespace, _, _ := k8s.GetClientConfig().Namespace()
|
||||
client, ns, _ := tekton.NewTektonClientAndResolvedNamespace(namespace)
|
||||
pipelines, err := client.Pipelines(ns).List(context.Background(), v1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
for _, pipeline := range pipelines.Items {
|
||||
if strings.HasPrefix(pipeline.Name, pipelinePrefix) && strings.HasSuffix(pipeline.Name, "-pipeline") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// TektonPipelineRunExists verifies pipelinerun with a given prefix exists on cluster
|
||||
func TektonPipelineRunExists(t *testing.T, pipelineRunPrefix string) bool {
|
||||
namespace, _, _ := k8s.GetClientConfig().Namespace()
|
||||
client, ns, _ := tekton.NewTektonClientAndResolvedNamespace(namespace)
|
||||
pipelineRuns, err := client.PipelineRuns(ns).List(context.Background(), v1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
for _, run := range pipelineRuns.Items {
|
||||
if strings.HasPrefix(run.Name, pipelineRunPrefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type PipelineRunSummary struct {
|
||||
PipelineRunName string
|
||||
PipelineRunStatus string
|
||||
TasksRunSummary []PipelineTaskRunSummary
|
||||
}
|
||||
type PipelineTaskRunSummary struct {
|
||||
TaskName string
|
||||
TaskStatus string
|
||||
}
|
||||
|
||||
func (p *PipelineRunSummary) ToString() string {
|
||||
r := fmt.Sprintf("run: %-42v, status: %v\n", p.PipelineRunName, p.PipelineRunStatus)
|
||||
for _, t := range p.TasksRunSummary {
|
||||
r = r + fmt.Sprintf(" task: %-15v, status: %v\n", t.TaskName, t.TaskStatus)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (p *PipelineRunSummary) IsSucceed() bool {
|
||||
return p.PipelineRunStatus == "Succeeded"
|
||||
}
|
||||
|
||||
// TektonPipelTektonPipelineLastRunSummary gather information about a pipeline run such as
|
||||
// list of tasks executed and status of each task execution. It is meant to be used on assertions
|
||||
func TektonPipelineLastRunSummary(t *testing.T, pipelinePrefix string) *PipelineRunSummary {
|
||||
namespace, _, _ := k8s.GetClientConfig().Namespace()
|
||||
client, ns, _ := tekton.NewTektonClientAndResolvedNamespace(namespace)
|
||||
pipelineRuns, err := client.PipelineRuns(ns).List(context.Background(), v1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
lr := PipelineRunSummary{}
|
||||
for _, run := range pipelineRuns.Items {
|
||||
if strings.HasPrefix(run.Name, pipelinePrefix) {
|
||||
lr.PipelineRunName = run.Name
|
||||
if len(run.Status.Conditions) > 0 {
|
||||
lr.PipelineRunStatus = run.Status.Conditions[0].Reason
|
||||
}
|
||||
lr.TasksRunSummary = []PipelineTaskRunSummary{}
|
||||
for _, taskRun := range run.Status.TaskRuns {
|
||||
trun := PipelineTaskRunSummary{}
|
||||
trun.TaskName = taskRun.PipelineTaskName
|
||||
if len(taskRun.Status.Conditions) > 0 {
|
||||
trun.TaskStatus = taskRun.Status.Conditions[0].Reason
|
||||
}
|
||||
lr.TasksRunSummary = append(lr.TasksRunSummary, trun)
|
||||
}
|
||||
}
|
||||
}
|
||||
return &lr
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
#!/usr/bin/env bash
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
#
|
||||
# Runs basic lifecycle E2E tests against kn func cli for a given language/runtime.
|
||||
# By default it will run e2e tests against 'func' binary, but you can change it to use 'kn func' instead
|
||||
#
|
||||
# The following environment variable can be set in order to customize e2e execution:
|
||||
#
|
||||
# E2E_USE_KN_FUNC When set to "true" indicates e2e to issue func command using kn cli.
|
||||
#
|
||||
# E2E_REGISTRY_URL Indicates a specific registry (i.e: "quay.io/user") should be used. Make sure
|
||||
# to authenticate to the registry (i.e: docker login ...) prior to execute the script
|
||||
# By default it uses "ttl.sh" registry
|
||||
#
|
||||
# E2E_FUNC_BIN_PATH Path to func binary. Derived by this script when not set
|
||||
#
|
||||
# E2E_RUNTIMES List of runtimes (space separated) to execute TestRuntime.
|
||||
#
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
runtime=${1:-}
|
||||
use_kn_func=${E2E_USE_KN_FUNC:-}
|
||||
|
||||
curdir=$(pwd)
|
||||
cd $(dirname $0)
|
||||
cd ../
|
||||
|
||||
REGISTRY_PROJ=knfunc$(head -c 128 </dev/urandom | LC_CTYPE=C tr -dc 'a-z0-9' | fold -w 8 | head -n 1)
|
||||
export E2E_REGISTRY_URL=${E2E_REGISTRY_URL:-ttl.sh/$REGISTRY_PROJ}
|
||||
export E2E_FUNC_BIN_PATH=${E2E_FUNC_BIN_PATH:-$(pwd)/func}
|
||||
|
||||
# Make sure 'func' binary is built in case KN FUNC was not required for testing
|
||||
if [[ ! -f "$E2E_FUNC_BIN_PATH" && "$use_kn_func" != "true" ]]; then
|
||||
echo "func binary not found. Please run 'make build' prior to run e2e."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
go clean -testcache
|
||||
go test -v -test.v -test.timeout=90m -tags="${TEST_TAGS:-oncluster}" ./test/_oncluster/
|
||||
ret=$?
|
||||
|
||||
cd $curdir
|
||||
exit $ret
|
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
git_server() {
|
||||
echo "Creating Git Server Knative service..."
|
||||
cat << EOF | kubectl apply -f -
|
||||
apiVersion: serving.knative.dev/v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: func-git
|
||||
labels:
|
||||
app: git
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
autoscaling.knative.dev/max-scale: "1"
|
||||
autoscaling.knative.dev/min-scale: "1"
|
||||
client.knative.dev/user-image: ghcr.io/jrangelramos/gitserver
|
||||
spec:
|
||||
containers:
|
||||
- image: ghcr.io/jrangelramos/gitserver
|
||||
ports:
|
||||
- containerPort: 80
|
||||
resources: {}
|
||||
status: {}
|
||||
EOF
|
||||
|
||||
kubectl wait ksvc --for=condition=RoutesReady --timeout=30s -l "app=git"
|
||||
}
|
||||
|
||||
git_server
|
||||
|
||||
echo Done
|
Loading…
Reference in New Issue