TestFallbackPollSkipsWhenRecentlyScanned pins the RunLoop optimization that swallows a fallback tick when a trigger-driven scan already covered the last fallback interval. Without the skip, a busy chat (agent editing + PathStore notifications) would pay the full fallback scan cost on top of trigger-
(t *testing.T)
| 1611 | // (agent editing + PathStore notifications) would pay the full fallback |
| 1612 | // scan cost on top of trigger-driven scans. |
| 1613 | func TestFallbackPollSkipsWhenRecentlyScanned(t *testing.T) { |
| 1614 | t.Parallel() |
| 1615 | |
| 1616 | ctx := testutil.Context(t, testutil.WaitLong) |
| 1617 | repoDir := initTestRepo(t) |
| 1618 | mClock := quartz.NewMock(t) |
| 1619 | |
| 1620 | ps := agentgit.NewPathStore() |
| 1621 | chatID := uuid.New() |
| 1622 | |
| 1623 | require.NoError(t, os.WriteFile(filepath.Join(repoDir, "a.go"), []byte("package a\n"), 0o600)) |
| 1624 | ps.AddPaths([]uuid.UUID{chatID}, []string{filepath.Join(repoDir, "a.go")}) |
| 1625 | |
| 1626 | stream := dialGitWatchWithPathStore(t, ps, chatID, agentgit.WithClock(mClock)) |
| 1627 | ch := stream.Chan() |
| 1628 | |
| 1629 | // Consume the initial scan from subscribe. |
| 1630 | msg1 := recvMsg(ctx, t, ch) |
| 1631 | require.Equal(t, codersdk.WorkspaceAgentGitServerMessageTypeChanges, msg1.Type) |
| 1632 | |
| 1633 | // A trigger-driven scan within the fallback interval should |
| 1634 | // cause the next fallback tick to be skipped. Advance part-way |
| 1635 | // to the 5s tick, fire a notification to trigger a scan, then |
| 1636 | // advance the rest of the way to the tick. The tick should be |
| 1637 | // swallowed because lastScanAt is recent. |
| 1638 | mClock.Advance(4 * time.Second).MustWait(context.Background()) |
| 1639 | require.NoError(t, os.WriteFile(filepath.Join(repoDir, "a.go"), []byte("package a\n// edit\n"), 0o600)) |
| 1640 | ps.Notify([]uuid.UUID{chatID}) |
| 1641 | |
| 1642 | // Consume the trigger-driven scan. lastScanAt is now ~t=4s. |
| 1643 | msg2 := recvMsg(ctx, t, ch) |
| 1644 | require.Equal(t, codersdk.WorkspaceAgentGitServerMessageTypeChanges, msg2.Type) |
| 1645 | |
| 1646 | // Dirty the tree further so the fallback tick would have |
| 1647 | // something to emit if it were not skipped. |
| 1648 | require.NoError(t, os.WriteFile(filepath.Join(repoDir, "b.go"), []byte("package b\n"), 0o600)) |
| 1649 | |
| 1650 | // Advance to the 5s ticker boundary. The tick fires but is |
| 1651 | // skipped because Since(lastScanAt) = 1s < fallbackPollInterval. |
| 1652 | mClock.Advance(1 * time.Second).MustWait(context.Background()) |
| 1653 | |
| 1654 | // Confirm no scan arrived for the skipped tick. |
| 1655 | select { |
| 1656 | case msg := <-ch: |
| 1657 | t.Fatalf("unexpected scan after skipped fallback tick: %+v", msg) |
| 1658 | case <-time.After(testutil.IntervalFast): |
| 1659 | } |
| 1660 | |
| 1661 | // Advance to the next ticker boundary (t=10s). lastScanAt is |
| 1662 | // ~4s, so Since = 6s >= fallbackPollInterval and the tick |
| 1663 | // should no longer be skipped. |
| 1664 | mClock.Advance(5 * time.Second).MustWait(context.Background()) |
| 1665 | |
| 1666 | msg3 := recvMsg(ctx, t, ch) |
| 1667 | require.Equal(t, codersdk.WorkspaceAgentGitServerMessageTypeChanges, msg3.Type) |
| 1668 | } |
nothing calls this directly
no test coverage detected