summaryrefslogtreecommitdiff
path: root/packages/core/src/utils/filesearch/crawlCache.test.ts
blob: 2feab61af11bb4987d7b006a1355ac1de029bd13 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

import { describe, it, expect, vi, afterEach, beforeEach } from 'vitest';
import { getCacheKey, read, write, clear } from './crawlCache.js';

describe('CrawlCache', () => {
  describe('getCacheKey', () => {
    it('should generate a consistent hash', () => {
      const key1 = getCacheKey('/foo', 'bar');
      const key2 = getCacheKey('/foo', 'bar');
      expect(key1).toBe(key2);
    });

    it('should generate a different hash for different directories', () => {
      const key1 = getCacheKey('/foo', 'bar');
      const key2 = getCacheKey('/bar', 'bar');
      expect(key1).not.toBe(key2);
    });

    it('should generate a different hash for different ignore content', () => {
      const key1 = getCacheKey('/foo', 'bar');
      const key2 = getCacheKey('/foo', 'baz');
      expect(key1).not.toBe(key2);
    });
  });

  describe('in-memory cache operations', () => {
    beforeEach(() => {
      // Ensure a clean slate before each test
      clear();
    });

    afterEach(() => {
      // Restore real timers after each test that uses fake ones
      vi.useRealTimers();
    });

    it('should write and read data from the cache', () => {
      const key = 'test-key';
      const data = ['foo', 'bar'];
      write(key, data, 10000); // 10 second TTL
      const cachedData = read(key);
      expect(cachedData).toEqual(data);
    });

    it('should return undefined for a nonexistent key', () => {
      const cachedData = read('nonexistent-key');
      expect(cachedData).toBeUndefined();
    });

    it('should clear the cache', () => {
      const key = 'test-key';
      const data = ['foo', 'bar'];
      write(key, data, 10000);
      clear();
      const cachedData = read(key);
      expect(cachedData).toBeUndefined();
    });

    it('should automatically evict a cache entry after its TTL expires', async () => {
      vi.useFakeTimers();
      const key = 'ttl-key';
      const data = ['foo'];
      const ttl = 5000; // 5 seconds

      write(key, data, ttl);

      // Should exist immediately after writing
      expect(read(key)).toEqual(data);

      // Advance time just before expiration
      await vi.advanceTimersByTimeAsync(ttl - 1);
      expect(read(key)).toEqual(data);

      // Advance time past expiration
      await vi.advanceTimersByTimeAsync(1);
      expect(read(key)).toBeUndefined();
    });

    it('should reset the timer when an entry is updated', async () => {
      vi.useFakeTimers();
      const key = 'update-key';
      const initialData = ['initial'];
      const updatedData = ['updated'];
      const ttl = 5000; // 5 seconds

      // Write initial data
      write(key, initialData, ttl);

      // Advance time, but not enough to expire
      await vi.advanceTimersByTimeAsync(3000);
      expect(read(key)).toEqual(initialData);

      // Update the data, which should reset the timer
      write(key, updatedData, ttl);
      expect(read(key)).toEqual(updatedData);

      // Advance time again. If the timer wasn't reset, the total elapsed
      // time (3000 + 3000 = 6000) would cause an eviction.
      await vi.advanceTimersByTimeAsync(3000);
      expect(read(key)).toEqual(updatedData);

      // Advance past the new expiration time
      await vi.advanceTimersByTimeAsync(2001);
      expect(read(key)).toBeUndefined();
    });
  });
});