1
0

watch-policy.test.ts 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. /**
  2. * Watch Policy Tests
  3. *
  4. * Covers the decision of whether the live file watcher runs, including the
  5. * WSL2 /mnt auto-detect and the env-var escape hatches (issue #199), plus
  6. * that FileWatcher.start() honors the decision.
  7. */
  8. import { describe, it, expect, afterEach, vi } from 'vitest';
  9. import * as fs from 'fs';
  10. import * as path from 'path';
  11. import * as os from 'os';
  12. import { watchDisabledReason } from '../src/sync/watch-policy';
  13. import { FileWatcher } from '../src/sync/watcher';
  14. import type { CodeGraphConfig } from '../src/types';
  15. describe('watchDisabledReason', () => {
  16. it('returns a reason when CODEGRAPH_NO_WATCH=1', () => {
  17. const reason = watchDisabledReason('/home/me/project', {
  18. env: { CODEGRAPH_NO_WATCH: '1' },
  19. isWsl: false,
  20. });
  21. expect(reason).toBeTruthy();
  22. expect(reason).toMatch(/CODEGRAPH_NO_WATCH/);
  23. });
  24. it('auto-disables on a WSL2 /mnt drive', () => {
  25. const reason = watchDisabledReason('/mnt/d/code/project', { env: {}, isWsl: true });
  26. expect(reason).toBeTruthy();
  27. expect(reason).toMatch(/mnt/);
  28. });
  29. it('does NOT disable on a native WSL home path', () => {
  30. expect(watchDisabledReason('/home/me/project', { env: {}, isWsl: true })).toBeNull();
  31. });
  32. it('does NOT disable on /mnt when not running under WSL', () => {
  33. // A real Linux box may legitimately have a fast /mnt mount.
  34. expect(watchDisabledReason('/mnt/d/code/project', { env: {}, isWsl: false })).toBeNull();
  35. });
  36. it('does NOT treat /mnt/wsl (fast Linux mount) as a Windows drive', () => {
  37. expect(watchDisabledReason('/mnt/wsl/project', { env: {}, isWsl: true })).toBeNull();
  38. });
  39. it('CODEGRAPH_FORCE_WATCH=1 overrides WSL auto-detect', () => {
  40. const reason = watchDisabledReason('/mnt/d/code/project', {
  41. env: { CODEGRAPH_FORCE_WATCH: '1' },
  42. isWsl: true,
  43. });
  44. expect(reason).toBeNull();
  45. });
  46. it('CODEGRAPH_NO_WATCH wins over CODEGRAPH_FORCE_WATCH', () => {
  47. const reason = watchDisabledReason('/home/me/project', {
  48. env: { CODEGRAPH_NO_WATCH: '1', CODEGRAPH_FORCE_WATCH: '1' },
  49. isWsl: false,
  50. });
  51. expect(reason).toBeTruthy();
  52. });
  53. });
  54. describe('FileWatcher honors the watch policy', () => {
  55. let testDir: string;
  56. const baseConfig: CodeGraphConfig = {
  57. version: 1,
  58. rootDir: '.',
  59. include: ['**/*.ts'],
  60. exclude: ['**/node_modules/**'],
  61. languages: [],
  62. frameworks: [],
  63. maxFileSize: 1024 * 1024,
  64. extractDocstrings: true,
  65. trackCallSites: true,
  66. };
  67. afterEach(() => {
  68. delete process.env.CODEGRAPH_NO_WATCH;
  69. if (testDir && fs.existsSync(testDir)) {
  70. fs.rmSync(testDir, { recursive: true, force: true });
  71. }
  72. });
  73. it('does not start when CODEGRAPH_NO_WATCH=1', () => {
  74. testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'codegraph-nowatch-'));
  75. process.env.CODEGRAPH_NO_WATCH = '1';
  76. const syncFn = vi.fn().mockResolvedValue({ filesChanged: 0, durationMs: 0 });
  77. const watcher = new FileWatcher(testDir, baseConfig, syncFn);
  78. expect(watcher.start()).toBe(false);
  79. expect(watcher.isActive()).toBe(false);
  80. });
  81. });