github.com/hairyhenderson/gomplate/v3@v3.11.7/internal/tests/integration/integration_test.go (about) 1 package integration 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "fmt" 8 "io" 9 "log" 10 "net" 11 "net/http" 12 "os" 13 "runtime" 14 "strings" 15 "testing" 16 "time" 17 18 gcmd "github.com/hairyhenderson/gomplate/v3/internal/cmd" 19 vaultapi "github.com/hashicorp/vault/api" 20 "github.com/stretchr/testify/assert" 21 "gotest.tools/v3/icmd" 22 ) 23 24 const isWindows = runtime.GOOS == "windows" 25 26 // a convenience... 27 func inOutTest(t *testing.T, i, o string) { 28 t.Helper() 29 30 stdout, stderr, err := cmd(t, "-i", i).run() 31 assert.NoError(t, err) 32 assert.Equal(t, "", stderr) 33 assert.Equal(t, o, stdout) 34 } 35 36 func inOutTestExperimental(t *testing.T, i, o string) { 37 t.Helper() 38 39 stdout, stderr, err := cmd(t, "--experimental", "-i", i).run() 40 assert.NoError(t, err) 41 assert.Equal(t, "", stderr) 42 assert.Equal(t, o, stdout) 43 } 44 45 func inOutContains(t *testing.T, i, o string) { 46 t.Helper() 47 48 stdout, stderr, err := cmd(t, "-i", i).run() 49 assert.NoError(t, err) 50 assert.Equal(t, "", stderr) 51 assert.Contains(t, stdout, o) 52 } 53 54 func assertSuccess(t *testing.T, o, e string, err error, expected string) { 55 t.Helper() 56 57 assert.NoError(t, err) 58 assert.Equal(t, "", e) 59 assert.Equal(t, expected, o) 60 } 61 62 // mirrorHandler - reflects back the HTTP headers from the request 63 func mirrorHandler(w http.ResponseWriter, r *http.Request) { 64 type Req struct { 65 Headers http.Header `json:"headers"` 66 } 67 req := Req{r.Header} 68 b, err := json.Marshal(req) 69 if err != nil { 70 log.Println(err) 71 w.WriteHeader(http.StatusBadRequest) 72 } 73 w.Header().Set("Content-Type", "application/json") 74 w.Write(b) 75 } 76 77 func typeHandler(t, body string) func(http.ResponseWriter, *http.Request) { 78 return func(w http.ResponseWriter, r *http.Request) { 79 w.Header().Set("Content-Type", t) 80 w.Write([]byte(body)) 81 } 82 } 83 84 // freeport - find a free TCP port for immediate use. No guarantees! 85 func freeport(t *testing.T) (port int, addr string) { 86 l, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP("127.0.0.1")}) 87 if err != nil { 88 t.Fatal(err) 89 } 90 defer l.Close() 91 a := l.Addr().(*net.TCPAddr) 92 port = a.Port 93 return port, a.String() 94 } 95 96 // waitForURL - waits up to 20s for a given URL to respond with a 200 97 func waitForURL(t *testing.T, url string) error { 98 client := http.DefaultClient 99 retries := 100 100 for retries > 0 { 101 retries-- 102 time.Sleep(200 * time.Millisecond) 103 resp, err := client.Get(url) 104 if err != nil { 105 t.Logf("Got error, retries left: %d (error: %v)", retries, err) 106 continue 107 } 108 body, err := io.ReadAll(resp.Body) 109 t.Logf("Body is: %s", body) 110 if err != nil { 111 return err 112 } 113 defer resp.Body.Close() 114 if resp.StatusCode == 200 { 115 return nil 116 } 117 } 118 return fmt.Errorf("URL %s never responded with 200", url) 119 } 120 121 type vaultClient struct { 122 vc *vaultapi.Client 123 addr string 124 rootToken string 125 } 126 127 func createVaultClient(addr string, rootToken string) (*vaultClient, error) { 128 config := vaultapi.DefaultConfig() 129 config.Address = "http://" + addr 130 client, err := vaultapi.NewClient(config) 131 if err != nil { 132 return nil, err 133 } 134 v := &vaultClient{ 135 vc: client, 136 addr: addr, 137 rootToken: rootToken, 138 } 139 client.SetToken(rootToken) 140 return v, nil 141 } 142 143 func (v *vaultClient) tokenCreate(policy string, uses int) (string, error) { 144 opts := &vaultapi.TokenCreateRequest{ 145 Policies: []string{policy}, 146 TTL: "1m", 147 NumUses: uses, 148 } 149 token, err := v.vc.Auth().Token().Create(opts) 150 if err != nil { 151 return "", err 152 } 153 return token.Auth.ClientToken, nil 154 } 155 156 type command struct { 157 t *testing.T 158 dir string 159 stdin string 160 env map[string]string 161 envK []string 162 args []string 163 } 164 165 func cmd(t *testing.T, args ...string) *command { 166 return &command{t: t, args: args} 167 } 168 169 func (c *command) withDir(dir string) *command { 170 c.dir = dir 171 return c 172 } 173 174 func (c *command) withStdin(in string) *command { 175 c.stdin = in 176 return c 177 } 178 179 func (c *command) withEnv(k, v string) *command { 180 if c.env == nil { 181 c.env = map[string]string{} 182 } 183 if c.envK == nil { 184 c.envK = []string{} 185 } 186 c.env[k] = v 187 c.envK = append(c.envK, k) 188 return c 189 } 190 191 // set this at 'go test' time to test with a pre-compiled binary instead of 192 // running all tests in-process 193 var GomplateBinPath = "" 194 195 func (c *command) run() (o, e string, err error) { 196 if GomplateBinPath != "" { 197 return c.runCompiled(GomplateBinPath) 198 } 199 return c.runInProcess() 200 } 201 202 func (c *command) runInProcess() (o, e string, err error) { 203 // iterate env vars by order of insertion 204 for _, k := range c.envK { 205 k := k 206 // clean up after ourselves 207 if orig, ok := os.LookupEnv(k); ok { 208 defer os.Setenv(k, orig) 209 } else { 210 defer os.Unsetenv(k) 211 } 212 os.Setenv(k, c.env[k]) 213 } 214 215 if c.dir != "" { 216 //nolint:govet 217 origWd, err := os.Getwd() 218 if err != nil { 219 c.t.Fatal(err) 220 } 221 defer os.Chdir(origWd) 222 223 err = os.Chdir(c.dir) 224 if err != nil { 225 c.t.Fatal(err) 226 } 227 } 228 229 stdin := strings.NewReader(c.stdin) 230 231 ctx := context.Background() 232 stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{} 233 err = gcmd.Main(ctx, c.args, stdin, stdout, stderr) 234 return stdout.String(), stderr.String(), err 235 } 236 237 func (c *command) runCompiled(bin string) (o, e string, err error) { 238 cmd := icmd.Command(bin, c.args...) 239 cmd.Dir = c.dir 240 cmd.Stdin = strings.NewReader(c.stdin) 241 cmd.Env = os.Environ() 242 cmd.Env = append(cmd.Env, "GOMPLATE_LOG_FORMAT=simple") 243 for _, k := range c.envK { 244 cmd.Env = append(cmd.Env, k+"="+c.env[k]) 245 } 246 247 result := icmd.RunCmd(cmd) 248 if result.Error != nil { 249 result.Error = fmt.Errorf("%w: %s", result.Error, result.Stderr()) 250 } 251 return result.Stdout(), result.Stderr(), result.Error 252 }