Add projects
This commit is contained in:
parent
2d3a9ad623
commit
8b607dd700
1802 changed files with 503346 additions and 2 deletions
234
backend/internal/config/credential_in_flight_test.go
Normal file
234
backend/internal/config/credential_in_flight_test.go
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestLoadConfigOptionalMissingFallbackAppliesCredentialInFlightDefaults(t *testing.T) {
|
||||
cfg, errLoad := LoadConfigOptional(filepath.Join(t.TempDir(), "missing.yaml"), true)
|
||||
if errLoad != nil {
|
||||
t.Fatalf("LoadConfigOptional() error = %v", errLoad)
|
||||
}
|
||||
assertOptionalConfigFallback(t, cfg)
|
||||
}
|
||||
|
||||
func TestLoadConfigOptionalEmptyFallbackAppliesCredentialInFlightDefaults(t *testing.T) {
|
||||
configPath := filepath.Join(t.TempDir(), "config.yaml")
|
||||
if errWrite := os.WriteFile(configPath, nil, 0o600); errWrite != nil {
|
||||
t.Fatal(errWrite)
|
||||
}
|
||||
cfg, errLoad := LoadConfigOptional(configPath, true)
|
||||
if errLoad != nil {
|
||||
t.Fatalf("LoadConfigOptional() error = %v", errLoad)
|
||||
}
|
||||
assertOptionalConfigFallback(t, cfg)
|
||||
}
|
||||
|
||||
func TestLoadConfigOptionalWhitespaceFallbackAppliesCredentialInFlightDefaults(t *testing.T) {
|
||||
configPath := filepath.Join(t.TempDir(), "config.yaml")
|
||||
if errWrite := os.WriteFile(configPath, []byte(" \t\n\r "), 0o600); errWrite != nil {
|
||||
t.Fatal(errWrite)
|
||||
}
|
||||
cfg, errLoad := LoadConfigOptional(configPath, true)
|
||||
if errLoad != nil {
|
||||
t.Fatalf("LoadConfigOptional() error = %v", errLoad)
|
||||
}
|
||||
assertOptionalConfigFallback(t, cfg)
|
||||
}
|
||||
|
||||
func TestLoadConfigOptionalInvalidFallbackAppliesCredentialInFlightDefaults(t *testing.T) {
|
||||
configPath := filepath.Join(t.TempDir(), "config.yaml")
|
||||
if errWrite := os.WriteFile(configPath, []byte(":"), 0o600); errWrite != nil {
|
||||
t.Fatal(errWrite)
|
||||
}
|
||||
cfg, errLoad := LoadConfigOptional(configPath, true)
|
||||
if errLoad != nil {
|
||||
t.Fatalf("LoadConfigOptional() error = %v", errLoad)
|
||||
}
|
||||
assertOptionalConfigFallback(t, cfg)
|
||||
}
|
||||
|
||||
func assertOptionalConfigFallback(t *testing.T, cfg *Config) {
|
||||
t.Helper()
|
||||
if cfg.CredentialInFlight != DefaultCredentialInFlightConfig() {
|
||||
t.Fatalf("CredentialInFlight = %#v, want %#v", cfg.CredentialInFlight, DefaultCredentialInFlightConfig())
|
||||
}
|
||||
if errValidate := cfg.CredentialInFlight.Validate(); errValidate != nil {
|
||||
t.Fatalf("CredentialInFlight.Validate() error = %v", errValidate)
|
||||
}
|
||||
if cfg.ErrorLogsMaxFiles != 0 || cfg.WebsocketAuth || cfg.CredentialConcurrency != (CredentialConcurrencyConfig{}) {
|
||||
t.Fatalf("fallback config changed existing empty-config defaults: %#v", cfg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCredentialInFlightConfigContractFixture(t *testing.T) {
|
||||
raw, errRead := os.ReadFile(filepath.Join("..", "home", "testdata", "credential_in_flight_contract.json"))
|
||||
if errRead != nil {
|
||||
t.Fatal(errRead)
|
||||
}
|
||||
fixture, errDecode := decodeCredentialInFlightConfigFixture(raw)
|
||||
if errDecode != nil {
|
||||
t.Fatal(errDecode)
|
||||
}
|
||||
if fixture.Config != DefaultCredentialInFlightConfig() {
|
||||
t.Fatalf("default config = %#v, want %#v", DefaultCredentialInFlightConfig(), fixture.Config)
|
||||
}
|
||||
if errValidate := fixture.Config.Validate(); errValidate != nil {
|
||||
t.Fatalf("Validate() error = %v", errValidate)
|
||||
}
|
||||
assertCredentialInFlightConfigFields(t)
|
||||
assertRequiredJSONKeys(t, raw, []string{"config", "part", "overflow"})
|
||||
assertRequiredJSONKeys(t, fixture.ConfigJSON, []string{"snapshot-interval", "stale-after", "max-part-bytes", "max-part-count", "max-revision-bytes", "max-aggregate-groups", "max-details", "max-string-bytes", "staging-retention"})
|
||||
}
|
||||
|
||||
func TestCredentialInFlightConfigFixtureRejectsInvalidJSON(t *testing.T) {
|
||||
raw, errRead := os.ReadFile(filepath.Join("..", "home", "testdata", "credential_in_flight_contract.json"))
|
||||
if errRead != nil {
|
||||
t.Fatal(errRead)
|
||||
}
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
raw []byte
|
||||
}{
|
||||
{name: "unknown config field", raw: bytes.Replace(raw, []byte(`"snapshot-interval": "2s"`), []byte(`"snapshot-interval": "2s", "secret": "secret"`), 1)},
|
||||
{name: "trailing JSON", raw: append(append([]byte{}, raw...), []byte(` {"config": {}}`)...)},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if _, errDecode := decodeCredentialInFlightConfigFixture(test.raw); errDecode == nil {
|
||||
t.Fatal("decodeCredentialInFlightConfigFixture() error = nil")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCredentialInFlightConfigDurationBounds(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
stale string
|
||||
every string
|
||||
valid bool
|
||||
}{
|
||||
{name: "exact three intervals", every: "1s", stale: "3s", valid: true},
|
||||
{name: "below three intervals", every: "1s", stale: "2999999999ns", valid: false},
|
||||
{name: "near duration maximum", every: time.Duration(math.MaxInt64 / 2).String(), stale: time.Duration(math.MaxInt64).String(), valid: false},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
cfg := DefaultCredentialInFlightConfig()
|
||||
cfg.SnapshotInterval = test.every
|
||||
cfg.StaleAfter = test.stale
|
||||
errValidate := cfg.Validate()
|
||||
if (errValidate == nil) != test.valid {
|
||||
t.Fatalf("Validate() error = %v, want valid = %t", errValidate, test.valid)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCredentialInFlightConfigRejectsUnsafeBounds(t *testing.T) {
|
||||
cfg := DefaultCredentialInFlightConfig()
|
||||
cfg.StaleAfter = "5s"
|
||||
if errValidate := cfg.Validate(); errValidate == nil {
|
||||
t.Fatal("Validate() error = nil, want stale-after error")
|
||||
}
|
||||
cfg = DefaultCredentialInFlightConfig()
|
||||
cfg.MaxRevisionBytes = 16*1024*1024 + 1
|
||||
if errValidate := cfg.Validate(); errValidate == nil {
|
||||
t.Fatal("Validate() error = nil, want hard revision bound error")
|
||||
}
|
||||
cfg = DefaultCredentialInFlightConfig()
|
||||
cfg.MaxPartBytes = math.MaxInt
|
||||
if errValidate := cfg.Validate(); errValidate == nil {
|
||||
t.Fatal("Validate() error = nil, want overflow-safe part bound error")
|
||||
}
|
||||
}
|
||||
|
||||
type credentialInFlightConfigFixture struct {
|
||||
Config CredentialInFlightConfig `json:"config"`
|
||||
ConfigJSON json.RawMessage `json:"-"`
|
||||
}
|
||||
|
||||
func decodeCredentialInFlightConfigFixture(raw []byte) (credentialInFlightConfigFixture, error) {
|
||||
var fixture credentialInFlightConfigFixture
|
||||
var document struct {
|
||||
Config json.RawMessage `json:"config"`
|
||||
Part json.RawMessage `json:"part"`
|
||||
Overflow json.RawMessage `json:"overflow"`
|
||||
}
|
||||
decoder := json.NewDecoder(bytes.NewReader(raw))
|
||||
decoder.DisallowUnknownFields()
|
||||
if errDecode := decoder.Decode(&document); errDecode != nil {
|
||||
return fixture, errDecode
|
||||
}
|
||||
if errDecode := decoder.Decode(&struct{}{}); errDecode == nil {
|
||||
return fixture, errors.New("unexpected trailing JSON")
|
||||
} else if errDecode != io.EOF {
|
||||
return fixture, errDecode
|
||||
}
|
||||
decoder = json.NewDecoder(bytes.NewReader(document.Config))
|
||||
decoder.DisallowUnknownFields()
|
||||
if errDecode := decoder.Decode(&fixture.Config); errDecode != nil {
|
||||
return fixture, errDecode
|
||||
}
|
||||
if errDecode := decoder.Decode(&struct{}{}); errDecode == nil {
|
||||
return fixture, errors.New("unexpected trailing config JSON")
|
||||
} else if errDecode != io.EOF {
|
||||
return fixture, errDecode
|
||||
}
|
||||
fixture.ConfigJSON = document.Config
|
||||
return fixture, nil
|
||||
}
|
||||
|
||||
func assertCredentialInFlightConfigFields(t *testing.T) {
|
||||
t.Helper()
|
||||
assertOrderedJSONFields(t, reflect.TypeOf(CredentialInFlightConfig{}), []jsonField{
|
||||
{name: "SnapshotInterval", tag: "snapshot-interval"},
|
||||
{name: "StaleAfter", tag: "stale-after"},
|
||||
{name: "MaxPartBytes", tag: "max-part-bytes"},
|
||||
{name: "MaxPartCount", tag: "max-part-count"},
|
||||
{name: "MaxRevisionBytes", tag: "max-revision-bytes"},
|
||||
{name: "MaxAggregateGroups", tag: "max-aggregate-groups"},
|
||||
{name: "MaxDetails", tag: "max-details"},
|
||||
{name: "MaxStringBytes", tag: "max-string-bytes"},
|
||||
{name: "StagingRetention", tag: "staging-retention"},
|
||||
})
|
||||
}
|
||||
|
||||
type jsonField struct {
|
||||
name string
|
||||
tag string
|
||||
}
|
||||
|
||||
func assertOrderedJSONFields(t *testing.T, structType reflect.Type, want []jsonField) {
|
||||
t.Helper()
|
||||
if structType.NumField() != len(want) {
|
||||
t.Fatalf("%s field count = %d, want %d", structType.Name(), structType.NumField(), len(want))
|
||||
}
|
||||
for index, expected := range want {
|
||||
field := structType.Field(index)
|
||||
if field.Name != expected.name || field.Tag.Get("json") != expected.tag {
|
||||
t.Fatalf("%s field %d = (%q, %q), want (%q, %q)", structType.Name(), index, field.Name, field.Tag.Get("json"), expected.name, expected.tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func assertRequiredJSONKeys(t *testing.T, raw json.RawMessage, required []string) {
|
||||
t.Helper()
|
||||
var fields map[string]json.RawMessage
|
||||
if errDecode := json.Unmarshal(raw, &fields); errDecode != nil {
|
||||
t.Fatalf("json.Unmarshal() error = %v", errDecode)
|
||||
}
|
||||
for _, key := range required {
|
||||
if _, ok := fields[key]; !ok {
|
||||
t.Fatalf("required JSON key %q is missing", key)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue