github.com/hairyhenderson/gomplate/v4@v4.0.0-pre-2.0.20240520121557-362f058f0c93/internal/tests/integration/config_test.go (about) 1 package integration 2 3 import ( 4 "io/fs" 5 "os" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 tfs "gotest.tools/v3/fs" 11 ) 12 13 func setupConfigTest(t *testing.T) *tfs.Dir { 14 t.Helper() 15 16 tmpDir := tfs.NewDir(t, "gomplate-inttests", 17 tfs.WithDir("indir"), 18 tfs.WithDir("outdir"), 19 tfs.WithFile(".gomplate.yaml", "in: hello world\n"), 20 tfs.WithFile("sleep.sh", "#!/bin/sh\n\nexec sleep $1\n", tfs.WithMode(0o755)), 21 ) 22 t.Cleanup(tmpDir.Remove) 23 return tmpDir 24 } 25 26 func writeFile(t *testing.T, dir *tfs.Dir, f, content string) { 27 t.Helper() 28 29 f = dir.Join(f) 30 err := os.WriteFile(f, []byte(content), 0o600) 31 if err != nil { 32 t.Fatal(err) 33 } 34 } 35 36 func writeConfig(t *testing.T, dir *tfs.Dir, content string) { 37 t.Helper() 38 39 writeFile(t, dir, ".gomplate.yaml", content) 40 t.Logf("writing config: %s", content) 41 } 42 43 func TestConfig_ReadsFromSimpleConfigFile(t *testing.T) { 44 tmpDir := setupConfigTest(t) 45 46 o, e, err := cmd(t).withDir(tmpDir.Path()).run() 47 assertSuccess(t, o, e, err, "hello world") 48 } 49 50 func TestConfig_ReadsStdin(t *testing.T) { 51 tmpDir := setupConfigTest(t) 52 writeConfig(t, tmpDir, "inputFiles: [-]") 53 54 o, e, err := cmd(t).withDir(tmpDir.Path()).withStdin("foo bar").run() 55 assertSuccess(t, o, e, err, "foo bar") 56 } 57 58 func TestConfig_FlagOverridesConfig(t *testing.T) { 59 tmpDir := setupConfigTest(t) 60 writeConfig(t, tmpDir, "inputFiles: [in]") 61 62 o, e, err := cmd(t, "-i", "hello from the cli"). 63 withDir(tmpDir.Path()).run() 64 assertSuccess(t, o, e, err, "hello from the cli") 65 } 66 67 func TestConfig_ReadsFromInputFile(t *testing.T) { 68 tmpDir := setupConfigTest(t) 69 writeConfig(t, tmpDir, "inputFiles: [in]") 70 writeFile(t, tmpDir, "in", "blah blah") 71 72 o, e, err := cmd(t).withDir(tmpDir.Path()).run() 73 assertSuccess(t, o, e, err, "blah blah") 74 } 75 76 func TestConfig_Datasource(t *testing.T) { 77 tmpDir := setupConfigTest(t) 78 writeConfig(t, tmpDir, `inputFiles: [in] 79 datasources: 80 data: 81 url: in.yaml 82 `) 83 writeFile(t, tmpDir, "in", `{{ (ds "data").value }}`) 84 writeFile(t, tmpDir, "in.yaml", `value: hello world`) 85 86 o, e, err := cmd(t).withDir(tmpDir.Path()).run() 87 assertSuccess(t, o, e, err, "hello world") 88 } 89 90 func TestConfig_OutputDir(t *testing.T) { 91 tmpDir := setupConfigTest(t) 92 93 writeConfig(t, tmpDir, `inputDir: indir/ 94 outputDir: outdir/ 95 datasources: 96 data: 97 url: in.yaml 98 `) 99 writeFile(t, tmpDir, "indir/file", `{{ (ds "data").value }}`) 100 writeFile(t, tmpDir, "in.yaml", `value: hello world`) 101 102 o, e, err := cmd(t).withDir(tmpDir.Path()).run() 103 assertSuccess(t, o, e, err, "") 104 105 b, err := os.ReadFile(tmpDir.Join("outdir", "file")) 106 require.NoError(t, err) 107 assert.Equal(t, "hello world", string(b)) 108 } 109 110 func TestConfig_ExecPipeOverridesConfigFile(t *testing.T) { 111 tmpDir := setupConfigTest(t) 112 113 // make sure exec-pipe works, and outFiles is replaced 114 writeConfig(t, tmpDir, `in: hello world 115 outputFiles: ['-'] 116 `) 117 o, e, err := cmd(t, "-i", "hi", "--exec-pipe", "--", "tr", "[a-z]", "[A-Z]"). 118 withDir(tmpDir.Path()).run() 119 assertSuccess(t, o, e, err, "HI") 120 } 121 122 func TestConfig_OutFile(t *testing.T) { 123 tmpDir := setupConfigTest(t) 124 125 writeConfig(t, tmpDir, `in: hello world 126 outputFiles: [out] 127 `) 128 o, e, err := cmd(t).withDir(tmpDir.Path()).run() 129 assertSuccess(t, o, e, err, "") 130 131 b, err := os.ReadFile(tmpDir.Join("out")) 132 require.NoError(t, err) 133 assert.Equal(t, "hello world", string(b)) 134 } 135 136 func TestConfig_AlternateConfigFile(t *testing.T) { 137 tmpDir := setupConfigTest(t) 138 writeFile(t, tmpDir, "config.yaml", `in: this is from an alternate config 139 `) 140 141 o, e, err := cmd(t, "--config=config.yaml").withDir(tmpDir.Path()).run() 142 assertSuccess(t, o, e, err, "this is from an alternate config") 143 } 144 145 func TestConfig_EnvConfigFile(t *testing.T) { 146 tmpDir := setupConfigTest(t) 147 148 writeFile(t, tmpDir, "envconfig.yaml", `in: yet another alternate config 149 `) 150 151 o, e, err := cmd(t).withDir(tmpDir.Path()). 152 withEnv("GOMPLATE_CONFIG", "./envconfig.yaml").run() 153 assertSuccess(t, o, e, err, "yet another alternate config") 154 } 155 156 func TestConfig_ConfigOverridesEnvDelim(t *testing.T) { 157 if isWindows { 158 t.Skip() 159 } 160 161 tmpDir := setupConfigTest(t) 162 163 writeConfig(t, tmpDir, `inputFiles: [in] 164 leftDelim: (╯°□°)╯︵ ┻━┻ 165 datasources: 166 data: 167 url: in.yaml 168 `) 169 writeFile(t, tmpDir, "in", `(╯°□°)╯︵ ┻━┻ (ds "data").value }}`) 170 writeFile(t, tmpDir, "in.yaml", `value: hello world`) 171 172 o, e, err := cmd(t).withDir(tmpDir.Path()). 173 withEnv("GOMPLATE_LEFT_DELIM", "<<").run() 174 require.NoError(t, err) 175 assert.Equal(t, "", e) 176 assert.Equal(t, "hello world", o) 177 } 178 179 func TestConfig_FlagOverridesAllDelim(t *testing.T) { 180 if isWindows { 181 t.Skip() 182 } 183 184 tmpDir := setupConfigTest(t) 185 186 writeConfig(t, tmpDir, `inputFiles: [in] 187 leftDelim: (╯°□°)╯︵ ┻━┻ 188 datasources: 189 data: 190 url: in.yaml 191 `) 192 writeFile(t, tmpDir, "in", `{{ (ds "data").value }}`) 193 writeFile(t, tmpDir, "in.yaml", `value: hello world`) 194 195 o, e, err := cmd(t, "--left-delim={{"). 196 withDir(tmpDir.Path()). 197 withEnv("GOMPLATE_LEFT_DELIM", "<<").run() 198 require.NoError(t, err) 199 assert.Equal(t, "", e) 200 assert.Equal(t, "hello world", o) 201 } 202 203 func TestConfig_ConfigOverridesEnvPluginTimeout(t *testing.T) { 204 if isWindows { 205 t.Skip() 206 } 207 208 tmpDir := setupConfigTest(t) 209 210 writeConfig(t, tmpDir, `in: hi there {{ sleep 2 }} 211 plugins: 212 sleep: echo 213 214 pluginTimeout: 500ms 215 `) 216 217 _, _, err := cmd(t, "--plugin", "sleep="+tmpDir.Join("sleep.sh")). 218 withDir(tmpDir.Path()). 219 withEnv("GOMPLATE_PLUGIN_TIMEOUT", "5s").run() 220 assert.ErrorContains(t, err, "plugin timed out") 221 } 222 223 func TestConfig_ConfigOverridesEnvSuppressEmpty(t *testing.T) { 224 tmpDir := setupConfigTest(t) 225 226 writeConfig(t, tmpDir, `in: | 227 {{- print "\t \n\n\r\n\t\t \v\n" -}} 228 229 {{ print " " -}} 230 out: ./missing 231 suppressEmpty: true 232 `) 233 234 _, _, err := cmd(t).withDir(tmpDir.Path()). 235 withEnv("GOMPLATE_SUPPRESS_EMPTY", "false").run() 236 require.NoError(t, err) 237 238 _, err = os.Stat(tmpDir.Join("missing")) 239 require.ErrorIs(t, err, fs.ErrNotExist) 240 } 241 242 func TestConfig_ConfigParseErrorSpecifiesFilename(t *testing.T) { 243 tmpDir := setupConfigTest(t) 244 245 writeConfig(t, tmpDir, `templates: 246 dir: /foo/bar 247 `) 248 _, _, err := cmd(t).withDir(tmpDir.Path()).run() 249 assert.ErrorContains(t, err, `parsing config file ".gomplate.yaml": YAML decoding failed`) 250 } 251 252 func TestConfig_ConfigTemplatesSupportsMap(t *testing.T) { 253 tmpDir := setupConfigTest(t) 254 255 writeConfig(t, tmpDir, `in: '{{ template "t1" (dict "testValue" "12345") }}' 256 templates: 257 t1: 258 url: t1.tmpl 259 `) 260 writeFile(t, tmpDir, "t1.tmpl", `{{ .testValue }}`) 261 262 o, e, err := cmd(t).withDir(tmpDir.Path()).run() 263 assertSuccess(t, o, e, err, "12345") 264 } 265 266 func TestConfig_ConfigTemplatesSupportsArray(t *testing.T) { 267 tmpDir := setupConfigTest(t) 268 269 // TODO: remove this test once the array format is no longer supported 270 writeConfig(t, tmpDir, `in: '{{ template "t1" (dict "testValue" "12345") }}' 271 templates: 272 - t1=t1.tmpl 273 `) 274 writeFile(t, tmpDir, "t1.tmpl", `{{ .testValue }}`) 275 276 o, e, err := cmd(t).withDir(tmpDir.Path()).run() 277 assert.Contains(t, e, "Deprecated: config: the YAML array form for 'templates' is deprecated") 278 assert.Equal(t, "12345", o) 279 require.NoError(t, err) 280 } 281 282 func TestConfig_MissingKeyDefault(t *testing.T) { 283 tmpDir := setupConfigTest(t) 284 writeConfig(t, tmpDir, `inputFiles: [in] 285 missingKey: default 286 `) 287 writeFile(t, tmpDir, "in", `{{ .name }}`) 288 289 o, e, err := cmd(t).withDir(tmpDir.Path()).run() 290 assertSuccess(t, o, e, err, `<no value>`) 291 } 292 293 func TestConfig_MissingKeyNotDefined(t *testing.T) { 294 tmpDir := setupConfigTest(t) 295 writeConfig(t, tmpDir, `inputFiles: [in]`) 296 writeFile(t, tmpDir, "in", `{{ .name }}`) 297 298 o, e, err := cmd(t).withDir(tmpDir.Path()).run() 299 assertFailed(t, o, e, err, `map has no entry for key \"name\"`) 300 }