90 lines
2.6 KiB
Go
90 lines
2.6 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"sync"
|
|
"testing"
|
|
)
|
|
|
|
func TestStorePublishesAndReturnsDetachedConfigurations(t *testing.T) {
|
|
t.Parallel()
|
|
initial := storeTestConfig("provider-a")
|
|
store, err := NewStore(initial)
|
|
if err != nil {
|
|
t.Fatalf("NewStore() error = %v", err)
|
|
}
|
|
|
|
initial.Upstreams["provider-a"] = Upstream{}
|
|
current := store.Current()
|
|
if current == nil || !current.Upstreams["provider-a"].Enabled {
|
|
t.Fatalf("Current() was changed through constructor input: %+v", current)
|
|
}
|
|
current.Routing[0].Upstreams[0] = "mutated"
|
|
if got := store.Current().Routing[0].Upstreams[0]; got != "provider-a" {
|
|
t.Fatalf("Current() shared mutable state: %q", got)
|
|
}
|
|
|
|
next := storeTestConfig("provider-b")
|
|
store.Publish(next)
|
|
next.Routing[0].Upstreams[0] = "mutated"
|
|
if got := store.Current().Routing[0].Upstreams[0]; got != "provider-b" {
|
|
t.Fatalf("Publish() retained caller state: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestStoreRejectsInvalidInitialConfiguration(t *testing.T) {
|
|
t.Parallel()
|
|
for _, configuration := range []*Config{nil, {}} {
|
|
if _, err := NewStore(configuration); !errors.Is(err, ErrInvalidStore) {
|
|
t.Fatalf("NewStore(%v) error = %v, want %v", configuration, err, ErrInvalidStore)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStoreSupportsConcurrentReadersAndPublishers(t *testing.T) {
|
|
store, err := NewStore(storeTestConfig("provider-a"))
|
|
if err != nil {
|
|
t.Fatalf("NewStore() error = %v", err)
|
|
}
|
|
var wait sync.WaitGroup
|
|
for index := 0; index < 100; index++ {
|
|
wait.Add(2)
|
|
go func(index int) {
|
|
defer wait.Done()
|
|
name := "provider-a"
|
|
if index%2 == 1 {
|
|
name = "provider-b"
|
|
}
|
|
store.Publish(storeTestConfig(name))
|
|
}(index)
|
|
go func() {
|
|
defer wait.Done()
|
|
current := store.Current()
|
|
if current == nil || len(current.Routing) != 1 || len(current.Routing[0].Upstreams) != 1 {
|
|
t.Errorf("Current() returned partial configuration: %+v", current)
|
|
}
|
|
}()
|
|
}
|
|
wait.Wait()
|
|
}
|
|
|
|
func storeTestConfig(upstreamName string) *Config {
|
|
return &Config{
|
|
Version: 1,
|
|
Upstreams: map[string]Upstream{
|
|
upstreamName: {
|
|
Enabled: true, Exposure: []string{"gateway"},
|
|
API: ProviderAPI{Auth: ProviderAuth{Type: "none"}},
|
|
ProxyAuth: ProxyAuth{Type: "response"},
|
|
Pool: Pool{MaxSize: 10}, Capacity: Capacity{MaxConcurrencyPerProxy: 1},
|
|
Lifecycle: Lifecycle{TTL: Duration(60_000_000_000), AllocationSafetyMargin: Duration(10_000_000_000)},
|
|
Fetch: Fetch{Timeout: Duration(1_000_000_000), MaxAttempts: 1, MaxInFlight: 1},
|
|
},
|
|
},
|
|
Routing: []Routing{{
|
|
Name: "default", Enabled: true, Purpose: "gateway", Upstreams: []string{upstreamName},
|
|
Strategy: Strategy{Type: "random"}, OnUnavailable: OnUnavailable{Action: "reject"},
|
|
}},
|
|
}
|
|
}
|