diff --git a/cmd/create.go b/cmd/create.go index 9c56921a..ef37e9d5 100644 --- a/cmd/create.go +++ b/cmd/create.go @@ -55,7 +55,7 @@ kn func create --runtime quarkus myfunc # Create a function project that uses a CloudEvent based function signature kn func create --template events myfunc `, - SuggestFor: []string{"inti", "new"}, + SuggestFor: []string{"vreate", "creaet", "craete", "new"}, PreRunE: bindEnv("runtime", "template", "repositories", "confirm"), } diff --git a/cmd/create_test.go b/cmd/create_test.go new file mode 100644 index 00000000..a5bd855e --- /dev/null +++ b/cmd/create_test.go @@ -0,0 +1,71 @@ +package cmd + +import ( + "errors" + "io/ioutil" + "os" + "testing" + + fn "github.com/boson-project/func" + "github.com/boson-project/func/utils" +) + +// TestCreateValidatesName ensures that the create command only accepts +// DNS-1123 labels for Function name. +func TestCreateValidatesName(t *testing.T) { + defer fromTempDir(t)() + + // Create a new Create command with a fn.Client construtor + // which returns a default (noop) client suitable for tests. + cmd := NewCreateCmd(func(string, bool) *fn.Client { + return fn.New() + }) + + // Execute the command with a function name containing invalid characters. + cmd.SetArgs([]string{"invalid!"}) + err := cmd.Execute() + + // Confirm the expected error is returned + var e utils.ErrInvalidFunctionName + if !errors.As(err, &e) { + t.Fatalf("Did not receive ErrInvalidFunctionName. Got %v", err) + } +} + +// Helpers ---- + +// change directory into a new temp directory. +// returned is a closure which cleans up; intended to be run as a defer: +// defer within(t, /some/path)() +func fromTempDir(t *testing.T) func() { + t.Helper() + tmp := mktmp(t) // create temp directory + owd := pwd(t) // original working directory + cd(t, tmp) // change to the temp directory + return func() { // return a deferable cleanup closure + os.RemoveAll(tmp) // remove temp directory + cd(t, owd) // change director back to original + } +} + +func mktmp(t *testing.T) string { + d, err := ioutil.TempDir("", "dir") + if err != nil { + t.Fatal(err) + } + return d +} + +func pwd(t *testing.T) string { + d, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + return d +} + +func cd(t *testing.T, dir string) { + if err := os.Chdir(dir); err != nil { + t.Fatal(err) + } +} diff --git a/utils/names.go b/utils/names.go index 83113e8e..7afdf40d 100644 --- a/utils/names.go +++ b/utils/names.go @@ -7,6 +7,12 @@ import ( "k8s.io/apimachinery/pkg/util/validation" ) +// ErrInvalidName indicates the name did not pass funciton name validation. +type ErrInvalidFunctionName error + +// ErrInvalidEnvVarName indicates the name did not pass env var name validation. +type ErrInvalidEnvVarName error + // ValidateFunctionName validatest that the input name is a valid function name, ie. valid DNS-1123 label. // It must consist of lower case alphanumeric characters or '-' and start and end with an alphanumeric character // (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?') @@ -18,7 +24,7 @@ func ValidateFunctionName(name string) error { // and must start and end with an alphanumeric character (e.g. 'my-name', // or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')" // Let's reuse it for our purposes, ie. replace "DNS-1123 label" substring with "function name" - return errors.New(strings.Replace(strings.Join(errs, ""), "a DNS-1123 label", "Function name", 1)) + return ErrInvalidFunctionName(errors.New(strings.Replace(strings.Join(errs, ""), "a DNS-1123 label", "Function name", 1))) } return nil @@ -29,7 +35,7 @@ func ValidateFunctionName(name string) error { // (e.g. 'my.env-name', or 'MY_ENV.NAME', or 'MyEnvName1', regex used for validation is '[-._a-zA-Z][-._a-zA-Z0-9]*')) func ValidateEnvVarName(name string) error { if errs := validation.IsEnvVarName(name); len(errs) > 0 { - return errors.New(strings.Join(errs, "")) + return ErrInvalidEnvVarName(errors.New(strings.Join(errs, ""))) } return nil