quorate/services/short/vault/client_test.go

87 lines
2.6 KiB
Go
Raw Permalink Normal View History

package vault
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strings"
"sync"
"testing"
)
func TestSeed(t *testing.T) {
var mu sync.Mutex
records := map[string]Record{
"short/api": {Data: map[string]any{"private_key": "PLACEHOLDER"}, Version: 1},
"short/public": {Data: map[string]any{"public_key": "PLACEHOLDER"}, Version: 1},
}
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mu.Lock()
defer mu.Unlock()
path := strings.TrimPrefix(r.URL.Path, "/v1/secret/data/")
record, ok := records[path]
if !ok {
http.NotFound(w, r)
return
}
if r.Method == http.MethodGet {
json.NewEncoder(w).Encode(map[string]any{"data": map[string]any{"data": record.Data, "metadata": map[string]int{"version": record.Version}}})
return
}
var request struct {
Data map[string]any `json:"data"`
Options struct {
CAS int `json:"cas"`
} `json:"options"`
}
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
t.Error(err)
}
if request.Options.CAS != record.Version {
w.WriteHeader(400)
return
}
records[path] = Record{Data: request.Data, Version: record.Version + 1}
fmt.Fprint(w, `{}`)
}))
defer s.Close()
c := Client{URL: s.URL, HTTP: s.Client()}
ctx := context.Background()
if err := c.Seed(ctx, "short/api"); err != nil {
t.Fatal(err)
}
key := records["short/api"].Data["private_key"]
for range 2 {
if err := c.Seed(ctx, "short/api"); err != nil {
t.Fatal(err)
}
}
if records["short/api"].Version != 2 || records["short/api"].Data["private_key"] != key {
t.Fatal("repeat seed rotated API identity")
}
if records["short/public"].Version != 2 || len(records["short/public"].Data) != 1 {
t.Fatal("public publication contains private material or redundant writes")
}
records["short/public"] = Record{Data: map[string]any{"public_key": "PLACEHOLDER"}, Version: 3}
if err := c.Seed(ctx, "short/api"); err != nil {
t.Fatal(err)
}
if records["short/api"].Data["private_key"] != key || records["short/public"].Version != 4 {
t.Fatal("interrupted seed did not resume without rotation")
}
records["short/api"] = Record{Data: map[string]any{"private_key": "PLACEHOLDER"}, Version: 5}
records["short/public"] = Record{Data: map[string]any{"public_key": "PLACEHOLDER"}, Version: 5}
var tasks sync.WaitGroup
for range 8 {
tasks.Go(func() { _ = c.Seed(ctx, "short/api") })
}
tasks.Wait()
if err := c.Seed(ctx, "short/api"); err != nil {
t.Fatal(err)
}
if records["short/api"].Version != 6 || records["short/public"].Version != 6 {
t.Fatal("concurrent bootstrap rotated or republished the API identity")
}
}