diff --git a/command/agent_test.go b/command/agent_test.go index 6012a983ba..b732e6b6a2 100644 --- a/command/agent_test.go +++ b/command/agent_test.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "net/http" "os" + "path/filepath" "reflect" "strings" "sync" @@ -770,19 +771,22 @@ func TestAgent_Template_Basic(t *testing.T) { for tcname, tc := range testCases { t.Run(tcname, func(t *testing.T) { - // make some template files - var templatePaths []string - for i := 0; i < tc.templateCount; i++ { - path := makeTempFile(t, fmt.Sprintf("render_%d", i), templateContents(i)) - templatePaths = append(templatePaths, path) - } - // create temp dir for this test run tmpDir, err := ioutil.TempDir(tmpDirRoot, tcname) if err != nil { t.Fatal(err) } + // make some template files + var templatePaths []string + for i := 0; i < tc.templateCount; i++ { + fileName := filepath.Join(tmpDir, fmt.Sprintf("render_%d.tmpl", i)) + if err := ioutil.WriteFile(fileName, []byte(templateContents(i)), 0600); err != nil { + t.Fatal(err) + } + templatePaths = append(templatePaths, fileName) + } + // build up the template config to be added to the Agent config.hcl file var templateConfigStrings []string for i, t := range templatePaths { @@ -854,50 +858,85 @@ auto_auth { // end and no longer be running. If we are not using exit_after_auth, then // we need to shut down the command if !tc.exitAfterAuth { + defer func() { + cmd.ShutdownCh <- struct{}{} + wg.Wait() + }() + } + + verify := func(suffix string) { + t.Helper() // We need to poll for a bit to give Agent time to render the // templates. Without this this, the test will attempt to read // the temp dir before Agent has had time to render and will // likely fail the test tick := time.Tick(1 * time.Second) - timeout := time.After(30 * time.Second) + timeout := time.After(10 * time.Second) + var err error for { select { case <-timeout: - t.Error("timed out waiting for templates to render") + t.Fatalf("timed out waiting for templates to render, last error: %v", err) case <-tick: } // Check for files rendered in the directory and break // early for shutdown if we do have all the files // rendered - if testListFiles(t, tmpDir) == len(templatePaths) { - break + + //---------------------------------------------------- + // Perform the tests + //---------------------------------------------------- + + if numFiles := testListFiles(t, tmpDir, ".json"); numFiles != len(templatePaths) { + err = fmt.Errorf("expected (%d) templates, got (%d)", len(templatePaths), numFiles) + continue } + + for i := range templatePaths { + fileName := filepath.Join(tmpDir, fmt.Sprintf("render_%d.json", i)) + var c []byte + c, err = ioutil.ReadFile(fileName) + if err != nil { + continue + } + if string(c) != templateRendered(i)+suffix { + err = fmt.Errorf("expected='%s', got='%s'", templateRendered(i)+suffix, string(c)) + continue + } + } + return } - - cmd.ShutdownCh <- struct{}{} } - wg.Wait() - //---------------------------------------------------- - // Perform the tests - //---------------------------------------------------- + verify("") - if numFiles := testListFiles(t, tmpDir); numFiles != len(templatePaths) { - t.Fatalf("expected (%d) templates, got (%d)", len(templatePaths), numFiles) + for i := 0; i < tc.templateCount; i++ { + fileName := filepath.Join(tmpDir, fmt.Sprintf("render_%d.tmpl", i)) + if err := ioutil.WriteFile(fileName, []byte(templateContents(i)+"{}"), 0600); err != nil { + t.Fatal(err) + } } + + verify("{}") }) } } -func testListFiles(t *testing.T, dir string) int { +func testListFiles(t *testing.T, dir, extension string) int { t.Helper() files, err := ioutil.ReadDir(dir) if err != nil { t.Fatal(err) } + var count int + for _, f := range files { + if filepath.Ext(f.Name()) == extension { + count++ + } + } - return len(files) + return count } // TestAgent_Template_ExitCounter tests that Vault Agent correctly renders all @@ -1117,24 +1156,22 @@ exit_after_auth = true // a slice of template options var templates = []string{ - `{{ with secret "secret/otherapp"}} -{ -{{ if .Data.data.username}}"username":"{{ .Data.data.username}}",{{ end }} -{{ if .Data.data.password }}"password":"{{ .Data.data.password }}",{{ end }} -{{ .Data.data.cert }} + `{{- with secret "secret/otherapp"}}{"secret": "other", +{{- if .Data.data.username}}"username":"{{ .Data.data.username}}",{{- end }} +{{- if .Data.data.password }}"password":"{{ .Data.data.password }}"{{- end }}} +{{- end }}`, + `{{- with secret "secret/myapp"}}{"secret": "myapp", +{{- if .Data.data.username}}"username":"{{ .Data.data.username}}",{{- end }} +{{- if .Data.data.password }}"password":"{{ .Data.data.password }}"{{- end }}} +{{- end }}`, + `{{- with secret "secret/myapp"}}{"secret": "myapp", +{{- if .Data.data.password }}"password":"{{ .Data.data.password }}"{{- end }}} +{{- end }}`, } -{{ end }}`, - `{{ with secret "secret/myapp"}} -{ -{{ if .Data.data.username}}"username":"{{ .Data.data.username}}",{{ end }} -{{ if .Data.data.password }}"password":"{{ .Data.data.password }}",{{ end }} -} -{{ end }}`, - `{{ with secret "secret/myapp"}} -{ -{{ if .Data.data.password }}"password":"{{ .Data.data.password }}",{{ end }} -} -{{ end }}`, +var rendered = []string{ + `{"secret": "other","username":"barstuff","password":"zap"}`, + `{"secret": "myapp","username":"bar","password":"zap"}`, + `{"secret": "myapp","password":"zap"}`, } // templateContents returns a template from the above templates slice. Each @@ -1145,6 +1182,10 @@ func templateContents(seed int) string { index := seed % len(templates) return templates[index] } +func templateRendered(seed int) string { + index := seed % len(templates) + return rendered[index] +} var templateConfigString = ` template {