Files
cmbuyer/admin/internal/config/config_test.go
T

99 lines
3.6 KiB
Go

package config_test
import (
"strings"
"testing"
"cmbuyer/admin/internal/config"
"golang.org/x/crypto/bcrypt"
)
func TestLoad(t *testing.T) {
hash, err := bcrypt.GenerateFromPassword([]byte("test-password"), bcrypt.MinCost)
if err != nil {
t.Fatalf("generate bcrypt hash: %v", err)
}
values := map[string]string{
"CMBUYER_ADMIN_USERNAME": "admin",
"CMBUYER_ADMIN_PASSWORD_BCRYPT": string(hash),
"CMBUYER_SESSION_SECRET": strings.Repeat("s", 32),
"CMBUYER_COOKIE_SECURE": "true",
"CMBUYER_DATABASE_SOURCE": ":memory:",
"CMBUYER_AUTHORIZATION_TTL": "10m",
"CMBUYER_MAX_TASK_QUANTITY": "99",
"CMBUYER_MAX_TOTAL_PRICE": "999.99",
"CMBUYER_EVIDENCE_DIR": t.TempDir(),
}
got, err := config.Load(lookup(values))
if err != nil {
t.Fatalf("Load: %v", err)
}
if got.AdminUsername != "admin" || !got.CookieSecure {
t.Fatalf("Load returned unexpected public configuration: %#v", got)
}
}
func TestLoadRejectsMissingOrInvalidConfiguration(t *testing.T) {
hash, err := bcrypt.GenerateFromPassword([]byte("test-password"), bcrypt.MinCost)
if err != nil {
t.Fatalf("generate bcrypt hash: %v", err)
}
base := map[string]string{
"CMBUYER_ADMIN_USERNAME": "admin",
"CMBUYER_ADMIN_PASSWORD_BCRYPT": string(hash),
"CMBUYER_SESSION_SECRET": strings.Repeat("s", 32),
"CMBUYER_DATABASE_SOURCE": ":memory:",
"CMBUYER_AUTHORIZATION_TTL": "10m",
"CMBUYER_MAX_TASK_QUANTITY": "99",
"CMBUYER_MAX_TOTAL_PRICE": "999.99",
"CMBUYER_EVIDENCE_DIR": t.TempDir(),
}
tests := []struct {
name string
mutate func(map[string]string)
want string
}{
{"missing username", func(values map[string]string) { delete(values, "CMBUYER_ADMIN_USERNAME") }, "CMBUYER_ADMIN_USERNAME"},
{"invalid bcrypt", func(values map[string]string) { values["CMBUYER_ADMIN_PASSWORD_BCRYPT"] = "not-a-bcrypt-hash" }, "CMBUYER_ADMIN_PASSWORD_BCRYPT"},
{"short secret", func(values map[string]string) { values["CMBUYER_SESSION_SECRET"] = "short" }, "CMBUYER_SESSION_SECRET"},
{"invalid secure flag", func(values map[string]string) { values["CMBUYER_COOKIE_SECURE"] = "1" }, "CMBUYER_COOKIE_SECURE"},
{"missing database", func(values map[string]string) { delete(values, "CMBUYER_DATABASE_SOURCE") }, "CMBUYER_DATABASE_SOURCE"},
{"invalid authorization ttl", func(values map[string]string) { values["CMBUYER_AUTHORIZATION_TTL"] = "0s" }, "CMBUYER_AUTHORIZATION_TTL"},
{"invalid maximum quantity", func(values map[string]string) { values["CMBUYER_MAX_TASK_QUANTITY"] = "0" }, "CMBUYER_MAX_TASK_QUANTITY"},
{"invalid maximum total price", func(values map[string]string) { values["CMBUYER_MAX_TOTAL_PRICE"] = "1" }, "CMBUYER_MAX_TOTAL_PRICE"},
{"missing evidence directory", func(values map[string]string) { delete(values, "CMBUYER_EVIDENCE_DIR") }, "CMBUYER_EVIDENCE_DIR"},
{"relative evidence directory", func(values map[string]string) { values["CMBUYER_EVIDENCE_DIR"] = "evidence" }, "CMBUYER_EVIDENCE_DIR"},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
values := copyValues(base)
test.mutate(values)
_, err := config.Load(lookup(values))
if err == nil || !strings.Contains(err.Error(), test.want) {
t.Fatalf("Load error = %v, want mention of %s", err, test.want)
}
})
}
}
func lookup(values map[string]string) func(string) (string, bool) {
return func(key string) (string, bool) {
value, ok := values[key]
return value, ok
}
}
func copyValues(values map[string]string) map[string]string {
copy := make(map[string]string, len(values))
for key, value := range values {
copy[key] = value
}
return copy
}