From c2003d134dcd12cc65eab1891a9f5bcaf66ea471 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 2 Sep 2019 09:27:36 +0200 Subject: [PATCH 1/5] Rename function to describe the correct behaviour --- cmd/commander/commander.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/commander/commander.go b/cmd/commander/commander.go index 2447442e..f14c5b60 100644 --- a/cmd/commander/commander.go +++ b/cmd/commander/commander.go @@ -36,7 +36,7 @@ func createCliApp() *cli.App { cliapp.Version = version cliapp.Commands = []cli.Command{ - createAddCommand(), + createTestCommand(), { Name: "add", Usage: "Automatically add a test to your test suite", @@ -61,7 +61,7 @@ func createCliApp() *cli.App { return cliapp } -func createAddCommand() cli.Command { +func createTestCommand() cli.Command { return cli.Command{ Name: "test", Usage: "Execute the test suite", From 7c0ef41c334a873b09bdb88ab660c519139da810 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 2 Sep 2019 09:30:15 +0200 Subject: [PATCH 2/5] Refactor add command creation --- cmd/commander/commander.go | 94 +++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/cmd/commander/commander.go b/cmd/commander/commander.go index f14c5b60..47641b65 100644 --- a/cmd/commander/commander.go +++ b/cmd/commander/commander.go @@ -37,26 +37,7 @@ func createCliApp() *cli.App { cliapp.Commands = []cli.Command{ createTestCommand(), - { - Name: "add", - Usage: "Automatically add a test to your test suite", - ArgsUsage: "[command]", - Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "stdout", - Usage: "Output test file to stdout", - }, - cli.BoolFlag{ - Name: "no-file", - Usage: "Don't create a commander.yaml", - }, - cli.StringFlag{ - Name: "file", - Usage: "Write to another file, default is commander.yaml", - }, - }, - Action: addCommand, - }, + createAddCommand(), } return cliapp } @@ -89,35 +70,56 @@ func createTestCommand() cli.Command { } } -func addCommand(c *cli.Context) error { - file := "" - var existedContent []byte +func createAddCommand() cli.Command { + return cli.Command{ + Name: "add", + Usage: "Automatically add a test to your test suite", + ArgsUsage: "[command]", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "stdout", + Usage: "Output test file to stdout", + }, + cli.BoolFlag{ + Name: "no-file", + Usage: "Don't create a commander.yaml", + }, + cli.StringFlag{ + Name: "file", + Usage: "Write to another file, default is commander.yaml", + }, + }, + Action: func(c *cli.Context) error { + file := "" + var existedContent []byte - if !c.Bool("no-file") { - dir, _ := os.Getwd() - file = path.Join(dir, app.CommanderFile) - if c.String("file") != "" { - file = c.String("file") - } - existedContent, _ = ioutil.ReadFile(file) - } + if !c.Bool("no-file") { + dir, _ := os.Getwd() + file = path.Join(dir, app.CommanderFile) + if c.String("file") != "" { + file = c.String("file") + } + existedContent, _ = ioutil.ReadFile(file) + } - content, err := app.AddCommand(strings.Join(c.Args(), " "), existedContent) + content, err := app.AddCommand(strings.Join(c.Args(), " "), existedContent) - if err != nil { - return err - } + if err != nil { + return err + } - if c.Bool("stdout") { - fmt.Println(string(content)) - } - if !c.Bool("no-file") { - fmt.Println("written to", file) - err := ioutil.WriteFile(file, content, 0755) - if err != nil { - return err - } - } + if c.Bool("stdout") { + fmt.Println(string(content)) + } + if !c.Bool("no-file") { + fmt.Println("written to", file) + err := ioutil.WriteFile(file, content, 0755) + if err != nil { + return err + } + } - return nil + return nil + }, + } } From 04b52ecc3c7dc957c08893b7c62d7e1b950eea32 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 2 Sep 2019 09:50:39 +0200 Subject: [PATCH 3/5] Add support for one env variable --- pkg/cmd/command.go | 17 +++++++++++++++++ pkg/cmd/command_test.go | 15 +++++++++++++++ pkg/runtime/runtime.go | 4 +++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/pkg/cmd/command.go b/pkg/cmd/command.go index 7e734b4f..47fe62a0 100644 --- a/pkg/cmd/command.go +++ b/pkg/cmd/command.go @@ -3,7 +3,9 @@ package cmd import ( "bytes" "fmt" + "os" "os/exec" + "strings" "syscall" "time" ) @@ -31,10 +33,25 @@ func NewCommand(cmd string) *Command { } // AddEnv adds an environment variable to the command +// If a variable gets passed like ${VAR_NAME} the env variable will be read out by the current shell func (c *Command) AddEnv(key string, value string) { + if isEnvFromShell(value) { + value = os.Getenv("COMMANDER_TEST_SOME_KEY") + } c.Env = append(c.Env, fmt.Sprintf("%s=%s", key, value)) } +func isEnvFromShell(val string) bool { + r := strings.Index(val, "${") + if r != 0 { + return false + } + if strings.Index(val, "}") != (len(val) - 1) { + return false + } + return true +} + //SetTimeoutMS sets the timeout in milliseconds func (c *Command) SetTimeoutMS(ms int) { if ms == 0 { diff --git a/pkg/cmd/command_test.go b/pkg/cmd/command_test.go index 6f94724a..a2041d3c 100644 --- a/pkg/cmd/command_test.go +++ b/pkg/cmd/command_test.go @@ -3,6 +3,7 @@ package cmd import ( "fmt" "github.com/stretchr/testify/assert" + "os" "runtime" "testing" "time" @@ -64,6 +65,20 @@ func TestCommand_AddEnv(t *testing.T) { assert.Equal(t, []string{"key=value"}, c.Env) } +func TestCommand_AddEnvWithShellVariable(t *testing.T) { + const TestEnvKey = "COMMANDER_TEST_SOME_KEY" + os.Setenv(TestEnvKey, "test from shell") + defer os.Unsetenv(TestEnvKey) + + c := NewCommand("echo $SOME_KEY") + c.AddEnv("SOME_KEY", fmt.Sprintf("${%s}", TestEnvKey)) + + err := c.Execute() + + assert.Nil(t, err) + assert.Equal(t, "test from shell", c.Stdout()) +} + func TestCommand_SetTimeoutMS_DefaultTimeout(t *testing.T) { c := NewCommand("echo test") c.SetTimeoutMS(0) diff --git a/pkg/runtime/runtime.go b/pkg/runtime/runtime.go index 29b2d2dd..e3f97782 100644 --- a/pkg/runtime/runtime.go +++ b/pkg/runtime/runtime.go @@ -18,6 +18,8 @@ const ( LineCount = "LineCount" ) +const WorkerCountMultiplicator = 5 + // Result status codes const ( //Success status @@ -108,7 +110,7 @@ func Start(tests []TestCase, maxConcurrent int) <-chan TestResult { workerCount := maxConcurrent if maxConcurrent == 0 { - workerCount = runtime.NumCPU() * 5 + workerCount = runtime.NumCPU() * WorkerCountMultiplicator } var wg sync.WaitGroup From 01764d608c2aa020dbddbb06108275fe7f057c35 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 2 Sep 2019 10:33:42 +0200 Subject: [PATCH 4/5] Add shell environment variables --- commander_unix.yaml | 4 ++++ commander_windows.yaml | 5 ++++- integration/unix/config_test.yaml | 6 ++++++ integration/windows/config_test.yaml | 1 + integration/windows/shell_env.yaml | 3 +++ pkg/cmd/command.go | 27 ++++++++++++++++----------- pkg/cmd/command_test.go | 20 ++++++++++++++++++++ 7 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 integration/windows/shell_env.yaml diff --git a/commander_unix.yaml b/commander_unix.yaml index 5f11da6a..1a6b2bc4 100644 --- a/commander_unix.yaml +++ b/commander_unix.yaml @@ -32,10 +32,14 @@ tests: test global and local configurations: command: ./commander test ./integration/unix/config_test.yaml + config: + env: + COMMANDER_FROM_SHELL: from_shell stdout: contains: - ✓ should print global env value - ✓ should print local env value + - ✓ should print env var from shell exit-code: 0 test add command: diff --git a/commander_windows.yaml b/commander_windows.yaml index 2b7106d1..7ff8910c 100644 --- a/commander_windows.yaml +++ b/commander_windows.yaml @@ -36,6 +36,9 @@ tests: test global and local configurations: command: commander.exe test ./integration/windows/config_test.yaml + config: + env: + COMMANDER_FROM_SHELL: from_shell stdout: contains: - should print global @@ -55,4 +58,4 @@ tests: stdout: contains: - ✗ echo hello, retries 3 - exit-code: 1 \ No newline at end of file + exit-code: 1 diff --git a/integration/unix/config_test.yaml b/integration/unix/config_test.yaml index abec91a3..904e91f2 100644 --- a/integration/unix/config_test.yaml +++ b/integration/unix/config_test.yaml @@ -2,6 +2,7 @@ config: env: KEY: value ANOTHER: global + COMMANDER_FROM_SHELL: ${COMMANDER_FROM_SHELL} tests: should print global env value: command: echo $KEY @@ -27,4 +28,9 @@ tests: command: echo hello config: timeout: 100ms + exit-code: 0 + + should print env var from shell: + command: echo read ${COMMANDER_FROM_SHELL} $KEY + stdout: read from_shell value exit-code: 0 \ No newline at end of file diff --git a/integration/windows/config_test.yaml b/integration/windows/config_test.yaml index fccdf422..041b675f 100644 --- a/integration/windows/config_test.yaml +++ b/integration/windows/config_test.yaml @@ -2,6 +2,7 @@ config: env: KEY: value ANOTHER: global + COMMANDER_FROM_SHELL: ${COMMANDER_FROM_SHELL} tests: should print global env value: command: echo %KEY% diff --git a/integration/windows/shell_env.yaml b/integration/windows/shell_env.yaml new file mode 100644 index 00000000..e2a3274a --- /dev/null +++ b/integration/windows/shell_env.yaml @@ -0,0 +1,3 @@ +tests: + it should read from shell env: + env: \ No newline at end of file diff --git a/pkg/cmd/command.go b/pkg/cmd/command.go index 47fe62a0..796d18a0 100644 --- a/pkg/cmd/command.go +++ b/pkg/cmd/command.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "os/exec" + "regexp" "strings" "syscall" "time" @@ -35,21 +36,25 @@ func NewCommand(cmd string) *Command { // AddEnv adds an environment variable to the command // If a variable gets passed like ${VAR_NAME} the env variable will be read out by the current shell func (c *Command) AddEnv(key string, value string) { - if isEnvFromShell(value) { - value = os.Getenv("COMMANDER_TEST_SOME_KEY") + vars := parseEnvVariableFromShell(value) + for _, v := range vars { + value = strings.Replace(value, v, os.Getenv(removeEnvVarSyntax(v)), -1) } + c.Env = append(c.Env, fmt.Sprintf("%s=%s", key, value)) } -func isEnvFromShell(val string) bool { - r := strings.Index(val, "${") - if r != 0 { - return false - } - if strings.Index(val, "}") != (len(val) - 1) { - return false - } - return true +// Removes the ${...} characters +func removeEnvVarSyntax(v string) string { + return v[2:(len(v) - 1)] +} + +//Read all environment variables from the given value +//with the syntax ${VAR_NAME} +func parseEnvVariableFromShell(val string) []string { + reg := regexp.MustCompile(`\$\{.*?\}`) + matches := reg.FindAllString(val, -1) + return matches } //SetTimeoutMS sets the timeout in milliseconds diff --git a/pkg/cmd/command_test.go b/pkg/cmd/command_test.go index a2041d3c..37f78cb9 100644 --- a/pkg/cmd/command_test.go +++ b/pkg/cmd/command_test.go @@ -79,6 +79,26 @@ func TestCommand_AddEnvWithShellVariable(t *testing.T) { assert.Equal(t, "test from shell", c.Stdout()) } +func TestCommand_AddMultipleEnvWithShellVariable(t *testing.T) { + const TestEnvKeyPlanet = "COMMANDER_TEST_PLANET" + const TestEnvKeyName = "COMMANDER_TEST_NAME" + os.Setenv(TestEnvKeyPlanet, "world") + os.Setenv(TestEnvKeyName, "Simon") + defer func() { + os.Unsetenv(TestEnvKeyPlanet) + os.Unsetenv(TestEnvKeyName) + }() + + c := NewCommand("echo $SOME_KEY") + envValue := fmt.Sprintf("Hello ${%s}, I am ${%s}", TestEnvKeyPlanet, TestEnvKeyName) + c.AddEnv("SOME_KEY", envValue) + + err := c.Execute() + + assert.Nil(t, err) + assert.Equal(t, "Hello world, I am Simon", c.Stdout()) +} + func TestCommand_SetTimeoutMS_DefaultTimeout(t *testing.T) { c := NewCommand("echo test") c.SetTimeoutMS(0) From e778856b8694577a757f4264f6b58d70b283004e Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 2 Sep 2019 10:43:52 +0200 Subject: [PATCH 5/5] Add documentation and fix windows unit tests --- CHANGELOG.md | 3 ++- docs/manual.md | 1 + pkg/cmd/command_test.go | 12 ++++++++++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e77c675c..873e8e41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # v1.2.0 - - Add `interval` option for `retries` which allows to execute a retry after a given period of time. I.e. `interval: 50ms` +- Add reading envrionment variables from shell +- Add `interval` option for `retries` which allows to execute a retry after a given period of time. I.e. `interval: 50ms` # v1.1.0 diff --git a/docs/manual.md b/docs/manual.md index f5d8e5c8..724d2f92 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -33,6 +33,7 @@ config: # Config for all tests dir: /tmp #Set working directory env: # Environment variables KEY: global + PATH_FROM_SHELL: ${PATH} # Read an env variable from the current shell timeout: 5000 # Timeout in ms retries: 2 # Define retries for each test diff --git a/pkg/cmd/command_test.go b/pkg/cmd/command_test.go index 37f78cb9..89b56561 100644 --- a/pkg/cmd/command_test.go +++ b/pkg/cmd/command_test.go @@ -70,7 +70,7 @@ func TestCommand_AddEnvWithShellVariable(t *testing.T) { os.Setenv(TestEnvKey, "test from shell") defer os.Unsetenv(TestEnvKey) - c := NewCommand("echo $SOME_KEY") + c := NewCommand(getCommand()) c.AddEnv("SOME_KEY", fmt.Sprintf("${%s}", TestEnvKey)) err := c.Execute() @@ -89,7 +89,7 @@ func TestCommand_AddMultipleEnvWithShellVariable(t *testing.T) { os.Unsetenv(TestEnvKeyName) }() - c := NewCommand("echo $SOME_KEY") + c := NewCommand(getCommand()) envValue := fmt.Sprintf("Hello ${%s}, I am ${%s}", TestEnvKeyPlanet, TestEnvKeyName) c.AddEnv("SOME_KEY", envValue) @@ -99,6 +99,14 @@ func TestCommand_AddMultipleEnvWithShellVariable(t *testing.T) { assert.Equal(t, "Hello world, I am Simon", c.Stdout()) } +func getCommand() string { + command := "echo $SOME_KEY" + if runtime.GOOS == "windows" { + command = "echo %SOME_KEY%" + } + return command +} + func TestCommand_SetTimeoutMS_DefaultTimeout(t *testing.T) { c := NewCommand("echo test") c.SetTimeoutMS(0)