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  }