test(01-02): add failing test for layered compass config
- Cover six-level precedence, env mapping, .env, Set/Persist/Reload - Require HasConfig merge before plugin Register - Assert hello command observes overlay and plugin defaults
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
)
|
||||
|
||||
func TestLoadStringFromAppSection(t *testing.T) {
|
||||
@@ -21,3 +22,222 @@ func TestLoadStringFromAppSection(t *testing.T) {
|
||||
t.Fatalf("String(app.name) = %q, want hello-app", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenDefaultsEnvToProduction(t *testing.T) {
|
||||
dir := writeConfigTree(t, map[string]string{
|
||||
"app.yaml": "name: base\ndebug: false\n",
|
||||
"env/production/app.yaml": "debug: true\n",
|
||||
"env/development/app.yaml": "name: dev\n",
|
||||
})
|
||||
cfg, err := Open(Options{Dir: dir, Environ: []string{}})
|
||||
if err != nil {
|
||||
t.Fatalf("Open: %v", err)
|
||||
}
|
||||
if cfg.Environment() != "production" {
|
||||
t.Fatalf("Environment = %q, want production", cfg.Environment())
|
||||
}
|
||||
if got := cfg.String("app.name"); got != "base" {
|
||||
t.Fatalf("name = %q, want base", got)
|
||||
}
|
||||
if !cfg.Bool("app.debug") {
|
||||
t.Fatal("production overlay should set app.debug")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExplicitEnvWinsOverSUMMER_ENV(t *testing.T) {
|
||||
dir := writeConfigTree(t, map[string]string{
|
||||
"app.yaml": "name: base\n",
|
||||
"env/development/app.yaml": "name: from-dev\n",
|
||||
"env/staging/app.yaml": "name: from-staging\n",
|
||||
})
|
||||
cfg, err := Open(Options{
|
||||
Dir: dir,
|
||||
Env: "staging",
|
||||
Environ: []string{"SUMMER_ENV=development"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Open: %v", err)
|
||||
}
|
||||
if cfg.Environment() != "staging" {
|
||||
t.Fatalf("Environment = %q, want staging", cfg.Environment())
|
||||
}
|
||||
if got := cfg.String("app.name"); got != "from-staging" {
|
||||
t.Fatalf("name = %q, want from-staging", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeepMergeKeepsUntouchedNestedKeys(t *testing.T) {
|
||||
dir := writeConfigTree(t, map[string]string{
|
||||
"database.yaml": `
|
||||
host: localhost
|
||||
port: 5432
|
||||
pool:
|
||||
max: 10
|
||||
idle: 2
|
||||
`,
|
||||
"env/development/database.yaml": `
|
||||
host: dev-db
|
||||
pool:
|
||||
max: 20
|
||||
`,
|
||||
})
|
||||
cfg, err := Open(Options{Dir: dir, Env: "development", Environ: []string{}})
|
||||
if err != nil {
|
||||
t.Fatalf("Open: %v", err)
|
||||
}
|
||||
if got := cfg.String("database.host"); got != "dev-db" {
|
||||
t.Fatalf("host = %q, want dev-db", got)
|
||||
}
|
||||
if got := cfg.Int("database.port"); got != 5432 {
|
||||
t.Fatalf("port = %d, want 5432", got)
|
||||
}
|
||||
if got := cfg.Int("database.pool.max"); got != 20 {
|
||||
t.Fatalf("pool.max = %d, want 20", got)
|
||||
}
|
||||
if got := cfg.Int("database.pool.idle"); got != 2 {
|
||||
t.Fatalf("pool.idle = %d, want 2", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergePluginConfigAtBarePluginID(t *testing.T) {
|
||||
dir := writeConfigTree(t, map[string]string{
|
||||
"app.yaml": "name: hello-app\n",
|
||||
})
|
||||
cfg, err := Open(Options{Dir: dir, Environ: []string{}})
|
||||
if err != nil {
|
||||
t.Fatalf("Open: %v", err)
|
||||
}
|
||||
fsys := fstest.MapFS{
|
||||
"config/config.yaml": {Data: []byte("posts_per_page: 10\nshow_author: true\n")},
|
||||
}
|
||||
if err := cfg.MergePlugin("golem15.hello", fsys); err != nil {
|
||||
t.Fatalf("MergePlugin: %v", err)
|
||||
}
|
||||
if got := cfg.Int("golem15.hello.posts_per_page"); got != 10 {
|
||||
t.Fatalf("posts_per_page = %d, want 10", got)
|
||||
}
|
||||
if !cfg.Bool("golem15.hello.show_author") {
|
||||
t.Fatal("show_author should be true")
|
||||
}
|
||||
if !cfg.Has("golem15.hello.posts_per_page") {
|
||||
t.Fatal("Has(golem15.hello.posts_per_page) = false")
|
||||
}
|
||||
got, ok := cfg.Lookup("golem15.hello.posts_per_page")
|
||||
if !ok {
|
||||
t.Fatal("Lookup missing posts_per_page")
|
||||
}
|
||||
switch v := got.(type) {
|
||||
case int:
|
||||
if v != 10 {
|
||||
t.Fatalf("Lookup = %v, want 10", got)
|
||||
}
|
||||
case int64:
|
||||
if v != 10 {
|
||||
t.Fatalf("Lookup = %v, want 10", got)
|
||||
}
|
||||
case uint64:
|
||||
if v != 10 {
|
||||
t.Fatalf("Lookup = %v, want 10", got)
|
||||
}
|
||||
default:
|
||||
// YAML may decode as int or the getter path may return the raw value.
|
||||
if cfg.Int("golem15.hello.posts_per_page") != 10 {
|
||||
t.Fatalf("Lookup type %T value %v", got, got)
|
||||
}
|
||||
}
|
||||
|
||||
var section struct {
|
||||
PostsPerPage int `koanf:"posts_per_page"`
|
||||
ShowAuthor bool `koanf:"show_author"`
|
||||
}
|
||||
if err := cfg.LoadSection("golem15.hello", §ion); err != nil {
|
||||
t.Fatalf("LoadSection: %v", err)
|
||||
}
|
||||
if section.PostsPerPage != 10 || !section.ShowAuthor {
|
||||
t.Fatalf("LoadSection = %+v", section)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvVarsOverridePluginDefaults(t *testing.T) {
|
||||
dir := writeConfigTree(t, map[string]string{
|
||||
"app.yaml": "name: hello-app\n",
|
||||
})
|
||||
cfg, err := Open(Options{
|
||||
Dir: dir,
|
||||
Environ: []string{
|
||||
"SUMMER_GOLEM15__HELLO__POSTS_PER_PAGE=25",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Open: %v", err)
|
||||
}
|
||||
fsys := fstest.MapFS{
|
||||
"config/config.yaml": {Data: []byte("posts_per_page: 10\n")},
|
||||
}
|
||||
if err := cfg.MergePlugin("golem15.hello", fsys); err != nil {
|
||||
t.Fatalf("MergePlugin: %v", err)
|
||||
}
|
||||
if got := cfg.Int("golem15.hello.posts_per_page"); got != 25 {
|
||||
t.Fatalf("posts_per_page = %d, want 25 (env over plugin default)", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPriorityRuntimeSetThenPersistThenEnvThenOverlayThenBaseThenPlugin(t *testing.T) {
|
||||
dir := writeConfigTree(t, map[string]string{
|
||||
"app.yaml": "name: base\n",
|
||||
"env/development/app.yaml": "name: overlay\n",
|
||||
"env/development/overrides.yaml": "app:\n name: persisted\n",
|
||||
})
|
||||
cfg, err := Open(Options{
|
||||
Dir: dir,
|
||||
Env: "development",
|
||||
Environ: []string{"SUMMER_APP__NAME=from-env"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Open: %v", err)
|
||||
}
|
||||
if got := cfg.String("app.name"); got != "persisted" {
|
||||
t.Fatalf("before Set, name = %q, want persisted", got)
|
||||
}
|
||||
if err := cfg.Set("app.name", "runtime"); err != nil {
|
||||
t.Fatalf("Set: %v", err)
|
||||
}
|
||||
if got := cfg.String("app.name"); got != "runtime" {
|
||||
t.Fatalf("after Set, name = %q, want runtime", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortedSectionFilesLoadDeterministically(t *testing.T) {
|
||||
dir := writeConfigTree(t, map[string]string{
|
||||
"b.yaml": "value: b\n",
|
||||
"a.yaml": "value: a\nshared: 1\n",
|
||||
})
|
||||
cfg, err := Open(Options{Dir: dir, Environ: []string{}})
|
||||
if err != nil {
|
||||
t.Fatalf("Open: %v", err)
|
||||
}
|
||||
if got := cfg.String("a.value"); got != "a" {
|
||||
t.Fatalf("a.value = %q, want a", got)
|
||||
}
|
||||
if got := cfg.String("b.value"); got != "b" {
|
||||
t.Fatalf("b.value = %q, want b", got)
|
||||
}
|
||||
if got := cfg.Int("a.shared"); got != 1 {
|
||||
t.Fatalf("a.shared = %d, want 1", got)
|
||||
}
|
||||
}
|
||||
|
||||
func writeConfigTree(t *testing.T, files map[string]string) string {
|
||||
t.Helper()
|
||||
dir := t.TempDir()
|
||||
for name, body := range files {
|
||||
path := filepath.Join(dir, name)
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(path, []byte(body), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
return dir
|
||||
}
|
||||
|
||||
120
compass/env_test.go
Normal file
120
compass/env_test.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package compass
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEnvDoubleUnderscoreMapsToDotPath(t *testing.T) {
|
||||
dir := writeConfigTree(t, map[string]string{
|
||||
"database.yaml": "host: localhost\n",
|
||||
"app.yaml": "name: base\n",
|
||||
})
|
||||
cfg, err := Open(Options{
|
||||
Dir: dir,
|
||||
Environ: []string{
|
||||
"SUMMER_DATABASE__HOST=from-env",
|
||||
"SUMMER_GOLEM15__HELLO__POSTS_PER_PAGE=25",
|
||||
"IGNORED_VALUE=nope",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Open: %v", err)
|
||||
}
|
||||
if got := cfg.String("database.host"); got != "from-env" {
|
||||
t.Fatalf("database.host = %q, want from-env", got)
|
||||
}
|
||||
if got := cfg.Int("golem15.hello.posts_per_page"); got != 25 {
|
||||
t.Fatalf("golem15.hello.posts_per_page = %d, want 25", got)
|
||||
}
|
||||
if cfg.Has("ignored_value") || cfg.Has("IGNORED_VALUE") {
|
||||
t.Fatal("non-SUMMER_ variables must not enter config")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSingleUnderscoreRemainsLiteralLeaf(t *testing.T) {
|
||||
dir := writeConfigTree(t, map[string]string{
|
||||
"app.yaml": "name: base\n",
|
||||
})
|
||||
cfg, err := Open(Options{
|
||||
Dir: dir,
|
||||
Environ: []string{
|
||||
"SUMMER_GOLEM15__HELLO__POSTS_PER_PAGE=9",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Open: %v", err)
|
||||
}
|
||||
if !cfg.Has("golem15.hello.posts_per_page") {
|
||||
t.Fatal("expected golem15.hello.posts_per_page")
|
||||
}
|
||||
if cfg.Has("golem15.hello.posts.per.page") {
|
||||
t.Fatal("single underscores must not become path separators")
|
||||
}
|
||||
if got := cfg.Int("golem15.hello.posts_per_page"); got != 9 {
|
||||
t.Fatalf("posts_per_page = %d, want 9", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDotEnvFillsOnlyAbsentRealEnvKeysAndDoesNotMutateProcess(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
dir := filepath.Join(root, "config")
|
||||
if err := os.Mkdir(dir, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(dir, "app.yaml"), []byte("name: base\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dotenv := "SUMMER_APP__NAME=from-dotenv\nSUMMER_DATABASE__HOST=dotenv-host\n"
|
||||
if err := os.WriteFile(filepath.Join(root, ".env"), []byte(dotenv), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
const sentinel = "SUMMER_COMPASS_DOTENV_SENTINEL"
|
||||
if _, ok := os.LookupEnv(sentinel); ok {
|
||||
t.Fatalf("%s already set in process env", sentinel)
|
||||
}
|
||||
|
||||
cfg, err := Open(Options{
|
||||
Dir: dir,
|
||||
Environ: []string{
|
||||
"SUMMER_APP__NAME=from-real",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Open: %v", err)
|
||||
}
|
||||
if got := cfg.String("app.name"); got != "from-real" {
|
||||
t.Fatalf("app.name = %q, want from-real (real env wins over .env)", got)
|
||||
}
|
||||
if got := cfg.String("database.host"); got != "dotenv-host" {
|
||||
t.Fatalf("database.host = %q, want dotenv-host (.env fills absent keys)", got)
|
||||
}
|
||||
if _, ok := os.LookupEnv("SUMMER_DATABASE__HOST"); ok {
|
||||
t.Fatal("Open must not mutate process environment with .env values")
|
||||
}
|
||||
if _, ok := os.LookupEnv(sentinel); ok {
|
||||
t.Fatal("Open must not mutate process environment")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSUMMER_ENVFromProcessSelectsOverlay(t *testing.T) {
|
||||
dir := writeConfigTree(t, map[string]string{
|
||||
"app.yaml": "name: base\n",
|
||||
"env/development/app.yaml": "name: hello-dev\n",
|
||||
})
|
||||
cfg, err := Open(Options{
|
||||
Dir: dir,
|
||||
Environ: []string{"SUMMER_ENV=development"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Open: %v", err)
|
||||
}
|
||||
if cfg.Environment() != "development" {
|
||||
t.Fatalf("Environment = %q, want development", cfg.Environment())
|
||||
}
|
||||
if got := cfg.String("app.name"); got != "hello-dev" {
|
||||
t.Fatalf("name = %q, want hello-dev", got)
|
||||
}
|
||||
}
|
||||
117
compass/persist_test.go
Normal file
117
compass/persist_test.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package compass
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
)
|
||||
|
||||
func TestSetWinsOverPersistedOverrides(t *testing.T) {
|
||||
dir := writeConfigTree(t, map[string]string{
|
||||
"app.yaml": "name: base\n",
|
||||
"env/development/overrides.yaml": "app:\n name: persisted\n",
|
||||
})
|
||||
cfg, err := Open(Options{Dir: dir, Env: "development", Environ: []string{}})
|
||||
if err != nil {
|
||||
t.Fatalf("Open: %v", err)
|
||||
}
|
||||
if got := cfg.String("app.name"); got != "persisted" {
|
||||
t.Fatalf("loaded persisted name = %q, want persisted", got)
|
||||
}
|
||||
if err := cfg.Set("app.name", "runtime"); err != nil {
|
||||
t.Fatalf("Set: %v", err)
|
||||
}
|
||||
if got := cfg.String("app.name"); got != "runtime" {
|
||||
t.Fatalf("Set should win, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPersistWritesEnvOverridesAtomicallyWithRestrictivePerms(t *testing.T) {
|
||||
dir := writeConfigTree(t, map[string]string{
|
||||
"app.yaml": "name: base\n",
|
||||
})
|
||||
cfg, err := Open(Options{Dir: dir, Env: "development", Environ: []string{}})
|
||||
if err != nil {
|
||||
t.Fatalf("Open: %v", err)
|
||||
}
|
||||
if err := cfg.Set("app.name", "saved"); err != nil {
|
||||
t.Fatalf("Set: %v", err)
|
||||
}
|
||||
if err := cfg.Persist(); err != nil {
|
||||
t.Fatalf("Persist: %v", err)
|
||||
}
|
||||
path := filepath.Join(dir, "env", "development", "overrides.yaml")
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
t.Fatalf("stat overrides: %v", err)
|
||||
}
|
||||
if info.Mode().Perm() != 0o600 {
|
||||
t.Fatalf("overrides perm = %o, want 0600", info.Mode().Perm())
|
||||
}
|
||||
body, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(string(body), "saved") {
|
||||
t.Fatalf("overrides.yaml = %q, want to contain saved", body)
|
||||
}
|
||||
tmp := filepath.Join(dir, "env", "development", "overrides.yaml.tmp")
|
||||
if _, err := os.Stat(tmp); !os.IsNotExist(err) {
|
||||
t.Fatalf("temporary persist file should not remain: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReloadClearsSetAndRereadsFiles(t *testing.T) {
|
||||
dir := writeConfigTree(t, map[string]string{
|
||||
"app.yaml": "name: base\n",
|
||||
})
|
||||
cfg, err := Open(Options{Dir: dir, Env: "development", Environ: []string{}})
|
||||
if err != nil {
|
||||
t.Fatalf("Open: %v", err)
|
||||
}
|
||||
fsys := fstest.MapFS{
|
||||
"config/config.yaml": {Data: []byte("posts_per_page: 10\n")},
|
||||
}
|
||||
if err := cfg.MergePlugin("golem15.hello", fsys); err != nil {
|
||||
t.Fatalf("MergePlugin: %v", err)
|
||||
}
|
||||
if err := cfg.Set("app.name", "runtime"); err != nil {
|
||||
t.Fatalf("Set: %v", err)
|
||||
}
|
||||
if err := cfg.Persist(); err != nil {
|
||||
t.Fatalf("Persist: %v", err)
|
||||
}
|
||||
if err := cfg.Set("app.name", "runtime2"); err != nil {
|
||||
t.Fatalf("Set runtime2: %v", err)
|
||||
}
|
||||
if err := cfg.Set("golem15.hello.posts_per_page", 99); err != nil {
|
||||
t.Fatalf("Set posts: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(dir, "app.yaml"), []byte("name: disk\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := cfg.Reload(); err != nil {
|
||||
t.Fatalf("Reload: %v", err)
|
||||
}
|
||||
if got := cfg.String("app.name"); got != "runtime" {
|
||||
t.Fatalf("after Reload, name = %q, want persisted runtime (Set cleared)", got)
|
||||
}
|
||||
if got := cfg.Int("golem15.hello.posts_per_page"); got != 10 {
|
||||
t.Fatalf("after Reload, posts_per_page = %d, want plugin default 10", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPersistRejectsInvalidEnvName(t *testing.T) {
|
||||
dir := writeConfigTree(t, map[string]string{
|
||||
"app.yaml": "name: base\n",
|
||||
})
|
||||
_, err := Open(Options{Dir: dir, Env: "../etc", Environ: []string{}})
|
||||
if err == nil {
|
||||
t.Fatal("expected invalid environment name to fail")
|
||||
}
|
||||
if strings.Contains(strings.ToLower(err.Error()), "etc") {
|
||||
t.Fatalf("error should not echo unsanitized env path: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -9,14 +9,42 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGreeterHelloPrintsAppName(t *testing.T) {
|
||||
func TestGreeterHelloPrintsLayeredConfig(t *testing.T) {
|
||||
got := runHello(t, nil)
|
||||
want := "name=hello-app posts_per_page=10 debug=false"
|
||||
if got != want {
|
||||
t.Fatalf("output = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGreeterHelloSeesDevelopmentOverlay(t *testing.T) {
|
||||
got := runHello(t, map[string]string{"SUMMER_ENV": "development"})
|
||||
want := "name=hello-dev posts_per_page=10 debug=true"
|
||||
if got != want {
|
||||
t.Fatalf("output = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGreeterHelloSeesEnvVarOverrideOfPluginDefault(t *testing.T) {
|
||||
got := runHello(t, map[string]string{
|
||||
"SUMMER_GOLEM15__HELLO__POSTS_PER_PAGE": "25",
|
||||
})
|
||||
want := "name=hello-app posts_per_page=25 debug=false"
|
||||
if got != want {
|
||||
t.Fatalf("output = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func runHello(t *testing.T, env map[string]string) string {
|
||||
t.Helper()
|
||||
for k, v := range env {
|
||||
t.Setenv(k, v)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := run([]string{"greeter:hello"}, &buf); err != nil {
|
||||
t.Fatalf("greeter:hello: %v", err)
|
||||
}
|
||||
if got := strings.TrimSpace(buf.String()); got != "hello-app" {
|
||||
t.Fatalf("output = %q, want %q", got, "hello-app")
|
||||
}
|
||||
return strings.TrimSpace(buf.String())
|
||||
}
|
||||
|
||||
func TestBuiltBinaryGreeterHello(t *testing.T) {
|
||||
@@ -33,8 +61,8 @@ func TestBuiltBinaryGreeterHello(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("bin/hello greeter:hello: %v\n%s", err, out)
|
||||
}
|
||||
if got := strings.TrimSpace(string(out)); got != "hello-app" {
|
||||
t.Fatalf("output = %q, want %q", got, "hello-app")
|
||||
if got := strings.TrimSpace(string(out)); got != "name=hello-app posts_per_page=10 debug=false" {
|
||||
t.Fatalf("output = %q, want layered production config", got)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package party
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
|
||||
"git.golem15.com/golem15/summercms/backpack"
|
||||
"git.golem15.com/golem15/summercms/compass"
|
||||
@@ -27,6 +31,51 @@ func (p *tracePlugin) Boot(*backpack.App) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type configPlugin struct {
|
||||
id string
|
||||
fsys fs.FS
|
||||
got *int
|
||||
}
|
||||
|
||||
func (p *configPlugin) ID() string { return p.id }
|
||||
func (p *configPlugin) Requires() []string { return nil }
|
||||
func (p *configPlugin) ConfigFS() fs.FS { return p.fsys }
|
||||
|
||||
func (p *configPlugin) Register(app *backpack.App) error {
|
||||
if app != nil && app.Config != nil {
|
||||
*p.got = app.Config.Int("golem15.hello.posts_per_page")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *configPlugin) Boot(*backpack.App) error { return nil }
|
||||
|
||||
func TestActivateMergesHasConfigBeforeRegister(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
if err := os.WriteFile(filepath.Join(dir, "app.yaml"), []byte("name: app\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cfg, err := compass.Load(dir)
|
||||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
var got int
|
||||
p := &configPlugin{
|
||||
id: "golem15.hello",
|
||||
got: &got,
|
||||
fsys: fstest.MapFS{
|
||||
"config/config.yaml": {Data: []byte("posts_per_page: 10\n")},
|
||||
},
|
||||
}
|
||||
app := backpack.New(cfg)
|
||||
if _, err := activate([]Plugin{p}, app, []string{"golem15.hello"}); err != nil {
|
||||
t.Fatalf("activate: %v", err)
|
||||
}
|
||||
if got != 10 {
|
||||
t.Fatalf("posts_per_page during Register = %d, want 10 (HasConfig must merge before Register)", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActivateRunsAllRegisterBeforeAnyBoot(t *testing.T) {
|
||||
var log []string
|
||||
hello := &tracePlugin{id: "golem15.hello", log: &log}
|
||||
|
||||
Reference in New Issue
Block a user