func/cmd/delete_test.go

179 lines
5.1 KiB
Go

package cmd
import (
"os"
"path/filepath"
"testing"
fn "knative.dev/func/pkg/functions"
"knative.dev/func/pkg/mock"
)
// TestDelete_Namespace ensures that the namespace provided to the client
// for use when deleting a function is set
// 1. The flag /env variable if provided
// 2. The namespace of the function at path if provided
// 3. The user's current active namespace
func TestDelete_Namespace(t *testing.T) {
root := fromTempDirectory(t)
// Ensure that the default is "default" when no context can be identified
t.Setenv("KUBECONFIG", filepath.Join(cwd(), "nonexistent"))
t.Setenv("KUBERNETES_SERVICE_HOST", "")
cmd := NewDeleteCmd(func(cc ClientConfig, options ...fn.Option) (*fn.Client, func()) {
if cc.Namespace != "" {
t.Fatalf("expected '', got '%v'", cc.Namespace)
}
return fn.New(), func() {}
})
cmd.SetArgs([]string{"somefunc"}) // delete by name such that no f need be created
if err := cmd.Execute(); err != nil {
t.Fatal(err)
}
// Ensure the extant function's namespace is used
f := fn.Function{
Root: root,
Runtime: "go",
Deploy: fn.DeploySpec{
Namespace: "deployed",
},
}
if _, err := fn.New().Init(f); err != nil {
t.Fatal(err)
}
cmd = NewDeleteCmd(func(cc ClientConfig, options ...fn.Option) (*fn.Client, func()) {
if cc.Namespace != "deployed" {
t.Fatalf("expected 'deployed', got '%v'", cc.Namespace)
}
return fn.New(), func() {}
})
cmd.SetArgs([]string{})
if err := cmd.Execute(); err != nil {
t.Fatal(err)
}
// Ensure an explicit namespace is plumbed through
cmd = NewDeleteCmd(func(cc ClientConfig, options ...fn.Option) (*fn.Client, func()) {
if cc.Namespace != "ns" {
t.Fatalf("expected 'ns', got '%v'", cc.Namespace)
}
return fn.New(), func() {}
})
cmd.SetArgs([]string{"--namespace", "ns"})
if err := cmd.Execute(); err != nil {
t.Fatal(err)
}
}
// TestDelete_ByName ensures that running delete specifying the name of the
// function explicitly as an argument invokes the remover appropriately.
func TestDelete_ByName(t *testing.T) {
var (
testname = "testname" // explicit name for the function
remover = mock.NewRemover() // with a mock remover
)
// Remover fails the test if it receives the incorrect name
// an incorrect name.
remover.RemoveFn = func(n string) error {
if n != testname {
t.Fatalf("expected delete name %v, got %v", testname, n)
}
return nil
}
// Create a command with a client constructor fn that instantiates a client
// with a the mocked remover.
cmd := NewDeleteCmd(NewTestClient(fn.WithRemover(remover)))
cmd.SetArgs([]string{testname})
if err := cmd.Execute(); err != nil {
t.Fatal(err)
}
// Fail if remover's .Remove not invoked at all
if !remover.RemoveInvoked {
t.Fatal("fn.Remover not invoked")
}
}
// TestDelete_ByProject ensures that running delete with a valid project as its
// context invokes remove and with the correct name (reads name from func.yaml)
func TestDelete_ByProject(t *testing.T) {
_ = fromTempDirectory(t)
// Write a func.yaml config which specifies a name
funcYaml := `name: bar
namespace: ""
runtime: go
image: ""
imageDigest: ""
builder: quay.io/boson/faas-go-builder
builders:
default: quay.io/boson/faas-go-builder
envs: []
annotations: {}
labels: []
created: 2021-01-01T00:00:00+00:00
`
if err := os.WriteFile("func.yaml", []byte(funcYaml), 0600); err != nil {
t.Fatal(err)
}
// A mock remover which fails if the name from the func.yaml is not received.
remover := mock.NewRemover()
remover.RemoveFn = func(n string) error {
if n != "bar" {
t.Fatalf("expected name 'bar', got '%v'", n)
}
return nil
}
// Command with a Client constructor that returns client with the
// mocked remover.
cmd := NewDeleteCmd(NewTestClient(fn.WithRemover(remover)))
cmd.SetArgs([]string{}) // Do not use test command args
// Execute the command simulating no arguments.
err := cmd.Execute()
if err != nil {
t.Fatal(err)
}
// Also fail if remover's .Remove is not invoked
if !remover.RemoveInvoked {
t.Fatal("fn.Remover not invoked")
}
}
// TestDelete_NameAndPathExclusivity ensures that providing both a name and a
// path generates an error.
// Providing the --path (-p) flag indicates the name of the function to delete
// is to be taken from the function at the given path. Providing the name as
// an argument as well is therefore redundant and an error.
func TestDelete_NameAndPathExclusivity(t *testing.T) {
// A mock remover which will be sampled to ensure it is not invoked.
remover := mock.NewRemover()
// Command with a Client constructor using the mock remover.
cmd := NewDeleteCmd(NewTestClient(fn.WithRemover(remover)))
// Execute the command simulating the invalid argument combination of both
// a path and an explicit name.
cmd.SetArgs([]string{"-p", "./testpath", "testname"})
err := cmd.Execute()
if err == nil {
// TODO should really either parse the output or use typed errors to ensure it's
// failing for the expected reason.
t.Fatalf("expected error on conflicting flags not received")
}
// Also fail if remover's .Remove is invoked.
if remover.RemoveInvoked {
t.Fatal("fn.Remover invoked despite invalid combination and an error")
}
}