146 lines
3.6 KiB
Go
146 lines
3.6 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
const validConfig = `
|
|
version: 1
|
|
security:
|
|
requireProtectionOnPublicListen: true
|
|
gateway:
|
|
enabled: true
|
|
listen: 127.0.0.1:8080
|
|
auth:
|
|
mode: none
|
|
distribution:
|
|
enabled: true
|
|
listen: 127.0.0.1:8081
|
|
auth:
|
|
mode: none
|
|
extraction:
|
|
fulfillment: partial
|
|
maxCountPerRequest: 20
|
|
minRemainingTTL: 30s
|
|
maxHealthCheckAge: 15s
|
|
reserveForGateway: 5
|
|
routing:
|
|
- name: extract
|
|
enabled: true
|
|
purpose: extract
|
|
upstreams: [provider-a]
|
|
strategy:
|
|
type: sequential
|
|
switchAfterEmptyFetch: 5
|
|
onUnavailable:
|
|
action: reject
|
|
upstreams:
|
|
provider-a:
|
|
enabled: true
|
|
exposure: [gateway, extract]
|
|
provider:
|
|
billingMode: fetch
|
|
protocols: [http]
|
|
api:
|
|
url: https://provider.example/proxies
|
|
method: GET
|
|
template: '{{.}}'
|
|
auth:
|
|
type: none
|
|
proxyAuth:
|
|
type: response
|
|
pool:
|
|
maxSize: 100
|
|
capacity:
|
|
maxConcurrencyPerProxy: 10
|
|
lifecycle:
|
|
ttl: 120s
|
|
allocationSafetyMargin: 10s
|
|
fetch:
|
|
requestInterval: 1s
|
|
timeout: 3s
|
|
maxAttempts: 5
|
|
maxInFlight: 1
|
|
maxTotal: 1000
|
|
check:
|
|
interval: 30s
|
|
jitter: 20
|
|
maxInFlight: 100
|
|
timeout: 2s
|
|
maxAttempts: 2
|
|
maxConsecutiveFailures: 3
|
|
urls: [http://connect.rom.miui.com/generate_204]
|
|
`
|
|
|
|
func TestLoadStrictValidConfiguration(t *testing.T) {
|
|
cfg, err := Load(strings.NewReader(validConfig))
|
|
if err != nil {
|
|
t.Fatalf("Load(): %v", err)
|
|
}
|
|
if cfg.Version != 1 || cfg.Upstreams["provider-a"].Pool.MaxSize != 100 {
|
|
t.Fatalf("unexpected config: %+v", cfg)
|
|
}
|
|
}
|
|
|
|
func TestLoadRejectsUnknownFields(t *testing.T) {
|
|
_, err := Load(strings.NewReader(validConfig + "unknownField: true\n"))
|
|
if err == nil || !strings.Contains(err.Error(), "unknownField") {
|
|
t.Fatalf("Load() error = %v, want unknown field error", err)
|
|
}
|
|
}
|
|
|
|
func TestValidateRejectsUnprotectedPublicListener(t *testing.T) {
|
|
cfg, err := Load(strings.NewReader(strings.Replace(validConfig,
|
|
"listen: 127.0.0.1:8080", "listen: 0.0.0.0:8080", 1)))
|
|
if err == nil || !strings.Contains(err.Error(), "gateway") || !strings.Contains(err.Error(), "public") {
|
|
t.Fatalf("Load() error = %v, want unprotected public listener error", err)
|
|
}
|
|
if cfg != nil {
|
|
t.Fatal("invalid config must not be returned")
|
|
}
|
|
}
|
|
|
|
func TestValidateRejectsMissingUpstreamReference(t *testing.T) {
|
|
broken := strings.Replace(validConfig, "upstreams: [provider-a]", "upstreams: [missing]", 1)
|
|
_, err := Load(strings.NewReader(broken))
|
|
if err == nil || !strings.Contains(err.Error(), "missing") {
|
|
t.Fatalf("Load() error = %v, want missing upstream error", err)
|
|
}
|
|
}
|
|
|
|
func TestValidateSeparatesPoolAndFetchLimits(t *testing.T) {
|
|
broken := strings.Replace(validConfig, "maxTotal: 1000", "maxTotal: 50", 1)
|
|
_, err := Load(strings.NewReader(broken))
|
|
if err == nil || !strings.Contains(err.Error(), "maxTotal") {
|
|
t.Fatalf("Load() error = %v, want maxTotal validation error", err)
|
|
}
|
|
}
|
|
|
|
func TestShippedConfigurationsAreValid(t *testing.T) {
|
|
paths, err := filepath.Glob(filepath.Join("..", "..", "examples", "config", "*.yaml"))
|
|
if err != nil {
|
|
t.Fatalf("Glob(): %v", err)
|
|
}
|
|
paths = append(paths, filepath.Join("..", "..", "configs", "proxy-pool.yaml"))
|
|
if len(paths) != 21 {
|
|
t.Fatalf("configuration count = %d, want 21", len(paths))
|
|
}
|
|
|
|
for _, path := range paths {
|
|
path := path
|
|
t.Run(filepath.Base(path), func(t *testing.T) {
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
t.Fatalf("Open(): %v", err)
|
|
}
|
|
defer file.Close()
|
|
if _, err := Load(file); err != nil {
|
|
t.Fatalf("Load(): %v", err)
|
|
}
|
|
})
|
|
}
|
|
}
|