package main
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/vaughan0/go-ini"
"sourcecraft.dev/bigbes/sr-ht-ecore/instconf"
)
// loadConf builds an ini.File directly from a literal, bypassing
// config.LoadConfig so the tests need no config.ini on disk and no
// internal-ipnet parsing.
func loadConf(t *testing.T, body string) ini.File {
t.Helper()
conf, err := ini.Load(strings.NewReader(body))
if err != nil {
t.Fatalf("ini.Load: %v", err)
}
return conf
}
func TestResolveSettingsDefaults(t *testing.T) {
conf := loadConf(t, `[dolt.sr.ht]
origin=https://dolt.example.org
connection-string=postgres://u@localhost/d?sslmode=disable
`)
got, err := resolveSettings(conf)
if err != nil {
t.Fatalf("resolveSettings: %v", err)
}
if got.connString != "postgres://u@localhost/d?sslmode=disable" {
t.Errorf("connString = %q", got.connString)
}
if got.httpHost != "dolt.example.org" {
t.Errorf("httpHost = %q, want dolt.example.org", got.httpHost)
}
if got.reposRoot != defaultReposRoot {
t.Errorf("reposRoot = %q, want %q", got.reposRoot, defaultReposRoot)
}
if got.staticDir != defaultStaticDir {
t.Errorf("staticDir = %q, want %q", got.staticDir, defaultStaticDir)
}
if got.remotesapiAddr != defaultRemotesapiAddr {
t.Errorf("remotesapiAddr = %q, want %q", got.remotesapiAddr, defaultRemotesapiAddr)
}
if got.credsapiAddr != defaultCredsapiAddr {
t.Errorf("credsapiAddr = %q, want %q", got.credsapiAddr, defaultCredsapiAddr)
}
}
func TestResolveSettingsOverrides(t *testing.T) {
conf := loadConf(t, `[dolt.sr.ht]
origin=https://dolt.example.org:8443
connection-string=postgres://u@localhost/d
repos=/srv/dolt
static-dir=/usr/share/sourcehut/dolt.sr.ht/static
remotesapi-listen=0.0.0.0:6306
credsapi-listen=0.0.0.0:6308
`)
got, err := resolveSettings(conf)
if err != nil {
t.Fatalf("resolveSettings: %v", err)
}
if got.reposRoot != "/srv/dolt" {
t.Errorf("reposRoot = %q", got.reposRoot)
}
if got.staticDir != "/usr/share/sourcehut/dolt.sr.ht/static" {
t.Errorf("staticDir = %q", got.staticDir)
}
if got.remotesapiAddr != "0.0.0.0:6306" {
t.Errorf("remotesapiAddr = %q", got.remotesapiAddr)
}
if got.credsapiAddr != "0.0.0.0:6308" {
t.Errorf("credsapiAddr = %q", got.credsapiAddr)
}
// The port is part of the sealed-URL authority and is preserved.
if got.httpHost != "dolt.example.org:8443" {
t.Errorf("httpHost = %q, want dolt.example.org:8443", got.httpHost)
}
}
func TestResolveSettingsMissingConnString(t *testing.T) {
conf := loadConf(t, `[dolt.sr.ht]
origin=https://dolt.example.org
`)
_, err := resolveSettings(conf)
require.Error(t, err)
assert.ErrorIs(t, err, instconf.ErrIncompleteConfig)
assert.Contains(t, err.Error(), "connection-string")
}
func TestResolveSettingsMissingOrigin(t *testing.T) {
conf := loadConf(t, `[dolt.sr.ht]
connection-string=postgres://u@localhost/d
`)
_, err := resolveSettings(conf)
require.Error(t, err)
assert.ErrorIs(t, err, instconf.ErrIncompleteConfig)
assert.Contains(t, err.Error(), "origin")
}
// TestResolveSettingsReportsEveryMissingKey is the reason the two checks became
// one Require: an operator with an empty section gets both keys off one boot
// rather than one key per restart.
func TestResolveSettingsReportsEveryMissingKey(t *testing.T) {
_, err := resolveSettings(loadConf(t, "[dolt.sr.ht]\n"))
require.Error(t, err)
assert.Contains(t, err.Error(), "connection-string")
assert.Contains(t, err.Error(), "origin")
}
// TestResolveSettingsHostlessOrigin covers the gap Require cannot: a present,
// non-blank origin that names no host. "dolt.example.org" without a scheme is a
// URL path, and a service whose sealed chunk URLs and JWT audience are built
// from an empty authority must refuse to start rather than guess a host.
func TestResolveSettingsHostlessOrigin(t *testing.T) {
conf := loadConf(t, `[dolt.sr.ht]
connection-string=postgres://u@localhost/d
origin=dolt.example.org
`)
_, err := resolveSettings(conf)
require.Error(t, err)
assert.Contains(t, err.Error(), "names no host")
}
// TestResolveSettingsTrimsTheOrigin: an origin written with a trailing slash is
// the same origin. It used to reach url.Parse untouched, which happened to
// answer the same host; the authority now comes off the canonical form, so the
// two spellings cannot diverge for any other consumer either.
func TestResolveSettingsTrimsTheOrigin(t *testing.T) {
conf := loadConf(t, `[dolt.sr.ht]
connection-string=postgres://u@localhost/d
origin=https://dolt.example.org:8443/
`)
got, err := resolveSettings(conf)
require.NoError(t, err)
assert.Equal(t, "dolt.example.org:8443", got.httpHost)
}