summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Henderson <dhenderson@gmail.com>2018-02-07 07:53:34 -0500
committerDave Henderson <dhenderson@gmail.com>2018-03-02 23:35:26 -0500
commit0d465ad2eab7e0f31213efd78be61347fc37f084 (patch)
tree46d5461400b6d48e458b11e3b60f4986f03475ec
parent8aa53b563b57b4debf9dfb9be6ffa2703ed3ca90 (diff)
Migrate from bats to pure Go for integration tests
Signed-off-by: Dave Henderson <dhenderson@gmail.com>
-rw-r--r--.dockerignore1
-rw-r--r--Dockerfile.integration14
-rw-r--r--Makefile41
-rw-r--r--circle.yml2
-rw-r--r--test/files/input-dir/config.yml2
-rw-r--r--test/files/input-dir/in/exclude.txt1
-rw-r--r--test/files/input-dir/in/inner/nested.txt1
-rw-r--r--test/files/input-dir/in/top.txt1
-rw-r--r--test/integration/.gitignore4
-rw-r--r--test/integration/Dockerfile31
-rw-r--r--test/integration/base64.bats25
-rw-r--r--test/integration/base64_test.go26
-rw-r--r--test/integration/basic.bats82
-rw-r--r--test/integration/basic_test.go154
-rw-r--r--test/integration/config.dbbin32768 -> 0 bytes
-rw-r--r--test/integration/datasources_boltdb.bats27
-rw-r--r--test/integration/datasources_boltdb_test.go65
-rw-r--r--test/integration/datasources_consul.bats56
-rw-r--r--test/integration/datasources_consul_test.go208
-rw-r--r--test/integration/datasources_file.bats49
-rw-r--r--test/integration/datasources_file_test.go67
-rw-r--r--test/integration/datasources_http.bats20
-rw-r--r--test/integration/datasources_http_test.go40
-rw-r--r--test/integration/datasources_vault.bats202
-rw-r--r--test/integration/datasources_vault_ec2_test.go155
-rw-r--r--test/integration/datasources_vault_test.go358
-rw-r--r--test/integration/envvars.bats52
-rw-r--r--test/integration/envvars_test.go52
-rw-r--r--test/integration/helper.bash107
-rw-r--r--test/integration/input-dir.bats77
-rw-r--r--test/integration/inputdir_test.go104
-rw-r--r--test/integration/integration.go1
-rw-r--r--test/integration/integration_test.go122
-rw-r--r--test/integration/math.bats45
-rw-r--r--test/integration/math_test.go22
-rw-r--r--test/integration/metasvc/main.go147
-rw-r--r--test/integration/mirrorsvc/main.go54
-rw-r--r--test/integration/net.bats19
-rw-r--r--test/integration/net_test.go19
-rw-r--r--test/integration/regexp.bats19
-rw-r--r--test/integration/regexp_test.go20
-rw-r--r--test/integration/strings.bats30
-rw-r--r--test/integration/strings_test.go31
-rwxr-xr-xtest/integration/test.sh16
-rw-r--r--test/integration/test_ec2_utils.go (renamed from test/integration/awssvc/main.go)120
-rw-r--r--test/integration/time.bats52
-rw-r--r--test/integration/time_test.go49
-rw-r--r--test/integration/typeconv_funcs.bats102
-rw-r--r--test/integration/typeconv_test.go87
-rw-r--r--vault/vault_test.go1
50 files changed, 1685 insertions, 1295 deletions
diff --git a/.dockerignore b/.dockerignore
index f745bfb4..582f99ee 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,6 +1,5 @@
Dockerfile
.vscode
*.md
-bin/
*.cid
*.iid
diff --git a/Dockerfile.integration b/Dockerfile.integration
new file mode 100644
index 00000000..0bd4ff77
--- /dev/null
+++ b/Dockerfile.integration
@@ -0,0 +1,14 @@
+FROM golang:1.10-alpine
+
+COPY --from=vault:0.9.5 /bin/vault /bin/vault
+COPY --from=consul:1.0.6 /bin/consul /bin/consul
+
+RUN apk add --no-cache make tzdata
+
+WORKDIR /go/src/github.com/hairyhenderson/gomplate/
+COPY vendor ./vendor
+COPY test/integration ./test/integration
+COPY Makefile ./Makefile
+COPY bin/gomplate_linux-amd64 ./bin/gomplate
+
+CMD ["make", "integration"]
diff --git a/Makefile b/Makefile
index 234b4878..8c7fb627 100644
--- a/Makefile
+++ b/Makefile
@@ -20,10 +20,6 @@ compressed-platforms := linux-amd64-slim linux-arm-slim linux-arm64-slim darwin-
clean:
rm -Rf $(PREFIX)/bin/*
rm -f $(PREFIX)/*.[ci]id
- rm -f $(PREFIX)/test/integration/gomplate
- rm -f $(PREFIX)/test/integration/mirror
- rm -f $(PREFIX)/test/integration/meta
- rm -f $(PREFIX)/test/integration/aws
build-x: $(patsubst %,$(PREFIX)/bin/$(PKG_NAME)_%,$(platforms))
@@ -54,7 +50,7 @@ build-release: artifacts.cid
docker-images: gomplate.iid gomplate-slim.iid
-$(PREFIX)/bin/$(PKG_NAME)_%: $(shell find $(PREFIX) -type f -name '*.go' -not -path "$(PREFIX)/test/*")
+$(PREFIX)/bin/$(PKG_NAME)_%: $(shell find $(PREFIX) -type f -name '*.go')
GOOS=$(shell echo $* | cut -f1 -d-) GOARCH=$(shell echo $* | cut -f2 -d- | cut -f1 -d.) CGO_ENABLED=0 \
$(GO) build \
-ldflags "-w -s $(COMMIT_FLAG) $(VERSION_FLAG)" \
@@ -63,41 +59,20 @@ $(PREFIX)/bin/$(PKG_NAME)_%: $(shell find $(PREFIX) -type f -name '*.go' -not -p
$(PREFIX)/bin/$(PKG_NAME)$(call extension,$(GOOS)): $(PREFIX)/bin/$(PKG_NAME)_$(GOOS)-$(GOARCH)$(call extension,$(GOOS))
cp $< $@
-$(PREFIX)/test/integration/mirror$(call extension,$(GOOS)): $(shell find $(PREFIX)/test/integration/mirrorsvc -type f -name '*.go')
- CGO_ENABLED=0 \
- $(GO) build -ldflags "-w -s $(COMMIT_FLAG) $(VERSION_FLAG)" -o $@ $(PREFIX)/test/integration/mirrorsvc
-
-$(PREFIX)/test/integration/meta$(call extension,$(GOOS)): $(shell find $(PREFIX)/test/integration/metasvc -type f -name '*.go')
- CGO_ENABLED=0 \
- $(GO) build -ldflags "-w -s $(COMMIT_FLAG) $(VERSION_FLAG)" -o $@ $(PREFIX)/test/integration/metasvc
-
-$(PREFIX)/test/integration/aws$(call extension,$(GOOS)): $(shell find $(PREFIX)/test/integration/awssvc -type f -name '*.go')
- CGO_ENABLED=0 \
- $(GO) build -ldflags "-w -s $(COMMIT_FLAG) $(VERSION_FLAG)" -o $@ $(PREFIX)/test/integration/awssvc
-
build: $(PREFIX)/bin/$(PKG_NAME)$(call extension,$(GOOS))
-build-mirror: $(PREFIX)/test/integration/mirror$(call extension,$(GOOS))
-
-build-meta: $(PREFIX)/test/integration/meta$(call extension,$(GOOS))
-
-build-aws: $(PREFIX)/test/integration/aws$(call extension,$(GOOS))
-
test:
$(GO) test -v -race ./...
-build-integration-image: $(PREFIX)/bin/$(PKG_NAME)_linux-amd64$(call extension,$(GOOS)) $(PREFIX)/bin/mirror_linux-amd64$(call extension,$(GOOS)) $(PREFIX)/bin/meta_linux-amd64$(call extension,$(GOOS)) $(PREFIX)/bin/aws_linux-amd64$(call extension,$(GOOS))
- cp $(PREFIX)/bin/$(PKG_NAME)_linux-amd64 test/integration/gomplate
- cp $(PREFIX)/bin/mirror_linux-amd64 test/integration/mirror
- cp $(PREFIX)/bin/meta_linux-amd64 test/integration/meta
- cp $(PREFIX)/bin/aws_linux-amd64 test/integration/aws
- docker build -f test/integration/Dockerfile -t gomplate-test test/integration/
+integration: ./bin/gomplate
+ $(GO) test -v -tags=integration \
+ ./test/integration -check.v
-test-integration-docker: build-integration-image
- docker run -it --rm gomplate-test
+integration.iid: Dockerfile.integration $(PREFIX)/bin/$(PKG_NAME)_linux-amd64$(call extension,$(GOOS))
+ docker build -f $< --iidfile $@ -t gomplate-test .
-test-integration: build build-mirror build-meta build-aws
- @test/integration/test.sh
+test-integration-docker: integration.iid
+ docker run -it --rm gomplate-test
gen-changelog:
docker run -it -v $(pwd):/app --workdir /app -e CHANGELOG_GITHUB_TOKEN hairyhenderson/github_changelog_generator \
diff --git a/circle.yml b/circle.yml
index 51788a10..d3e27ba5 100644
--- a/circle.yml
+++ b/circle.yml
@@ -13,7 +13,7 @@ jobs:
name: make test
command: make test | go-junit-report > $CIRCLE_TEST_REPORTS/report.xml
- run: make lint
- - run: make test-integration
+ - run: make integration
- store_artifacts:
path: bin
destination: binaries
diff --git a/test/files/input-dir/config.yml b/test/files/input-dir/config.yml
deleted file mode 100644
index 1ec99548..00000000
--- a/test/files/input-dir/config.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-one: eins
-two: zwei
diff --git a/test/files/input-dir/in/exclude.txt b/test/files/input-dir/in/exclude.txt
deleted file mode 100644
index d9cfae16..00000000
--- a/test/files/input-dir/in/exclude.txt
+++ /dev/null
@@ -1 +0,0 @@
-Should not be included
diff --git a/test/files/input-dir/in/inner/nested.txt b/test/files/input-dir/in/inner/nested.txt
deleted file mode 100644
index 55e06b79..00000000
--- a/test/files/input-dir/in/inner/nested.txt
+++ /dev/null
@@ -1 +0,0 @@
-{{ (datasource "config").two }} \ No newline at end of file
diff --git a/test/files/input-dir/in/top.txt b/test/files/input-dir/in/top.txt
deleted file mode 100644
index 9069510b..00000000
--- a/test/files/input-dir/in/top.txt
+++ /dev/null
@@ -1 +0,0 @@
-{{ (datasource "config").one }} \ No newline at end of file
diff --git a/test/integration/.gitignore b/test/integration/.gitignore
deleted file mode 100644
index 62c29879..00000000
--- a/test/integration/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-gomplate
-mirror
-meta
-aws
diff --git a/test/integration/Dockerfile b/test/integration/Dockerfile
deleted file mode 100644
index a82c7dc5..00000000
--- a/test/integration/Dockerfile
+++ /dev/null
@@ -1,31 +0,0 @@
-FROM alpine:edge
-
-ENV VAULT_VER 0.9.3
-ENV CONSUL_VER 1.0.3
-RUN apk add --no-cache \
- curl \
- bash \
- bats \
- jq \
- && curl -L -o /tmp/vault.zip https://releases.hashicorp.com/vault/${VAULT_VER}/vault_${VAULT_VER}_linux_amd64.zip \
- && unzip /tmp/vault.zip \
- && mv vault /bin/vault \
- && rm /tmp/vault.zip \
- && curl -L -o /tmp/consul.zip https://releases.hashicorp.com/consul/${CONSUL_VER}/consul_${CONSUL_VER}_linux_amd64.zip \
- && unzip /tmp/consul.zip \
- && mv consul /bin/consul \
- && rm /tmp/consul.zip
-
-RUN mkdir /lib64 \
- && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2
-
-COPY gomplate /bin/gomplate
-COPY mirror /bin/mirror
-COPY meta /bin/meta
-COPY aws /bin/aws
-COPY *.sh /tests/
-COPY *.bash /tests/
-COPY *.bats /tests/
-COPY *.db /test/integration/
-
-CMD ["/tests/test.sh"]
diff --git a/test/integration/base64.bats b/test/integration/base64.bats
deleted file mode 100644
index 43b623d6..00000000
--- a/test/integration/base64.bats
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/env bats
-
-load helper
-
-tmpdir=$(mktemp -u)
-
-function setup () {
- mkdir -p $tmpdir
-}
-
-function teardown () {
- rm -rf $tmpdir
-}
-
-@test "'base64.Encode'" {
- gomplate -i '{{ "foo" | base64.Encode }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "Zm9v" ]]
-}
-
-@test "'base64.Decode'" {
- gomplate -i '{{ "Zm9v" | base64.Decode }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "foo" ]]
-} \ No newline at end of file
diff --git a/test/integration/base64_test.go b/test/integration/base64_test.go
new file mode 100644
index 00000000..28dddd00
--- /dev/null
+++ b/test/integration/base64_test.go
@@ -0,0 +1,26 @@
+//+build integration
+//+build !windows
+
+package integration
+
+import (
+ . "gopkg.in/check.v1"
+
+ "github.com/gotestyourself/gotestyourself/icmd"
+)
+
+type Base64Suite struct{}
+
+var _ = Suite(&Base64Suite{})
+
+func (s *Base64Suite) TestBase64Encode(c *C) {
+ result := icmd.RunCommand(GomplateBin, "-i",
+ `{{ "foo" | base64.Encode }}`)
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "Zm9v"})
+}
+
+func (s *Base64Suite) TestBase64Decode(c *C) {
+ result := icmd.RunCommand(GomplateBin, "-i",
+ `{{ "Zm9v" | base64.Decode }}`)
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "foo"})
+}
diff --git a/test/integration/basic.bats b/test/integration/basic.bats
deleted file mode 100644
index 974ef3d8..00000000
--- a/test/integration/basic.bats
+++ /dev/null
@@ -1,82 +0,0 @@
-#!/usr/bin/env bats
-
-load helper
-
-tmpdir=$(mktemp -u)
-
-function setup () {
- mkdir -p $tmpdir
- echo 'hi' > $tmpdir/one
- echo 'hello' > $tmpdir/two
-}
-
-function teardown () {
- rm -rf $tmpdir
-}
-
-@test "reports version" {
- gomplate -v
- [ "$status" -eq 0 ]
- [[ "${output}" == "gomplate version "* ]]
-}
-
-@test "takes stdin by default" {
- gomplate_stdin "hello world"
- [ "$status" -eq 0 ]
- [[ "${output}" == "hello world" ]]
-}
-
-@test "takes stdin with --file -" {
- gomplate_stdin "hello world" --file -
- [ "$status" -eq 0 ]
- [[ "${output}" == "hello world" ]]
-}
-
-@test "writes to stdout with --out -" {
- gomplate_stdin "hello world" --out -
- [ "$status" -eq 0 ]
- [[ "${output}" == "hello world" ]]
-}
-
-@test "ignores stdin with --in" {
- gomplate_stdin "hello world" --in "hi"
- [ "$status" -eq 0 ]
- [[ "${output}" == "hi" ]]
-}
-
-@test "errors given more inputs than outputs" {
- gomplate -f $tmpdir/one -f $tmpdir/two -o $tmpdir/out
- [ "$status" -eq 1 ]
- [[ "${lines[0]}" == "Error: Must provide same number of --out (1) as --file (2) options" ]]
-}
-
-@test "routes inputs to their proper outputs" {
- gomplate -f $tmpdir/one -f $tmpdir/two -o $tmpdir/one.out -o $tmpdir/two.out
- [ "$status" -eq 0 ]
- [[ "$(cat $tmpdir/one.out)" == "hi" ]]
- [[ "$(cat $tmpdir/two.out)" == "hello" ]]
-}
-
-@test "can't mix --in and --file" {
- gomplate -i 'HELLO WORLD' -f -
- [ "$status" -eq 1 ]
- [[ "${lines[0]}" == "Error: --in and --file may not be used together" ]]
-}
-
-@test "delimiters can be changed through opts" {
- gomplate --left-delim "((" --right-delim "))" -i '((print "hi"))'
- [ "$status" -eq 0 ]
- [[ "${output}" == "hi" ]]
-}
-
-@test "delimiters can be changed through envvars" {
- GOMPLATE_LEFT_DELIM="<<" GOMPLATE_RIGHT_DELIM=">>" gomplate -i '<<print "hi">>'
- [ "$status" -eq 0 ]
- [[ "${output}" == "hi" ]]
-}
-
-@test "unknown argument results in error" {
- gomplate -in flibbit
- [ "$status" -eq 1 ]
- [[ "${lines[0]}" == 'Error: unknown command "flibbit" for "gomplate"' ]]
-}
diff --git a/test/integration/basic_test.go b/test/integration/basic_test.go
new file mode 100644
index 00000000..c0a52a0b
--- /dev/null
+++ b/test/integration/basic_test.go
@@ -0,0 +1,154 @@
+//+build integration
+//+build !windows
+
+package integration
+
+import (
+ "bytes"
+ "io/ioutil"
+
+ . "gopkg.in/check.v1"
+
+ "github.com/gotestyourself/gotestyourself/assert"
+ "github.com/gotestyourself/gotestyourself/assert/cmp"
+ "github.com/gotestyourself/gotestyourself/fs"
+ "github.com/gotestyourself/gotestyourself/icmd"
+)
+
+type BasicSuite struct {
+ tmpDir *fs.Dir
+}
+
+var _ = Suite(&BasicSuite{})
+
+func (s *BasicSuite) SetUpSuite(c *C) {
+ s.tmpDir = fs.NewDir(c, "gomplate-inttests",
+ fs.WithFile("one", "hi\n"),
+ fs.WithFile("two", "hello\n"))
+}
+
+func (s *BasicSuite) TearDownSuite(c *C) {
+ s.tmpDir.Remove()
+}
+
+func (s *BasicSuite) TestReportsVersion(c *C) {
+ result := icmd.RunCommand(GomplateBin, "-v")
+ result.Assert(c, icmd.Success)
+ assert.Assert(c, cmp.Contains(result.Combined(), "gomplate version "))
+}
+
+func (s *BasicSuite) TestTakesStdinByDefault(c *C) {
+ result := icmd.RunCmd(icmd.Command(GomplateBin), func(cmd *icmd.Cmd) {
+ cmd.Stdin = bytes.NewBufferString("hello world")
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "hello world"})
+}
+
+func (s *BasicSuite) TestTakesStdinWithFileFlag(c *C) {
+ result := icmd.RunCmd(icmd.Command(GomplateBin, "--file", "-"), func(cmd *icmd.Cmd) {
+ cmd.Stdin = bytes.NewBufferString("hello world")
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "hello world"})
+}
+func (s *BasicSuite) TestWritesToStdoutWithOutFlag(c *C) {
+ result := icmd.RunCmd(icmd.Command(GomplateBin, "--out", "-"), func(cmd *icmd.Cmd) {
+ cmd.Stdin = bytes.NewBufferString("hello world")
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "hello world"})
+}
+
+func (s *BasicSuite) TestIgnoresStdinWithInFlag(c *C) {
+ result := icmd.RunCmd(icmd.Command(GomplateBin, "--in", "hi"), func(cmd *icmd.Cmd) {
+ cmd.Stdin = bytes.NewBufferString("hello world")
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "hi"})
+}
+
+func (s *BasicSuite) TestErrorsWithInputOutputImbalance(c *C) {
+ result := icmd.RunCmd(icmd.Command(GomplateBin,
+ "-f", s.tmpDir.Join("one"),
+ "-f", s.tmpDir.Join("two"),
+ "-o", s.tmpDir.Join("out")), func(cmd *icmd.Cmd) {
+ cmd.Stdin = bytes.NewBufferString("hello world")
+ })
+ result.Assert(c, icmd.Expected{
+ ExitCode: 1,
+ Err: "Error: Must provide same number of --out (1) as --file (2) options",
+ })
+}
+
+func (s *BasicSuite) TestRoutesInputsToProperOutputs(c *C) {
+ oneOut := s.tmpDir.Join("one.out")
+ twoOut := s.tmpDir.Join("two.out")
+ result := icmd.RunCmd(icmd.Command(GomplateBin,
+ "-f", s.tmpDir.Join("one"),
+ "-f", s.tmpDir.Join("two"),
+ "-o", oneOut,
+ "-o", twoOut), func(cmd *icmd.Cmd) {
+ cmd.Stdin = bytes.NewBufferString("hello world")
+ })
+ result.Assert(c, icmd.Success)
+
+ content, err := ioutil.ReadFile(oneOut)
+ assert.NilError(c, err)
+ assert.Equal(c, "hi\n", string(content))
+ content, err = ioutil.ReadFile(twoOut)
+ assert.NilError(c, err)
+ assert.Equal(c, "hello\n", string(content))
+}
+
+func (s *BasicSuite) TestFlagRules(c *C) {
+ result := icmd.RunCommand(GomplateBin, "-f", "-", "-i", "HELLO WORLD")
+ result.Assert(c, icmd.Expected{
+ ExitCode: 1,
+ Out: "--in and --file may not be used together",
+ })
+
+ result = icmd.RunCommand(GomplateBin, "--output-dir", ".")
+ result.Assert(c, icmd.Expected{
+ ExitCode: 1,
+ Out: "--input-dir must be set when --output-dir is set",
+ })
+
+ result = icmd.RunCommand(GomplateBin, "--input-dir", ".", "--in", "param")
+ result.Assert(c, icmd.Expected{
+ ExitCode: 1,
+ Out: "--input-dir can not be used together with --in or --file",
+ })
+
+ result = icmd.RunCommand(GomplateBin, "--input-dir", ".", "--file", "input.txt")
+ result.Assert(c, icmd.Expected{
+ ExitCode: 1,
+ Out: "--input-dir can not be used together with --in or --file",
+ })
+
+ result = icmd.RunCommand(GomplateBin, "--output-dir", ".", "--out", "param")
+ result.Assert(c, icmd.Expected{
+ ExitCode: 1,
+ Out: "--output-dir can not be used together with --out",
+ })
+}
+
+func (s *BasicSuite) TestDelimsChangedThroughOpts(c *C) {
+ result := icmd.RunCommand(GomplateBin,
+ "--left-delim", "((",
+ "--right-delim", "))",
+ "-i", `((print "hi"))`)
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "hi"})
+}
+
+func (s *BasicSuite) TestDelimsChangedThroughEnvVars(c *C) {
+ result := icmd.RunCmd(icmd.Command(GomplateBin, "-i", `<<print "hi">>`),
+ func(cmd *icmd.Cmd) {
+ cmd.Env = []string{
+ "GOMPLATE_LEFT_DELIM=<<",
+ "GOMPLATE_RIGHT_DELIM=>>",
+ }
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "hi"})
+}
+
+func (s *BasicSuite) TestUnknownArgErrors(c *C) {
+ result := icmd.RunCommand(GomplateBin, "-in", "flibbit")
+ result.Assert(c, icmd.Expected{ExitCode: 1, Out: `unknown command "flibbit" for "gomplate"`})
+}
diff --git a/test/integration/config.db b/test/integration/config.db
deleted file mode 100644
index e68a29c6..00000000
--- a/test/integration/config.db
+++ /dev/null
Binary files differ
diff --git a/test/integration/datasources_boltdb.bats b/test/integration/datasources_boltdb.bats
deleted file mode 100644
index 8260cbf6..00000000
--- a/test/integration/datasources_boltdb.bats
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env bats
-
-load helper
-
-tmpdir=$(mktemp -u)
-
-function setup () {
- mkdir -p $tmpdir
-}
-
-function teardown () {
- rm -rf $tmpdir || true
-}
-
-@test "supports BoltDB datasource file" {
- cp test/integration/config.db $tmpdir/config.db
- gomplate -d config=boltdb://$tmpdir/config.db#Bucket1 -i '{{(datasource "config" "foo")}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "bar" ]]
-}
-
-@test "supports multi-bucket BoltDB datasource file" {
- cp test/integration/config.db $tmpdir/config.db
- gomplate -d config=boltdb://$tmpdir/config.db#Bucket1 -d config2=boltdb://$tmpdir/config.db#Bucket2 -i '{{(datasource "config" "foo")}}-{{(datasource "config2" "foobar")}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "bar-baz" ]]
-}
diff --git a/test/integration/datasources_boltdb_test.go b/test/integration/datasources_boltdb_test.go
new file mode 100644
index 00000000..a81e2b20
--- /dev/null
+++ b/test/integration/datasources_boltdb_test.go
@@ -0,0 +1,65 @@
+//+build integration
+//+build !windows
+
+package integration
+
+import (
+ . "gopkg.in/check.v1"
+
+ "github.com/boltdb/bolt"
+ "github.com/gotestyourself/gotestyourself/fs"
+ "github.com/gotestyourself/gotestyourself/icmd"
+)
+
+type BoltDBDatasourcesSuite struct {
+ tmpDir *fs.Dir
+}
+
+var _ = Suite(&BoltDBDatasourcesSuite{})
+
+func (s *BoltDBDatasourcesSuite) SetUpSuite(c *C) {
+ s.tmpDir = fs.NewDir(c, "gomplate-inttests")
+ db, err := bolt.Open(s.tmpDir.Join("config.db"), 0600, nil)
+ handle(c, err)
+ defer db.Close()
+
+ err = db.Update(func(tx *bolt.Tx) error {
+ var b *bolt.Bucket
+ b, err = tx.CreateBucket([]byte("Bucket1"))
+ if err != nil {
+ return err
+ }
+ // the first 8 bytes are ignored when read by libkv, so we prefix with gibberish
+ err = b.Put([]byte("foo"), []byte("00000000bar"))
+ if err != nil {
+ return err
+ }
+
+ b, err = tx.CreateBucket([]byte("Bucket2"))
+ if err != nil {
+ return err
+ }
+ err = b.Put([]byte("foobar"), []byte("00000000baz"))
+ return err
+ })
+ handle(c, err)
+}
+
+func (s *BoltDBDatasourcesSuite) TearDownSuite(c *C) {
+ s.tmpDir.Remove()
+}
+
+func (s *BoltDBDatasourcesSuite) TestBoltDBDatasource(c *C) {
+ result := icmd.RunCommand(GomplateBin,
+ "-d", "config=boltdb://"+s.tmpDir.Join("config.db#Bucket1"),
+ "-i", `{{(ds "config" "foo")}}`,
+ )
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
+
+ result = icmd.RunCommand(GomplateBin,
+ "-d", "config=boltdb://"+s.tmpDir.Join("config.db#Bucket1"),
+ "-d", "config2=boltdb://"+s.tmpDir.Join("config.db#Bucket2"),
+ "-i", `{{(ds "config" "foo")}}-{{(ds "config2" "foobar")}}`,
+ )
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar-baz"})
+}
diff --git a/test/integration/datasources_consul.bats b/test/integration/datasources_consul.bats
deleted file mode 100644
index b62848a1..00000000
--- a/test/integration/datasources_consul.bats
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env bats
-
-load helper
-
-function setup () {
- start_consul 8501
- export CONSUL_HTTP_ADDR=http://127.0.0.1:8501
-}
-
-function teardown () {
- export CONSUL_HTTP_ADDR=http://127.0.0.1:8501
- consul kv delete foo
- vault secrets disable consul
- stop_consul
-}
-
-@test "Testing consul" {
- consul kv put foo "$BATS_TEST_DESCRIPTION"
- gomplate -d consul=consul:// -i '{{(datasource "consul" "foo")}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "$BATS_TEST_DESCRIPTION" ]]
-}
-
-@test "Consul datasource works with MIME override" {
- consul kv put foo "{\"desc\":$BATS_TEST_DESCRIPTION}"
- gomplate -d consul=consul://?type=application/json -i '{{(datasource "consul" "foo").desc}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "$BATS_TEST_DESCRIPTION" ]]
-}
-
-@test "Consul datasource works with hostname in URL" {
- consul kv put foo "$BATS_TEST_DESCRIPTION"
- unset CONSUL_HTTP_ADDR
- gomplate -d consul=consul://127.0.0.1:8501/ -i '{{(datasource "consul" "foo")}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "$BATS_TEST_DESCRIPTION" ]]
-}
-
-@test "Consul datasource works with consul+http scheme" {
- consul kv put foo "$BATS_TEST_DESCRIPTION"
- unset CONSUL_HTTP_ADDR
- gomplate -d consul=consul+http://127.0.0.1:8501/ -i '{{(datasource "consul" "foo")}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "$BATS_TEST_DESCRIPTION" ]]
-}
-
-@test "Consul datasource works with Vault auth" {
- vault mount consul
- vault write consul/config/access address=127.0.0.1:8501 token=${CONSUL_ROOT_TOKEN}
- POLICY='key "" { policy = "read" }'
- vault write consul/roles/readonly policy=`echo $POLICY | base64`
- consul kv put foo "$BATS_TEST_DESCRIPTION"
- CONSUL_VAULT_ROLE=readonly gomplate -d consul=consul:// -i '{{(datasource "consul" "foo")}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "$BATS_TEST_DESCRIPTION" ]]
-}
diff --git a/test/integration/datasources_consul_test.go b/test/integration/datasources_consul_test.go
new file mode 100644
index 00000000..f0c58f68
--- /dev/null
+++ b/test/integration/datasources_consul_test.go
@@ -0,0 +1,208 @@
+//+build integration
+//+build !windows
+
+package integration
+
+import (
+ "encoding/base64"
+ "io/ioutil"
+ "os"
+ "os/user"
+ "path"
+ "strconv"
+
+ . "gopkg.in/check.v1"
+
+ "github.com/gotestyourself/gotestyourself/fs"
+ "github.com/gotestyourself/gotestyourself/icmd"
+ vaultapi "github.com/hashicorp/vault/api"
+)
+
+type ConsulDatasourcesSuite struct {
+ tmpDir *fs.Dir
+ pidDir *fs.Dir
+ consulAddr string
+ consulResult *icmd.Result
+ vaultAddr string
+ vaultResult *icmd.Result
+}
+
+var _ = Suite(&ConsulDatasourcesSuite{})
+
+const consulRootToken = "00000000-1111-2222-3333-444455556666"
+
+func (s *ConsulDatasourcesSuite) SetUpSuite(c *C) {
+ s.pidDir = fs.NewDir(c, "gomplate-inttests-pid")
+ s.tmpDir = fs.NewDir(c, "gomplate-inttests",
+ fs.WithFile(
+ "consul.json",
+ `{"acl_datacenter": "dc1", "acl_master_token": "`+consulRootToken+`"}`,
+ ),
+ fs.WithFile("vault.json", `{
+ "pid_file": "`+s.pidDir.Join("vault.pid")+`"
+ }`),
+ )
+ var port int
+ port, s.consulAddr = freeport()
+ consul := icmd.Command("consul", "agent",
+ "-dev",
+ "-config-file="+s.tmpDir.Join("consul.json"),
+ "-log-level=err",
+ "-http-port="+strconv.Itoa(port),
+ "-pid-file="+s.pidDir.Join("consul.pid"),
+ )
+ s.consulResult = icmd.StartCmd(consul)
+
+ c.Logf("Fired up Consul: %v", consul)
+
+ err := waitForURL(c, "http://"+s.consulAddr+"/v1/status/leader")
+ handle(c, err)
+
+ s.startVault(c)
+}
+
+func (s *ConsulDatasourcesSuite) startVault(c *C) {
+ // rename any existing token so it doesn't get overridden
+ u, _ := user.Current()
+ homeDir := u.HomeDir
+ tokenFile := path.Join(homeDir, ".vault-token")
+ info, err := os.Stat(tokenFile)
+ if err == nil && info.Mode().IsRegular() {
+ os.Rename(tokenFile, path.Join(homeDir, ".vault-token.bak"))
+ }
+
+ _, s.vaultAddr = freeport()
+ vault := icmd.Command("vault", "server",
+ "-dev",
+ "-dev-root-token-id="+vaultRootToken,
+ "-log-level=err",
+ "-dev-listen-address="+s.vaultAddr,
+ "-config="+s.tmpDir.Join("vault.json"),
+ )
+ s.vaultResult = icmd.StartCmd(vault)
+
+ c.Logf("Fired up Vault: %v", vault)
+
+ err = waitForURL(c, "http://"+s.vaultAddr+"/v1/sys/health")
+ handle(c, err)
+}
+
+func killByPidFile(pidFile string) error {
+ p, err := ioutil.ReadFile(pidFile)
+ if err != nil {
+ return err
+ }
+ pid, err := strconv.Atoi(string(p))
+ if err != nil {
+ return err
+ }
+ process, err := os.FindProcess(pid)
+ if err != nil {
+ return err
+ }
+ err = process.Kill()
+ return err
+}
+
+func (s *ConsulDatasourcesSuite) TearDownSuite(c *C) {
+ defer s.tmpDir.Remove()
+ defer s.pidDir.Remove()
+
+ err := killByPidFile(s.pidDir.Join("vault.pid"))
+ handle(c, err)
+
+ err = killByPidFile(s.pidDir.Join("consul.pid"))
+ handle(c, err)
+
+ // restore old vault token if it was backed up
+ u, _ := user.Current()
+ homeDir := u.HomeDir
+ tokenFile := path.Join(homeDir, ".vault-token.bak")
+ info, err := os.Stat(tokenFile)
+ if err == nil && info.Mode().IsRegular() {
+ os.Rename(tokenFile, path.Join(homeDir, ".vault-token"))
+ }
+}
+
+func (s *ConsulDatasourcesSuite) consulPut(c *C, k string, v string) {
+ result := icmd.RunCmd(icmd.Command("consul", "kv", "put", k, v),
+ func(c *icmd.Cmd) {
+ c.Env = []string{"CONSUL_HTTP_ADDR=http://" + s.consulAddr}
+ })
+ result.Assert(c, icmd.Success)
+}
+
+func (s *ConsulDatasourcesSuite) consulDelete(c *C, k string) {
+ result := icmd.RunCmd(icmd.Command("consul", "kv", "delete", k),
+ func(c *icmd.Cmd) {
+ c.Env = []string{"CONSUL_HTTP_ADDR=http://" + s.consulAddr}
+ })
+ result.Assert(c, icmd.Success)
+}
+
+func (s *ConsulDatasourcesSuite) TestConsulDatasource(c *C) {
+ s.consulPut(c, "foo", "bar")
+ defer s.consulDelete(c, "foo")
+ result := icmd.RunCmd(icmd.Command(GomplateBin,
+ "-d", "consul=consul://",
+ "-i", `{{(ds "consul" "foo")}}`,
+ ), func(c *icmd.Cmd) {
+ c.Env = []string{"CONSUL_HTTP_ADDR=http://" + s.consulAddr}
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
+
+ s.consulPut(c, "foo", `{"bar": "baz"}`)
+ result = icmd.RunCmd(icmd.Command(GomplateBin,
+ "-d", "consul=consul://?type=application/json",
+ "-i", `{{(ds "consul" "foo").bar}}`,
+ ), func(c *icmd.Cmd) {
+ c.Env = []string{"CONSUL_HTTP_ADDR=http://" + s.consulAddr}
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "baz"})
+
+ s.consulPut(c, "foo", `bar`)
+ result = icmd.RunCmd(icmd.Command(GomplateBin,
+ "-d", "consul=consul://"+s.consulAddr,
+ "-i", `{{(ds "consul" "foo")}}`,
+ ))
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
+
+ s.consulPut(c, "foo", `bar`)
+ result = icmd.RunCmd(icmd.Command(GomplateBin,
+ "-d", "consul=consul+http://"+s.consulAddr,
+ "-i", `{{(ds "consul" "foo")}}`,
+ ))
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
+}
+
+func (s *ConsulDatasourcesSuite) TestConsulWithVaultAuth(c *C) {
+ v, err := createVaultClient(s.vaultAddr, vaultRootToken)
+ handle(c, err)
+
+ err = v.vc.Sys().Mount("consul/", &vaultapi.MountInput{Type: "consul"})
+ handle(c, err)
+ defer v.vc.Sys().Unmount("consul/")
+
+ _, err = v.vc.Logical().Write("consul/config/access", map[string]interface{}{
+ "address": s.consulAddr, "token": consulRootToken,
+ })
+ handle(c, err)
+ policy := base64.StdEncoding.EncodeToString([]byte(`key "" { policy = "read" }`))
+ _, err = v.vc.Logical().Write("consul/roles/readonly", map[string]interface{}{"policy": policy})
+ handle(c, err)
+
+ s.consulPut(c, "foo", "bar")
+ defer s.consulDelete(c, "foo")
+ result := icmd.RunCmd(icmd.Command(GomplateBin,
+ "-d", "consul=consul://",
+ "-i", `{{(ds "consul" "foo")}}`,
+ ), func(c *icmd.Cmd) {
+ c.Env = []string{
+ "VAULT_TOKEN=" + vaultRootToken,
+ "VAULT_ADDR=http://" + s.vaultAddr,
+ "CONSUL_VAULT_ROLE=readonly",
+ "CONSUL_HTTP_ADDR=http://" + s.consulAddr,
+ }
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
+}
diff --git a/test/integration/datasources_file.bats b/test/integration/datasources_file.bats
deleted file mode 100644
index cfabcb65..00000000
--- a/test/integration/datasources_file.bats
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/env bats
-
-load helper
-
-tmpdir=$(mktemp -u)
-
-function setup () {
- mkdir -p $tmpdir
-}
-
-function teardown () {
- rm -rf $tmpdir || true
-}
-
-@test "supports json datasource file" {
- echo '{"foo": {"bar": "baz"}}' > $tmpdir/config.json
- gomplate -d config=$tmpdir/config.json -i '{{(datasource "config").foo.bar}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "baz" ]]
-}
-
-@test "supports YAML datasource file" {
- echo -e 'foo:\n bar: baz' > $tmpdir/config.yml
- gomplate -d config=$tmpdir/config.yml -i '{{(datasource "config").foo.bar}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "baz" ]]
-}
-
-@test "ds alias" {
- echo 'foo: bar' > $tmpdir/config.yml
- gomplate -d config=$tmpdir/config.yml -i '{{(ds "config").foo}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "bar" ]]
-}
-
-@test "supports CSV datasource file" {
- echo -e 'A,B\nA1,B1\nA2,"foo""\nbar"\n' > $tmpdir/foo.csv
- gomplate -d csv=$tmpdir/foo.csv -i '{{ index (index (ds "csv") 2) 1 }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "foo\"
-bar" ]]
-}
-
-@test "'include' doesn't parse file" {
- echo 'foo: bar' > $tmpdir/config.yml
- gomplate -d config=$tmpdir/config.yml -i '{{include "config"}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "foo: bar" ]]
-}
diff --git a/test/integration/datasources_file_test.go b/test/integration/datasources_file_test.go
new file mode 100644
index 00000000..1c8d1530
--- /dev/null
+++ b/test/integration/datasources_file_test.go
@@ -0,0 +1,67 @@
+//+build integration
+//+build !windows
+
+package integration
+
+import (
+ . "gopkg.in/check.v1"
+
+ "github.com/gotestyourself/gotestyourself/fs"
+ "github.com/gotestyourself/gotestyourself/icmd"
+)
+
+type FileDatasourcesSuite struct {
+ tmpDir *fs.Dir
+}
+
+var _ = Suite(&FileDatasourcesSuite{})
+
+func (s *FileDatasourcesSuite) SetUpSuite(c *C) {
+ s.tmpDir = fs.NewDir(c, "gomplate-inttests",
+ fs.WithFile("config.json", `{"foo": {"bar": "baz"}}`),
+ fs.WithFile("config.yml", "foo:\n bar: baz\n"),
+ fs.WithFile("config2.yml", "foo: bar\n"),
+ fs.WithFile("foo.csv", `A,B
+A1,B1
+A2,"foo""
+bar"
+`),
+ )
+}
+
+func (s *FileDatasourcesSuite) TearDownSuite(c *C) {
+ s.tmpDir.Remove()
+}
+
+func (s *FileDatasourcesSuite) TestFileDatasources(c *C) {
+ result := icmd.RunCommand(GomplateBin,
+ "-d", "config="+s.tmpDir.Join("config.json"),
+ "-i", `{{(datasource "config").foo.bar}}`,
+ )
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "baz"})
+
+ result = icmd.RunCommand(GomplateBin,
+ "-d", "config="+s.tmpDir.Join("config.yml"),
+ "-i", `{{(datasource "config").foo.bar}}`,
+ )
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "baz"})
+
+ result = icmd.RunCommand(GomplateBin,
+ "-d", "config="+s.tmpDir.Join("config2.yml"),
+ "-i", `{{(ds "config").foo}}`,
+ )
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
+
+ result = icmd.RunCommand(GomplateBin,
+ "-d", "csv="+s.tmpDir.Join("foo.csv"),
+ "-i", `{{ index (index (ds "csv") 2) 1 }}`,
+ )
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: `foo"
+bar`})
+
+ result = icmd.RunCommand(GomplateBin,
+ "-d", "config="+s.tmpDir.Join("config2.yml"),
+ "-i", `{{ include "config" }}`,
+ )
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: `foo: bar`})
+}
diff --git a/test/integration/datasources_http.bats b/test/integration/datasources_http.bats
deleted file mode 100644
index 4a510e8c..00000000
--- a/test/integration/datasources_http.bats
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env bats
-
-load helper
-
-function setup() {
- start_mirror_svc
-}
-
-function teardown() {
- stop_mirror_svc
-}
-
-@test "HTTP datasource with headers" {
- gomplate \
- -d foo=http://127.0.0.1:8080/ \
- -H foo=Foo:bar \
- -i '{{ index (datasource "foo").headers.Foo 0 }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "bar" ]]
-}
diff --git a/test/integration/datasources_http_test.go b/test/integration/datasources_http_test.go
new file mode 100644
index 00000000..8e516790
--- /dev/null
+++ b/test/integration/datasources_http_test.go
@@ -0,0 +1,40 @@
+//+build integration
+//+build !windows
+
+package integration
+
+import (
+ "net"
+ "net/http"
+
+ . "gopkg.in/check.v1"
+
+ "github.com/gotestyourself/gotestyourself/icmd"
+)
+
+type DatasourcesHTTPSuite struct {
+ l *net.TCPListener
+}
+
+var _ = Suite(&DatasourcesHTTPSuite{})
+
+func (s *DatasourcesHTTPSuite) SetUpSuite(c *C) {
+ var err error
+ s.l, err = net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP("127.0.0.1")})
+ handle(c, err)
+
+ http.HandleFunc("/", mirrorHandler)
+ go http.Serve(s.l, nil)
+}
+
+func (s *DatasourcesHTTPSuite) TearDownSuite(c *C) {
+ s.l.Close()
+}
+
+func (s *DatasourcesHTTPSuite) TestReportsVersion(c *C) {
+ result := icmd.RunCommand(GomplateBin,
+ "-d", "foo=http://"+s.l.Addr().String()+"/",
+ "-H", "foo=Foo:bar",
+ "-i", "{{ index (ds `foo`).headers.Foo 0 }}")
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
+}
diff --git a/test/integration/datasources_vault.bats b/test/integration/datasources_vault.bats
deleted file mode 100644
index 18d338c1..00000000
--- a/test/integration/datasources_vault.bats
+++ /dev/null
@@ -1,202 +0,0 @@
-#!/usr/bin/env bats
-
-load helper
-
-function setup () {
- unset VAULT_TOKEN
- cat <<EOF | vault policy-write writepol - >& /dev/null
-path "*" {
- policy = "write"
-}
-EOF
- cat <<EOF | vault policy-write readpol - >& /dev/null
-path "*" {
- policy = "read"
-}
-EOF
- tmpdir=$(mktemp -d)
- cp ~/.vault-token ${tmpdir}/.vault-token.bak
- start_meta_svc
- start_aws_svc
-}
-
-function teardown () {
- mv ${tmpdir}/.vault-token.bak ~/.vault-token
- stop_meta_svc
- stop_aws_svc
- rm -rf $tmpdir
- unset VAULT_TOKEN
- vault delete secret/foo
- vault auth disable userpass
- vault auth disable userpass2
- vault auth disable approle
- vault auth disable approle2
- vault auth disable app-id
- vault auth disable app-id2
- vault auth disable aws
- vault policy delete writepol
- vault policy delete readpol
- vault secrets disable ssh
-}
-
-@test "Testing token vault auth" {
- vault write secret/foo value="$BATS_TEST_DESCRIPTION"
- VAULT_TOKEN=$(vault token create -format=json -policy=readpol -use-limit=1 -ttl=1m | jq -j .auth.client_token)
- VAULT_TOKEN=$VAULT_TOKEN gomplate -d vault=vault:///secret -i '{{(datasource "vault" "foo").value}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "$BATS_TEST_DESCRIPTION" ]]
-}
-
-@test "Testing token vault auth with addr in URL" {
- vault write secret/foo value="$BATS_TEST_DESCRIPTION"
- VAULT_TOKEN=$(vault token create -format=json -policy=readpol -use-limit=1 -ttl=1m | jq -j .auth.client_token)
- addr=$VAULT_ADDR
- unset VAULT_ADDR
- VAULT_TOKEN=$VAULT_TOKEN gomplate -d vault=vault+${addr}/secret -i '{{(datasource "vault" "foo").value}}'
- export VAULT_ADDR=$addr
- [ "$status" -eq 0 ]
- [[ "${output}" == "$BATS_TEST_DESCRIPTION" ]]
-}
-
-@test "Testing failure with non-existant secret" {
- VAULT_TOKEN=$(vault token create -format=json -policy=readpol -use-limit=1 -ttl=1m | jq -j .auth.client_token)
- VAULT_TOKEN=$VAULT_TOKEN gomplate -d vault=vault:///secret -i '{{(datasource "vault" "bar").value}}'
- [ "$status" -eq 1 ]
- [[ "${output}" == *"No value found for [bar] from datasource 'vault'" ]]
-}
-
-@test "Testing token vault auth using file" {
- vault write secret/foo value="$BATS_TEST_DESCRIPTION"
- vault token create -format=json -policy=readpol -use-limit=1 -ttl=1m | jq -j .auth.client_token > $tmpdir/token
- unset VAULT_TOKEN
- VAULT_TOKEN_FILE=$tmpdir/token gomplate -d vault=vault:///secret -i '{{(datasource "vault" "foo").value}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "$BATS_TEST_DESCRIPTION" ]]
-}
-
-@test "Testing userpass vault auth" {
- vault write secret/foo value="$BATS_TEST_DESCRIPTION"
- vault auth enable userpass
- vault write auth/userpass/users/dave password=foo ttl=30s policies=readpol
- VAULT_AUTH_USERNAME=dave VAULT_AUTH_PASSWORD=foo gomplate -d vault=vault:///secret -i '{{(datasource "vault" "foo").value}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "$BATS_TEST_DESCRIPTION" ]]
-}
-
-@test "Testing userpass vault auth using files" {
- vault write secret/foo value="$BATS_TEST_DESCRIPTION"
- vault auth enable userpass
- vault write auth/userpass/users/dave password=foo ttl=30s policies=readpol
- echo -n "dave" > $tmpdir/username
- echo -n "foo" > $tmpdir/password
- VAULT_AUTH_USERNAME_FILE=$tmpdir/username VAULT_AUTH_PASSWORD_FILE=$tmpdir/password gomplate -d vault=vault:///secret -i '{{(datasource "vault" "foo").value}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "$BATS_TEST_DESCRIPTION" ]]
-}
-
-@test "Testing userpass vault auth with custom mount" {
- vault write secret/foo value="$BATS_TEST_DESCRIPTION"
- vault auth enable -path=userpass2 userpass
- vault write auth/userpass2/users/dave password=foo ttl=30s policies=readpol
- VAULT_AUTH_USERPASS_MOUNT=userpass2 VAULT_AUTH_USERNAME=dave VAULT_AUTH_PASSWORD=foo gomplate -d vault=vault:///secret -i '{{(datasource "vault" "foo").value}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "$BATS_TEST_DESCRIPTION" ]]
-}
-
-@test "Testing approle vault auth" {
- vault write secret/foo value="$BATS_TEST_DESCRIPTION"
- vault auth enable approle
- vault write auth/approle/role/testrole secret_id_ttl=30s token_ttl=35s token_max_ttl=3m secret_id_num_uses=1 policies=readpol
- VAULT_ROLE_ID=$(vault read -field role_id auth/approle/role/testrole/role-id)
- VAULT_SECRET_ID=$(vault write -f -field=secret_id auth/approle/role/testrole/secret-id)
- VAULT_ROLE_ID=$VAULT_ROLE_ID VAULT_SECRET_ID=$VAULT_SECRET_ID gomplate -d vault=vault:///secret -i '{{(datasource "vault" "foo").value}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "$BATS_TEST_DESCRIPTION" ]]
-}
-
-@test "Testing approle vault auth with custom mount" {
- vault write secret/foo value="$BATS_TEST_DESCRIPTION"
- vault auth enable -path=approle2 approle
- vault write auth/approle2/role/testrole secret_id_ttl=30s token_ttl=35s token_max_ttl=3m secret_id_num_uses=1 policies=readpol
- VAULT_ROLE_ID=$(vault read -field role_id auth/approle2/role/testrole/role-id)
- VAULT_SECRET_ID=$(vault write -f -field=secret_id auth/approle2/role/testrole/secret-id)
- VAULT_AUTH_APPROLE_MOUNT=approle2 VAULT_ROLE_ID=$VAULT_ROLE_ID VAULT_SECRET_ID=$VAULT_SECRET_ID gomplate -d vault=vault:///secret -i '{{(datasource "vault" "foo").value}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "$BATS_TEST_DESCRIPTION" ]]
-}
-
-@test "Testing app-id vault auth" {
- vault write secret/foo value="$BATS_TEST_DESCRIPTION"
- vault auth enable app-id
- vault write auth/app-id/map/app-id/testappid value=readpol display_name=test_app_id
- vault write auth/app-id/map/user-id/testuserid value=testappid
- VAULT_APP_ID=testappid VAULT_USER_ID=testuserid gomplate -d vault=vault:///secret -i '{{(datasource "vault" "foo").value}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "$BATS_TEST_DESCRIPTION" ]]
-}
-
-@test "Testing app-id vault auth with custom mount" {
- vault write secret/foo value="$BATS_TEST_DESCRIPTION"
- vault auth enable -path=app-id2 app-id
-
- vault write auth/app-id2/map/app-id/testappid value=readpol display_name=test_app_id
- vault write auth/app-id2/map/user-id/testuserid value=testappid
-
- VAULT_APP_ID=testappid VAULT_USER_ID=testuserid VAULT_AUTH_APP_ID_MOUNT=app-id2 gomplate -d vault=vault:///secret -i '{{(datasource "vault" "foo").value}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "$BATS_TEST_DESCRIPTION" ]]
-}
-
-@test "Testing ec2 vault auth" {
- vault write secret/foo value="$BATS_TEST_DESCRIPTION"
- vault auth enable aws
- vault write auth/aws/config/client secret_key=secret access_key=access endpoint=http://127.0.0.1:8082/ec2 iam_endpoint=http://127.0.0.1:8082/iam sts_endpoint=http://127.0.0.1:8082/sts
- curl -o $tmpdir/certificate -s -f http://127.0.0.1:8081/certificate
- vault write auth/aws/config/certificate/testcert type=pkcs7 aws_public_cert=@$tmpdir/certificate
- vault write auth/aws/role/ami-00000000 auth_type=ec2 bound_ami_id=ami-00000000 policies=readpol
- unset VAULT_TOKEN
- rm ~/.vault-token
- AWS_META_ENDPOINT=http://127.0.0.1:8081 gomplate -d vault=vault:///secret -i '{{(datasource "vault" "foo").value}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "$BATS_TEST_DESCRIPTION" ]]
-}
-
-@test "Testing vault auth with dynamic secret" {
- vault mount ssh
- vault write ssh/roles/test key_type=otp default_user=user cidr_list=10.0.0.0/8
- VAULT_TOKEN=$(vault token create -format=json -policy=writepol -use-limit=2 -ttl=1m | jq -j .auth.client_token)
- VAULT_TOKEN=$VAULT_TOKEN gomplate -d vault=vault:/// -i '{{(datasource "vault" "ssh/creds/test?ip=10.1.2.3&username=user").ip}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "10.1.2.3" ]]
-}
-
-@test "Testing vault auth with dynamic secret using prefix" {
- vault mount ssh
- vault write ssh/roles/test key_type=otp default_user=user cidr_list=10.0.0.0/8
- VAULT_TOKEN=$(vault token create -format=json -policy=writepol -use-limit=2 -ttl=1m | jq -j .auth.client_token)
- VAULT_TOKEN=$VAULT_TOKEN gomplate -d vault=vault:///ssh/creds/test -i '{{(datasource "vault" "?ip=10.1.2.3&username=user").ip}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "10.1.2.3" ]]
-}
-
-@test "Testing vault auth with dynamic secret using prefix and options in URL" {
- vault mount ssh
- vault write ssh/roles/test key_type=otp default_user=user cidr_list=10.0.0.0/8
- VAULT_TOKEN=$(vault token create -format=json -policy=writepol -use-limit=2 -ttl=1m | jq -j .auth.client_token)
- VAULT_TOKEN=$VAULT_TOKEN gomplate -d vault=vault:///ssh/creds/test?ip=10.1.2.3\&username=user -i '{{(datasource "vault").ip}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "10.1.2.3" ]]
-}
-
-@test "Testing vault auth with dynamic secret using options in URL and path in template" {
- vault mount ssh
- vault write ssh/roles/test key_type=otp default_user=user cidr_list=10.0.0.0/8
- VAULT_TOKEN=$(vault token create -format=json -policy=writepol -use-limit=2 -ttl=1m | jq -j .auth.client_token)
- VAULT_TOKEN=$VAULT_TOKEN gomplate -d vault=vault:///?ip=10.1.2.3\&username=user -i '{{(datasource "vault" "ssh/creds/test").ip}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "10.1.2.3" ]]
-}
-
-# TODO: test the github auth backend at some point... this needs a github token though, so...
-# vault write auth/github/config organization=DockerOttawaMeetup
-# vault write auth/github/map/teams/organizers value=pol
diff --git a/test/integration/datasources_vault_ec2_test.go b/test/integration/datasources_vault_ec2_test.go
new file mode 100644
index 00000000..eeeeae8b
--- /dev/null
+++ b/test/integration/datasources_vault_ec2_test.go
@@ -0,0 +1,155 @@
+//+build integration
+//+build !windows
+
+package integration
+
+import (
+ "encoding/pem"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "os"
+ "os/user"
+ "path"
+ "strconv"
+
+ . "gopkg.in/check.v1"
+
+ "github.com/gotestyourself/gotestyourself/fs"
+ "github.com/gotestyourself/gotestyourself/icmd"
+)
+
+type VaultEc2DatasourcesSuite struct {
+ tmpDir *fs.Dir
+ pidDir *fs.Dir
+ vaultAddr string
+ vaultResult *icmd.Result
+ v *vaultClient
+ l *net.TCPListener
+ cert []byte
+}
+
+var _ = Suite(&VaultEc2DatasourcesSuite{})
+
+func (s *VaultEc2DatasourcesSuite) SetUpSuite(c *C) {
+ var err error
+ s.l, err = net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP("127.0.0.1")})
+ handle(c, err)
+ priv, der, _ := certificateGenerate()
+ s.cert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der})
+ http.HandleFunc("/latest/dynamic/instance-identity/pkcs7", pkcsHandler(priv, der))
+ http.HandleFunc("/latest/dynamic/instance-identity/document", instanceDocumentHandler)
+ http.HandleFunc("/sts/", stsHandler)
+ http.HandleFunc("/ec2/", ec2Handler)
+ go http.Serve(s.l, nil)
+
+ s.startVault(c)
+
+ s.v, err = createVaultClient(s.vaultAddr, vaultRootToken)
+ handle(c, err)
+
+ err = s.v.vc.Sys().PutPolicy("writepol", `path "*" {
+ policy = "write"
+}`)
+ handle(c, err)
+ err = s.v.vc.Sys().PutPolicy("readpol", `path "*" {
+ policy = "read"
+}`)
+ handle(c, err)
+}
+
+func (s *VaultEc2DatasourcesSuite) startVault(c *C) {
+ s.pidDir = fs.NewDir(c, "gomplate-inttests-vaultpid")
+ s.tmpDir = fs.NewDir(c, "gomplate-inttests",
+ fs.WithFile("config.json", `{
+ "pid_file": "`+s.pidDir.Join("vault.pid")+`"
+ }`),
+ )
+
+ // rename any existing token so it doesn't get overridden
+ u, _ := user.Current()
+ homeDir := u.HomeDir
+ tokenFile := path.Join(homeDir, ".vault-token")
+ info, err := os.Stat(tokenFile)
+ if err == nil && info.Mode().IsRegular() {
+ os.Rename(tokenFile, path.Join(homeDir, ".vault-token.bak"))
+ }
+
+ _, s.vaultAddr = freeport()
+ vault := icmd.Command("vault", "server",
+ "-dev",
+ "-dev-root-token-id="+vaultRootToken,
+ "-log-level=trace",
+ "-dev-listen-address="+s.vaultAddr,
+ "-config="+s.tmpDir.Join("config.json"),
+ )
+ s.vaultResult = icmd.StartCmd(vault)
+
+ c.Logf("Fired up Vault: %v", vault)
+
+ err = waitForURL(c, "http://"+s.vaultAddr+"/v1/sys/health")
+ handle(c, err)
+}
+
+func (s *VaultEc2DatasourcesSuite) TearDownSuite(c *C) {
+ s.l.Close()
+
+ defer s.tmpDir.Remove()
+ defer s.pidDir.Remove()
+
+ p, err := ioutil.ReadFile(s.pidDir.Join("vault.pid"))
+ handle(c, err)
+ pid, err := strconv.Atoi(string(p))
+ handle(c, err)
+ process, err := os.FindProcess(pid)
+ handle(c, err)
+ err = process.Kill()
+ handle(c, err)
+
+ // restore old token if it was backed up
+ u, _ := user.Current()
+ homeDir := u.HomeDir
+ tokenFile := path.Join(homeDir, ".vault-token.bak")
+ info, err := os.Stat(tokenFile)
+ if err == nil && info.Mode().IsRegular() {
+ os.Rename(tokenFile, path.Join(homeDir, ".vault-token"))
+ }
+}
+
+func (s *VaultEc2DatasourcesSuite) TestEc2Auth(c *C) {
+ s.v.vc.Logical().Write("secret/foo", map[string]interface{}{"value": "bar"})
+ defer s.v.vc.Logical().Delete("secret/foo")
+ err := s.v.vc.Sys().EnableAuth("aws", "aws", "")
+ handle(c, err)
+ defer s.v.vc.Sys().DisableAuth("aws")
+ _, err = s.v.vc.Logical().Write("auth/aws/config/client", map[string]interface{}{
+ "secret_key": "secret", "access_key": "access",
+ "endpoint": "http://" + s.l.Addr().String() + "/ec2",
+ "iam_endpoint": "http://" + s.l.Addr().String() + "/iam",
+ "sts_endpoint": "http://" + s.l.Addr().String() + "/sts",
+ })
+ handle(c, err)
+
+ _, err = s.v.vc.Logical().Write("auth/aws/config/certificate/testcert", map[string]interface{}{
+ "type": "pkcs7", "aws_public_cert": string(s.cert),
+ })
+ handle(c, err)
+
+ _, err = s.v.vc.Logical().Write("auth/aws/role/ami-00000000", map[string]interface{}{
+ "auth_type": "ec2", "bound_ami_id": "ami-00000000",
+ "policies": "readpol",
+ })
+ handle(c, err)
+
+ result := icmd.RunCmd(icmd.Command(GomplateBin,
+ "-d", "vault=vault:///secret",
+ "-i", `{{(ds "vault" "foo").value}}`,
+ ), func(c *icmd.Cmd) {
+ c.Env = []string{
+ "HOME=" + s.tmpDir.Join("home"),
+ "VAULT_ADDR=http://" + s.v.addr,
+ "AWS_META_ENDPOINT=http://" + s.l.Addr().String(),
+ }
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
+}
diff --git a/test/integration/datasources_vault_test.go b/test/integration/datasources_vault_test.go
new file mode 100644
index 00000000..cfa6552a
--- /dev/null
+++ b/test/integration/datasources_vault_test.go
@@ -0,0 +1,358 @@
+//+build integration
+//+build !windows
+
+package integration
+
+import (
+ "io/ioutil"
+ "os"
+ "os/user"
+ "path"
+ "strconv"
+
+ . "gopkg.in/check.v1"
+
+ "github.com/gotestyourself/gotestyourself/fs"
+ "github.com/gotestyourself/gotestyourself/icmd"
+ vaultapi "github.com/hashicorp/vault/api"
+)
+
+type VaultDatasourcesSuite struct {
+ tmpDir *fs.Dir
+ pidDir *fs.Dir
+ vaultAddr string
+ vaultResult *icmd.Result
+ v *vaultClient
+}
+
+var _ = Suite(&VaultDatasourcesSuite{})
+
+const vaultRootToken = "00000000-1111-2222-3333-444455556666"
+
+func (s *VaultDatasourcesSuite) SetUpSuite(c *C) {
+ s.startVault(c)
+
+ var err error
+ s.v, err = createVaultClient(s.vaultAddr, vaultRootToken)
+ handle(c, err)
+
+ err = s.v.vc.Sys().PutPolicy("writepol", `path "*" {
+ policy = "write"
+}`)
+ handle(c, err)
+ err = s.v.vc.Sys().PutPolicy("readpol", `path "*" {
+ policy = "read"
+}`)
+ handle(c, err)
+}
+
+func (s *VaultDatasourcesSuite) startVault(c *C) {
+ s.pidDir = fs.NewDir(c, "gomplate-inttests-vaultpid")
+ s.tmpDir = fs.NewDir(c, "gomplate-inttests",
+ fs.WithFile("config.json", `{
+ "pid_file": "`+s.pidDir.Join("vault.pid")+`"
+ }`),
+ )
+
+ // rename any existing token so it doesn't get overridden
+ u, _ := user.Current()
+ homeDir := u.HomeDir
+ tokenFile := path.Join(homeDir, ".vault-token")
+ info, err := os.Stat(tokenFile)
+ if err == nil && info.Mode().IsRegular() {
+ os.Rename(tokenFile, path.Join(homeDir, ".vault-token.bak"))
+ }
+
+ _, s.vaultAddr = freeport()
+ vault := icmd.Command("vault", "server",
+ "-dev",
+ "-dev-root-token-id="+vaultRootToken,
+ "-log-level=err",
+ "-dev-listen-address="+s.vaultAddr,
+ "-config="+s.tmpDir.Join("config.json"),
+ )
+ s.vaultResult = icmd.StartCmd(vault)
+
+ c.Logf("Fired up Vault: %v", vault)
+
+ err = waitForURL(c, "http://"+s.vaultAddr+"/v1/sys/health")
+ handle(c, err)
+}
+
+func (s *VaultDatasourcesSuite) TearDownSuite(c *C) {
+ defer s.tmpDir.Remove()
+ defer s.pidDir.Remove()
+
+ p, err := ioutil.ReadFile(s.pidDir.Join("vault.pid"))
+ handle(c, err)
+ pid, err := strconv.Atoi(string(p))
+ handle(c, err)
+ process, err := os.FindProcess(pid)
+ handle(c, err)
+ err = process.Kill()
+ handle(c, err)
+
+ // restore old token if it was backed up
+ u, _ := user.Current()
+ homeDir := u.HomeDir
+ tokenFile := path.Join(homeDir, ".vault-token.bak")
+ info, err := os.Stat(tokenFile)
+ if err == nil && info.Mode().IsRegular() {
+ os.Rename(tokenFile, path.Join(homeDir, ".vault-token"))
+ }
+}
+
+func (s *VaultDatasourcesSuite) TestTokenAuth(c *C) {
+ s.v.vc.Logical().Write("secret/foo", map[string]interface{}{"value": "bar"})
+ defer s.v.vc.Logical().Delete("secret/foo")
+ tok, err := s.v.tokenCreate("readpol", 4)
+ handle(c, err)
+
+ result := icmd.RunCmd(icmd.Command(GomplateBin,
+ "-d", "vault=vault:///secret",
+ "-i", `{{(ds "vault" "foo").value}}`,
+ ), func(c *icmd.Cmd) {
+ c.Env = []string{
+ "VAULT_ADDR=http://" + s.v.addr,
+ "VAULT_TOKEN=" + tok,
+ }
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
+
+ result = icmd.RunCmd(icmd.Command(GomplateBin,
+ "-d", "vault=vault+http://"+s.v.addr+"/secret",
+ "-i", `{{(ds "vault" "foo").value}}`,
+ ), func(c *icmd.Cmd) {
+ c.Env = []string{
+ "VAULT_TOKEN=" + tok,
+ }
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
+
+ result = icmd.RunCmd(icmd.Command(GomplateBin,
+ "-d", "vault=vault:///secret",
+ "-i", `{{(ds "vault" "bar").value}}`,
+ ), func(c *icmd.Cmd) {
+ c.Env = []string{
+ "VAULT_ADDR=http://" + s.v.addr,
+ "VAULT_TOKEN=" + tok,
+ }
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 1, Err: "No value found for [bar] from datasource 'vault'"})
+
+ tokFile := fs.NewFile(c, "test-vault-token", fs.WithContent(tok))
+ defer tokFile.Remove()
+ result = icmd.RunCmd(icmd.Command(GomplateBin,
+ "-d", "vault=vault:///secret",
+ "-i", `{{(ds "vault" "foo").value}}`,
+ ), func(c *icmd.Cmd) {
+ c.Env = []string{
+ "VAULT_ADDR=http://" + s.v.addr,
+ "VAULT_TOKEN_FILE=" + tokFile.Path(),
+ }
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
+}
+
+func (s *VaultDatasourcesSuite) TestUserPassAuth(c *C) {
+ s.v.vc.Logical().Write("secret/foo", map[string]interface{}{"value": "bar"})
+ defer s.v.vc.Logical().Delete("secret/foo")
+ err := s.v.vc.Sys().EnableAuth("userpass", "userpass", "")
+ handle(c, err)
+ err = s.v.vc.Sys().EnableAuth("userpass2", "userpass", "")
+ handle(c, err)
+ defer s.v.vc.Sys().DisableAuth("userpass")
+ defer s.v.vc.Sys().DisableAuth("userpass2")
+ _, err = s.v.vc.Logical().Write("auth/userpass/users/dave", map[string]interface{}{
+ "password": "foo", "ttl": "10s", "policies": "readpol"})
+ handle(c, err)
+ _, err = s.v.vc.Logical().Write("auth/userpass2/users/dave", map[string]interface{}{
+ "password": "bar", "ttl": "10s", "policies": "readpol"})
+ handle(c, err)
+
+ result := icmd.RunCmd(icmd.Command(GomplateBin,
+ "-d", "vault=vault:///secret",
+ "-i", `{{(ds "vault" "foo").value}}`,
+ ), func(c *icmd.Cmd) {
+ c.Env = []string{
+ "VAULT_ADDR=http://" + s.v.addr,
+ "VAULT_AUTH_USERNAME=dave", "VAULT_AUTH_PASSWORD=foo",
+ }
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
+
+ userFile := fs.NewFile(c, "test-vault-user", fs.WithContent("dave"))
+ passFile := fs.NewFile(c, "test-vault-pass", fs.WithContent("foo"))
+ defer userFile.Remove()
+ defer passFile.Remove()
+ result = icmd.RunCmd(icmd.Command(GomplateBin,
+ "-d", "vault=vault:///secret",
+ "-i", `{{(ds "vault" "foo").value}}`,
+ ), func(c *icmd.Cmd) {
+ c.Env = []string{
+ "VAULT_ADDR=http://" + s.v.addr,
+ "VAULT_AUTH_USERNAME_FILE=" + userFile.Path(),
+ "VAULT_AUTH_PASSWORD_FILE=" + passFile.Path(),
+ }
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
+
+ result = icmd.RunCmd(icmd.Command(GomplateBin,
+ "-d", "vault=vault:///secret",
+ "-i", `{{(ds "vault" "foo").value}}`,
+ ), func(c *icmd.Cmd) {
+ c.Env = []string{
+ "VAULT_ADDR=http://" + s.v.addr,
+ "VAULT_AUTH_USERNAME=dave", "VAULT_AUTH_PASSWORD=bar",
+ "VAULT_AUTH_USERPASS_MOUNT=userpass2",
+ }
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
+}
+
+func (s *VaultDatasourcesSuite) TestAppRoleAuth(c *C) {
+ s.v.vc.Logical().Write("secret/foo", map[string]interface{}{"value": "bar"})
+ defer s.v.vc.Logical().Delete("secret/foo")
+ err := s.v.vc.Sys().EnableAuth("approle", "approle", "")
+ handle(c, err)
+ err = s.v.vc.Sys().EnableAuth("approle2", "approle", "")
+ handle(c, err)
+ defer s.v.vc.Sys().DisableAuth("approle")
+ defer s.v.vc.Sys().DisableAuth("approle2")
+ _, err = s.v.vc.Logical().Write("auth/approle/role/testrole", map[string]interface{}{
+ "secret_id_ttl": "10s", "token_ttl": "20s",
+ "secret_id_num_uses": "1", "policies": "readpol",
+ })
+ handle(c, err)
+ _, err = s.v.vc.Logical().Write("auth/approle2/role/testrole", map[string]interface{}{
+ "secret_id_ttl": "10s", "token_ttl": "20s",
+ "secret_id_num_uses": "1", "policies": "readpol",
+ })
+ handle(c, err)
+
+ rid, _ := s.v.vc.Logical().Read("auth/approle/role/testrole/role-id")
+ roleID := rid.Data["role_id"].(string)
+ sid, _ := s.v.vc.Logical().Write("auth/approle/role/testrole/secret-id", nil)
+ secretID := sid.Data["secret_id"].(string)
+ result := icmd.RunCmd(icmd.Command(GomplateBin,
+ "-d", "vault=vault:///secret",
+ "-i", `{{(ds "vault" "foo").value}}`,
+ ), func(c *icmd.Cmd) {
+ c.Env = []string{
+ "VAULT_ADDR=http://" + s.v.addr,
+ "VAULT_ROLE_ID=" + roleID,
+ "VAULT_SECRET_ID=" + secretID,
+ }
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
+
+ rid, _ = s.v.vc.Logical().Read("auth/approle2/role/testrole/role-id")
+ roleID = rid.Data["role_id"].(string)
+ sid, _ = s.v.vc.Logical().Write("auth/approle2/role/testrole/secret-id", nil)
+ secretID = sid.Data["secret_id"].(string)
+ result = icmd.RunCmd(icmd.Command(GomplateBin,
+ "-d", "vault=vault:///secret",
+ "-i", `{{(ds "vault" "foo").value}}`,
+ ), func(c *icmd.Cmd) {
+ c.Env = []string{
+ "VAULT_ADDR=http://" + s.v.addr,
+ "VAULT_ROLE_ID=" + roleID,
+ "VAULT_SECRET_ID=" + secretID,
+ "VAULT_AUTH_APPROLE_MOUNT=approle2",
+ }
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
+}
+
+func (s *VaultDatasourcesSuite) TestAppIDAuth(c *C) {
+ s.v.vc.Logical().Write("secret/foo", map[string]interface{}{"value": "bar"})
+ defer s.v.vc.Logical().Delete("secret/foo")
+ err := s.v.vc.Sys().EnableAuth("app-id", "app-id", "")
+ handle(c, err)
+ err = s.v.vc.Sys().EnableAuth("app-id2", "app-id", "")
+ handle(c, err)
+ defer s.v.vc.Sys().DisableAuth("app-id")
+ defer s.v.vc.Sys().DisableAuth("app-id2")
+ _, err = s.v.vc.Logical().Write("auth/app-id/map/app-id/testappid", map[string]interface{}{
+ "display_name": "test_app_id", "value": "readpol",
+ })
+ handle(c, err)
+ _, err = s.v.vc.Logical().Write("auth/app-id/map/user-id/testuserid", map[string]interface{}{
+ "value": "testappid",
+ })
+ handle(c, err)
+ _, err = s.v.vc.Logical().Write("auth/app-id2/map/app-id/testappid", map[string]interface{}{
+ "display_name": "test_app_id", "value": "readpol",
+ })
+ handle(c, err)
+ _, err = s.v.vc.Logical().Write("auth/app-id2/map/user-id/testuserid", map[string]interface{}{
+ "value": "testappid",
+ })
+ handle(c, err)
+
+ result := icmd.RunCmd(icmd.Command(GomplateBin,
+ "-d", "vault=vault:///secret",
+ "-i", `{{(ds "vault" "foo").value}}`,
+ ), func(c *icmd.Cmd) {
+ c.Env = []string{
+ "VAULT_ADDR=http://" + s.v.addr,
+ "VAULT_APP_ID=testappid",
+ "VAULT_USER_ID=testuserid",
+ }
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
+
+ result = icmd.RunCmd(icmd.Command(GomplateBin,
+ "-d", "vault=vault:///secret",
+ "-i", `{{(ds "vault" "foo").value}}`,
+ ), func(c *icmd.Cmd) {
+ c.Env = []string{
+ "VAULT_ADDR=http://" + s.v.addr,
+ "VAULT_APP_ID=testappid",
+ "VAULT_USER_ID=testuserid",
+ "VAULT_AUTH_APP_ID_MOUNT=app-id2",
+ }
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
+}
+
+func (s *VaultDatasourcesSuite) TestDynamicAuth(c *C) {
+ err := s.v.vc.Sys().Mount("ssh/", &vaultapi.MountInput{Type: "ssh"})
+ handle(c, err)
+ defer s.v.vc.Sys().Unmount("ssh")
+
+ _, err = s.v.vc.Logical().Write("ssh/roles/test", map[string]interface{}{
+ "key_type": "otp", "default_user": "user", "cidr_list": "10.0.0.0/8",
+ })
+ handle(c, err)
+ testCommands := []icmd.Cmd{
+ icmd.Command(GomplateBin,
+ "-d", "vault=vault:///",
+ "-i", `{{(ds "vault" "ssh/creds/test?ip=10.1.2.3&username=user").ip}}`,
+ ),
+ icmd.Command(GomplateBin,
+ "-d", "vault=vault:///ssh/creds/test",
+ "-i", `{{(ds "vault" "?ip=10.1.2.3&username=user").ip}}`,
+ ),
+ icmd.Command(GomplateBin,
+ "-d", "vault=vault:///ssh/creds/test?ip=10.1.2.3&username=user",
+ "-i", `{{(ds "vault").ip}}`,
+ ),
+ icmd.Command(GomplateBin,
+ "-d", "vault=vault:///?ip=10.1.2.3&username=user",
+ "-i", `{{(ds "vault" "ssh/creds/test").ip}}`,
+ ),
+ }
+ tok, err := s.v.tokenCreate("writepol", len(testCommands)*2)
+ handle(c, err)
+
+ for _, v := range testCommands {
+ result := icmd.RunCmd(v, func(c *icmd.Cmd) {
+ c.Env = []string{
+ "VAULT_ADDR=http://" + s.v.addr,
+ "VAULT_TOKEN=" + tok,
+ }
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "10.1.2.3"})
+ }
+}
diff --git a/test/integration/envvars.bats b/test/integration/envvars.bats
deleted file mode 100644
index aef1d3a8..00000000
--- a/test/integration/envvars.bats
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env bats
-
-load helper
-
-# function setup () {
-# }
-
-# function teardown () {
-# # rm -rf $tmpdir
-# }
-
-@test "errors with non-existant env var using .Env" {
- gomplate -i '{{.Env.FOO}}'
- [ "$status" -eq 1 ]
- [[ "${lines[0]}" == *"map has no entry for key"* ]]
-}
-
-@test "empty string with non-existant env var using getenv" {
- gomplate -i '{{getenv "FOO" }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "" ]]
-}
-
-@test "default string with non-existant env var using getenv" {
- gomplate -i '{{getenv "FOO" "foo"}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "foo" ]]
-}
-
-@test "default string with empty env var using getenv" {
- FOO="" gomplate -i '{{getenv "FOO" "foo"}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "foo" ]]
-}
-
-@test "existant env var using .Env" {
- gomplate -i '{{.Env.HOME}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "${HOME}" ]]
-}
-
-@test "existant env var using getenv" {
- gomplate -i '{{getenv "HOME"}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "${HOME}" ]]
-}
-
-@test "existant env var using env.Getenv" {
- gomplate -i '{{env.Getenv "HOME"}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "${HOME}" ]]
-}
diff --git a/test/integration/envvars_test.go b/test/integration/envvars_test.go
new file mode 100644
index 00000000..aa8ccc41
--- /dev/null
+++ b/test/integration/envvars_test.go
@@ -0,0 +1,52 @@
+//+build integration
+//+build !windows
+
+package integration
+
+import (
+ . "gopkg.in/check.v1"
+
+ "github.com/gotestyourself/gotestyourself/icmd"
+)
+
+type EnvvarsSuite struct{}
+
+var _ = Suite(&EnvvarsSuite{})
+
+func (s *EnvvarsSuite) TestNonExistantEnvVar(c *C) {
+ result := icmd.RunCommand(GomplateBin, "-i",
+ `{{ .Env.FOO }}`)
+ result.Assert(c, icmd.Expected{ExitCode: 1, Err: "map has no entry for key"})
+
+ result = icmd.RunCommand(GomplateBin, "-i",
+ `{{ getenv "FOO" }}`)
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: ""})
+
+ result = icmd.RunCommand(GomplateBin, "-i",
+ `{{ getenv "FOO" "foo" }}`)
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "foo"})
+
+ result = icmd.RunCmd(icmd.Command(GomplateBin, "-i", `{{ getenv "FOO" "foo" }}`),
+ func(c *icmd.Cmd) {
+ c.Env = []string{"FOO="}
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "foo"})
+}
+
+func (s *EnvvarsSuite) TestExistantEnvVar(c *C) {
+ setFoo := func(c *icmd.Cmd) {
+ c.Env = []string{"FOO=foo"}
+ }
+ expected := icmd.Expected{ExitCode: 0, Out: "foo"}
+ result := icmd.RunCmd(icmd.Command(GomplateBin, "-i",
+ `{{ .Env.FOO }}`), setFoo)
+ result.Assert(c, expected)
+
+ result = icmd.RunCmd(icmd.Command(GomplateBin, "-i",
+ `{{ getenv "FOO" }}`), setFoo)
+ result.Assert(c, expected)
+
+ result = icmd.RunCmd(icmd.Command(GomplateBin, "-i",
+ `{{ env.Getenv "FOO" }}`), setFoo)
+ result.Assert(c, expected)
+}
diff --git a/test/integration/helper.bash b/test/integration/helper.bash
deleted file mode 100644
index 5ae28e16..00000000
--- a/test/integration/helper.bash
+++ /dev/null
@@ -1,107 +0,0 @@
-#!/bin/bash
-
-helper_dir=${BASH_SOURCE%/*}
-
-function gomplate () {
- run bin/gomplate "$@"
-
- # Some debug information to make life easier. bats will only print it if the
- # test failed, in which case the output is useful.
- echo "gomplate $@ (status=$status):" >&2
- echo "$output" >&2
-}
-
-function gomplate_stdin () {
- run __gomplate_stdin "$@"
-
- # Some debug information to make life easier. bats will only print it if the
- # test failed, in which case the output is useful.
- in=$1
- shift
- echo "echo \"$in\" | gomplate $@ (status=$status):" >&2
- echo "$output" >&2
-}
-
-function __gomplate_stdin () {
- in=$1
- shift 1
- echo "$in" | bin/gomplate "$@"
-}
-
-function start_mirror_svc () {
- ${helper_dir}/mirror &
- wait_for_url http://127.0.0.1:8080/
-}
-
-function stop_mirror_svc () {
- wget -q -O - http://127.0.0.1:8080/quit
-}
-
-function start_meta_svc () {
- ${helper_dir}/meta &> /tmp/meta.log &
- wait_for_url http://127.0.0.1:8081/
-}
-
-function stop_meta_svc () {
- wget -q -O - http://127.0.0.1:8081/quit
-}
-
-function start_aws_svc () {
- ${helper_dir}/aws &
- wait_for_url http://127.0.0.1:8082/
-}
-
-function stop_aws_svc () {
- wget -q -O - http://127.0.0.1:8082/quit
-}
-
-function wait_for_url () {
- url=$1
- for i in {0..10}; do
- curl -o /dev/null -s -f $url && break || sleep 1
- done
-}
-
-function start_consul () {
- port=$1
- if [ -z $port ]; then
- port=8500
- fi
- PID_FILE=/tmp/gomplate-test-consul.pid
- rm -f $PID_FILE || true
- export CONSUL_ROOT_TOKEN=00000000-1111-2222-3333-444455556666
- echo "{\"acl_datacenter\": \"dc1\", \"acl_master_token\": \"${CONSUL_ROOT_TOKEN}\"}" >> /tmp/gomplate-test-consul.json
- consul agent -dev -config-file=/tmp/gomplate-test-consul.json -log-level=err -http-port=$port -pid-file=$PID_FILE >/dev/null &
- wait_for_url http://127.0.0.1:$port/v1/status/leader
-}
-
-function stop_consul () {
- PID_FILE=/tmp/gomplate-test-consul.pid
- kill $(cat $PID_FILE) &>/dev/null
- rm /tmp/gomplate-test-consul.json
-}
-
-function start_vault () {
- port=$1
- PID_FILE=/tmp/gomplate-test-vault.pid
- export VAULT_ROOT_TOKEN=00000000-1111-2222-3333-444455556666
-
- # back up any existing token so it doesn't get overridden
- if [ -f ~/.vault-token ]; then
- cp ~/.vault-token ~/.vault-token.bak
- fi
-
- vault server -dev -dev-root-token-id=${VAULT_ROOT_TOKEN} -log-level=err >&/dev/null &
- echo $! > $PID_FILE
- wait_for_url http://127.0.0.1:$port/sys/health
-}
-
-function stop_vault () {
- PID_FILE=/tmp/gomplate-test-vault.pid
- kill $(cat $PID_FILE) &>/dev/null
-
- # restore old token if it was backed up
- if [ -f ~/.vault-token.bak ]; then
- mv ~/.vault-token.bak ~/.vault-token
- fi
-}
diff --git a/test/integration/input-dir.bats b/test/integration/input-dir.bats
deleted file mode 100644
index fb222d26..00000000
--- a/test/integration/input-dir.bats
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/usr/bin/env bats
-
-load helper
-
-tmpdir=$(mktemp -u)
-
-function setup () {
- mkdir -p $tmpdir
- mkdir -p $tmpdir/in/inner
- echo -n "{{ (datasource \"config\").one }}" > $tmpdir/in/eins.txt
- echo -n "{{ (datasource \"config\").two }}" > $tmpdir/in/inner/deux.txt
-
- cat <<"EOT" > $tmpdir/config.yml
-one: eins
-two: deux
-EOT
-}
-
-function teardown () {
- # rm -rf $tmpdir
- echo
-}
-
-@test "takes --input-dir and produces proper output files" {
- rm -rf $tmpdir/out || true
- gomplate --input-dir $tmpdir/in --output-dir $tmpdir/out -d config=$tmpdir/config.yml
- [ "$status" -eq 0 ]
- [[ "$(ls $tmpdir/out | wc -l)" == 2 ]]
- [[ "$(ls $tmpdir/out/inner | wc -l)" == 1 ]]
- [[ "$(cat $tmpdir/out/eins.txt)" == "eins" ]]
- [[ "$(cat $tmpdir/out/inner/deux.txt)" == "deux" ]]
-}
-
-@test "test . as default --output-dir param" {
- rm -rf $tmpdir/out_dot || true
- mkdir -p $tmpdir/out_dot
- g=$(pwd)/bin/gomplate
- cd $tmpdir/out_dot
- run $g --input-dir $tmpdir/in -d config=$tmpdir/config.yml
- [ "$?" -eq 0 ]
- [[ "$(ls | wc -l)" == 2 ]]
- [[ "$(ls inner | wc -l)" == 1 ]]
- [[ "$(cat eins.txt)" == "eins" ]]
- [[ "$(cat inner/deux.txt)" == "deux" ]]
-}
-
-@test "errors given --output-dir but no --input-dir" {
- gomplate --output-dir "."
- [ "$status" -eq 1 ]
- [[ "${output}" == "Error: --input-dir must be set when --output-dir is set"* ]]
-}
-
-@test "errors given both --input-dir and --in" {
- gomplate --input-dir "." --in "param"
- [ "$status" -eq 1 ]
- [[ "${output}" == "Error: --input-dir can not be used together with --in or --file"* ]]
-}
-
-@test "errors given both --input-dir and --file" {
- gomplate --input-dir "." --file input.txt
- [ "$status" -eq 1 ]
- [[ "${output}" == "Error: --input-dir can not be used together with --in or --file"* ]]
-}
-
-@test "errors given both --output-dir and --out" {
- gomplate --input-dir "." --output-dir /tmp --out out
- [ "$status" -eq 1 ]
- [[ "${output}" == "Error: --output-dir can not be used together with --out"* ]]
-}
-
-@test "errors with filename when using input dir and bad input file" {
- rm -rf $tmpdir/out || true
- echo -n "{{end}}" > $tmpdir/in/bad.tmpl
- gomplate --input-dir $tmpdir/in --output-dir $tmpdir/out -d config=$tmpdir/config.yml
- [ "$status" -eq 1 ]
- [[ "${output}" == "Error: template: $tmpdir/in/bad.tmpl:1: unexpected {{end}}"* ]]
-} \ No newline at end of file
diff --git a/test/integration/inputdir_test.go b/test/integration/inputdir_test.go
new file mode 100644
index 00000000..6c0bbf88
--- /dev/null
+++ b/test/integration/inputdir_test.go
@@ -0,0 +1,104 @@
+//+build integration
+//+build !windows
+
+package integration
+
+import (
+ "io/ioutil"
+
+ . "gopkg.in/check.v1"
+
+ "github.com/gotestyourself/gotestyourself/assert"
+ "github.com/gotestyourself/gotestyourself/fs"
+ "github.com/gotestyourself/gotestyourself/icmd"
+ tassert "github.com/stretchr/testify/assert"
+)
+
+type InputDirSuite struct {
+ tmpDir *fs.Dir
+}
+
+var _ = Suite(&InputDirSuite{})
+
+func (s *InputDirSuite) SetUpTest(c *C) {
+ s.tmpDir = fs.NewDir(c, "gomplate-inttests",
+ fs.WithFile("config.yml", "one: eins\ntwo: deux\n"),
+ fs.WithDir("in",
+ fs.WithFile("eins.txt", `{{ (ds "config").one }}`),
+ fs.WithDir("inner",
+ fs.WithFile("deux.txt", `{{ (ds "config").two }}`),
+ ),
+ ),
+ fs.WithDir("out"),
+ fs.WithDir("bad_in",
+ fs.WithFile("bad.tmpl", "{{end}}"),
+ ),
+ )
+}
+
+func (s *InputDirSuite) TearDownTest(c *C) {
+ s.tmpDir.Remove()
+}
+
+func (s *InputDirSuite) TestInputDir(c *C) {
+ result := icmd.RunCommand(GomplateBin,
+ "--input-dir", s.tmpDir.Join("in"),
+ "--output-dir", s.tmpDir.Join("out"),
+ "-d", "config="+s.tmpDir.Join("config.yml"),
+ )
+ result.Assert(c, icmd.Success)
+
+ files, err := ioutil.ReadDir(s.tmpDir.Join("out"))
+ assert.NilError(c, err)
+ tassert.Len(c, files, 2)
+
+ files, err = ioutil.ReadDir(s.tmpDir.Join("out", "inner"))
+ assert.NilError(c, err)
+ tassert.Len(c, files, 1)
+
+ content, err := ioutil.ReadFile(s.tmpDir.Join("out", "eins.txt"))
+ assert.NilError(c, err)
+ assert.Equal(c, "eins", string(content))
+
+ content, err = ioutil.ReadFile(s.tmpDir.Join("out", "inner", "deux.txt"))
+ assert.NilError(c, err)
+ assert.Equal(c, "deux", string(content))
+}
+
+func (s *InputDirSuite) TestDefaultOutputDir(c *C) {
+ result := icmd.RunCmd(icmd.Command(GomplateBin,
+ "--input-dir", s.tmpDir.Join("in"),
+ "-d", "config="+s.tmpDir.Join("config.yml"),
+ ), func(c *icmd.Cmd) {
+ c.Dir = s.tmpDir.Join("out")
+ })
+ result.Assert(c, icmd.Success)
+
+ files, err := ioutil.ReadDir(s.tmpDir.Join("out"))
+ assert.NilError(c, err)
+ tassert.Len(c, files, 2)
+
+ files, err = ioutil.ReadDir(s.tmpDir.Join("out", "inner"))
+ assert.NilError(c, err)
+ tassert.Len(c, files, 1)
+
+ content, err := ioutil.ReadFile(s.tmpDir.Join("out", "eins.txt"))
+ assert.NilError(c, err)
+ assert.Equal(c, "eins", string(content))
+
+ content, err = ioutil.ReadFile(s.tmpDir.Join("out", "inner", "deux.txt"))
+ assert.NilError(c, err)
+ assert.Equal(c, "deux", string(content))
+}
+
+func (s *InputDirSuite) TestReportsFilenameWithBadInputFile(c *C) {
+ result := icmd.RunCommand(GomplateBin,
+ "--input-dir", s.tmpDir.Join("bad_in"),
+ "--output-dir", s.tmpDir.Join("out"),
+ "-d", "config="+s.tmpDir.Join("config.yml"),
+ )
+ result.Assert(c, icmd.Expected{
+ ExitCode: 1,
+ Out: "template: " + s.tmpDir.Join("bad_in", "bad.tmpl") + ":1: unexpected {{end}}",
+ })
+}
diff --git a/test/integration/integration.go b/test/integration/integration.go
new file mode 100644
index 00000000..76ab1b72
--- /dev/null
+++ b/test/integration/integration.go
@@ -0,0 +1 @@
+package integration
diff --git a/test/integration/integration_test.go b/test/integration/integration_test.go
new file mode 100644
index 00000000..e22945b0
--- /dev/null
+++ b/test/integration/integration_test.go
@@ -0,0 +1,122 @@
+package integration
+
+import (
+ "encoding/json"
+ "go/build"
+ "io/ioutil"
+ "log"
+ "net"
+ "net/http"
+ "testing"
+ "time"
+
+ "github.com/gotestyourself/gotestyourself/icmd"
+ vaultapi "github.com/hashicorp/vault/api"
+ . "gopkg.in/check.v1"
+)
+
+var (
+ GomplateBin = build.Default.GOPATH + "/src/github.com/hairyhenderson/gomplate/bin/gomplate"
+)
+
+// Hook up gocheck into the "go test" runner.
+func Test(t *testing.T) { TestingT(t) }
+
+// a convenience...
+func inOutTest(c *C, i string, o string) {
+ result := icmd.RunCommand(GomplateBin, "-i", i)
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: o})
+}
+
+func handle(c *C, err error) {
+ if err != nil {
+ c.Fatal(err)
+ }
+}
+
+// mirrorHandler - reflects back the HTTP headers from the request
+func mirrorHandler(w http.ResponseWriter, r *http.Request) {
+ type Req struct {
+ Headers http.Header `json:"headers"`
+ }
+ req := Req{r.Header}
+ b, err := json.Marshal(req)
+ if err != nil {
+ log.Println(err)
+ w.WriteHeader(http.StatusBadRequest)
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.Write(b)
+}
+
+// freeport - find a free TCP port for immediate use. No guarantees!
+func freeport() (port int, addr string) {
+ l, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP("127.0.0.1")})
+ defer l.Close()
+ if err != nil {
+ panic(err)
+ }
+ a := l.Addr().(*net.TCPAddr)
+ port = a.Port
+ return port, a.String()
+}
+
+// waitForURL - waits up to 20s for a given URL to respond with a 200
+func waitForURL(c *C, url string) error {
+ client := http.DefaultClient
+ retries := 100
+ for retries > 0 {
+ retries--
+ time.Sleep(200 * time.Millisecond)
+ resp, err := client.Get(url)
+ if err != nil {
+ c.Logf("Got error, retries left: %d (error: %v)", retries, err)
+ continue
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ c.Logf("Body is: %s", body)
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode == 200 {
+ return nil
+ }
+ }
+ return nil
+}
+
+type vaultClient struct {
+ addr string
+ rootToken string
+ vc *vaultapi.Client
+}
+
+func createVaultClient(addr string, rootToken string) (*vaultClient, error) {
+ config := vaultapi.DefaultConfig()
+ config.Address = "http://" + addr
+ client, err := vaultapi.NewClient(config)
+ if err != nil {
+ return nil, err
+ }
+ v := &vaultClient{
+ addr: addr,
+ rootToken: rootToken,
+ vc: client,
+ }
+ client.SetToken(rootToken)
+ return v, nil
+}
+
+func (v *vaultClient) tokenCreate(policy string, uses int) (string, error) {
+ opts := &vaultapi.TokenCreateRequest{
+ Policies: []string{policy},
+ TTL: "1m",
+ NumUses: uses,
+ }
+ token, err := v.vc.Auth().Token().Create(opts)
+ if err != nil {
+ return "", err
+ }
+ return token.Auth.ClientToken, nil
+}
diff --git a/test/integration/math.bats b/test/integration/math.bats
deleted file mode 100644
index 09168f3a..00000000
--- a/test/integration/math.bats
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env bats
-
-load helper
-
-@test "'math.Add'" {
- gomplate -i '{{ math.Add 1 2 3 4 }} {{ add -5 5 }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "10 0" ]]
-}
-
-@test "'math.Sub'" {
- gomplate -i '{{ math.Sub 10 5 }} {{ sub -5 5 }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "5 -10" ]]
-}
-
-@test "'math.Mul'" {
- gomplate -i '{{ math.Mul 1 2 3 4 }} {{ mul -5 5 }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "24 -25" ]]
-}
-
-@test "'math.Div'" {
- gomplate -i '{{ math.Div 5 3 }} {{ div -5 5 }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "1 -1" ]]
-}
-
-@test "'math.Rem'" {
- gomplate -i '{{ math.Rem 5 3 }} {{ rem 2 2 }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "2 0" ]]
-}
-
-@test "'math.Pow'" {
- gomplate -i '{{ math.Pow 8 4 }} {{ pow 2 2 }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "4096 4" ]]
-}
-
-@test "'math.Seq'" {
- gomplate -i '{{ math.Seq 0 }}, {{ seq 0 3 }}, {{ seq -5 -10 2 }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "[1 0], [0 1 2 3], [-5 -7 -9]" ]]
-} \ No newline at end of file
diff --git a/test/integration/math_test.go b/test/integration/math_test.go
new file mode 100644
index 00000000..cfdeaab0
--- /dev/null
+++ b/test/integration/math_test.go
@@ -0,0 +1,22 @@
+//+build integration
+//+build !windows
+
+package integration
+
+import (
+ . "gopkg.in/check.v1"
+)
+
+type MathSuite struct{}
+
+var _ = Suite(&MathSuite{})
+
+func (s *MathSuite) TestMath(c *C) {
+ inOutTest(c, `{{ math.Add 1 2 3 4 }} {{ add -5 5 }}`, "10 0")
+ inOutTest(c, `{{ math.Sub 10 5 }} {{ sub -5 5 }}`, "5 -10")
+ inOutTest(c, `{{ math.Mul 1 2 3 4 }} {{ mul -5 5 }}`, "24 -25")
+ inOutTest(c, `{{ math.Div 5 3 }} {{ div -5 5 }}`, "1 -1")
+ inOutTest(c, `{{ math.Rem 5 3 }} {{ rem 2 2 }}`, "2 0")
+ inOutTest(c, `{{ math.Pow 8 4 }} {{ pow 2 2 }}`, "4096 4")
+ inOutTest(c, `{{ math.Seq 0 }}, {{ seq 0 3 }}, {{ seq -5 -10 2 }}`, "[1 0], [0 1 2 3], [-5 -7 -9]")
+}
diff --git a/test/integration/metasvc/main.go b/test/integration/metasvc/main.go
deleted file mode 100644
index 2350736d..00000000
--- a/test/integration/metasvc/main.go
+++ /dev/null
@@ -1,147 +0,0 @@
-package main
-
-import (
- "bytes"
- "crypto/rand"
- "crypto/rsa"
- "crypto/x509"
- "crypto/x509/pkix"
- "encoding/pem"
- "flag"
- "log"
- "math/big"
- "net"
- "net/http"
- "time"
-
- "github.com/fullsailor/pkcs7"
-)
-
-var port int
-var priv *rsa.PrivateKey
-var derBytes []byte
-
-const instanceDocument = `{
- "devpayProductCodes" : null,
- "availabilityZone" : "xx-test-1b",
- "privateIp" : "10.1.2.3",
- "version" : "2010-08-31",
- "instanceId" : "i-00000000000000000",
- "billingProducts" : null,
- "instanceType" : "t2.micro",
- "accountId" : "1",
- "imageId" : "ami-00000000",
- "pendingTime" : "2000-00-01T0:00:00Z",
- "architecture" : "x86_64",
- "kernelId" : null,
- "ramdiskId" : null,
- "region" : "xx-test-1"
-}`
-
-func main() {
- flag.IntVar(&port, "p", 8081, "Port to listen to")
- flag.Parse()
-
- l, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: port})
- if err != nil {
- log.Fatal(err)
- }
- // defer l.Close()
- http.HandleFunc("/", rootHandler)
-
- http.HandleFunc("/latest/dynamic/instance-identity/pkcs7", pkcsHandler)
- http.HandleFunc("/latest/dynamic/instance-identity/document", documentHandler)
- http.HandleFunc("/certificate", certificateHandler)
-
- http.HandleFunc("/quit", quitHandler(l))
-
- http.Serve(l, nil)
-}
-
-func certificateGenerate() {
- var err error
- priv, err = rsa.GenerateKey(rand.Reader, 2048)
- if err != nil {
- log.Fatalf("failed to generate private key: %s", err)
- }
-
- serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
- serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
- if err != nil {
- log.Fatalf("failed to generate serial number: %s", err)
- }
-
- template := x509.Certificate{
- SerialNumber: serialNumber,
- Subject: pkix.Name{
- Organization: []string{"Test"},
- },
- }
-
- derBytes, err = x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
- if err != nil {
- log.Fatalf("Failed to create certificate: %s", err)
- }
-}
-
-func rootHandler(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "text/plain")
- w.Write([]byte(""))
-}
-
-func pkcsHandler(w http.ResponseWriter, r *http.Request) {
- cert, err := x509.ParseCertificate(derBytes)
- if err != nil {
- log.Fatalf("Cannot decode certificate: %s", err)
- }
-
- // Initialize a SignedData struct with content to be signed
- signedData, err := pkcs7.NewSignedData([]byte(instanceDocument))
- if err != nil {
- log.Fatalf("Cannot initialize signed data: %s", err)
- }
-
- // Add the signing cert and private key
- if err := signedData.AddSigner(cert, priv, pkcs7.SignerInfoConfig{}); err != nil {
- log.Fatalf("Cannot add signer: %s", err)
- }
-
- // Finish() to obtain the signature bytes
- detachedSignature, err := signedData.Finish()
- if err != nil {
- log.Fatalf("Cannot finish signing data: %s", err)
- }
-
- encoded := pem.EncodeToMemory(&pem.Block{Type: "PKCS7", Bytes: detachedSignature})
-
- encoded = bytes.TrimPrefix(encoded, []byte("-----BEGIN PKCS7-----\n"))
- encoded = bytes.TrimSuffix(encoded, []byte("\n-----END PKCS7-----\n"))
-
- w.Header().Set("Content-Type", "text/plain")
- w.Write(encoded)
-}
-
-func documentHandler(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "application/json")
- w.Write([]byte(instanceDocument))
-}
-
-func certificateHandler(w http.ResponseWriter, r *http.Request) {
- if derBytes == nil {
- certificateGenerate()
- }
- encoded := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
-
- w.Header().Set("Content-Type", "text/plain")
- w.Write(encoded)
-}
-
-func quitHandler(l net.Listener) func(http.ResponseWriter, *http.Request) {
- return func(w http.ResponseWriter, r *http.Request) {
- w.WriteHeader(http.StatusNoContent)
- go func() {
- time.Sleep(500 * time.Millisecond)
- l.Close()
- }()
- }
-}
diff --git a/test/integration/mirrorsvc/main.go b/test/integration/mirrorsvc/main.go
deleted file mode 100644
index f05113a5..00000000
--- a/test/integration/mirrorsvc/main.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package main
-
-import (
- "encoding/json"
- "flag"
- "log"
- "net"
- "net/http"
- "time"
-)
-
-// Req -
-type Req struct {
- Headers http.Header `json:"headers"`
-}
-
-var port int
-
-func main() {
- flag.IntVar(&port, "p", 8080, "Port to listen to")
- flag.Parse()
-
- l, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: port})
- if err != nil {
- log.Fatal(err)
- }
- // defer l.Close()
- http.HandleFunc("/", rootHandler)
-
- http.HandleFunc("/quit", quitHandler(l))
-
- http.Serve(l, nil)
-}
-
-func rootHandler(w http.ResponseWriter, r *http.Request) {
- req := Req{r.Header}
- b, err := json.Marshal(req)
- if err != nil {
- log.Println(err)
- w.WriteHeader(http.StatusBadRequest)
- }
- w.Header().Set("Content-Type", "application/json")
- w.Write(b)
-}
-
-func quitHandler(l net.Listener) func(http.ResponseWriter, *http.Request) {
- return func(w http.ResponseWriter, r *http.Request) {
- w.WriteHeader(http.StatusNoContent)
- go func() {
- time.Sleep(500 * time.Millisecond)
- l.Close()
- }()
- }
-}
diff --git a/test/integration/net.bats b/test/integration/net.bats
deleted file mode 100644
index d63eaf1b..00000000
--- a/test/integration/net.bats
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env bats
-
-load helper
-
-tmpdir=$(mktemp -u)
-
-function setup () {
- mkdir -p $tmpdir
-}
-
-function teardown () {
- rm -rf $tmpdir || true
-}
-
-@test "'net.LookupIP'" {
- gomplate -i '{{ net.LookupIP "localhost" }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "127.0.0.1" ]]
-}
diff --git a/test/integration/net_test.go b/test/integration/net_test.go
new file mode 100644
index 00000000..dc9f1f76
--- /dev/null
+++ b/test/integration/net_test.go
@@ -0,0 +1,19 @@
+//+build integration
+//+build !windows
+
+package integration
+
+import (
+ . "gopkg.in/check.v1"
+
+ "github.com/gotestyourself/gotestyourself/icmd"
+)
+
+type NetSuite struct{}
+
+var _ = Suite(&NetSuite{})
+
+func (s *NetSuite) TestLookupIP(c *C) {
+ result := icmd.RunCommand(GomplateBin, "-i", `{{ net.LookupIP "localhost" }}`)
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "127.0.0.1"})
+}
diff --git a/test/integration/regexp.bats b/test/integration/regexp.bats
deleted file mode 100644
index 17b5a743..00000000
--- a/test/integration/regexp.bats
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env bats
-
-load helper
-
-tmpdir=$(mktemp -u)
-
-function setup () {
- mkdir -p $tmpdir
-}
-
-function teardown () {
- rm -rf $tmpdir || true
-}
-
-@test "'regexp.Replace'" {
- gomplate -i '{{ "1.2.3-59" | regexp.Replace `-([0-9]*)` `.$1` }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "1.2.3.59" ]]
-}
diff --git a/test/integration/regexp_test.go b/test/integration/regexp_test.go
new file mode 100644
index 00000000..c476877f
--- /dev/null
+++ b/test/integration/regexp_test.go
@@ -0,0 +1,20 @@
+//+build integration
+//+build !windows
+
+package integration
+
+import (
+ . "gopkg.in/check.v1"
+
+ "github.com/gotestyourself/gotestyourself/icmd"
+)
+
+type RegexpSuite struct{}
+
+var _ = Suite(&RegexpSuite{})
+
+func (s *RegexpSuite) TestReplace(c *C) {
+ result := icmd.RunCommand(GomplateBin, "-i",
+ `{{ "1.2.3-59" | regexp.Replace "-([0-9]*)" ".$1" }}`)
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "1.2.3.59"})
+}
diff --git a/test/integration/strings.bats b/test/integration/strings.bats
deleted file mode 100644
index 9d16eb25..00000000
--- a/test/integration/strings.bats
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/env bats
-
-load helper
-
-tmpdir=$(mktemp -u)
-
-function setup () {
- mkdir -p $tmpdir
-}
-
-function teardown () {
- rm -rf $tmpdir || true
-}
-
-@test "'strings.Indent'" {
- gomplate -i '{{ strings.Indent " " "hello world" }}
-{{ "hello\nmultiline\nworld" | indent 2 "-" }}
-{{ "foo\nbar" | strings.Indent 2 }}
- {{"hello\nworld" | strings.Indent 5 | strings.TrimSpace }}
-'
- [ "$status" -eq 0 ]
- [[ "${output}" == " hello world
---hello
---multiline
---world
- foo
- bar
- hello
- world" ]]
-}
diff --git a/test/integration/strings_test.go b/test/integration/strings_test.go
new file mode 100644
index 00000000..cd570e16
--- /dev/null
+++ b/test/integration/strings_test.go
@@ -0,0 +1,31 @@
+//+build integration
+//+build !windows
+
+package integration
+
+import (
+ . "gopkg.in/check.v1"
+
+ "github.com/gotestyourself/gotestyourself/icmd"
+)
+
+type StringsSuite struct{}
+
+var _ = Suite(&StringsSuite{})
+
+func (s *StringsSuite) TestIndent(c *C) {
+ result := icmd.RunCommand(GomplateBin, "-i",
+ `{{ strings.Indent " " "hello world" }}
+{{ "hello\nmultiline\nworld" | indent 2 "-" }}
+{{ "foo\nbar" | strings.Indent 2 }}
+ {{"hello\nworld" | strings.Indent 5 | strings.TrimSpace }}
+`)
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: ` hello world
+--hello
+--multiline
+--world
+ foo
+ bar
+ hello
+ world`})
+}
diff --git a/test/integration/test.sh b/test/integration/test.sh
deleted file mode 100755
index 18d7bc48..00000000
--- a/test/integration/test.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-set -euo pipefail
-
-source $(dirname $0)/helper.bash
-
-function finish {
- stop_vault
-}
-trap finish EXIT
-
-export VAULT_ADDR=http://127.0.0.1:8200
-export VAULT_ROOT_TOKEN=00000000-1111-2222-3333-444455556666
-
-start_vault 8200
-
-bats $(dirname $0)
diff --git a/test/integration/awssvc/main.go b/test/integration/test_ec2_utils.go
index a377cd99..2435aeb9 100644
--- a/test/integration/awssvc/main.go
+++ b/test/integration/test_ec2_utils.go
@@ -1,48 +1,100 @@
-package main
+package integration
import (
- "encoding/json"
- "flag"
+ "bytes"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/pem"
"log"
- "net"
+ "math/big"
"net/http"
- "time"
+
+ "github.com/fullsailor/pkcs7"
)
-// Req -
-type Req struct {
- Headers http.Header `json:"headers"`
-}
+const instanceDocument = `{
+ "devpayProductCodes" : null,
+ "availabilityZone" : "xx-test-1b",
+ "privateIp" : "10.1.2.3",
+ "version" : "2010-08-31",
+ "instanceId" : "i-00000000000000000",
+ "billingProducts" : null,
+ "instanceType" : "t2.micro",
+ "accountId" : "1",
+ "imageId" : "ami-00000000",
+ "pendingTime" : "2000-00-01T0:00:00Z",
+ "architecture" : "x86_64",
+ "kernelId" : null,
+ "ramdiskId" : null,
+ "region" : "xx-test-1"
+}`
-var port int
+func instanceDocumentHandler(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.Write([]byte(instanceDocument))
+}
-func main() {
- flag.IntVar(&port, "p", 8082, "Port to listen to")
- flag.Parse()
+func certificateGenerate() (priv *rsa.PrivateKey, derBytes []byte, err error) {
+ priv, err = rsa.GenerateKey(rand.Reader, 2048)
+ if err != nil {
+ log.Fatalf("failed to generate private key: %s", err)
+ }
- l, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: port})
+ serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+ serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
- log.Fatal(err)
+ log.Fatalf("failed to generate serial number: %s", err)
}
- // defer l.Close()
- http.HandleFunc("/", rootHandler)
- http.HandleFunc("/sts/", stsHandler)
- http.HandleFunc("/ec2/", ec2Handler)
- http.HandleFunc("/quit", quitHandler(l))
+ template := x509.Certificate{
+ SerialNumber: serialNumber,
+ Subject: pkix.Name{
+ Organization: []string{"Test"},
+ },
+ }
+
+ derBytes, err = x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
+ if err != nil {
+ log.Fatalf("Failed to create certificate: %s", err)
+ }
- http.Serve(l, nil)
+ return priv, derBytes, err
}
-func rootHandler(w http.ResponseWriter, r *http.Request) {
- req := Req{r.Header}
- b, err := json.Marshal(req)
- if err != nil {
- log.Println(err)
- w.WriteHeader(http.StatusBadRequest)
+func pkcsHandler(priv *rsa.PrivateKey, derBytes []byte) func(http.ResponseWriter, *http.Request) {
+ return func(w http.ResponseWriter, r *http.Request) {
+ cert, err := x509.ParseCertificate(derBytes)
+ if err != nil {
+ log.Fatalf("Cannot decode certificate: %s", err)
+ }
+
+ // Initialize a SignedData struct with content to be signed
+ signedData, err := pkcs7.NewSignedData([]byte(instanceDocument))
+ if err != nil {
+ log.Fatalf("Cannot initialize signed data: %s", err)
+ }
+
+ // Add the signing cert and private key
+ if err = signedData.AddSigner(cert, priv, pkcs7.SignerInfoConfig{}); err != nil {
+ log.Fatalf("Cannot add signer: %s", err)
+ }
+
+ // Finish() to obtain the signature bytes
+ detachedSignature, err := signedData.Finish()
+ if err != nil {
+ log.Fatalf("Cannot finish signing data: %s", err)
+ }
+
+ encoded := pem.EncodeToMemory(&pem.Block{Type: "PKCS7", Bytes: detachedSignature})
+
+ encoded = bytes.TrimPrefix(encoded, []byte("-----BEGIN PKCS7-----\n"))
+ encoded = bytes.TrimSuffix(encoded, []byte("\n-----END PKCS7-----\n"))
+
+ w.Header().Set("Content-Type", "text/plain")
+ w.Write(encoded)
}
- w.Header().Set("Content-Type", "application/json")
- w.Write(b)
}
func stsHandler(w http.ResponseWriter, r *http.Request) {
@@ -182,13 +234,3 @@ func ec2Handler(w http.ResponseWriter, r *http.Request) {
</reservationSet>
</DescribeInstancesResponse>`))
}
-
-func quitHandler(l net.Listener) func(http.ResponseWriter, *http.Request) {
- return func(w http.ResponseWriter, r *http.Request) {
- w.WriteHeader(http.StatusNoContent)
- go func() {
- time.Sleep(500 * time.Millisecond)
- l.Close()
- }()
- }
-}
diff --git a/test/integration/time.bats b/test/integration/time.bats
deleted file mode 100644
index 83441f60..00000000
--- a/test/integration/time.bats
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env bats
-
-load helper
-
-@test "'time.ZoneName'" {
- gomplate -i '{{ time.ZoneName }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == `date +"%Z"` ]]
-}
-
-@test "'time.ZoneOffset'" {
- TZ=UTC gomplate -i '{{ time.ZoneOffset }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "0" ]]
-}
-
-@test "'(time.Now).Format'" {
- gomplate -i '{{ (time.Now).Format "2006-01-02 15 -0700" }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == `date +"%Y-%m-%d %H %z"` ]]
-}
-
-@test "'(time.Parse).Format'" {
- in=`date -u --date='@1234567890'`
- gomplate -i "{{ (time.Parse \"Mon Jan 02 15:04:05 MST 2006\" \"${in}\").Format \"2006-01-02 15 -0700\" }}"
- [ "$status" -eq 0 ]
- [[ "${output}" == "2009-02-13 23 +0000" ]]
-}
-
-@test "'(time.ParseLocal).Format'" {
- TZ=Africa/Luanda gomplate -i "{{ (time.ParseLocal time.Kitchen \"6:00AM\").Format \"15:04 MST\" }}"
- [ "$status" -eq 0 ]
- [[ "${output}" == "06:00 LMT" ]]
-}
-
-@test "'(time.ParseInLocation).Format'" {
- gomplate -i "{{ (time.ParseInLocation time.Kitchen \"Africa/Luanda\" \"6:00AM\").Format \"15:04 MST\" }}"
- [ "$status" -eq 0 ]
- [[ "${output}" == "06:00 LMT" ]]
-}
-
-@test "'(time.Unix).UTC.Format' int" {
- gomplate -i '{{ (time.Unix 1234567890).UTC.Format "2006-01-02 15 -0700" }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "2009-02-13 23 +0000" ]]
-}
-
-@test "'(time.Unix).UTC.Format' string" {
- gomplate -i '{{ (time.Unix "1234567890").UTC.Format "2006-01-02 15 -0700" }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "2009-02-13 23 +0000" ]]
-}
diff --git a/test/integration/time_test.go b/test/integration/time_test.go
new file mode 100644
index 00000000..65ec5f8f
--- /dev/null
+++ b/test/integration/time_test.go
@@ -0,0 +1,49 @@
+//+build integration
+//+build !windows
+
+package integration
+
+import (
+ "time"
+
+ "github.com/gotestyourself/gotestyourself/icmd"
+ . "gopkg.in/check.v1"
+)
+
+type TimeSuite struct{}
+
+var _ = Suite(&TimeSuite{})
+
+func (s *TimeSuite) TestTime(c *C) {
+ f := `Mon Jan 02 15:04:05 MST 2006`
+ i := `Fri Feb 13 23:31:30 UTC 2009`
+ inOutTest(c, `{{ (time.Parse "`+f+`" "`+i+`").Format "2006-01-02 15 -0700" }}`,
+ "2009-02-13 23 +0000")
+
+ result := icmd.RunCmd(icmd.Command(GomplateBin, "-i",
+ `{{ (time.ParseLocal time.Kitchen "6:00AM").Format "15:04 MST" }}`), func(cmd *icmd.Cmd) {
+ cmd.Env = []string{"TZ=Africa/Luanda"}
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "06:00 LMT"})
+
+ result = icmd.RunCmd(icmd.Command(GomplateBin, "-i",
+ `{{ time.ZoneOffset }}`), func(cmd *icmd.Cmd) {
+ cmd.Env = []string{"TZ=UTC"}
+ })
+ result.Assert(c, icmd.Expected{ExitCode: 0, Out: "0"})
+
+ zname, _ := time.Now().Zone()
+ inOutTest(c, `{{ time.ZoneName }}`, zname)
+
+ inOutTest(c, `{{ (time.Now).Format "2006-01-02 15 -0700" }}`,
+ time.Now().Format("2006-01-02 15 -0700"))
+
+ inOutTest(c, `{{ (time.ParseInLocation time.Kitchen "Africa/Luanda" "6:00AM").Format "15:04 MST" }}`,
+ "06:00 LMT")
+
+ inOutTest(c, `{{ (time.Unix 1234567890).UTC.Format "2006-01-02 15 -0700" }}`,
+ "2009-02-13 23 +0000")
+
+ inOutTest(c, `{{ (time.Unix "1234567890").UTC.Format "2006-01-02 15 -0700" }}`,
+ "2009-02-13 23 +0000")
+}
diff --git a/test/integration/typeconv_funcs.bats b/test/integration/typeconv_funcs.bats
deleted file mode 100644
index bb6f52bd..00000000
--- a/test/integration/typeconv_funcs.bats
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/usr/bin/env bats
-
-load helper
-
-tmpdir=$(mktemp -u)
-
-function setup () {
- mkdir -p $tmpdir
-}
-
-function teardown () {
- rm -rf $tmpdir || true
-}
-
-@test "'has' can handle sub-maps in nested maps" {
- gomplate -d config=$tmpdir/config.yml -i '{{ has ("foo:\n bar:\n baz: qux" | yaml).foo.bar "baz"}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "true" ]]
-}
-
-@test "'toJSON' can handle nested maps" {
- gomplate -i '{{ "foo:\n bar:\n baz: qux" | yaml | toJSON }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == '{"foo":{"bar":{"baz":"qux"}}}' ]]
-}
-
-@test "'toJSONPretty' can handle nested maps" {
- gomplate -i '{{ `{"foo":{"bar":{"baz":"qux"}}}` | json | toJSONPretty " " }}
-{{ toJSONPretty "" (`{"foo":{"bar":{"baz":"qux"}}}` | json) }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == '{
- "foo": {
- "bar": {
- "baz": "qux"
- }
- }
-}
-{
-"foo": {
-"bar": {
-"baz": "qux"
-}
-}
-}' ]]
-}
-
-@test "join" {
- gomplate -i '{{ $a := `[1, 2, 3]` | jsonArray }}{{ join $a "-" }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "1-2-3" ]]
-}
-
-@test "'csv'" {
- gomplate -i '{{ $c := `lang,keywords
-C,32
-Go,25
-COBOL,357` | csv -}}
-{{ index (index $c 0) 1 }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "keywords" ]]
-}
-
-@test "'csvByRow' with default settings" {
- gomplate -i '{{ $c := `lang,keywords
-C,32
-Go,25
-COBOL,357` | csvByRow }}{{ range $c }}{{ .lang }} has {{ .keywords }} keywords.
-{{end}}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "C has 32 keywords.
-Go has 25 keywords.
-COBOL has 357 keywords." ]]
-}
-
-@test "'csvByColumn' (tab-separated)" {
- gomplate -i '{{ $c := `lang keywords
-C 32
-Go 25
-COBOL 357` | csvByColumn "\t" -}}
-Languages are: {{ join $c.lang " and " }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "Languages are: C and Go and COBOL" ]]
-}
-
-@test "'toml'" {
- gomplate -i '{{ $t := `# comment
-foo = "bar"
-
-[baz]
-qux = "quux"` | toml -}}
-{{ $t.baz.qux }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "quux" ]]
-}
-
-@test "'toTOML'" {
- gomplate -i '{{ "foo:\n bar:\n baz: qux" | yaml | toTOML }}'
- [ "$status" -eq 0 ]
- [[ "${output}" == "[foo]
- [foo.bar]
- baz = \"qux\"" ]]
-} \ No newline at end of file
diff --git a/test/integration/typeconv_test.go b/test/integration/typeconv_test.go
new file mode 100644
index 00000000..fece8180
--- /dev/null
+++ b/test/integration/typeconv_test.go
@@ -0,0 +1,87 @@
+//+build integration
+//+build !windows
+
+package integration
+
+import (
+ . "gopkg.in/check.v1"
+)
+
+type TypeconvSuite struct{}
+
+var _ = Suite(&TypeconvSuite{})
+
+const (
+ testYAML = "foo:\\n bar:\\n baz: qux"
+ testJSON = `{"foo":{"bar":{"baz":"qux"}}}`
+ testCsv = `lang,keywords
+C,32
+Go,25
+COBOL,357`
+ testTsv = `lang keywords
+C 32
+Go 25
+COBOL 357`
+)
+
+func (s *TypeconvSuite) TestTypeconvFuncs(c *C) {
+ //@test "'has' can handle sub-maps in nested maps" {
+ inOutTest(c, `{{ has ("`+testYAML+`" | yaml).foo.bar "baz"}}`,
+ "true")
+}
+func (s *TypeconvSuite) TestJSON(c *C) {
+ inOutTest(c, `{{ "`+testYAML+`" | yaml | toJSON }}`, testJSON)
+
+ inOutTest(c, `{{ `+"`"+testJSON+"`"+` | json | toJSONPretty " " }}
+{{ toJSONPretty "" (`+"`"+testJSON+"`"+` | json) }}`,
+ `{
+ "foo": {
+ "bar": {
+ "baz": "qux"
+ }
+ }
+}
+{
+"foo": {
+"bar": {
+"baz": "qux"
+}
+}
+}`)
+}
+
+func (s *TypeconvSuite) TestJoin(c *C) {
+ inOutTest(c, `{{ $a := "[1, 2, 3]" | jsonArray }}{{ join $a "-" }}`,
+ "1-2-3")
+}
+
+func (s *TypeconvSuite) TestCSV(c *C) {
+ inOutTest(c, `{{ $c := `+"`"+testCsv+"`"+` | csv -}}
+{{ index (index $c 0) 1 }}`,
+ "keywords")
+
+ inOutTest(c, `{{ $c := `+"`"+testCsv+"`"+` | csvByRow -}}
+{{ range $c }}{{ .lang }} has {{ .keywords }} keywords.
+{{end}}`,
+ `C has 32 keywords.
+Go has 25 keywords.
+COBOL has 357 keywords.`)
+
+ inOutTest(c, `{{ $c := `+"`"+testTsv+"`"+` | csvByColumn "\t" -}}
+Languages are: {{ join $c.lang " and " }}`,
+ "Languages are: C and Go and COBOL")
+}
+
+func (s *TypeconvSuite) TestTOML(c *C) {
+ inOutTest(c, `{{ $t := `+"`"+`# comment
+foo = "bar"
+
+[baz]
+qux = "quux"`+"`"+` | toml -}}
+{{ $t.baz.qux }}`, "quux")
+
+ inOutTest(c, `{{ "foo:\n bar:\n baz: qux" | yaml | toTOML }}`,
+ `[foo]
+ [foo.bar]
+ baz = "qux"`)
+}
diff --git a/vault/vault_test.go b/vault/vault_test.go
index 0bcc3259..39893026 100644
--- a/vault/vault_test.go
+++ b/vault/vault_test.go
@@ -9,6 +9,7 @@ import (
)
func TestNew(t *testing.T) {
+ os.Unsetenv("VAULT_ADDR")
v := New(nil)
assert.Equal(t, "https://127.0.0.1:8200", v.client.Address())