Files
llmgw/internal/cli/storeflag_test.go
T
Ilker ManapandClaude Opus 5 ebce41e22d Stop calling the PostgreSQL store SQLite, and stop guessing where it is
Two things that were only ever confusing, and one of them stopped a command
working on the cluster.

The store type was named SQLite and kept the name when PostgreSQL was added, so
OpenPostgres returned a *SQLite and all seventy-odd methods on the production
store were spelled after the database it was not running on. Nothing broke;
people did. Earlier today I added three methods to *SQLite for a table that on
this cluster only ever lives in PostgreSQL, and the name did not once look
wrong. It is a field, which is all it ever was.

`llmgw users` and `llmgw keys` defaulted --store to a SQLite path. On a
deployment whose store is PostgreSQL every one of them failed with "unable to
open database file" while the right answer sat in auth.store in the config file
beside them; the conclusion an operator draws is that the tool is broken, and
they are not far off. They now ask the server's own configuration before
falling back, and the error names which of the three sources chose the address
— the failure was never the path, it was which one picked it.

The single-machine default still applies last, so a deployment with no config
file keeps working with no flags.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-27 12:20:40 +02:00

83 lines
2.7 KiB
Go

package cli
import (
"os"
"path/filepath"
"strings"
"testing"
)
func writeConfig(t *testing.T, body string) string {
t.Helper()
p := filepath.Join(t.TempDir(), "server.yaml")
if err := os.WriteFile(p, []byte(body), 0o600); err != nil {
t.Fatal(err)
}
return p
}
func TestAnExplicitStoreWins(t *testing.T) {
cfg := writeConfig(t, "listen: \":8080\"\nauth:\n enabled: true\n store: postgres://from-config/db\n")
f := storeFlags{address: "postgres://explicit/db", config: cfg}
got, from := f.resolve()
if got != "postgres://explicit/db" || !strings.Contains(from, "--store") {
t.Errorf("an explicit --store should win; got %q from %q", got, from)
}
}
func TestTheServerConfigIsAskedBeforeTheDefault(t *testing.T) {
cfg := writeConfig(t, "listen: \":8080\"\nauth:\n enabled: true\n store: postgres://from-config/db\n")
f := storeFlags{config: cfg}
got, from := f.resolve()
// The whole defect: on a cluster whose store is PostgreSQL, these commands
// reached for a SQLite path and failed with "unable to open database file"
// while the right answer sat in the config beside them.
if got != "postgres://from-config/db" {
t.Errorf("expected the address from the config, got %q", got)
}
if !strings.Contains(from, "auth.store") {
t.Errorf("the source should be named for the error message; got %q", from)
}
}
func TestTheSingleMachineDefaultStillApplies(t *testing.T) {
f := storeFlags{config: filepath.Join(t.TempDir(), "absent.yaml")}
got, from := f.resolve()
// A deployment with no config file is the single-machine one, and it worked
// before this existed. It has to keep working with no flags at all.
if got != defaultStorePath {
t.Errorf("expected the default path, got %q", got)
}
if !strings.Contains(from, "default") {
t.Errorf("the source should say it fell back; got %q", from)
}
}
func TestAConfigWithNoStoreFallsThrough(t *testing.T) {
// Authentication off means no store at all. Reading an empty value as the
// answer would open a database named "".
cfg := writeConfig(t, "listen: \":8080\"\n")
f := storeFlags{config: cfg}
if got, _ := f.resolve(); got != defaultStorePath {
t.Errorf("expected the default when the config names no store, got %q", got)
}
}
func TestTheErrorSaysWhichSourceChoseThePath(t *testing.T) {
f := storeFlags{address: filepath.Join(t.TempDir(), "nope", "x.db")}
_, err := f.openCtx(t.Context())
if err == nil {
t.Fatal("expected opening a store in a missing directory to fail")
}
// "unable to open database file" says nothing about which of three sources
// picked that path, and the whole problem is that the wrong one did.
if !strings.Contains(err.Error(), "--store") {
t.Errorf("the error should name where the address came from; got %q", err)
}
}