mirror of
https://github.com/coder/coder.git
synced 2026-06-03 21:18:24 +00:00
140 lines
4.2 KiB
Go
140 lines
4.2 KiB
Go
package watcher_test
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"testing"
|
|
|
|
"github.com/fsnotify/fsnotify"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/coder/coder/v2/agent/agentcontainers/watcher"
|
|
"github.com/coder/coder/v2/testutil"
|
|
)
|
|
|
|
func TestFSNotifyWatcher(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Create test files.
|
|
dir := t.TempDir()
|
|
testFile := filepath.Join(dir, "test.json")
|
|
err := os.WriteFile(testFile, []byte(`{"test": "initial"}`), 0o600)
|
|
require.NoError(t, err, "create test file failed")
|
|
|
|
// Create the watcher under test.
|
|
wut, err := watcher.NewFSNotify()
|
|
require.NoError(t, err, "create FSNotify watcher failed")
|
|
defer wut.Close()
|
|
|
|
// Add the test file to the watch list.
|
|
err = wut.Add(testFile)
|
|
require.NoError(t, err, "add file to watcher failed")
|
|
|
|
ctx := testutil.Context(t, testutil.WaitShort)
|
|
|
|
// Modify the test file to trigger an event.
|
|
err = os.WriteFile(testFile, []byte(`{"test": "modified"}`), 0o600)
|
|
require.NoError(t, err, "modify test file failed")
|
|
|
|
// Verify that we receive the event we want.
|
|
for {
|
|
event, err := wut.Next(ctx)
|
|
require.NoError(t, err, "next event failed")
|
|
|
|
require.NotNil(t, event, "want non-nil event")
|
|
if !event.Has(fsnotify.Write) {
|
|
t.Logf("Ignoring event: %s", event)
|
|
continue
|
|
}
|
|
require.Truef(t, event.Has(fsnotify.Write), "want write event: %s", event.String())
|
|
require.Equal(t, event.Name, testFile, "want event for test file")
|
|
break
|
|
}
|
|
|
|
// Rename the test file to trigger a rename event.
|
|
err = os.Rename(testFile, testFile+".bak")
|
|
require.NoError(t, err, "rename test file failed")
|
|
|
|
// Verify that we receive the event we want.
|
|
for {
|
|
event, err := wut.Next(ctx)
|
|
require.NoError(t, err, "next event failed")
|
|
require.NotNil(t, event, "want non-nil event")
|
|
if !event.Has(fsnotify.Rename) {
|
|
t.Logf("Ignoring event: %s", event)
|
|
continue
|
|
}
|
|
require.Truef(t, event.Has(fsnotify.Rename), "want rename event: %s", event.String())
|
|
require.Equal(t, event.Name, testFile, "want event for test file")
|
|
break
|
|
}
|
|
|
|
err = os.WriteFile(testFile, []byte(`{"test": "new"}`), 0o600)
|
|
require.NoError(t, err, "write new test file failed")
|
|
|
|
// Verify that we receive the event we want.
|
|
for {
|
|
event, err := wut.Next(ctx)
|
|
require.NoError(t, err, "next event failed")
|
|
require.NotNil(t, event, "want non-nil event")
|
|
if !event.Has(fsnotify.Create) {
|
|
t.Logf("Ignoring event: %s", event)
|
|
continue
|
|
}
|
|
require.Truef(t, event.Has(fsnotify.Create), "want create event: %s", event.String())
|
|
require.Equal(t, event.Name, testFile, "want event for test file")
|
|
break
|
|
}
|
|
|
|
// TODO(DanielleMaywood):
|
|
// Unfortunately it appears this atomic-rename phase of the test is flakey on macOS.
|
|
//
|
|
// This test flake could be indicative of an issue that may present itself
|
|
// in a running environment. Fortunately, we only use this (as of 2025-07-29)
|
|
// for our dev container integration. We do not expect the host workspace
|
|
// (where this is used), to ever be run on macOS, as containers are a linux
|
|
// paradigm.
|
|
if runtime.GOOS != "darwin" {
|
|
err = os.WriteFile(testFile+".atomic", []byte(`{"test": "atomic"}`), 0o600)
|
|
require.NoError(t, err, "write new atomic test file failed")
|
|
|
|
err = os.Rename(testFile+".atomic", testFile)
|
|
require.NoError(t, err, "rename atomic test file failed")
|
|
|
|
// Verify that we receive the event we want.
|
|
for {
|
|
event, err := wut.Next(ctx)
|
|
require.NoError(t, err, "next event failed")
|
|
require.NotNil(t, event, "want non-nil event")
|
|
if !event.Has(fsnotify.Create) {
|
|
t.Logf("Ignoring event: %s", event)
|
|
continue
|
|
}
|
|
require.Truef(t, event.Has(fsnotify.Create), "want create event: %s", event.String())
|
|
require.Equal(t, event.Name, testFile, "want event for test file")
|
|
break
|
|
}
|
|
}
|
|
|
|
// Test removing the file from the watcher.
|
|
err = wut.Remove(testFile)
|
|
require.NoError(t, err, "remove file from watcher failed")
|
|
}
|
|
|
|
func TestFSNotifyWatcher_CloseBeforeNext(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
wut, err := watcher.NewFSNotify()
|
|
require.NoError(t, err, "create FSNotify watcher failed")
|
|
|
|
err = wut.Close()
|
|
require.NoError(t, err, "close watcher failed")
|
|
|
|
ctx := context.Background()
|
|
_, err = wut.Next(ctx)
|
|
assert.Error(t, err, "want Next to return error when watcher is closed")
|
|
}
|