mirror of https://github.com/knative/func.git
integration test isolation (#2894)
- Default builder and pusher set to embedded Host Builder/Pusher(oci) - Most tests clear environment - Environment defaults can be controlled via environment variables - Tests which require back-compat `git` binary actively check and skip when running with a cleared environment (both integration and unit). - Bugfixes for when run in tandem with E2E tests - Ignores go-created directories in the default home path (testdata)
This commit is contained in:
parent
a18f763b6a
commit
18a119abff
|
@ -10,10 +10,13 @@
|
|||
/hack/bin
|
||||
/.artifacts
|
||||
|
||||
/e2e/testdata/default_home/go
|
||||
/e2e/testdata/default_home/.cache
|
||||
|
||||
/pkg/functions/testdata/migrations/*/.gitignore
|
||||
/pkg/functions/testdata/default_home/go
|
||||
/pkg/functions/testdata/default_home/.cache
|
||||
/pkg/functions/testdata/migrations/*/.gitignore
|
||||
|
||||
# Go
|
||||
/templates/go/cloudevents/go.sum
|
||||
|
||||
# JS
|
||||
node_modules
|
||||
|
@ -25,10 +28,12 @@ __pycache__
|
|||
/templates/python/cloudevents/.venv
|
||||
/templates/python/http/.venv
|
||||
|
||||
# VSCode
|
||||
.vscode
|
||||
# E2E Tests
|
||||
/e2e/testdata/default_home/go
|
||||
/e2e/testdata/default_home/.cache
|
||||
|
||||
# IntelliJ
|
||||
# Editors
|
||||
.vscode
|
||||
.idea
|
||||
|
||||
# Operating system temporary files
|
||||
|
|
|
@ -9,8 +9,9 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -18,11 +19,11 @@ import (
|
|||
"github.com/docker/docker/api/types/volume"
|
||||
"github.com/docker/docker/client"
|
||||
|
||||
"knative.dev/func/pkg/builders/buildpacks"
|
||||
"knative.dev/func/pkg/builders/s2i"
|
||||
"knative.dev/func/pkg/docker"
|
||||
fn "knative.dev/func/pkg/functions"
|
||||
"knative.dev/func/pkg/knative"
|
||||
"knative.dev/func/pkg/oci"
|
||||
. "knative.dev/func/pkg/testing"
|
||||
"knative.dev/pkg/ptr"
|
||||
)
|
||||
|
@ -31,57 +32,60 @@ import (
|
|||
//
|
||||
// go test -tags integration ./...
|
||||
//
|
||||
// ## Cluster Required
|
||||
// ## Requirements
|
||||
//
|
||||
// These integration tests require a properly configured cluster,
|
||||
// such as that which is setup and configured in CI (see .github/workflows).
|
||||
// Linux developers can set up the cluster via:
|
||||
// A cluster is required. See .github/workflows for more. For example:
|
||||
//
|
||||
// ./hack/install-binaries.sh && ./hack/allocate.sh && ./hack/registry.sh
|
||||
//
|
||||
// Binaries are required: go for compiling functions and git for
|
||||
// repository-related tests.
|
||||
//
|
||||
// ## Cluster Cleanup
|
||||
//
|
||||
// The test cluster and most resources can be removed with:
|
||||
// ./hack/delete.sh
|
||||
//
|
||||
// ## Configuration
|
||||
//
|
||||
// Use the FUNC_INT_* environment variables to alter behavior, binaries to
|
||||
// use, etc.
|
||||
//
|
||||
// NOTE: Downloaded images are not removed.
|
||||
//
|
||||
|
||||
const (
|
||||
// DefaultRegistry must contain both the registry host and
|
||||
// registry namespace at this time. This will likely be
|
||||
// split and defaulted to the forthcoming in-cluster registry.
|
||||
DefaultRegistry = "localhost:50000/func"
|
||||
|
||||
// DefaultNamespace for the underlying deployments. Must be the same
|
||||
// as is set up and configured (see hack/configure.sh)
|
||||
DefaultNamespace = "func"
|
||||
DefaultIntTestHome = "./testdata/default_home"
|
||||
DefaultIntTestKubeconfig = "../../hack/bin/kubeconfig.yaml"
|
||||
DefaultIntTestRegistry = "localhost:50000/func"
|
||||
DefaultIntTestNamespace = "default"
|
||||
DefaultIntTestVerbose = false
|
||||
)
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
verbose := true
|
||||
var (
|
||||
Go = getEnvAsBin("FUNC_INT_GO", "go")
|
||||
Git = getEnvAsBin("FUNC_INT_GIT", "git")
|
||||
Kubeconfig = getEnvAsPath("FUNC_INT_KUBECONFIG", DefaultIntTestKubeconfig)
|
||||
Verbose = getEnvAsBool("FUNC_INT_VERBOSE", DefaultIntTestVerbose)
|
||||
Registry = getEnv("FUNC_INT_REGISTRY", DefaultIntTestRegistry)
|
||||
Home, _ = filepath.Abs(DefaultIntTestHome)
|
||||
)
|
||||
|
||||
// Assemble
|
||||
lister := knative.NewLister(verbose)
|
||||
|
||||
client := fn.New(
|
||||
fn.WithLister(lister),
|
||||
fn.WithVerbose(verbose))
|
||||
|
||||
// Act
|
||||
names, err := client.List(context.Background(), DefaultNamespace)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Assert
|
||||
if len(names) != 0 {
|
||||
t.Fatalf("Expected no functions, got %v", names)
|
||||
// containsInstance checks if the list includes the given instance.
|
||||
func containsInstance(list []fn.ListItem, name, namespace string) bool {
|
||||
for _, v := range list {
|
||||
if v.Name == name && v.Namespace == namespace {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
// Note that client.List is tested implicitly via its use in TestInt_New
|
||||
// and TestInt_Delete.
|
||||
}
|
||||
|
||||
// TestNew creates
|
||||
func TestNew(t *testing.T) {
|
||||
// TestInt_New creates
|
||||
func TestInt_New(t *testing.T) {
|
||||
resetEnv()
|
||||
// Assemble
|
||||
root, cleanup := Mktemp(t)
|
||||
defer cleanup()
|
||||
|
@ -90,32 +94,32 @@ func TestNew(t *testing.T) {
|
|||
client := newClient(verbose)
|
||||
|
||||
// Act
|
||||
if _, _, err := client.New(context.Background(), fn.Function{Name: name, Namespace: DefaultNamespace, Root: root, Runtime: "go"}); err != nil {
|
||||
if _, _, err := client.New(context.Background(), fn.Function{Name: name, Namespace: DefaultIntTestNamespace, Root: root, Runtime: "go"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer del(t, client, name, DefaultNamespace)
|
||||
defer del(t, client, name, DefaultIntTestNamespace)
|
||||
|
||||
// Assert
|
||||
items, err := client.List(context.Background(), DefaultNamespace)
|
||||
names := []string{}
|
||||
for _, item := range items {
|
||||
names = append(names, item.Name)
|
||||
}
|
||||
list, err := client.List(context.Background(), DefaultIntTestNamespace)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(names, []string{name}) {
|
||||
t.Fatalf("Expected function list ['%v'], got %v", name, names)
|
||||
|
||||
if !containsInstance(list, name, DefaultIntTestNamespace) {
|
||||
t.Log(list)
|
||||
t.Fatalf("deployed instance list does not contain function %q", name)
|
||||
}
|
||||
}
|
||||
|
||||
// TestDeploy_Defaults deployes using client methods from New but manually
|
||||
func TestDeploy_Defaults(t *testing.T) {
|
||||
defer Within(t, "testdata/example.com/deploy")()
|
||||
// TestInt_Deploy_Defaults deployes using client methods from New but manually
|
||||
func TestInt_Deploy_Defaults(t *testing.T) {
|
||||
resetEnv()
|
||||
_, cleanup := Mktemp(t)
|
||||
defer cleanup()
|
||||
verbose := true
|
||||
|
||||
client := newClient(verbose)
|
||||
f := fn.Function{Name: "deploy", Namespace: DefaultNamespace, Root: ".", Runtime: "go"}
|
||||
f := fn.Function{Name: "deploy", Namespace: DefaultIntTestNamespace, Runtime: "go"}
|
||||
var err error
|
||||
|
||||
if f, err = client.Init(f); err != nil {
|
||||
|
@ -128,7 +132,7 @@ func TestDeploy_Defaults(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer del(t, client, "deploy", DefaultNamespace)
|
||||
defer del(t, client, "deploy", DefaultIntTestNamespace)
|
||||
// TODO: gauron99 -- remove this when you set full image name after build instead
|
||||
// of push -- this has to be here because of a workaround
|
||||
f.Deploy.Image = f.Build.Image
|
||||
|
@ -138,13 +142,14 @@ func TestDeploy_Defaults(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestDeploy_WithOptions deploys function with all options explicitly set
|
||||
func TestDeploy_WithOptions(t *testing.T) {
|
||||
// TestInt_Deploy_WithOptions deploys function with all options explicitly set
|
||||
func TestInt_Deploy_WithOptions(t *testing.T) {
|
||||
resetEnv()
|
||||
root, cleanup := Mktemp(t)
|
||||
defer cleanup()
|
||||
verbose := false
|
||||
|
||||
f := fn.Function{Runtime: "go", Name: "test-deploy-with-options", Root: root, Namespace: DefaultNamespace}
|
||||
f := fn.Function{Runtime: "go", Name: "test-deploy-with-options", Root: root, Namespace: DefaultIntTestNamespace}
|
||||
f.Deploy = fn.DeploySpec{
|
||||
Options: fn.Options{
|
||||
Scale: &fn.ScaleOptions{
|
||||
|
@ -172,15 +177,16 @@ func TestDeploy_WithOptions(t *testing.T) {
|
|||
if _, _, err := client.New(context.Background(), f); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer del(t, client, "test-deploy-with-options", DefaultNamespace)
|
||||
defer del(t, client, "test-deploy-with-options", DefaultIntTestNamespace)
|
||||
}
|
||||
|
||||
func TestDeployWithTriggers(t *testing.T) {
|
||||
func TestInt_Deploy_WithTriggers(t *testing.T) {
|
||||
resetEnv()
|
||||
root, cleanup := Mktemp(t)
|
||||
defer cleanup()
|
||||
verbose := true
|
||||
|
||||
f := fn.Function{Runtime: "go", Name: "test-deploy-with-triggers", Root: root, Namespace: DefaultNamespace}
|
||||
f := fn.Function{Runtime: "go", Name: "test-deploy-with-triggers", Root: root, Namespace: DefaultIntTestNamespace}
|
||||
f.Deploy = fn.DeploySpec{
|
||||
Subscriptions: []fn.KnativeSubscription{
|
||||
{
|
||||
|
@ -197,27 +203,29 @@ func TestDeployWithTriggers(t *testing.T) {
|
|||
if _, _, err := client.New(context.Background(), f); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer del(t, client, "test-deploy-with-triggers", DefaultNamespace)
|
||||
defer del(t, client, "test-deploy-with-triggers", DefaultIntTestNamespace)
|
||||
}
|
||||
|
||||
func TestUpdateWithAnnotationsAndLabels(t *testing.T) {
|
||||
func TestInt_Update_WithAnnotationsAndLabels(t *testing.T) {
|
||||
resetEnv()
|
||||
_, cleanup := Mktemp(t)
|
||||
defer cleanup()
|
||||
functionName := "updateannlab"
|
||||
defer Within(t, "testdata/example.com/"+functionName)()
|
||||
verbose := false
|
||||
|
||||
servingClient, err := knative.NewServingClient(DefaultNamespace)
|
||||
servingClient, err := knative.NewServingClient(DefaultIntTestNamespace)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Deploy a function without any annotations or labels
|
||||
client := newClient(verbose)
|
||||
f := fn.Function{Name: functionName, Root: ".", Runtime: "go", Namespace: DefaultNamespace}
|
||||
f := fn.Function{Name: functionName, Runtime: "go", Namespace: DefaultIntTestNamespace}
|
||||
|
||||
if _, f, err = client.New(context.Background(), f); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer del(t, client, functionName, DefaultNamespace)
|
||||
defer del(t, client, functionName, DefaultIntTestNamespace)
|
||||
|
||||
// Updated function with a new set of annotations and labels
|
||||
// deploy and check that deployed kcsv contains correct annotations and labels
|
||||
|
@ -295,41 +303,47 @@ func TestUpdateWithAnnotationsAndLabels(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestRemove ensures removal of a function instance.
|
||||
func TestRemove(t *testing.T) {
|
||||
defer Within(t, "testdata/example.com/remove")()
|
||||
// TestInt_Remove ensures removal of a function instance.
|
||||
func TestInt_Remove(t *testing.T) {
|
||||
resetEnv()
|
||||
_, cleanup := Mktemp(t)
|
||||
defer cleanup()
|
||||
verbose := true
|
||||
name := "remove"
|
||||
|
||||
client := newClient(verbose)
|
||||
f := fn.Function{Name: "remove", Namespace: DefaultNamespace, Root: ".", Runtime: "go"}
|
||||
f := fn.Function{Name: name, Namespace: DefaultIntTestNamespace, Runtime: "go"}
|
||||
var err error
|
||||
if _, _, err = client.New(context.Background(), f); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
del(t, client, "remove", DefaultNamespace)
|
||||
del(t, client, "remove", DefaultIntTestNamespace)
|
||||
|
||||
names, err := client.List(context.Background(), DefaultNamespace)
|
||||
list, err := client.List(context.Background(), DefaultIntTestNamespace)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(names) != 0 {
|
||||
t.Fatalf("Expected empty functions list, got %v", names)
|
||||
if containsInstance(list, name, DefaultIntTestNamespace) {
|
||||
t.Log(list)
|
||||
t.Fatalf("deployed instance list still contains function %q", name)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRemoteRepositories ensures that initializing a function
|
||||
// TestInt_RemoteRepositories ensures that initializing a function
|
||||
// defined in a remote repository finds the template, writes
|
||||
// the expected files, and retains the expected modes.
|
||||
// NOTE: this test only succeeds due to an override in
|
||||
// templates' copyNode which forces mode 755 for directories.
|
||||
// See https://github.com/go-git/go-git/issues/364
|
||||
func TestRemoteRepositories(t *testing.T) {
|
||||
defer Within(t, "testdata/example.com/remote")()
|
||||
func TestInt_RemoteRepositories(t *testing.T) {
|
||||
resetEnv()
|
||||
_, cleanup := Mktemp(t)
|
||||
defer cleanup()
|
||||
|
||||
// Write the test template from the remote onto root
|
||||
client := fn.New(
|
||||
fn.WithRegistry(DefaultRegistry),
|
||||
fn.WithRegistry(DefaultIntTestRegistry),
|
||||
fn.WithRepository("https://github.com/boson-project/test-templates"),
|
||||
)
|
||||
_, err := client.Init(fn.Function{
|
||||
|
@ -368,22 +382,23 @@ func TestRemoteRepositories(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestInvoke_ClientToService ensures that the client can invoke a remotely
|
||||
// TestInt_Invoke_ClientToService ensures that the client can invoke a remotely
|
||||
// deployed service, both by the route returned directly as well as using
|
||||
// the invocation helper client.Invoke.
|
||||
func TestInvoke_ClientToService(t *testing.T) {
|
||||
func TestInt_Invoke_ClientToService(t *testing.T) {
|
||||
resetEnv()
|
||||
root, cleanup := Mktemp(t)
|
||||
defer cleanup()
|
||||
var (
|
||||
root, done = Mktemp(t)
|
||||
verbose = true
|
||||
ctx = context.Background()
|
||||
client = newClient(verbose)
|
||||
route string
|
||||
err error
|
||||
)
|
||||
defer done()
|
||||
|
||||
// Create a function
|
||||
f := fn.Function{Name: "f", Runtime: "go", Namespace: DefaultNamespace}
|
||||
f := fn.Function{Name: "f", Runtime: "go", Namespace: DefaultIntTestNamespace}
|
||||
f, err = client.Init(f)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -391,12 +406,9 @@ func TestInvoke_ClientToService(t *testing.T) {
|
|||
source := `
|
||||
package function
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
import "net/http"
|
||||
|
||||
func Handle(ctx context.Context, res http.ResponseWriter, req *http.Request) {
|
||||
func Handle(res http.ResponseWriter, req *http.Request) {
|
||||
res.Write([]byte("TestInvoke_ClientToService OK"))
|
||||
}
|
||||
`
|
||||
|
@ -411,7 +423,7 @@ func Handle(ctx context.Context, res http.ResponseWriter, req *http.Request) {
|
|||
if err := f.Write(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer del(t, client, "f", DefaultNamespace)
|
||||
defer del(t, client, "f", DefaultIntTestNamespace)
|
||||
|
||||
// Invoke via the route
|
||||
resp, err := http.Get(route)
|
||||
|
@ -439,9 +451,10 @@ func Handle(ctx context.Context, res http.ResponseWriter, req *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestInvoke_ServiceToService ensures that a Function can invoke another
|
||||
// TestInt_Invoke_ServiceToService ensures that a Function can invoke another
|
||||
// service via localhost service discovery api provided by the Dapr sidecar.
|
||||
func TestInvoke_ServiceToService(t *testing.T) {
|
||||
func TestInt_Invoke_ServiceToService(t *testing.T) {
|
||||
resetEnv()
|
||||
var (
|
||||
verbose = true
|
||||
ctx = context.Background()
|
||||
|
@ -455,7 +468,7 @@ func TestInvoke_ServiceToService(t *testing.T) {
|
|||
// A function which responds to GET requests with a static value.
|
||||
root, done := Mktemp(t)
|
||||
defer done()
|
||||
f := fn.Function{Name: "a", Runtime: "go", Namespace: DefaultNamespace}
|
||||
f := fn.Function{Name: "a", Runtime: "go", Namespace: DefaultIntTestNamespace}
|
||||
f, err = client.Init(f)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -463,12 +476,9 @@ func TestInvoke_ServiceToService(t *testing.T) {
|
|||
source = `
|
||||
package function
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
import "net/http"
|
||||
|
||||
func Handle(ctx context.Context, res http.ResponseWriter, req *http.Request) {
|
||||
func Handle(res http.ResponseWriter, req *http.Request) {
|
||||
res.Write([]byte("TestInvoke_ServiceToService OK"))
|
||||
}
|
||||
`
|
||||
|
@ -479,15 +489,16 @@ func Handle(ctx context.Context, res http.ResponseWriter, req *http.Request) {
|
|||
if _, _, err = client.Apply(ctx, f); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer del(t, client, "a", DefaultNamespace)
|
||||
defer del(t, client, "a", DefaultIntTestNamespace)
|
||||
|
||||
// Create Function B
|
||||
// which responds with the response from an invocation of 'a' via the
|
||||
// localhost service discovery and invocation API.
|
||||
client2 := newClient(verbose)
|
||||
root, done = Mktemp(t)
|
||||
defer done()
|
||||
f = fn.Function{Name: "b", Runtime: "go", Namespace: DefaultNamespace}
|
||||
f, err = client.Init(f)
|
||||
f = fn.Function{Name: "b", Runtime: "go", Namespace: DefaultIntTestNamespace}
|
||||
f, err = client2.Init(f)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -497,7 +508,6 @@ package function
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
@ -505,7 +515,7 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
func Handle(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
func Handle(w http.ResponseWriter, req *http.Request) {
|
||||
var e error
|
||||
var r *http.Response
|
||||
var buff bytes.Buffer
|
||||
|
@ -535,10 +545,10 @@ func Handle(ctx context.Context, w http.ResponseWriter, req *http.Request) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if route, _, err = client.Apply(ctx, f); err != nil {
|
||||
if route, f, err = client2.Apply(ctx, f); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer del(t, client, "b", DefaultNamespace)
|
||||
defer client2.Remove(ctx, "", "", f, true)
|
||||
|
||||
resp, err := http.Get(route)
|
||||
if err != nil {
|
||||
|
@ -566,7 +576,7 @@ func TestDeployWithoutHome(t *testing.T) {
|
|||
verbose := false
|
||||
name := "test-deploy-no-home"
|
||||
|
||||
f := fn.Function{Runtime: "node", Name: name, Root: root, Namespace: DefaultNamespace}
|
||||
f := fn.Function{Runtime: "node", Name: name, Root: root, Namespace: DefaultIntTestNamespace}
|
||||
|
||||
// client with s2i builder because pack needs HOME
|
||||
client := newClientWithS2i(verbose)
|
||||
|
@ -577,32 +587,84 @@ func TestDeployWithoutHome(t *testing.T) {
|
|||
t.Fatalf("expected no errors but got %v", err)
|
||||
}
|
||||
|
||||
defer del(t, client, name, DefaultNamespace)
|
||||
defer del(t, client, name, DefaultIntTestNamespace)
|
||||
}
|
||||
|
||||
// ***********
|
||||
// Helpers
|
||||
// ***********
|
||||
|
||||
func getEnvAsPath(env, dflt string) (val string) {
|
||||
val = getEnv(env, dflt)
|
||||
if !filepath.IsAbs(val) { // convert to abs
|
||||
var err error
|
||||
if val, err = filepath.Abs(val); err != nil {
|
||||
panic(fmt.Sprintf("error converting path to absolute. %v", err))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getEnvAsBool(env string, dfltBool bool) bool {
|
||||
dflt := fmt.Sprintf("%t", dfltBool)
|
||||
val, err := strconv.ParseBool(getEnv(env, dflt))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("value for %v expected to be boolean. %v", env, err))
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func getEnvAsBin(env, dflt string) string {
|
||||
val, err := exec.LookPath(getEnv(env, dflt))
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error locating command %q. %v", val, err)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func getEnv(env, dflt string) (val string) {
|
||||
if v := os.Getenv(env); v != "" {
|
||||
val = v
|
||||
}
|
||||
if val == "" {
|
||||
val = dflt
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func resetEnv() {
|
||||
os.Clearenv()
|
||||
os.Setenv("HOME", Home)
|
||||
os.Setenv("KUBECONFIG", Kubeconfig)
|
||||
os.Setenv("FUNC_GO", Go)
|
||||
os.Setenv("FUNC_GIT", Git)
|
||||
os.Setenv("FUNC_VERBOSE", fmt.Sprintf("%t", Verbose))
|
||||
|
||||
// The Registry will be set either during first-time setup using the
|
||||
// global config, or already defaulted by the user via environment variable.
|
||||
os.Setenv("FUNC_REGISTRY", Registry)
|
||||
|
||||
// The following host-builder related settings will become the defaults
|
||||
// once the host builder supports the core runtimes. Setting them here in
|
||||
// order to futureproof individual tests.
|
||||
os.Setenv("FUNC_ENABLE_HOST_BUILDER", "true") // Enable the host builder
|
||||
os.Setenv("FUNC_BUILDER", "host") // default to host builder
|
||||
os.Setenv("FUNC_CONTAINER", "false") // "run" uses host builder
|
||||
|
||||
}
|
||||
|
||||
// newClient creates an instance of the func client with concrete impls
|
||||
// sufficient for running integration tests.
|
||||
func newClient(verbose bool) *fn.Client {
|
||||
builder := buildpacks.NewBuilder(buildpacks.WithVerbose(verbose))
|
||||
pusher := docker.NewPusher(docker.WithVerbose(verbose))
|
||||
deployer := knative.NewDeployer(knative.WithDeployerVerbose(verbose))
|
||||
describer := knative.NewDescriber(verbose)
|
||||
remover := knative.NewRemover(verbose)
|
||||
lister := knative.NewLister(verbose)
|
||||
|
||||
return fn.New(
|
||||
fn.WithRegistry(DefaultRegistry),
|
||||
fn.WithRegistry(DefaultIntTestRegistry),
|
||||
fn.WithBuilder(oci.NewBuilder("", verbose)),
|
||||
fn.WithPusher(oci.NewPusher(true, true, verbose)),
|
||||
fn.WithDeployer(knative.NewDeployer(knative.WithDeployerVerbose(verbose))),
|
||||
fn.WithDescriber(knative.NewDescriber(verbose)),
|
||||
fn.WithRemover(knative.NewRemover(verbose)),
|
||||
fn.WithLister(knative.NewLister(verbose)),
|
||||
fn.WithVerbose(verbose),
|
||||
fn.WithBuilder(builder),
|
||||
fn.WithPusher(pusher),
|
||||
fn.WithDeployer(deployer),
|
||||
fn.WithDescriber(describer),
|
||||
fn.WithRemover(remover),
|
||||
fn.WithLister(lister),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -616,7 +678,7 @@ func newClientWithS2i(verbose bool) *fn.Client {
|
|||
lister := knative.NewLister(verbose)
|
||||
|
||||
return fn.New(
|
||||
fn.WithRegistry(DefaultRegistry),
|
||||
fn.WithRegistry(DefaultIntTestRegistry),
|
||||
fn.WithVerbose(verbose),
|
||||
fn.WithBuilder(builder),
|
||||
fn.WithPusher(pusher),
|
||||
|
@ -640,10 +702,23 @@ func newClientWithS2i(verbose bool) *fn.Client {
|
|||
func del(t *testing.T, c *fn.Client, name, namespace string) {
|
||||
t.Helper()
|
||||
waitFor(t, c, name, namespace)
|
||||
f := fn.Function{Name: name, Deploy: fn.DeploySpec{Namespace: DefaultNamespace}}
|
||||
f := fn.Function{Name: name, Deploy: fn.DeploySpec{Namespace: DefaultIntTestNamespace}}
|
||||
if err := c.Remove(context.Background(), "", "", f, false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// TODO(lkingland): The below breaks things
|
||||
// The following should not exist, nor its imports.
|
||||
//
|
||||
// If there is ever a problem with dangling volumes, that is
|
||||
// something which should be fixed in the _remover_, and tested there.
|
||||
//
|
||||
// ... check with Jefferson what caused such a state, open an
|
||||
// issue to alter remover if necessary, and then delete all of this.
|
||||
if true {
|
||||
return
|
||||
}
|
||||
|
||||
cli, _, err := docker.NewClient(client.DefaultDockerHost)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
|
@ -45,7 +45,7 @@ const (
|
|||
// but functional deployer, use fn.WithDeployer(mock.NewDeployer()) which
|
||||
// will return a result with the target namespace populated "mocking"
|
||||
// that the function was actually deployed.
|
||||
TestNamespace = "func"
|
||||
TestNamespace = "default"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -348,7 +348,9 @@ func TestClient_New_HiddenFilesIgnored(t *testing.T) {
|
|||
// $FUNC_REPOSITORIES_PATH/boson/go/json
|
||||
// See the CLI for full details, but a standard default location is
|
||||
// $HOME/.config/func/repositories/boson/go/json
|
||||
func TestClient_New_RepositoriesExtensible(t *testing.T) {
|
||||
func TestClient_New_RepositoriesExtensible_B(t *testing.T) {
|
||||
skipIfNoGit(t) // see function doc
|
||||
|
||||
root := "testdata/example.com/test-repositories-extensible"
|
||||
defer Using(t, root)()
|
||||
|
||||
|
@ -391,6 +393,7 @@ func TestClient_New_RuntimeNotFoundError(t *testing.T) {
|
|||
// TestClient_New_RuntimeNotFoundCustom ensures that the correct error is returned
|
||||
// when the requested runtime is not found in a given custom repository
|
||||
func TestClient_New_RuntimeNotFoundCustom(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
root := "testdata/example.com/testRuntimeNotFoundCustom"
|
||||
defer Using(t, root)()
|
||||
|
||||
|
@ -429,6 +432,7 @@ func TestClient_New_TemplateNotFoundError(t *testing.T) {
|
|||
// TestClient_New_TemplateNotFoundCustom ensures that the correct error is returned
|
||||
// when the requested template is not found in the given custom repository.
|
||||
func TestClient_New_TemplateNotFoundCustom(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
root := "testdata/example.com/testTemplateNotFoundCustom"
|
||||
defer Using(t, root)()
|
||||
|
||||
|
@ -1611,6 +1615,7 @@ func TestClient_Scaffold(t *testing.T) {
|
|||
|
||||
// TestClient_Runtimes ensures that the total set of runtimes are returned.
|
||||
func TestClient_Runtimes(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
// TODO: test when a specific repo override is indicated
|
||||
// (remote repo which takes precedence over embedded and extended)
|
||||
|
||||
|
|
|
@ -448,8 +448,7 @@ func TestFunction_Local(t *testing.T) {
|
|||
//
|
||||
// The new function should not have Local.Remote set (as it is a transient field)
|
||||
func TestFunction_LocalTransient(t *testing.T) {
|
||||
|
||||
// Initialise a new function
|
||||
skipIfNoGit(t) // see docs
|
||||
root, rm := Mktemp(t)
|
||||
defer rm()
|
||||
|
||||
|
@ -520,7 +519,7 @@ func TestFunction_LocalTransient(t *testing.T) {
|
|||
InsecureSkipTLS: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal()
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create a new directory to clone the function in
|
||||
|
|
|
@ -5,6 +5,7 @@ package functions_test
|
|||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
|
@ -52,6 +53,7 @@ func TestRepositories_GetInvalid(t *testing.T) {
|
|||
|
||||
// TestRepositories_Get ensures a repository can be accessed by name.
|
||||
func TestRepositories_Get(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
client := fn.New(fn.WithRepositoriesPath("testdata/repositories"))
|
||||
|
||||
// valid should not error
|
||||
|
@ -69,6 +71,7 @@ func TestRepositories_Get(t *testing.T) {
|
|||
// TestRepositories_All ensures repos are returned from
|
||||
// .All accessor. Tests both builtin and buitlin+extensible cases.
|
||||
func TestRepositories_All(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
uri := ServeRepo(RepositoriesTestRepo, t)
|
||||
root, rm := Mktemp(t)
|
||||
defer rm()
|
||||
|
@ -106,6 +109,7 @@ func TestRepositories_All(t *testing.T) {
|
|||
|
||||
// TestRepositories_Add checks basic adding of a repository by URI.
|
||||
func TestRepositories_Add(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
uri := ServeRepo(RepositoriesTestRepo, t) // ./testdata/$RepositoriesTestRepo.git
|
||||
root, rm := Mktemp(t) // create and cd to a temp dir, returning path.
|
||||
defer rm()
|
||||
|
@ -140,6 +144,7 @@ func TestRepositories_Add(t *testing.T) {
|
|||
// TestRepositories_AddDefaultName ensures that repository name is optional,
|
||||
// by default being set to the name of the repoisotory from the URI.
|
||||
func TestRepositories_AddDeafultName(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
// The test repository is the "base case" repo, which is a manifestless
|
||||
// repo meant to exemplify the simplest use case: a repo with no metadata
|
||||
// that simply contains templates, grouped by runtime. It therefore does
|
||||
|
@ -175,6 +180,7 @@ func TestRepositories_AddDeafultName(t *testing.T) {
|
|||
// a manfest wherein a default name is specified, is used as the name for the
|
||||
// added repository when a name is not explicitly specified.
|
||||
func TestRepositories_AddWithManifest(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
// repository-b is meant to exemplify the use case of a repository which
|
||||
// defines a custom language pack and makes full use of the manifest.yaml.
|
||||
// The manifest.yaml is included which specifies things like custom templates
|
||||
|
@ -210,6 +216,7 @@ func TestRepositories_AddWithManifest(t *testing.T) {
|
|||
// TestRepositories_AddExistingErrors ensures that adding a repository that
|
||||
// already exists yields an error.
|
||||
func TestRepositories_AddExistingErrors(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
uri := ServeRepo(RepositoriesTestRepo, t)
|
||||
root, rm := Mktemp(t) // create and cd to a temp dir, returning path.
|
||||
defer rm()
|
||||
|
@ -244,6 +251,7 @@ func TestRepositories_AddExistingErrors(t *testing.T) {
|
|||
|
||||
// TestRepositories_Rename ensures renaming a repository succeeds.
|
||||
func TestRepositories_Rename(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
uri := ServeRepo(RepositoriesTestRepo, t)
|
||||
root, rm := Mktemp(t) // create and cd to a temp dir, returning path.
|
||||
defer rm()
|
||||
|
@ -278,6 +286,7 @@ func TestRepositories_Rename(t *testing.T) {
|
|||
// TestRepositories_Remove ensures that removing a repository by name
|
||||
// removes it from the list and FS.
|
||||
func TestRepositories_Remove(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
uri := ServeRepo(RepositoriesTestRepo, t) // ./testdata/repository.git
|
||||
root, rm := Mktemp(t) // create and cd to a temp dir
|
||||
defer rm()
|
||||
|
@ -313,6 +322,7 @@ func TestRepositories_Remove(t *testing.T) {
|
|||
// TestRepositories_URL ensures that a repository populates its URL member
|
||||
// from the git repository's origin url (if it is a git repo and exists)
|
||||
func TestRepositories_URL(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
uri := ServeRepo(RepositoriesTestRepo, t)
|
||||
root, rm := Mktemp(t)
|
||||
defer rm()
|
||||
|
@ -353,3 +363,34 @@ func TestRepositories_Missing(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// skipIfNoGit skips the test if there is no 'git' available in PATH.
|
||||
//
|
||||
// The 'go-git' dependency only has partial support for file:// paths.
|
||||
// see: https://github.com/go-git/go-git/blob/master/COMPATIBILITY.md
|
||||
// Therefore the "git" binary is used as a fallback.
|
||||
//
|
||||
// These file:// paths we rely on for cloning repositories from the
|
||||
// inbuilt repositories. Therefore, it is not a "pure-go" implementation
|
||||
// of git. This results in there being a hard dependency on the "git"
|
||||
// program, which this library uses as a fallback.
|
||||
// TODO: We can either 1) reimplement this functionality ourselves
|
||||
// by capturing file:// paths and just copying the files (we don't need
|
||||
// the git repository; just the files), 2) find a library which
|
||||
// does actually implmement this part of git without relying on "git",
|
||||
// 3) submit a patch upstream which implements this functionality.
|
||||
// 4) At least submit a patch upstream allowing the path of the git bin
|
||||
// to be specified when no PATH.
|
||||
// Temporary workaround: Detect when this test is being run alongside
|
||||
// the integration/e2e tests (which clear the environment), and skip.
|
||||
func skipIfNoGit(t *testing.T) {
|
||||
// integration and e2e tests clear their environment in order to
|
||||
// obtain isolation. If there is no 'git' available; skip the test.
|
||||
// Note that our libraries accept an environmental override for these
|
||||
// binaries (FUNC_E2E_GIT for example). There is no such setting for
|
||||
// the go-git dependency.
|
||||
_, err := exec.LookPath("git")
|
||||
if err != nil {
|
||||
t.Skip("No 'git' found in path. Skipping test.")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
// TestRepository_TemplatesPath ensures that repositories can specify
|
||||
// an alternate location for templates using a manifest.
|
||||
func TestRepository_TemplatesPath(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
client := fn.New(fn.WithRepositoriesPath("testdata/repositories"))
|
||||
|
||||
// The repo ./testdata/repositories/customLanguagePackRepo includes a
|
||||
|
@ -40,6 +41,7 @@ func TestRepository_TemplatesPath(t *testing.T) {
|
|||
// and template level. The tests check for both embedded structures:
|
||||
// HealthEndpoints BuildConfig.
|
||||
func TestRepository_Inheritance(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
var err error
|
||||
client := fn.New(fn.WithRepositoriesPath("testdata/repositories"))
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
// TestTemplates_List ensures that all templates are listed taking into account
|
||||
// both internal and extensible (prefixed) repositories.
|
||||
func TestTemplates_List(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
// A client which specifies a location of exensible repositoreis on disk
|
||||
// will list all builtin plus exensible
|
||||
client := fn.New(fn.WithRepositoriesPath("testdata/repositories"))
|
||||
|
@ -48,6 +49,8 @@ func TestTemplates_List(t *testing.T) {
|
|||
// when retrieving the list of templates for a runtime that does not exist
|
||||
// in an extended repository, but does in the default.
|
||||
func TestTemplates_List_ExtendedNotFound(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
|
||||
// An external template repo which does not contain python
|
||||
client := fn.New(fn.WithRepositoriesPath("testdata/repositories"))
|
||||
|
||||
|
@ -72,6 +75,7 @@ func TestTemplates_List_ExtendedNotFound(t *testing.T) {
|
|||
// TestTemplates_Get ensures that a template's metadata object can
|
||||
// be retrieved by full name (full name prefix optional for embedded).
|
||||
func TestTemplates_Get(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
client := fn.New(fn.WithRepositoriesPath("testdata/repositories"))
|
||||
|
||||
// Check embedded
|
||||
|
@ -127,6 +131,7 @@ func TestTemplates_Embedded(t *testing.T) {
|
|||
// (ie. custom provider on disk) can be specified as the source for a
|
||||
// template.
|
||||
func TestTemplates_Custom(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
// Create test directory
|
||||
root := "testdata/testTemplatesCustom"
|
||||
defer Using(t, root)()
|
||||
|
@ -160,6 +165,7 @@ func TestTemplates_Custom(t *testing.T) {
|
|||
// can be specificed on creation of client, with subsequent calls to Create
|
||||
// using this remote by default.
|
||||
func TestTemplates_Remote(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
var err error
|
||||
|
||||
root := "testdata/testTemplatesRemote"
|
||||
|
@ -285,6 +291,7 @@ func TestTemplates_ModeEmbedded(t *testing.T) {
|
|||
// TestTemplates_ModeCustom ensures that templates written from custom templates
|
||||
// retain their mode.
|
||||
func TestTemplates_ModeCustom(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
if runtime.GOOS == "windows" {
|
||||
return // not applicable
|
||||
}
|
||||
|
@ -320,6 +327,7 @@ func TestTemplates_ModeCustom(t *testing.T) {
|
|||
// TestTemplates_ModeRemote ensures that templates written from remote templates
|
||||
// retain their mode.
|
||||
func TestTemplates_ModeRemote(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
var err error
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
|
@ -370,6 +378,7 @@ func TestTemplates_ModeRemote(t *testing.T) {
|
|||
// TestTemplates_RuntimeManifestBuildEnvs ensures that BuildEnvs specified in a
|
||||
// runtimes's manifest are included in the final function.
|
||||
func TestTemplates_RuntimeManifestBuildEnvs(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
// create test directory
|
||||
root := "testdata/testTemplatesRuntimeManifestBuildEnvs"
|
||||
defer Using(t, root)()
|
||||
|
@ -417,6 +426,7 @@ func TestTemplates_RuntimeManifestBuildEnvs(t *testing.T) {
|
|||
// TestTemplates_ManifestBuildEnvs ensures that BuildEnvs specified in a
|
||||
// template's manifest are included in the final function.
|
||||
func TestTemplates_ManifestBuildEnvs(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
// create test directory
|
||||
root := "testdata/testTemplatesManifestBuildEnvs"
|
||||
defer Using(t, root)()
|
||||
|
@ -464,6 +474,7 @@ func TestTemplates_ManifestBuildEnvs(t *testing.T) {
|
|||
// TestTemplates_RepositoryManifestBuildEnvs ensures that BuildEnvs specified in a
|
||||
// repository's manifest are included in the final function.
|
||||
func TestTemplates_RepositoryManifestBuildEnvs(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
// create test directory
|
||||
root := "testdata/testRepositoryManifestBuildEnvs"
|
||||
defer Using(t, root)()
|
||||
|
@ -511,6 +522,7 @@ func TestTemplates_RepositoryManifestBuildEnvs(t *testing.T) {
|
|||
// TestTemplates_ManifestInvocationHints ensures that invocation hints
|
||||
// from a template's manifest are included in the final function.
|
||||
func TestTemplates_ManifestInvocationHints(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
root := "testdata/testTemplatesManifestInvocationHints"
|
||||
defer Using(t, root)()
|
||||
|
||||
|
@ -535,6 +547,7 @@ func TestTemplates_ManifestInvocationHints(t *testing.T) {
|
|||
// TestTemplates_ManifestRemoved ensures that the manifest is not left in
|
||||
// the resultant function after write.
|
||||
func TestTemplates_ManifestRemoved(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
// create test directory
|
||||
root := "testdata/testTemplateManifestRemoved"
|
||||
defer Using(t, root)()
|
||||
|
@ -571,6 +584,7 @@ func TestTemplates_ManifestRemoved(t *testing.T) {
|
|||
// does not define an invocation hint defaults to empty string (since 0.35.0
|
||||
// default value is omitted from func.yaml file for Invoke)
|
||||
func TestTemplates_InvocationDefault(t *testing.T) {
|
||||
skipIfNoGit(t) // see docs
|
||||
expectedInvoke := ""
|
||||
root := "testdata/testTemplatesInvocationDefault"
|
||||
defer Using(t, root)()
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# default_home
|
||||
|
||||
For use by tests which isolate their environment and need a HOME
|
|
@ -127,8 +127,8 @@ func goBuildCmd(p v1.Platform, cfg buildJob) (gobin string, args []string, outpa
|
|||
* Either replace or append to gobin
|
||||
*/
|
||||
|
||||
// Use the binary specified FUNC_GO_PATH if defined
|
||||
gobin = os.Getenv("FUNC_GO_PATH") // TODO: move to main and plumb through
|
||||
// Use the binary specified FUNC_GO if defined
|
||||
gobin = os.Getenv("FUNC_GO") // TODO: move to main and plumb through
|
||||
if gobin == "" {
|
||||
gobin = "go"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue