add tests for delete cmd

Signed-off-by: Matej Vasek <mvasek@redhat.com>
This commit is contained in:
Matej Vasek 2021-05-10 20:33:34 +02:00
parent cf9ce0bbd6
commit 5a3d385432
2 changed files with 183 additions and 56 deletions

View File

@ -2,7 +2,6 @@ package cmd
import (
"fmt"
"github.com/ory/viper"
"github.com/spf13/cobra"
@ -13,15 +12,13 @@ import (
func init() {
root.AddCommand(deleteCmd)
deleteCmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all configuration options (Env: $FUNC_CONFIRM)")
deleteCmd.Flags().StringP("path", "p", cwd(), "Path to the function project that should be undeployed (Env: $FUNC_PATH)")
deleteCmd.Flags().StringP("namespace", "n", "", "Namespace of the function to undeploy. By default, the namespace in func.yaml is used or the actual active namespace if not set in the configuration. (Env: $FUNC_NAMESPACE)")
}
var deleteCmd = &cobra.Command{
Use: "delete [NAME]",
Short: "Undeploy a function",
Long: `Undeploy a function
func NewDeleteCmd(newRemover func(ns string, verbose bool) (fn.Remover, error)) *cobra.Command {
delCmd := &cobra.Command{
Use: "delete [NAME]",
Short: "Undeploy a function",
Long: `Undeploy a function
This command undeploys a function from the cluster. By default the function from
the project in the current directory is undeployed. Alternatively either the name
@ -29,64 +26,75 @@ of the function can be given as argument or the project path provided with --pat
No local files are deleted.
`,
Example: `
Example: `
# Undeploy the function defined in the local directory
kn func delete
# Undeploy the function 'myfunc' in namespace 'apps'
kn func delete -n apps myfunc
`,
SuggestFor: []string{"remove", "rm", "del"},
ValidArgsFunction: CompleteFunctionList,
PreRunE: bindEnv("path", "confirm", "namespace"),
RunE: runDelete,
SuggestFor: []string{"remove", "rm", "del"},
ValidArgsFunction: CompleteFunctionList,
PreRunE: bindEnv("path", "confirm", "namespace"),
RunE: func(cmd *cobra.Command, args []string) (err error) {
config := newDeleteConfig(args).Prompt()
var function fn.Function
// Initialize func with explicit name (when provided)
if len(args) > 0 && args[0] != "" {
pathChanged := cmd.Flags().Changed("path")
if pathChanged {
return fmt.Errorf("Only one of --path and [NAME] should be provided")
}
function = fn.Function{
Name: args[0],
}
} else {
function, err = fn.NewFunction(config.Path)
if err != nil {
return
}
// Check if the Function has been initialized
if !function.Initialized() {
return fmt.Errorf("the given path '%v' does not contain an initialized function", config.Path)
}
}
ns := config.Namespace
if ns == "" {
ns = function.Namespace
}
remover, err := newRemover(ns, config.Verbose)
if err != nil {
return
}
client := fn.New(
fn.WithVerbose(config.Verbose),
fn.WithRemover(remover))
return client.Remove(cmd.Context(), function)
},
}
delCmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all configuration options (Env: $FUNC_CONFIRM)")
delCmd.Flags().StringP("path", "p", cwd(), "Path to the function project that should be undeployed (Env: $FUNC_PATH)")
delCmd.Flags().StringP("namespace", "n", "", "Namespace of the function to undeploy. By default, the namespace in func.yaml is used or the actual active namespace if not set in the configuration. (Env: $FUNC_NAMESPACE)")
return delCmd
}
func runDelete(cmd *cobra.Command, args []string) (err error) {
config := newDeleteConfig(args).Prompt()
var function fn.Function
// Initialize func with explicit name (when provided)
if len(args) > 0 && args[0] != "" {
pathChanged := cmd.Flags().Changed("path")
if pathChanged {
return fmt.Errorf("Only one of --path and [NAME] should be provided")
}
function = fn.Function{
Name: args[0],
}
} else {
function, err = fn.NewFunction(config.Path)
if err != nil {
return
}
// Check if the Function has been initialized
if !function.Initialized() {
return fmt.Errorf("the given path '%v' does not contain an initialized function", config.Path)
}
}
ns := config.Namespace
if ns == "" {
ns = function.Namespace
}
remover, err := knative.NewRemover(ns)
var deleteCmd = NewDeleteCmd(func(ns string, verbose bool) (fn.Remover, error) {
r, err := knative.NewRemover(ns)
if err != nil {
return
return nil, err
}
remover.Verbose = config.Verbose
client := fn.New(
fn.WithVerbose(config.Verbose),
fn.WithRemover(remover))
return client.Remove(cmd.Context(), function)
}
r.Verbose = verbose
return r, nil
})
type deleteConfig struct {
Name string

119
cmd/delete_test.go Normal file
View File

@ -0,0 +1,119 @@
package cmd
import (
"context"
fn "github.com/boson-project/func"
"io/ioutil"
"os"
"path/filepath"
"testing"
)
type testRemover struct {
invokedWith *string
}
func (t *testRemover) Remove(ctx context.Context, name string) error {
t.invokedWith = &name
return nil
}
// test delete outside project just using function name
func TestDeleteCmdWithoutProject(t *testing.T) {
tr := &testRemover{}
cmd := NewDeleteCmd(func(ns string, verbose bool) (fn.Remover, error) {
return tr, nil
})
cmd.SetArgs([]string{"foo"})
err := cmd.Execute()
if err != nil {
t.Fatal(err)
}
if tr.invokedWith == nil {
t.Fatal("fn.Remover has not been invoked")
}
if *tr.invokedWith != "foo" {
t.Fatalf("expected fn.Remover to be called with 'foo', but was called with '%s'", *tr.invokedWith)
}
}
// test delete from inside project directory (reading func name from func.yaml)
func TestDeleteCmdWithProject(t *testing.T) {
funcYaml := `name: bar
namespace: ""
runtime: go
image: ""
imageDigest: ""
trigger: http
builder: quay.io/boson/faas-go-builder
builderMap:
default: quay.io/boson/faas-go-builder
env: {}
annotations: {}
`
tmpDir, err := ioutil.TempDir("", "bar")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
f, err := os.Create(filepath.Join(tmpDir, "func.yaml"))
if err != nil {
t.Fatal(err)
}
defer f.Close()
f.WriteString(funcYaml)
f.Close()
oldWD, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
defer os.Chdir(oldWD)
err = os.Chdir(tmpDir)
if err != nil {
t.Fatal(err)
}
tr := &testRemover{}
cmd := NewDeleteCmd(func(ns string, verbose bool) (fn.Remover, error) {
return tr, nil
})
cmd.SetArgs([]string{"-p", "."})
err = cmd.Execute()
if err != nil {
t.Fatal(err)
}
if tr.invokedWith == nil {
t.Fatal("fn.Remover has not been invoked")
}
if *tr.invokedWith != "bar" {
t.Fatalf("expected fn.Remover to be called with 'bar', but was called with '%s'", *tr.invokedWith)
}
}
// test where both name and path are provided
func TestDeleteCmdWithBothPathAndName(t *testing.T) {
tr := &testRemover{}
cmd := NewDeleteCmd(func(ns string, verbose bool) (fn.Remover, error) {
return tr, nil
})
cmd.SetArgs([]string{"foo", "-p", "/adir/"})
err := cmd.Execute()
if err == nil {
t.Fatal("error was expected as both name an path cannot be used together")
}
if tr.invokedWith != nil {
t.Fatal("fn.Remove was call when it shouldn't have been")
}
}