aboutsummaryrefslogtreecommitdiffstats
path: root/watcher_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'watcher_test.go')
-rw-r--r--watcher_test.go149
1 files changed, 149 insertions, 0 deletions
diff --git a/watcher_test.go b/watcher_test.go
index db0defb..8fac419 100644
--- a/watcher_test.go
+++ b/watcher_test.go
@@ -318,6 +318,155 @@ func TestWatcher_NestedGitignore_CreateUnignore(t *testing.T) {
assertFileEventually(t, data, "sub/important.txt", "keep me", 2*time.Second)
}
+func TestWatcher_CreateSymlink(t *testing.T) {
+ host := t.TempDir()
+ data := t.TempDir()
+
+ writeFile(t, host, "target.txt", "target content")
+
+ stack := NewGitignoreStack(host)
+ manifest, err := initialSync(host, data, stack, false)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go watch(ctx, host, data, manifest, stack, false, false)
+
+ time.Sleep(100 * time.Millisecond)
+
+ if err := os.Symlink("target.txt", filepath.Join(host, "link.txt")); err != nil {
+ t.Fatal(err)
+ }
+
+ deadline := time.Now().Add(2 * time.Second)
+ for time.Now().Before(deadline) {
+ info, err := os.Lstat(filepath.Join(data, "link.txt"))
+ if err == nil && info.Mode()&os.ModeSymlink != 0 {
+ target, _ := os.Readlink(filepath.Join(data, "link.txt"))
+ if target == "target.txt" {
+ return
+ }
+ }
+ time.Sleep(50 * time.Millisecond)
+ }
+ t.Error("symlink not created in /data within timeout")
+}
+
+func TestWatcher_UpdateSymlinkTarget(t *testing.T) {
+ host := t.TempDir()
+ data := t.TempDir()
+
+ writeFile(t, host, "v1.txt", "version 1")
+ writeFile(t, host, "v2.txt", "version 2")
+ if err := os.Symlink("v1.txt", filepath.Join(host, "link.txt")); err != nil {
+ t.Fatal(err)
+ }
+
+ stack := NewGitignoreStack(host)
+ manifest, err := initialSync(host, data, stack, false)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Verify initial symlink
+ linkInfo, err := os.Lstat(filepath.Join(data, "link.txt"))
+ if err != nil || linkInfo.Mode()&os.ModeSymlink == 0 {
+ t.Fatal("initial symlink not created")
+ }
+ target, _ := os.Readlink(filepath.Join(data, "link.txt"))
+ if target != "v1.txt" {
+ t.Fatalf("initial symlink target = %q, want %q", target, "v1.txt")
+ }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go watch(ctx, host, data, manifest, stack, false, false)
+
+ time.Sleep(100 * time.Millisecond)
+
+ // Update symlink to point to v2.txt
+ os.Remove(filepath.Join(host, "link.txt"))
+ os.Symlink("v2.txt", filepath.Join(host, "link.txt"))
+
+ deadline := time.Now().Add(2 * time.Second)
+ for time.Now().Before(deadline) {
+ info, err := os.Lstat(filepath.Join(data, "link.txt"))
+ if err == nil && info.Mode()&os.ModeSymlink != 0 {
+ tgt, _ := os.Readlink(filepath.Join(data, "link.txt"))
+ if tgt == "v2.txt" {
+ return
+ }
+ }
+ time.Sleep(50 * time.Millisecond)
+ }
+ t.Error("symlink target not updated within timeout")
+}
+
+func TestWatcher_RemoveSymlink(t *testing.T) {
+ host := t.TempDir()
+ data := t.TempDir()
+
+ writeFile(t, host, "target.txt", "content")
+ if err := os.Symlink("target.txt", filepath.Join(host, "link.txt")); err != nil {
+ t.Fatal(err)
+ }
+
+ stack := NewGitignoreStack(host)
+ manifest, err := initialSync(host, data, stack, false)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go watch(ctx, host, data, manifest, stack, false, false)
+
+ time.Sleep(100 * time.Millisecond)
+
+ os.Remove(filepath.Join(host, "link.txt"))
+
+ assertFileRemovedEventually(t, data, "link.txt", 2*time.Second)
+}
+
+func TestWatcher_ModifySymlinkTargetFile(t *testing.T) {
+ host := t.TempDir()
+ data := t.TempDir()
+
+ writeFile(t, host, "target.txt", "original")
+ if err := os.Symlink("target.txt", filepath.Join(host, "link.txt")); err != nil {
+ t.Fatal(err)
+ }
+
+ stack := NewGitignoreStack(host)
+ manifest, err := initialSync(host, data, stack, false)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go watch(ctx, host, data, manifest, stack, false, false)
+
+ time.Sleep(100 * time.Millisecond)
+
+ // Modify the target file, not the symlink itself
+ writeFile(t, host, "target.txt", "modified")
+
+ // The symlink should still exist and point to the target
+ deadline := time.Now().Add(2 * time.Second)
+ for time.Now().Before(deadline) {
+ info, err := os.Lstat(filepath.Join(data, "link.txt"))
+ if err == nil && info.Mode()&os.ModeSymlink != 0 {
+ // Symlink still exists, which is correct
+ return
+ }
+ time.Sleep(50 * time.Millisecond)
+ }
+ t.Error("symlink lost after target file modification")
+}
+
// Helpers
func assertFileEventually(t *testing.T, dir, path, expectedContent string, timeout time.Duration) {