Skip to content

Commit d323dc2

Browse files
committed
fix(test): Wait for Vault server in watch tests
Fix flaky tests by polling Vault's /v1/sys/health endpoint. This ensures the server is ready before tests attempt to connect, preventing a race condition during Vault dev server startup. Signed-off-by: Ville Vesilehto <[email protected]>
1 parent 1adb94d commit d323dc2

File tree

1 file changed

+62
-1
lines changed

1 file changed

+62
-1
lines changed

watch/watch_test.go

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,31 @@ package watch
55

66
import (
77
"encoding/json"
8+
"fmt"
89
"io"
910
"log"
11+
"net"
12+
"net/http"
1013
"os"
1114
"os/exec"
1215
"path/filepath"
1316
"strings"
1417
"testing"
18+
"time"
1519

1620
dep "github.com/hashicorp/consul-template/dependency"
1721
"github.com/hashicorp/vault/api"
1822
)
1923

2024
const (
21-
vaultAddr = "http://127.0.0.1:8200"
2225
vaultToken = "a_token"
2326
)
2427

2528
var (
2629
testVault *vaultServer
2730
testClients *dep.ClientSet
2831
tokenRoleId string
32+
vaultAddr string
2933
)
3034

3135
func TestMain(m *testing.M) {
@@ -35,6 +39,14 @@ func TestMain(m *testing.M) {
3539
// sub-main so I can use defer
3640
func main(m *testing.M) int {
3741
log.SetOutput(io.Discard)
42+
// Find a free port for the Vault server
43+
listener, err := net.Listen("tcp", "127.0.0.1:0")
44+
if err != nil {
45+
panic(fmt.Sprintf("failed to find free port for vault: %v", err))
46+
}
47+
vaultAddr = fmt.Sprintf("http://%s", listener.Addr().String())
48+
listener.Close()
49+
3850
testVault = newTestVault()
3951
defer func() { testVault.Stop() }()
4052

@@ -71,6 +83,7 @@ func newTestVault() *vaultServer {
7183
args := []string{
7284
"server", "-dev", "-dev-root-token-id", vaultToken,
7385
"-dev-no-store-token",
86+
"-dev-listen-address", strings.TrimPrefix(vaultAddr, "http://"),
7487
}
7588
cmd := exec.Command("vault", args...)
7689
cmd.Stdout = io.Discard
@@ -79,6 +92,54 @@ func newTestVault() *vaultServer {
7992
if err := cmd.Start(); err != nil {
8093
panic("vault failed to start: " + err.Error())
8194
}
95+
96+
// Wait for Vault to become available
97+
client := &http.Client{Timeout: 1 * time.Second}
98+
healthURL := vaultAddr + "/v1/sys/health"
99+
startTime := time.Now()
100+
timeout := 30 * time.Second
101+
102+
for {
103+
if time.Since(startTime) > timeout {
104+
panic("timed out waiting for vault dev server to start")
105+
}
106+
107+
resp, err := client.Get(healthURL)
108+
if err != nil {
109+
time.Sleep(200 * time.Millisecond)
110+
continue
111+
}
112+
113+
if resp.StatusCode == http.StatusOK {
114+
bodyBytes, readErr := io.ReadAll(resp.Body)
115+
resp.Body.Close()
116+
117+
if readErr != nil {
118+
time.Sleep(200 * time.Millisecond)
119+
continue
120+
}
121+
122+
var healthStatus map[string]interface{}
123+
jsonErr := json.Unmarshal(bodyBytes, &healthStatus)
124+
if jsonErr != nil {
125+
time.Sleep(200 * time.Millisecond)
126+
continue
127+
}
128+
129+
// Check for initialized and unsealed status
130+
initialized, initOk := healthStatus["initialized"].(bool)
131+
sealed, sealedOk := healthStatus["sealed"].(bool)
132+
133+
if initOk && sealedOk && initialized && !sealed {
134+
break
135+
}
136+
} else {
137+
resp.Body.Close()
138+
}
139+
140+
time.Sleep(1 * time.Second)
141+
}
142+
82143
return &vaultServer{
83144
cmd: cmd,
84145
}

0 commit comments

Comments
 (0)