| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- package config
- import (
- "errors"
- "log/slog"
- "testing"
- "github.com/slackhq/nebula/test"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- )
- func TestReloadConfigString(t *testing.T) {
- c := NewC(test.NewLogger())
- require.NoError(t, c.LoadString("a: 1"))
- fail := false
- ran := 0
- c.RegisterReloadCallback(func(c *C, r *Reload) {
- ran++
- if fail {
- r.Failed()
- }
- })
- assert.Equal(t, ReloadResult{}, c.ReloadConfigString("a: 2"))
- fail = true
- assert.Equal(t, ReloadResult{Failed: true}, c.ReloadConfigString("a: 3"))
- assert.Equal(t, 2, ran)
- // A config that fails to load runs no callbacks and returns the error
- res := c.ReloadConfigString("a: [")
- require.Error(t, res.Err)
- assert.False(t, res.Failed)
- assert.Equal(t, 2, ran)
- assert.Equal(t, 3, c.GetInt("a", 0))
- }
- func TestReloadRestartRequiredLatches(t *testing.T) {
- c := NewC(test.NewLogger())
- require.NoError(t, c.LoadString("a: 1\nb: 1"))
- c.RegisterReloadCallback(func(c *C, r *Reload) { r.RestartRequiredIfChanged("a", "b") })
- // Nothing that needs a restart changed
- assert.Equal(t, ReloadResult{}, c.ReloadConfigString("a: 1\nb: 1\nc: 1"))
- assert.Equal(t, ReloadResult{RestartRequired: true, RestartKeys: []string{"a"}}, c.ReloadConfigString("a: 2\nb: 1\nc: 1"))
- // The restart sticks through a reload with no changes, reverting the key and a config that fails to load. Only the
- // reload that changed the key lists it
- assert.Equal(t, ReloadResult{RestartRequired: true}, c.ReloadConfigString("a: 2\nb: 1\nc: 1"))
- assert.Equal(t, ReloadResult{RestartRequired: true, RestartKeys: []string{"a"}}, c.ReloadConfigString("a: 1\nb: 1\nc: 1"))
- res := c.ReloadConfigString("a: [")
- require.Error(t, res.Err)
- assert.True(t, res.RestartRequired)
- }
- // A key reported by more than one callback is listed once
- func TestReloadRestartKeysDeduped(t *testing.T) {
- c := NewC(test.NewLogger())
- require.NoError(t, c.LoadString("a: 1\nb: 1"))
- c.RegisterReloadCallback(func(c *C, r *Reload) { r.RestartRequiredIfChanged("a") })
- c.RegisterReloadCallback(func(c *C, r *Reload) { r.RestartRequiredIfChanged("a", "b") })
- assert.Equal(t, []string{"a", "b"}, c.ReloadConfigString("a: 2\nb: 2").RestartKeys)
- }
- // A callback can require a restart without a key changing, a file the config points at may have
- func TestReloadRestartRequiredWithoutAChange(t *testing.T) {
- c := NewC(test.NewLogger())
- require.NoError(t, c.LoadString("a: 1"))
- c.RegisterReloadCallback(func(c *C, r *Reload) { r.RestartRequired() })
- assert.Equal(t, ReloadResult{RestartRequired: true}, c.ReloadConfigString("a: 1"))
- }
- func TestReloadResultSummary(t *testing.T) {
- cases := []struct {
- res ReloadResult
- level slog.Level
- msg string
- }{
- {ReloadResult{}, slog.LevelInfo, "Config reload complete"},
- {ReloadResult{RestartRequired: true}, slog.LevelWarn, "Config reload was completed but requires a restart to fully apply"},
- {ReloadResult{Failed: true}, slog.LevelError, "Config reload completed with errors, review the logs"},
- {ReloadResult{Failed: true, RestartRequired: true}, slog.LevelError, "Config reload completed with errors and requires a restart to fully apply, review the logs"},
- {ReloadResult{Err: errors.New("bad yaml")}, slog.LevelError, "Config reload failed, the new config did not load"},
- {ReloadResult{Err: errors.New("bad yaml"), RestartRequired: true}, slog.LevelError, "Config reload failed, the new config did not load and a restart is still required"},
- }
- for _, tc := range cases {
- level, msg := tc.res.Summary()
- assert.Equal(t, tc.level, level, tc.msg)
- assert.Equal(t, tc.msg, msg)
- }
- res := ReloadResult{RestartRequired: true, RestartKeys: []string{"a", "b"}}
- assert.Equal(t, "Config reload was completed but requires a restart to fully apply, keys [a b]", res.String())
- // String includes the error
- assert.Equal(t, "Config reload failed, the new config did not load: bad yaml", ReloadResult{Err: errors.New("bad yaml")}.String())
- }
- // The initial load passes a nil Reload
- func TestReloadNilIsSafe(t *testing.T) {
- var r *Reload
- r.Failed()
- r.RestartRequired()
- r.RestartRequiredIfChanged("a")
- }
|