test(git-watch): reset scheduler between tests

This commit is contained in:
Neil
2026-08-23 20:57:04 -07:00
parent 94b13a2aba
commit cc32b37a79
2 changed files with 35 additions and 1 deletions
@@ -67,6 +67,7 @@ export class GitMetadataPollScheduler {
private nextId = 1
private activePolls = 0
private activeFilesystemOperations = 0
private resetGeneration = 0
constructor(
private readonly concurrency = GIT_METADATA_FILESYSTEM_CONCURRENCY,
@@ -160,6 +161,24 @@ export class GitMetadataPollScheduler {
return promise
}
resetForTests(): void {
this.resetGeneration++
if (this.timer) {
clearTimeout(this.timer)
this.timer = null
}
for (const poll of this.polls.values()) {
poll.disposed = true
poll.unsubscribeVisibility()
poll.queued = false
}
this.polls.clear()
this.pollQueue.length = 0
this.filesystemQueue.length = 0
this.activePolls = 0
this.activeFilesystemOperations = 0
}
private unsubscribePoll(poll: ScheduledPoll): void {
if (poll.disposed) {
return
@@ -252,6 +271,7 @@ export class GitMetadataPollScheduler {
}
const isVisibilityCatchUp = poll.pendingVisibilityCatchUp
poll.pendingVisibilityCatchUp = false
const resetGeneration = this.resetGeneration
poll.running = true
this.activePolls++
let result: void | Promise<void>
@@ -265,6 +285,9 @@ export class GitMetadataPollScheduler {
// Each poller owns its transient-error policy; keep the host scheduler alive.
})
.finally(() => {
if (resetGeneration !== this.resetGeneration) {
return
}
poll.running = false
this.activePolls--
if (!poll.disposed && poll.rerunPending) {
@@ -281,8 +304,12 @@ export class GitMetadataPollScheduler {
private drainFilesystemQueue(): void {
while (this.activeFilesystemOperations < this.concurrency && this.filesystemQueue.length > 0) {
const operation = this.filesystemQueue.shift()!
const resetGeneration = this.resetGeneration
this.activeFilesystemOperations++
void operation.execute().finally(() => {
if (resetGeneration !== this.resetGeneration) {
return
}
this.activeFilesystemOperations--
this.drainFilesystemQueue()
})
@@ -1,4 +1,4 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { appendFile, mkdtemp, mkdir, realpath, rm, writeFile } from 'node:fs/promises'
import type * as NodeFsPromises from 'node:fs/promises'
import { performance as nodePerformance } from 'node:perf_hooks'
@@ -18,11 +18,16 @@ import type {
} from './worktree-base-directory-poller'
import { startGitCommonWatch } from './worktree-git-common-watch'
import { startGitCommonPolling } from './worktree-git-common-polling'
import { gitMetadataPollScheduler } from './git-metadata-poll-scheduler'
vi.mock('./parcel-watcher-process', () => ({
subscribeViaWatcherProcess: vi.fn()
}))
beforeEach(() => {
gitMetadataPollScheduler.resetForTests()
})
// Records every stat target so a test can assert which paths a parked poll stopped touching.
const { statCalls } = vi.hoisted(() => ({ statCalls: [] as string[] }))
@@ -94,6 +99,7 @@ describe('worktree git-common narrow watch (darwin)', () => {
afterEach(async () => {
await Promise.all(cleanups.splice(0).map((cleanup) => cleanup()))
gitMetadataPollScheduler.resetForTests()
childSubscriptions = []
statCalls.length = 0
subscribeMock.mockReset()
@@ -662,6 +668,7 @@ describe('worktree git-common polling gate (non-darwin)', () => {
afterEach(async () => {
await Promise.all(cleanups.splice(0).map((cleanup) => cleanup()))
gitMetadataPollScheduler.resetForTests()
})
async function makePollingCommonDir(): Promise<string> {