diff options
Diffstat (limited to 'internal/service/file_watcher_test.go')
| -rw-r--r-- | internal/service/file_watcher_test.go | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/internal/service/file_watcher_test.go b/internal/service/file_watcher_test.go new file mode 100644 index 000000000..f4dce095f --- /dev/null +++ b/internal/service/file_watcher_test.go @@ -0,0 +1,211 @@ +package service + +import ( + "context" + "os" + "path/filepath" + "regexp" + "testing" + "time" + + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/authelia/authelia/v4/internal/authentication" + "github.com/authelia/authelia/v4/internal/configuration/schema" + "github.com/authelia/authelia/v4/internal/logging" + "github.com/authelia/authelia/v4/internal/middlewares" + "github.com/authelia/authelia/v4/internal/templates" +) + +func TestProvisionUsersFileWatcher(t *testing.T) { + dir := t.TempDir() + + f, err := os.Create(filepath.Join(dir, "users.yml")) + require.NoError(t, err) + require.NoError(t, f.Close()) + + tx, err := templates.New(templates.Config{}) + require.NoError(t, err) + + address, err := schema.NewAddress("tcp://:9091") + require.NoError(t, err) + + config := &schema.Configuration{ + Server: schema.Server{ + Address: &schema.AddressTCP{Address: *address}, + }, + } + + provision := ProvisionUsersFileWatcher + + ctx := &testCtx{ + Context: context.Background(), + Configuration: config, + Providers: middlewares.Providers{ + Templates: tx, + }, + Logger: logrus.NewEntry(logging.Logger()), + } + + watcher, err := provision(ctx) + assert.NoError(t, err) + assert.Nil(t, watcher) + + watcher, err = provision(ctx) + assert.NoError(t, err) + assert.Nil(t, watcher) + + config.AuthenticationBackend.File = &schema.AuthenticationBackendFile{ + Path: filepath.Join(dir, "users.yml"), + Watch: true, + } + + watcher, err = provision(ctx) + assert.EqualError(t, err, "error occurred asserting user provider") + assert.Nil(t, watcher) + + ctx.Providers.UserProvider = authentication.NewFileUserProvider(config.AuthenticationBackend.File) + + config.AuthenticationBackend.File = &schema.AuthenticationBackendFile{ + Watch: true, + } + + watcher, err = provision(ctx) + assert.EqualError(t, err, "error initializing file watcher: path must be specified") + assert.Nil(t, watcher) + + config.AuthenticationBackend.File = &schema.AuthenticationBackendFile{ + Path: filepath.Join(dir, "users.yml"), + Watch: true, + } + + watcher, err = provision(ctx) + assert.NoError(t, err) + assert.NotNil(t, watcher) + assert.NotNil(t, watcher.Log()) + assert.Equal(t, "users", watcher.ServiceName()) + assert.Equal(t, "watcher", watcher.ServiceType()) + + watcher.Shutdown() +} + +func TestNewFileWatcher(t *testing.T) { + dir := t.TempDir() + + reloader := &testReloader{reload: true} + + f, err := os.Create(filepath.Join(dir, "test.log")) + require.NoError(t, err) + + service, err := NewFileWatcher("example", filepath.Join(dir, "test.log"), reloader, logrus.NewEntry(logging.Logger())) + + assert.NoError(t, err) + + go func() { + require.NoError(t, service.Run()) + }() + + // Give the service a moment to start. + time.Sleep(100 * time.Millisecond) + + _, err = f.Write([]byte("test")) + require.NoError(t, err) + + require.NoError(t, f.Close()) + + time.Sleep(time.Second) + + assert.Equal(t, 1, reloader.count) + + assert.NoError(t, os.WriteFile(filepath.Join(dir, "test2.log"), []byte("test"), 0600)) + + assert.Equal(t, 1, reloader.count) + + assert.NoError(t, os.Remove(filepath.Join(dir, "test2.log"))) + + assert.Equal(t, 1, reloader.count) + + service.Shutdown() +} + +func TestNewFileWatcherDirectory(t *testing.T) { + dir := t.TempDir() + + reloader := &testReloader{reload: true} + + service, err := NewFileWatcher("example", dir, reloader, logrus.NewEntry(logging.Logger())) + + assert.NoError(t, err) + + go func() { + require.NoError(t, service.Run()) + }() + + // Give the service a moment to start. + time.Sleep(100 * time.Millisecond) + + f, err := os.Create(filepath.Join(dir, "test.log")) + require.NoError(t, err) + + _, err = f.Write([]byte("test")) + require.NoError(t, err) + + require.NoError(t, f.Close()) + + time.Sleep(time.Second) + + assert.Equal(t, 2, reloader.count) + + service.Shutdown() +} + +func TestNewFileWatcherBadPath(t *testing.T) { + dir := t.TempDir() + + reloader := &testReloader{reload: true} + + service, err := NewFileWatcher("example", filepath.Join(dir, "test.log"), reloader, logrus.NewEntry(logging.Logger())) + + require.Error(t, err) + assert.Regexp(t, regexp.MustCompile(`^error initializing file watcher: error stating file '/tmp/[^/]+/\d+/test.log': file does not exist$`), err.Error()) + + assert.Nil(t, service) +} + +func TestNewFileWatcherBadPermission(t *testing.T) { + dir := t.TempDir() + + reloader := &testReloader{reload: true} + + require.NoError(t, os.Mkdir(filepath.Join(dir, "tmp"), 0700)) + + f, err := os.Create(filepath.Join(dir, "tmp", "test.log")) + + require.NoError(t, err) + require.NoError(t, f.Close()) + + require.NoError(t, os.Chmod(filepath.Join(dir, "tmp"), 0o000)) + + service, err := NewFileWatcher("example", filepath.Join(dir, "tmp", "test.log"), reloader, logrus.NewEntry(logging.Logger())) + + require.Error(t, err) + assert.Regexp(t, regexp.MustCompile(`^error initializing file watcher: error stating file '/tmp/[^/]+/\d+/tmp/test.log': permission denied trying to read the file$`), err.Error()) + + require.NoError(t, os.Chmod(filepath.Join(dir, "tmp"), 0o700)) + + assert.Nil(t, service) +} + +type testReloader struct { + count int + reload bool + err error +} + +func (r *testReloader) Reload() (bool, error) { + r.count++ + + return r.reload, r.err +} |
