Skip to content

Commit 1e71d45

Browse files
Add test cases (#64)
1 parent ce9aad4 commit 1e71d45

44 files changed

Lines changed: 1435 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,53 @@ get merged *if* there's a decent signal they're correct. Merely "it compiles" it
2727
not enough, because so much of this relies on runtime behaviour. Either a new
2828
test should be added, or patches should be tested manually.
2929

30+
### Test Scripts
31+
Support for test scripts akin to ones in [fsnotify](https://github.com/fsnotify/fsnotify)
32+
have been added.
33+
34+
All the scripts are in the `testdata` folder, and test can be ran individually
35+
using the pattern:
36+
37+
```go test -run TestScript/<path to test script file>```
38+
39+
Scripts are written using a simple DSL which runs a few available shell commands,
40+
and also allows setting/unsetting the watcher, as well as verifying the output.
41+
42+
Available commands:
43+
```
44+
watch path [ops] # Watch the path, reporting events for it. Nothing is
45+
# watched by default.
46+
unwatch path # Stop watching the path.
47+
watchlist n # Assert watchlist length.
48+
49+
stop # Stop running the script; for debugging.
50+
51+
touch path
52+
mkdir [-p] dir
53+
ln -s target link # Only ln -s supported.
54+
mv src dst
55+
rm [-r] path
56+
chmod mode path # Octal only
57+
sleep time-in-ms
58+
59+
cat path # Read path (does nothing with the data; just reads it).
60+
echo str >>path # Append "str" to "path".
61+
echo str >path # Truncate "path" and write "str".
62+
```
63+
64+
Output can be verified in the scripts using the events and event flags emitted
65+
by FSEvents. Assertions are defined in the `Output` section of the test script.
66+
All the flags in test script assertions are equivalent to the ones defined in
67+
`wrap.go` with the type EventFlags.
68+
69+
The output section format:
70+
```
71+
Output:
72+
# Comment
73+
EventFlag1|EventFlag2 path # Comment
74+
```
75+
76+
3077
Really quick FSEvents overview
3178
==============================
3279
For those new to FSEvents itself (the Apple technology), here's a really quick

fsevents_test.go

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,44 @@ package fsevents
44

55
import (
66
"fmt"
7+
"io/fs"
78
"os"
89
"path/filepath"
10+
"strings"
11+
"sync"
912
"testing"
1013
"time"
1114
)
1215

16+
func TestScript(t *testing.T) {
17+
err := filepath.Walk("./testdata", func(path string, info fs.FileInfo, err error) error {
18+
if err != nil {
19+
return err
20+
}
21+
22+
if info.IsDir() {
23+
return nil
24+
}
25+
26+
n := strings.Split(filepath.ToSlash(path), "/")
27+
t.Run(strings.Join(n[1:], "/"), func(t *testing.T) {
28+
t.Parallel()
29+
30+
d, err := os.ReadFile(path)
31+
if err != nil {
32+
t.Fatal(err)
33+
}
34+
35+
parseScript(t, string(d))
36+
})
37+
38+
return nil
39+
})
40+
if err != nil {
41+
t.Fatal(err)
42+
}
43+
}
44+
1345
func TestBasicExample(t *testing.T) {
1446
path, err := os.MkdirTemp("", "fsexample")
1547
if err != nil {
@@ -169,3 +201,133 @@ func TestRegistry(t *testing.T) {
169201
t.Error("failed to delete registry")
170202
}
171203
}
204+
205+
func TestMany(t *testing.T) {
206+
tmp := t.TempDir()
207+
208+
path, err := filepath.EvalSymlinks(tmp)
209+
if err != nil {
210+
t.Fatal(err)
211+
}
212+
213+
dev, err := DeviceForPath(path)
214+
if err != nil {
215+
t.Fatal(err)
216+
}
217+
218+
es := &EventStream{
219+
Paths: []string{path},
220+
Latency: 0,
221+
Device: dev,
222+
Flags: FileEvents | NoDefer,
223+
}
224+
225+
err = es.Start()
226+
if err != nil {
227+
t.Fatal(err)
228+
}
229+
230+
events := make(map[string]EventFlags, 810)
231+
232+
wait := make(chan struct{})
233+
234+
go func() {
235+
for {
236+
select {
237+
case msg := <-es.Events:
238+
for _, event := range msg {
239+
if _, ok := events[event.Path]; !ok {
240+
events[event.Path] = event.Flags
241+
} else {
242+
events[event.Path] = events[event.Path].set(event.Flags)
243+
}
244+
}
245+
case <-time.After(3 * time.Second):
246+
wait <- struct{}{}
247+
}
248+
}
249+
}()
250+
251+
const data = "data"
252+
253+
var wg sync.WaitGroup
254+
wg.Add(200)
255+
256+
for i := 0; i < 100; i++ {
257+
i := i
258+
259+
go func() {
260+
defer wg.Done()
261+
echoAppend(t, data, fmt.Sprintf("%s/file-%d", path, i))
262+
}()
263+
264+
go func() {
265+
defer wg.Done()
266+
mkdir(t, fmt.Sprintf("%s/dir-%d", path, i))
267+
}()
268+
}
269+
wg.Wait()
270+
271+
wg.Add(100)
272+
for i := 0; i < 100; i++ {
273+
i := i
274+
275+
go func() {
276+
defer wg.Done()
277+
echoAppend(t, data, fmt.Sprintf("%s/dir-%d/file-%d", path, i, i))
278+
}()
279+
}
280+
wg.Wait()
281+
282+
wg.Add(200)
283+
for i := 0; i < 100; i++ {
284+
i := i
285+
go func() {
286+
defer wg.Done()
287+
rm(t, fmt.Sprintf("%s/file-%d", tmp, i))
288+
}()
289+
go func() {
290+
defer wg.Done()
291+
rmAll(t, fmt.Sprintf("%s/dir-%d", tmp, i))
292+
}()
293+
}
294+
wg.Wait()
295+
296+
select {
297+
case <-wait:
298+
case <-time.After(5 * time.Second):
299+
t.Fatal("timed out waiting for events")
300+
}
301+
302+
const fileExpectedFlags = ItemIsFile | ItemCreated | ItemModified | ItemRemoved
303+
const dirExpectedFlags = ItemIsDir | ItemCreated | ItemRemoved
304+
305+
for p, flags := range events {
306+
if p == strings.TrimPrefix(path, "/") {
307+
continue
308+
}
309+
310+
switch {
311+
case flags.hasFlag(ItemIsFile):
312+
if flags.String() != fileExpectedFlags.String() {
313+
t.Fatalf(
314+
"file flags for path '%s' did not match expected '%s' found '%s'",
315+
p,
316+
fileExpectedFlags.String(),
317+
flags.String(),
318+
)
319+
}
320+
case flags.hasFlag(ItemIsDir):
321+
if flags.String() != dirExpectedFlags.String() {
322+
t.Fatalf(
323+
"file flags for path '%s' did not match expected '%s' found '%s'",
324+
p,
325+
dirExpectedFlags.String(),
326+
flags.String(),
327+
)
328+
}
329+
default:
330+
t.Fatal("unrecognized flag")
331+
}
332+
}
333+
}

0 commit comments

Comments
 (0)