// Copyright 2022 schukai GmbH // SPDX-License-Identifier: AGPL-3.0 package configuration import ( "github.com/stretchr/testify/assert" "os" "sync" "testing" "time" ) func runTestFilesChange(fn string, data []testHostTimeout, t *testing.T) { for _, x := range data { h := x.host b := []byte("Host: \"" + h + "\"") err := os.WriteFile(fn, b, 0644) if err != nil { t.Error(err) return } time.Sleep(x.timeout) } } func createTestFileForWatch1() (string, error) { f, err := os.CreateTemp("", "watch_test") if err != nil { return "", err } _, _ = f.WriteString("Host: \"127.0.0.1\"") _ = f.Close() return f.Name(), nil } type testHostTimeout struct { host string timeout time.Duration } func TestMultiChange(t *testing.T) { tmpFn, err := createTestFileForWatch1() if err != nil { t.Error(err) return } defer func() { err := os.Remove(tmpFn) if err != nil { t.Error(err) } }() config := struct { Host string `yaml:"Host"` }{ Host: "localhost", } c := New(config) c.SetMnemonic("my-app") assert.Equal(t, c.Config().Host, "localhost") var mu sync.Mutex result := []string{} signal := make(chan string) var h ChangeHook h = &ChangeEventHandler{ Callback: func(event ChangeEvent) { mu.Lock() result = append(result, event.Changelog[0].To.(string)) mu.Unlock() signal <- event.Changelog[0].To.(string) }, } var e ErrorHook e = &ErrorEventHandler{ Callback: func(event ErrorEvent) { //for _, err := range c.Errors() { // t.Error(err) //} }, } c.AddFile(tmpFn, Yaml) c.Import() if c.HasErrors() { t.Error(c.Errors()) } data := []testHostTimeout{ // important to have a timeout > 500ms, because the decoupled file watcher will only trigger every 500ms { host: "1.org", timeout: time.Millisecond * 550, }, { host: "2.org", timeout: time.Millisecond * 610, }, { host: "3.org", timeout: time.Millisecond * 602, }, { host: "4.org", timeout: time.Millisecond * 700, }, { host: "9.org", timeout: time.Millisecond * 700, }, } c.OnChange(h).OnError(e).Watch() go runTestFilesChange(tmpFn, data, t) mu.Lock() length := len(result) mu.Unlock() for length < len(data) { select { case <-signal: mu.Lock() length = len(result) mu.Unlock() continue case <-time.After(time.Second * 20): t.Log(result) t.Fatalf("Timeout") } } assert.Equal(t, "9.org", c.Config().Host) } func TestWatch(t *testing.T) { f, err := os.CreateTemp("", "watch_test") if err != nil { t.Error(err) return } defer os.Remove(f.Name()) config := struct { Host string `yaml:"Host"` }{ Host: "localhost", } c := New(config) c.SetMnemonic("my-app") assert.Equal(t, c.Config().Host, "localhost") c.AddFile(f.Name(), Yaml) c.Import() signal := make(chan bool) var h ChangeHook h = &ChangeEventHandler{ Callback: func(event ChangeEvent) { assert.Equal(t, event.Changelog[0].From, "localhost") assert.Equal(t, event.Changelog[0].To, "example.org") signal <- true }, } c.OnChange(h) c.Watch() _, err = f.WriteString("Host: example.org") if err != nil { t.Error(err) return } select { case <-signal: assert.Equal(t, c.Config().Host, "example.org") case <-time.After(time.Second): t.Fatalf("Timeout") } } func TestSettingStopWatching(t *testing.T) { f, err := os.CreateTemp("", "watch_test") if err != nil { t.Error(err) return } defer func() { _ = os.Remove(f.Name()) _ = f.Close() }() config := struct { Host string `yaml:"Host"` }{ Host: "localhost", } c := New(config) c.SetMnemonic("my-app") assert.Equal(t, c.Config().Host, "localhost") c.AddFile(f.Name(), Yaml) c.Import().ResetErrors() // Import error is not relevant here c.Watch() c.StopWatching() if c.HasErrors() { t.Error(c.Errors()) } } func TestSettingStopWatchingNotOnWatch(t *testing.T) { config := struct { Host string `yaml:"Host"` }{ Host: "localhost", } c := New(config) c.StopWatching() if c.HasErrors() { t.Error("Expected to have no error") } } func TestSettingStopWatchingTwice(t *testing.T) { f, err := os.CreateTemp("", "watch_test") if err != nil { t.Error(err) return } defer func() { _ = os.Remove(f.Name()) _ = f.Close() }() config := struct { Host string `yaml:"Host"` }{ Host: "localhost", } _, _ = f.WriteString("Host: example.org") c := New(config) c.AddFile(f.Name(), Yaml) c.Import() c.Watch() c.StopWatching() c.StopWatching() e := c.Errors() if len(e) != 1 { t.Error("Expected to have an error") } errText := e[0].Error() assert.Equal(t, errText, "Watcher is not active") }