feat: centralize Barkfile schema
This commit is contained in:
254
parser_test.go
Normal file
254
parser_test.go
Normal file
@@ -0,0 +1,254 @@
|
||||
package barkfile
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestParseValidConfiguration(t *testing.T) {
|
||||
cfg, err := Parse([]byte(`pawsql {
|
||||
listen :5432
|
||||
tls {
|
||||
cert "./certs/fullchain.pem"
|
||||
key ./certs/privkey.pem
|
||||
}
|
||||
database gramps {
|
||||
hostname Gramps.PawSQL.Barkstack.Dev
|
||||
upstream 192.168.27.10:5432
|
||||
}
|
||||
}`))
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
if cfg.Listen != ":5432" {
|
||||
t.Errorf("Listen = %q", cfg.Listen)
|
||||
}
|
||||
if cfg.TLS.CertFile != "./certs/fullchain.pem" || cfg.TLS.KeyFile != "./certs/privkey.pem" {
|
||||
t.Errorf("TLS = %#v", cfg.TLS)
|
||||
}
|
||||
if len(cfg.Databases) != 1 {
|
||||
t.Fatalf("databases = %d", len(cfg.Databases))
|
||||
}
|
||||
if got := cfg.Databases[0]; got.Name != "gramps" || got.Hostname != "Gramps.PawSQL.Barkstack.Dev" || got.Upstream != "192.168.27.10:5432" {
|
||||
t.Errorf("database = %#v", got)
|
||||
}
|
||||
if err := cfg.Validate(); err != nil {
|
||||
t.Fatalf("Validate() error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseCommentsAndMultipleDatabases(t *testing.T) {
|
||||
cfg, err := Parse([]byte(`# external comment
|
||||
pawsql {
|
||||
listen :5432 # client port
|
||||
tls { cert cert.pem # inline
|
||||
key key.pem }
|
||||
database one { hostname one.pawsql.test
|
||||
upstream postgres-one:5432 }
|
||||
# route another application
|
||||
database two { hostname two.pawsql.test
|
||||
upstream 127.0.0.1:55432 }
|
||||
}`))
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
if len(cfg.Databases) != 2 {
|
||||
t.Fatalf("databases = %d, want 2", len(cfg.Databases))
|
||||
}
|
||||
if cfg.Databases[1].Name != "two" || cfg.Databases[1].Upstream != "127.0.0.1:55432" {
|
||||
t.Errorf("second database = %#v", cfg.Databases[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateMissingFieldsAndDuplicateHostname(t *testing.T) {
|
||||
cfg, err := Parse([]byte(`pawsql {
|
||||
listen :5432
|
||||
tls { cert cert.pem }
|
||||
database one {
|
||||
hostname FOO.pawsql.test
|
||||
}
|
||||
database two {
|
||||
hostname foo.pawsql.test
|
||||
upstream postgres-two:5432
|
||||
}
|
||||
}`))
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
err = cfg.Validate()
|
||||
if err == nil {
|
||||
t.Fatal("Validate() error = nil")
|
||||
}
|
||||
for _, want := range []string{"TLS private key is required", "upstream or postgres is required", "duplicate hostname"} {
|
||||
if !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Validate() error = %q, missing %q", err, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRejectsMalformedUpstreamAddress(t *testing.T) {
|
||||
cfg := Config{
|
||||
Listen: ":5432",
|
||||
TLS: TLSConfig{CertFile: "cert.pem", KeyFile: "key.pem"},
|
||||
Databases: []DatabaseConfig{{
|
||||
Name: "foo",
|
||||
Hostname: "foo.pawsql.test",
|
||||
Upstream: "postgres-foo",
|
||||
}},
|
||||
}
|
||||
err := cfg.Validate()
|
||||
if err == nil || !strings.Contains(err.Error(), "missing port") {
|
||||
t.Fatalf("Validate() error = %v, want malformed upstream address", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateAllowsDatabaseWithoutHostname(t *testing.T) {
|
||||
cfg := Config{
|
||||
Listen: ":5432",
|
||||
TLS: TLSConfig{CertFile: "cert.pem", KeyFile: "key.pem"},
|
||||
Databases: []DatabaseConfig{{
|
||||
Name: "analytics",
|
||||
Upstream: "postgres-foo:5432",
|
||||
}},
|
||||
}
|
||||
if err := cfg.Validate(); err != nil {
|
||||
t.Fatalf("Validate() error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRejectsDuplicateDatabaseName(t *testing.T) {
|
||||
cfg := Config{
|
||||
Listen: ":5432",
|
||||
TLS: TLSConfig{CertFile: "cert.pem", KeyFile: "key.pem"},
|
||||
Databases: []DatabaseConfig{
|
||||
{Name: "analytics", Upstream: "postgres-foo:5432"},
|
||||
{Name: "analytics", Upstream: "postgres-bar:5432"},
|
||||
},
|
||||
}
|
||||
err := cfg.Validate()
|
||||
if err == nil || !strings.Contains(err.Error(), "duplicate database name") {
|
||||
t.Fatalf("Validate() error = %v, want duplicate database name", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePostgresContainer(t *testing.T) {
|
||||
cfg, err := Parse([]byte(`pawsql {
|
||||
listen :5432
|
||||
tls {
|
||||
cert cert.pem
|
||||
key key.pem
|
||||
}
|
||||
database analytics {
|
||||
postgres {
|
||||
image postgres:18
|
||||
volume analytics-data
|
||||
password_env ANALYTICS_POSTGRES_PASSWORD
|
||||
idle_timeout 15m
|
||||
traffic_idle_timeout 1h
|
||||
}
|
||||
}
|
||||
}`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
database := cfg.Databases[0]
|
||||
if database.Postgres == nil || database.Postgres.Image != "postgres:18" || database.Postgres.Volume != "analytics-data" || database.Postgres.PasswordEnv != "ANALYTICS_POSTGRES_PASSWORD" || database.Postgres.IdleTimeout != 15*time.Minute || database.Postgres.TrafficIdleTimeout != time.Hour {
|
||||
t.Errorf("Postgres = %#v", database.Postgres)
|
||||
}
|
||||
if err := cfg.Validate(); err != nil {
|
||||
t.Fatalf("Validate() error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRejectsInvalidPostgresIdleTimeout(t *testing.T) {
|
||||
_, err := Parse([]byte(`pawsql {
|
||||
listen :5432
|
||||
tls {
|
||||
cert cert.pem
|
||||
key key.pem
|
||||
}
|
||||
database analytics {
|
||||
postgres {
|
||||
image postgres:18
|
||||
volume analytics-data
|
||||
password_env ANALYTICS_POSTGRES_PASSWORD
|
||||
idle_timeout whenever
|
||||
}
|
||||
}
|
||||
}`))
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid idle_timeout") {
|
||||
t.Fatalf("Parse() error = %v, want invalid idle_timeout", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRejectsInvalidPostgresTrafficIdleTimeout(t *testing.T) {
|
||||
_, err := Parse([]byte(`pawsql {
|
||||
listen :5432
|
||||
tls {
|
||||
cert cert.pem
|
||||
key key.pem
|
||||
}
|
||||
database analytics {
|
||||
postgres {
|
||||
image postgres:18
|
||||
volume analytics-data
|
||||
password_env ANALYTICS_POSTGRES_PASSWORD
|
||||
traffic_idle_timeout whenever
|
||||
}
|
||||
}
|
||||
}`))
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid traffic_idle_timeout") {
|
||||
t.Fatalf("Parse() error = %v, want invalid traffic_idle_timeout", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateAllowsSupportedPostgresImages(t *testing.T) {
|
||||
for _, image := range []string{"postgres:16", "postgres:17", "postgres:18"} {
|
||||
cfg := Config{
|
||||
Listen: ":5432",
|
||||
TLS: TLSConfig{CertFile: "cert.pem", KeyFile: "key.pem"},
|
||||
Databases: []DatabaseConfig{{
|
||||
Name: "analytics",
|
||||
Postgres: &PostgresConfig{Image: image, Volume: "analytics-data", PasswordEnv: "ANALYTICS_POSTGRES_PASSWORD"},
|
||||
}},
|
||||
}
|
||||
if err := cfg.Validate(); err != nil {
|
||||
t.Errorf("Validate() image %q error = %v", image, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRejectsUnsupportedPostgresImage(t *testing.T) {
|
||||
cfg := Config{
|
||||
Listen: ":5432",
|
||||
TLS: TLSConfig{CertFile: "cert.pem", KeyFile: "key.pem"},
|
||||
Databases: []DatabaseConfig{{
|
||||
Name: "analytics",
|
||||
Postgres: &PostgresConfig{Image: "postgres:15", Volume: "analytics-data", PasswordEnv: "ANALYTICS_POSTGRES_PASSWORD"},
|
||||
}},
|
||||
}
|
||||
err := cfg.Validate()
|
||||
if err == nil || !strings.Contains(err.Error(), "postgres:16") {
|
||||
t.Fatalf("Validate() error = %v, want unsupported PostgreSQL image", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMalformedBlocksReportLine(t *testing.T) {
|
||||
_, err := Parse([]byte("pawsql {\n tls {\n cert cert.pem\n"))
|
||||
if err == nil {
|
||||
t.Fatal("Parse() error = nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "line 4") {
|
||||
t.Errorf("error = %q, want line number", err)
|
||||
}
|
||||
|
||||
_, err = Parse([]byte("pawsql {\n listen :5432 unexpected\n}"))
|
||||
if err == nil {
|
||||
t.Fatal("Parse() error = nil for trailing directive")
|
||||
}
|
||||
if errors.Is(err, nil) {
|
||||
t.Fatal("unexpected nil error")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user