get.porter.sh/porter@v1.3.0/pkg/exec/builder/execute_test.go (about) 1 package builder 2 3 import ( 4 "context" 5 "os" 6 "path/filepath" 7 "runtime" 8 "strings" 9 "testing" 10 11 "get.porter.sh/porter/pkg" 12 porterruntime "get.porter.sh/porter/pkg/runtime" 13 "get.porter.sh/porter/pkg/test" 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 ) 17 18 type TestAction struct { 19 Steps []TestStep 20 } 21 22 func (a TestAction) GetSteps() []ExecutableStep { 23 steps := make([]ExecutableStep, len(a.Steps)) 24 for i := range a.Steps { 25 steps[i] = a.Steps[i] 26 } 27 return steps 28 } 29 30 func TestMain(m *testing.M) { 31 test.TestMainWithMockedCommandHandlers(m) 32 } 33 34 func TestExecuteSingleStepAction(t *testing.T) { 35 ctx := context.Background() 36 c := porterruntime.NewTestRuntimeConfig(t) 37 38 err := c.FileSystem.WriteFile("config.txt", []byte("abc123"), pkg.FileModeWritable) 39 require.NoError(t, err) 40 41 a := TestAction{ 42 Steps: []TestStep{ 43 { 44 Command: "foo", 45 Outputs: []Output{ 46 TestFileOutput{Name: "file", FilePath: "config.txt"}, 47 TestJsonPathOutput{Name: "jsonpath", JsonPath: "$.*"}, 48 TestRegexOutput{Name: "regex", Regex: "(.*)"}, 49 }}, 50 }, 51 } 52 53 c.Setenv(test.ExpectedCommandEnv, "foo") 54 55 _, err = ExecuteSingleStepAction(ctx, c.RuntimeConfig, a) 56 require.NoError(t, err, "ExecuteSingleStepAction should not have returned an error") 57 58 exists, _ := c.FileSystem.Exists("/cnab/app/porter/outputs/file") 59 assert.True(t, exists, "file output was not evaluated") 60 61 exists, _ = c.FileSystem.Exists("/cnab/app/porter/outputs/regex") 62 assert.True(t, exists, "regex output was not evaluated") 63 64 exists, _ = c.FileSystem.Exists("/cnab/app/porter/outputs/jsonpath") 65 assert.True(t, exists, "jsonpath output was not evaluated") 66 } 67 68 func Test_splitCommand(t *testing.T) { 69 t.Run("split space", func(t *testing.T) { 70 result := splitCommand([]string{"cmd", "--myarg", "val1 val2"}) 71 assert.Equal(t, []string{"cmd", "--myarg", "val1", "val2"}, result, "strings not enclosed should be split apart") 72 }) 73 74 t.Run("split tab", func(t *testing.T) { 75 result := splitCommand([]string{"cmd", "--myarg", "val1\tval2"}) 76 assert.Equal(t, []string{"cmd", "--myarg", "val1", "val2"}, result, "strings not enclosed should be split apart") 77 }) 78 79 t.Run("split newline", func(t *testing.T) { 80 result := splitCommand([]string{"cmd", "--myarg", "val1\nval2"}) 81 assert.Equal(t, []string{"cmd", "--myarg", "val1", "val2"}, result, "strings not enclosed should be split apart") 82 }) 83 84 t.Run("keep double quoted whitespace", func(t *testing.T) { 85 result := splitCommand([]string{"cmd", "--myarg", `"val1 val2" val3`}) 86 assert.Equal(t, []string{"cmd", "--myarg", "val1 val2", "val3"}, result, "strings in the enclosing quotes should be grouped together") 87 }) 88 89 t.Run("embedded single quote", func(t *testing.T) { 90 result := splitCommand([]string{"cmd", "--myarg", `"Patty O'Brien" true`}) 91 assert.Equal(t, []string{"cmd", "--myarg", "Patty O'Brien", "true"}, result, "single quotes should be included in the enclosing quotes") 92 }) 93 94 t.Run("escaped double quotes", func(t *testing.T) { 95 result := splitCommand([]string{"c", `"echo { \"test\": \"myvalue\" }"`}) 96 assert.Equal(t, []string{"c", `echo { \"test\": \"myvalue\" }`}, result, "escaped double quotes should be included in the enclosing quotes") 97 }) 98 99 t.Run("escaped single quotes", func(t *testing.T) { 100 result := splitCommand([]string{"c", `"echo $'I\'m a linux admin.'"`}) 101 assert.Equal(t, []string{"c", `echo $'I\'m a linux admin.'`}, result, "escaped single quotes should be included in the enclosing quotes") 102 }) 103 104 t.Run("unmatched double quote", func(t *testing.T) { 105 result := splitCommand([]string{"cmd", "--myarg", `"Patty O"Brien" true`}) 106 assert.Equal(t, []string{"cmd", "--myarg", `"Patty O"Brien" true`}, result, "unmatched double quotes should cause the grouping to fail") 107 }) 108 109 t.Run("unmatched single quote", func(t *testing.T) { 110 result := splitCommand([]string{"cmd", "--myarg", `'Patty O'Brien' true`}) 111 assert.Equal(t, []string{"cmd", "--myarg", `'Patty O'Brien' true`}, result, "unmatched single quotes should cause the grouping to fail") 112 }) 113 } 114 115 var _ HasOrderedArguments = TestOrderedStep{} 116 117 type TestOrderedStep struct { 118 TestStep 119 SuffixArguments []string 120 } 121 122 func (s TestOrderedStep) GetSuffixArguments() []string { 123 return s.SuffixArguments 124 } 125 126 func TestExecuteStep_HasOrderedArguments(t *testing.T) { 127 ctx := context.Background() 128 c := porterruntime.NewTestRuntimeConfig(t) 129 step := TestOrderedStep{ 130 TestStep: TestStep{ 131 Command: "docker", 132 Arguments: []string{"build"}, 133 Flags: []Flag{ 134 NewFlag("t", "getporter/porter-hello:latest"), 135 }, 136 }, 137 SuffixArguments: []string{"."}, 138 } 139 140 c.Setenv(test.ExpectedCommandEnv, "docker build -t getporter/porter-hello:latest .") 141 142 _, err := ExecuteStep(ctx, c.RuntimeConfig, step) 143 require.NoError(t, err, "ExecuteStep failed") 144 } 145 146 func TestExecuteStep_SpecifiesCustomWorkingDirectory(t *testing.T) { 147 ctx := context.Background() 148 c := porterruntime.NewTestRuntimeConfig(t) 149 c.TestContext.UseFilesystem() 150 wd, _ := filepath.EvalSymlinks(os.TempDir()) 151 152 step := TestOrderedStep{ 153 TestStep: TestStep{ 154 Command: "pwd", 155 Arguments: []string{}, 156 WorkingDirectory: wd, 157 }, 158 SuffixArguments: []string{}, 159 } 160 161 if runtime.GOOS == "windows" { 162 step.TestStep.Command = "cmd.exe" 163 step.Arguments = []string{"/c", "cd"} 164 } 165 166 _, err := ExecuteStep(ctx, c.RuntimeConfig, step) 167 assert.Equal(t, wd, strings.TrimRight(c.TestContext.GetOutput(), "\r\n")) 168 require.NoError(t, err, "Execute Step failed") 169 } 170 171 func (s TestOrderedStep) GetEnvironmentVars() map[string]string { 172 return s.EnvironmentVars 173 } 174 175 func TestExecuteStep_WithEnvironmentVars(t *testing.T) { 176 if runtime.GOOS == "windows" { 177 t.Skip() 178 } 179 180 ctx := context.Background() 181 c := porterruntime.NewTestRuntimeConfig(t) 182 c.TestContext.UseFilesystem() 183 step := TestOrderedStep{ 184 TestStep: TestStep{ 185 Command: "env", 186 EnvironmentVars: map[string]string{"SOME_VAR_123": "foo"}, 187 }, 188 } 189 190 c.Setenv(test.ExpectedCommandEnv, "env") 191 192 _, err := ExecuteStep(ctx, c.RuntimeConfig, step) 193 require.NoError(t, err, "Execute Step failed") 194 containsEnv := strings.Contains(c.TestContext.GetOutput(), "SOME_VAR_123=foo") 195 // use assert.True rather than assert.Contains so that the env vars are not all sent to the test output. There might 196 // be sensitive stuff in there. 197 assert.True(t, containsEnv, "Env did not contain the key/value we expected.") 198 }