taler-merchant-demos

Python-based Frontends for the Demonstration Web site
Log | Files | Refs | README | LICENSE

config_test.go (6894B)


      1 package config
      2 
      3 import (
      4 	"bytes"
      5 	"fmt"
      6 	"os"
      7 	"path/filepath"
      8 	"slices"
      9 	"strings"
     10 	"testing"
     11 )
     12 
     13 func TestLoadIncludesOverridesAndExpands(t *testing.T) {
     14 	t.Setenv(baseConfigEnv, t.TempDir())
     15 	dir := t.TempDir()
     16 	child := filepath.Join(dir, "child.conf")
     17 	main := filepath.Join(dir, "main.conf")
     18 	if err := os.WriteFile(child, []byte("[taler]\ncurrency = TEST\n[paths]\nprefix = /srv/taler\n"), 0o600); err != nil {
     19 		t.Fatal(err)
     20 	}
     21 	if err := os.WriteFile(main, []byte("@INLINE@ child.conf\n[taler]\ncurrency = KUDOS\n[frontend-demo-blog]\nhttp_port = 8080\nhttp_unixpath = ${prefix}/blog.sock\n"), 0o600); err != nil {
     22 		t.Fatal(err)
     23 	}
     24 	c, err := Load(main)
     25 	if err != nil {
     26 		t.Fatal(err)
     27 	}
     28 	if got := c.Get("TALER", "CURRENCY"); got != "KUDOS" {
     29 		t.Fatalf("currency = %q", got)
     30 	}
     31 	if got := c.Filename("frontend-demo-blog", "http_unixpath"); got != "/srv/taler/blog.sock" {
     32 		t.Fatalf("expanded path = %q", got)
     33 	}
     34 	if got, err := c.Int("frontend-demo-blog", "http_port", 0); err != nil || got != 8080 {
     35 		t.Fatalf("port = %d, %v", got, err)
     36 	}
     37 }
     38 
     39 func TestIncludeCycle(t *testing.T) {
     40 	t.Setenv(baseConfigEnv, t.TempDir())
     41 	path := filepath.Join(t.TempDir(), "cycle.conf")
     42 	if err := os.WriteFile(path, []byte("@INLINE@ cycle.conf\n"), 0o600); err != nil {
     43 		t.Fatal(err)
     44 	}
     45 	_, err := Load(path)
     46 	if err == nil || !strings.Contains(err.Error(), "include cycle") {
     47 		t.Fatalf("unexpected error: %v", err)
     48 	}
     49 }
     50 
     51 func TestDumpIncludesLoadOrderAndWinningSources(t *testing.T) {
     52 	defaults := t.TempDir()
     53 	base := filepath.Join(defaults, "base.conf")
     54 	dir := t.TempDir()
     55 	child := filepath.Join(dir, "child.conf")
     56 	main := filepath.Join(dir, "main.conf")
     57 	if err := os.WriteFile(base, []byte("[demo]\ndefault = base\noverridden = base\n"), 0o600); err != nil {
     58 		t.Fatal(err)
     59 	}
     60 	if err := os.WriteFile(child, []byte("[child]\nvalue = included\n"), 0o600); err != nil {
     61 		t.Fatal(err)
     62 	}
     63 	if err := os.WriteFile(main, []byte("@INLINE@ child.conf\n[demo]\noverridden = main\n"), 0o600); err != nil {
     64 		t.Fatal(err)
     65 	}
     66 	t.Setenv(baseConfigEnv, defaults)
     67 
     68 	c, err := Load(main)
     69 	if err != nil {
     70 		t.Fatal(err)
     71 	}
     72 	var output bytes.Buffer
     73 	if err := c.Dump(&output); err != nil {
     74 		t.Fatal(err)
     75 	}
     76 	want := fmt.Sprintf(`#
     77 # Configuration file load order:
     78 # %s
     79 # %s
     80 # %s
     81 #
     82 
     83 [child]
     84 
     85 # %s:2
     86 value = included
     87 
     88 
     89 [demo]
     90 
     91 # %s:2
     92 default = base
     93 
     94 # %s:3
     95 overridden = main
     96 
     97 `, base, main, child, child, base, main)
     98 	if got := output.String(); got != want {
     99 		t.Fatalf("dump =\n%s\nwant:\n%s", got, want)
    100 	}
    101 }
    102 
    103 func TestLoadDefaultsFromMerchantDemosPrefix(t *testing.T) {
    104 	prefix := t.TempDir()
    105 	defaults := filepath.Join(prefix, "share", "taler-merchant-demos", "config.d")
    106 	if err := os.MkdirAll(defaults, 0o700); err != nil {
    107 		t.Fatal(err)
    108 	}
    109 	if err := os.WriteFile(filepath.Join(defaults, "demo.conf"), []byte("[taler]\ncurrency = DEFAULT\n"), 0o600); err != nil {
    110 		t.Fatal(err)
    111 	}
    112 	main := filepath.Join(t.TempDir(), "main.conf")
    113 	if err := os.WriteFile(main, []byte("[unrelated]\nvalue = main\n"), 0o600); err != nil {
    114 		t.Fatal(err)
    115 	}
    116 	t.Setenv(baseConfigEnv, "")
    117 	t.Setenv(prefixEnv, prefix)
    118 
    119 	c, err := Load(main)
    120 	if err != nil {
    121 		t.Fatal(err)
    122 	}
    123 	if got := c.Get("taler", "currency"); got != "DEFAULT" {
    124 		t.Fatalf("currency = %q, want DEFAULT", got)
    125 	}
    126 }
    127 
    128 func TestLoadOrderMatchesComponentConfiguration(t *testing.T) {
    129 	defaults := t.TempDir()
    130 	if err := os.WriteFile(filepath.Join(defaults, "b.conf"), []byte("[order]\nvalue = second-default\n"), 0o600); err != nil {
    131 		t.Fatal(err)
    132 	}
    133 	if err := os.WriteFile(filepath.Join(defaults, "a.conf"), []byte("[order]\nvalue = first-default\n"), 0o600); err != nil {
    134 		t.Fatal(err)
    135 	}
    136 	xdg := t.TempDir()
    137 	child := filepath.Join(xdg, "child.conf")
    138 	main := filepath.Join(xdg, configFilename)
    139 	if err := os.WriteFile(child, []byte("[order]\nvalue = inline\n"), 0o600); err != nil {
    140 		t.Fatal(err)
    141 	}
    142 	if err := os.WriteFile(main, []byte("@INLINE@ child.conf\n[order]\nvalue = main\n"), 0o600); err != nil {
    143 		t.Fatal(err)
    144 	}
    145 	t.Setenv(baseConfigEnv, defaults)
    146 	t.Setenv("XDG_CONFIG_HOME", xdg)
    147 
    148 	c, err := Load("")
    149 	if err != nil {
    150 		t.Fatal(err)
    151 	}
    152 	if got := c.Get("order", "value"); got != "main" {
    153 		t.Fatalf("value = %q, want main", got)
    154 	}
    155 	wantFiles := []string{
    156 		filepath.Join(defaults, "a.conf"),
    157 		filepath.Join(defaults, "b.conf"),
    158 		main,
    159 		child,
    160 	}
    161 	if got := c.loadedFiles; !slices.Equal(got, wantFiles) {
    162 		t.Fatalf("loaded files = %q, want %q", got, wantFiles)
    163 	}
    164 
    165 	explicit := filepath.Join(t.TempDir(), "explicit.conf")
    166 	if err := os.WriteFile(explicit, []byte("[order]\nvalue = explicit\n"), 0o600); err != nil {
    167 		t.Fatal(err)
    168 	}
    169 	c, err = Load(explicit)
    170 	if err != nil {
    171 		t.Fatal(err)
    172 	}
    173 	if got := c.Get("order", "value"); got != "explicit" {
    174 		t.Fatalf("value with explicit config = %q, want explicit", got)
    175 	}
    176 	wantFiles = []string{
    177 		filepath.Join(defaults, "a.conf"),
    178 		filepath.Join(defaults, "b.conf"),
    179 		explicit,
    180 	}
    181 	if got := c.loadedFiles; !slices.Equal(got, wantFiles) {
    182 		t.Fatalf("loaded files with explicit config = %q, want %q", got, wantFiles)
    183 	}
    184 }
    185 
    186 func TestLoadWithoutMainConfiguration(t *testing.T) {
    187 	defaults := t.TempDir()
    188 	if err := os.WriteFile(filepath.Join(defaults, "defaults.conf"), []byte("[demo]\nvalue = default\n"), 0o600); err != nil {
    189 		t.Fatal(err)
    190 	}
    191 	t.Setenv(baseConfigEnv, defaults)
    192 	t.Setenv("XDG_CONFIG_HOME", t.TempDir())
    193 
    194 	c, err := Load("")
    195 	if err != nil {
    196 		t.Fatal(err)
    197 	}
    198 	if got := c.Get("demo", "value"); got != "default" {
    199 		t.Fatalf("value = %q, want default", got)
    200 	}
    201 }
    202 
    203 func TestFilenameExpansionMatchesTalerSyntax(t *testing.T) {
    204 	t.Setenv("DEMO_ENV_ROOT", "/environment")
    205 	t.Setenv("DEMO_ENV_ONLY_ROOT", "/environment")
    206 	t.Setenv("DEMO_ENV_ALIAS", "$DEMO_ENV_ONLY_ROOT/from-env")
    207 	c := &Config{sections: map[string]map[string]string{
    208 		"paths": {
    209 			"root":          "/srv/taler",
    210 			"alias":         "${ROOT}/shared",
    211 			"empty":         "",
    212 			"cycle_one":     "$CYCLE_TWO",
    213 			"cycle_two":     "$CYCLE_ONE",
    214 			"demo_env_root": "/paths",
    215 		},
    216 		"demo": {
    217 			"recursive":   "${ALIAS}/socket",
    218 			"fallback":    "${MISSING_ONE:-${MISSING_TWO:-/tmp}}/socket",
    219 			"environment": "$DEMO_ENV_ALIAS/socket",
    220 			"precedence":  "$DEMO_ENV_ROOT/socket",
    221 			"empty":       "before${EMPTY:-fallback}after",
    222 			"unknown":     "$DEMO_NOT_DEFINED/socket",
    223 			"cycle":       "$CYCLE_ONE/socket",
    224 		},
    225 	}}
    226 
    227 	tests := map[string]string{
    228 		"recursive":   "/srv/taler/shared/socket",
    229 		"fallback":    "/tmp/socket",
    230 		"environment": "/environment/from-env/socket",
    231 		"precedence":  "/paths/socket",
    232 		"empty":       "beforeafter",
    233 		"unknown":     "$DEMO_NOT_DEFINED/socket",
    234 	}
    235 	for option, want := range tests {
    236 		if got := c.Filename("demo", option); got != want {
    237 			t.Errorf("%s expansion = %q, want %q", option, got, want)
    238 		}
    239 	}
    240 	if got := c.Filename("demo", "cycle"); !strings.Contains(got, "$CYCLE_") {
    241 		t.Fatalf("recursive expansion was not bounded: %q", got)
    242 	}
    243 }