package config import ( "os" "path/filepath" "reflect" "testing" "time" ) func TestExampleParses(t *testing.T) { path := filepath.Join(t.TempDir(), "jarl.yaml") os.WriteFile(path, []byte(Example), 0o644) c, err := Load(path, false) if err != nil { t.Fatal(err) } d := Default() if c.BIND.ZoneDir != d.BIND.ZoneDir || time.Duration(c.Session.IdleTimeout) != 2*time.Hour || c.Listen[0] != "127.0.0.1:8053" { t.Errorf("example differs from defaults: %+v", c) } if !reflect.DeepEqual(c.ACME, d.ACME) || !reflect.DeepEqual(c.Certificates, d.Certificates) || c.ACME.HTTPReq.Enabled || !c.ACME.HTTPReq.RequireHTTPS { t.Errorf("acme = %+v, want the defaults %+v", c.ACME, d.ACME) } } func TestHTTPReqDefaults(t *testing.T) { path := filepath.Join(t.TempDir(), "jarl.yaml") // Enabling the endpoint keeps require_https on unless it is turned off. os.WriteFile(path, []byte("acme: {httpreq: {enabled: true}}\n"), 0o644) c, err := Load(path, false) if err != nil { t.Fatal(err) } if h := c.ACME.HTTPReq; !h.Enabled || !h.RequireHTTPS || h.AllowLoopbackHTTP { t.Errorf("httpreq = %+v", h) } } func TestLoad(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "jarl.yaml") os.WriteFile(path, []byte("listen: [\"0.0.0.0:8443\"]\ntls: {cert_file: /a, key_file: /b}\ntrusted_proxies: [10.0.0.1, 192.168.0.0/16]\nsession: {lifetime: 1d}\n"), 0o644) c, err := Load(path, false) if err != nil { t.Fatal(err) } if time.Duration(c.Session.Lifetime) != 24*time.Hour || len(c.Proxies()) != 2 || c.BIND.FileGroup != "bind" { t.Errorf("config = %+v", c) } os.WriteFile(path, []byte("lisen: []\n"), 0o644) if _, err := Load(path, false); err == nil { t.Error("unknown field accepted") } os.WriteFile(path, []byte("tls: {cert_file: /a}\n"), 0o644) if _, err := Load(path, false); err == nil { t.Error("half TLS config accepted") } if _, err := Load(filepath.Join(dir, "missing.yaml"), true); err != nil { t.Errorf("missing file with allowMissing: %v", err) } } func TestStatsConfig(t *testing.T) { d := Default() if d.Stats.Enabled || !d.Stats.QueryLog || d.Stats.TopN != 100 || time.Duration(d.Stats.Retention.Hour) != 90*24*time.Hour { t.Errorf("defaults = %+v", d.Stats) } dir := t.TempDir() path := filepath.Join(dir, "jarl.yaml") for _, tc := range []struct { yaml string ok bool }{ {"stats: {enabled: true}", true}, {"stats: {enabled: true, query_log: false, retention: {minute: 2d}}", true}, {"stats: {enabled: true, statistics_channel: 0.0.0.0:8058}", false}, // must be loopback {"stats: {enabled: true, statistics_channel: localhost}", false}, {"stats: {enabled: true, log_size: lots}", false}, {"stats: {enabled: true, retention: {minute: 10m}}", false}, {"stats: {enabled: true, exclude_clients: [not-an-ip]}", false}, {"stats: {enabled: false, statistics_channel: nonsense}", true}, // only checked when enabled } { os.WriteFile(path, []byte(tc.yaml+"\n"), 0o644) _, err := Load(path, false) if (err == nil) != tc.ok { t.Errorf("%s: err = %v, want ok=%v", tc.yaml, err, tc.ok) } } } func TestMetricsConfig(t *testing.T) { d := Default() if d.Metrics.Enabled || len(d.Metrics.AllowPrefixes()) != 2 || d.Metrics.Token != "" { t.Errorf("defaults = %+v", d.Metrics) } path := filepath.Join(t.TempDir(), "jarl.yaml") for _, tc := range []struct { yaml string ok bool }{ {"metrics: {enabled: true}", true}, {"metrics: {enabled: true, listen: [\"0.0.0.0:9450\", \"[::]:9450\"], allow: [10.0.0.5, 192.168.1.0/24]}", true}, {"metrics: {enabled: true, allow: [], token: 0123456789abcdef}", true}, {"metrics: {enabled: true, allow: []}", false}, // nobody could scrape {"metrics: {enabled: true, token: short}", false}, {"metrics: {enabled: true, token: \"has space 0123456789\"}", false}, {"metrics: {enabled: true, listen: [\"9450\"]}", false}, {"metrics: {enabled: true, allow: [prometheus.lan]}", false}, {"metrics: {enabled: false, listen: [nonsense]}", true}, // only checked when enabled } { os.WriteFile(path, []byte(tc.yaml+"\n"), 0o644) _, err := Load(path, false) if (err == nil) != tc.ok { t.Errorf("%s: err = %v, want ok=%v", tc.yaml, err, tc.ok) } } }