1// Copyright 2011 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// +build windows
6
7package winfsnotify
8
9import (
10	"io/ioutil"
11	"os"
12	"sync/atomic"
13	"testing"
14	"time"
15)
16
17func expect(t *testing.T, eventstream <-chan *Event, name string, mask uint32) {
18	t.Logf(`expected: "%s": 0x%x`, name, mask)
19	select {
20	case event := <-eventstream:
21		if event == nil {
22			t.Fatal("nil event received")
23		}
24		t.Logf("received: %s", event)
25		if event.Name != name || event.Mask != mask {
26			t.Fatal("did not receive expected event")
27		}
28	case <-time.After(1 * time.Second):
29		t.Fatal("timed out waiting for event")
30	}
31}
32
33func TestNotifyEvents(t *testing.T) {
34	watcher, err := NewWatcher()
35	if err != nil {
36		t.Fatalf("NewWatcher() failed: %s", err)
37	}
38
39	testDir := "TestNotifyEvents.testdirectory"
40	testFile := testDir + "/TestNotifyEvents.testfile"
41	testFile2 := testFile + ".new"
42	const mask = FS_ALL_EVENTS & ^(FS_ATTRIB|FS_CLOSE) | FS_IGNORED
43
44	// Add a watch for testDir
45	os.RemoveAll(testDir)
46	if err = os.Mkdir(testDir, 0777); err != nil {
47		t.Fatalf("Failed to create test directory: %s", err)
48	}
49	defer os.RemoveAll(testDir)
50	err = watcher.AddWatch(testDir, mask)
51	if err != nil {
52		t.Fatalf("Watcher.Watch() failed: %s", err)
53	}
54
55	// Receive errors on the error channel on a separate goroutine
56	go func() {
57		for err := range watcher.Error {
58			t.Fatalf("error received: %s", err)
59		}
60	}()
61
62	// Create a file
63	file, err := os.Create(testFile)
64	if err != nil {
65		t.Fatalf("creating test file failed: %s", err)
66	}
67	expect(t, watcher.Event, testFile, FS_CREATE)
68
69	err = watcher.AddWatch(testFile, mask)
70	if err != nil {
71		t.Fatalf("Watcher.Watch() failed: %s", err)
72	}
73
74	if _, err = file.WriteString("hello, world"); err != nil {
75		t.Fatalf("failed to write to test file: %s", err)
76	}
77	if err = file.Close(); err != nil {
78		t.Fatalf("failed to close test file: %s", err)
79	}
80	expect(t, watcher.Event, testFile, FS_MODIFY)
81	expect(t, watcher.Event, testFile, FS_MODIFY)
82
83	if err = os.Rename(testFile, testFile2); err != nil {
84		t.Fatalf("failed to rename test file: %s", err)
85	}
86	expect(t, watcher.Event, testFile, FS_MOVED_FROM)
87	expect(t, watcher.Event, testFile2, FS_MOVED_TO)
88	expect(t, watcher.Event, testFile, FS_MOVE_SELF)
89
90	if err = os.RemoveAll(testDir); err != nil {
91		t.Fatalf("failed to remove test directory: %s", err)
92	}
93	expect(t, watcher.Event, testFile2, FS_DELETE_SELF)
94	expect(t, watcher.Event, testFile2, FS_IGNORED)
95	expect(t, watcher.Event, testFile2, FS_DELETE)
96	expect(t, watcher.Event, testDir, FS_DELETE_SELF)
97	expect(t, watcher.Event, testDir, FS_IGNORED)
98
99	t.Log("calling Close()")
100	if err = watcher.Close(); err != nil {
101		t.Fatalf("failed to close watcher: %s", err)
102	}
103}
104
105func TestNotifyClose(t *testing.T) {
106	watcher, _ := NewWatcher()
107	watcher.Close()
108
109	var done int32
110	go func() {
111		watcher.Close()
112		atomic.StoreInt32(&done, 1)
113	}()
114
115	time.Sleep(50 * time.Millisecond)
116	if atomic.LoadInt32(&done) == 0 {
117		t.Fatal("double Close() test failed: second Close() call didn't return")
118	}
119
120	dir, err := ioutil.TempDir("", "wininotify")
121	if err != nil {
122		t.Fatalf("TempDir failed: %s", err)
123	}
124	defer os.RemoveAll(dir)
125
126	err = watcher.Watch(dir)
127	if err == nil {
128		t.Fatal("expected error on Watch() after Close(), got nil")
129	}
130}
131