Test both walk cancellation checks on their own (closes #81)
check / check (push) Failing after 1s
check / check (push) Failing after 1s
walkOneDir's check was hiding the worker's: a worker that walked a queued directory on a cancelled scan still emitted nothing, because walkOneDir stopped at its first entry. The worker test now queues a missing directory, whose read fails and sends a warning before walkOneDir's check is reached. A new test calls walkOneDir directly on a cancelled scan and checks it returns no subdirectory to descend into. Model: opus-5-5
This commit was merged in pull request #85.
This commit is contained in:
@@ -29,6 +29,9 @@
|
|||||||
|
|
||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
|
- a test fails when either walk cancellation check in `scan.go` is
|
||||||
|
removed (2026-10-04, https://git.eeqj.de/sneak/sfdupes/issues/81)
|
||||||
|
|
||||||
- test that `scan` refuses a database with another schema version
|
- test that `scan` refuses a database with another schema version
|
||||||
(2026-10-04, https://git.eeqj.de/sneak/sfdupes/issues/64)
|
(2026-10-04, https://git.eeqj.de/sneak/sfdupes/issues/64)
|
||||||
|
|
||||||
|
|||||||
+37
-8
@@ -586,20 +586,49 @@ func TestSendEventAbandonsBlockedSend(t *testing.T) {
|
|||||||
awaitReturn(t, done, "sendEvent")
|
awaitReturn(t, done, "sendEvent")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestWalkWorkersDropQueuedDirs checks that cancelled walk workers keep
|
// TestWalkOneDirStopsWhenCancelled checks that a cancelled scan stops
|
||||||
// reading jobs and drop the directories rather than stopping their
|
// reading a directory instead of going through the rest of its
|
||||||
// read: the range over jobs has to run out for the pool to tear down
|
// entries. A walk that kept going would return the subdirectory below
|
||||||
// and close its event stream.
|
// to descend into. Unlike a file event, that return is not a send the
|
||||||
func TestWalkWorkersDropQueuedDirs(t *testing.T) {
|
// cancellation can abandon, so the test catches the regression every
|
||||||
|
// time.
|
||||||
|
func TestWalkOneDirStopsWhenCancelled(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
writeEmptyFiles(t, dir, walkCancelFilesPerDir)
|
|
||||||
|
err := os.Mkdir(filepath.Join(dir, "sub"), 0o750)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unbuffered and unread: on a cancelled scan every send gives up.
|
||||||
|
events := make(chan walkEvent)
|
||||||
|
|
||||||
|
subs := walkOneDir(cancelledContext(t), dirJob{path: dir}, false, events)
|
||||||
|
if len(subs) != 0 {
|
||||||
|
t.Errorf("cancelled walkOneDir returned %+v to descend into, "+
|
||||||
|
"want none", subs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestWalkWorkersDropQueuedDirs checks that cancelled walk workers keep
|
||||||
|
// reading jobs and drop the directories rather than stopping their
|
||||||
|
// read: the range over jobs has to run out for the pool to tear down
|
||||||
|
// and close its event stream. The queued directory does not exist, so
|
||||||
|
// a worker that walked it anyway would send a warning before
|
||||||
|
// walkOneDir's own cancellation check could stop it. On a cancelled
|
||||||
|
// scan that send delivers or gives up at random, so with 64 jobs
|
||||||
|
// queued the regression has a one in 2^64 chance of passing.
|
||||||
|
func TestWalkWorkersDropQueuedDirs(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
missing := filepath.Join(t.TempDir(), "missing")
|
||||||
|
|
||||||
jobs, _, events := startWalkWorkers(cancelledContext(t), 2, false)
|
jobs, _, events := startWalkWorkers(cancelledContext(t), 2, false)
|
||||||
|
|
||||||
for range 4 {
|
for range 64 {
|
||||||
jobs <- dirJob{path: dir}
|
jobs <- dirJob{path: missing}
|
||||||
}
|
}
|
||||||
|
|
||||||
close(jobs)
|
close(jobs)
|
||||||
|
|||||||
Reference in New Issue
Block a user