Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/chatSessions/common/test/ttlCache.spec.ts
13405 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
7
import { SingleSlotTtlCache, TtlCache } from '../ttlCache';
8
9
describe('TtlCache', () => {
10
beforeEach(() => {
11
vi.useFakeTimers();
12
});
13
14
afterEach(() => {
15
vi.useRealTimers();
16
});
17
18
it('returns undefined for missing keys', () => {
19
const cache = new TtlCache<string>(1000);
20
expect(cache.get('missing')).toBeUndefined();
21
});
22
23
it('stores and retrieves values within TTL', () => {
24
const cache = new TtlCache<number>(5000);
25
cache.set('key', 42);
26
expect(cache.get('key')).toBe(42);
27
});
28
29
it('expires entries after TTL elapses', () => {
30
const cache = new TtlCache<string>(1000);
31
cache.set('key', 'value');
32
33
vi.advanceTimersByTime(999);
34
expect(cache.get('key')).toBe('value');
35
36
vi.advanceTimersByTime(1);
37
expect(cache.get('key')).toBeUndefined();
38
});
39
40
it('supports multiple independent keys', () => {
41
const cache = new TtlCache<string>(2000);
42
cache.set('a', 'alpha');
43
44
vi.advanceTimersByTime(1000);
45
cache.set('b', 'beta');
46
47
vi.advanceTimersByTime(1000);
48
// 'a' was set 2000ms ago → expired
49
expect(cache.get('a')).toBeUndefined();
50
// 'b' was set 1000ms ago → still valid
51
expect(cache.get('b')).toBe('beta');
52
});
53
54
it('overwrites existing entry and resets TTL', () => {
55
const cache = new TtlCache<string>(1000);
56
cache.set('key', 'old');
57
58
vi.advanceTimersByTime(800);
59
cache.set('key', 'new');
60
61
vi.advanceTimersByTime(800);
62
// 800ms since last set → still valid
63
expect(cache.get('key')).toBe('new');
64
});
65
66
it('delete removes entry', () => {
67
const cache = new TtlCache<string>(5000);
68
cache.set('key', 'value');
69
cache.delete('key');
70
expect(cache.get('key')).toBeUndefined();
71
});
72
73
it('clear removes all entries', () => {
74
const cache = new TtlCache<string>(5000);
75
cache.set('a', '1');
76
cache.set('b', '2');
77
cache.clear();
78
expect(cache.get('a')).toBeUndefined();
79
expect(cache.get('b')).toBeUndefined();
80
});
81
82
it('has returns true for non-expired entries and false otherwise', () => {
83
const cache = new TtlCache<string>(1000);
84
expect(cache.has('key')).toBe(false);
85
86
cache.set('key', 'value');
87
expect(cache.has('key')).toBe(true);
88
89
vi.advanceTimersByTime(1000);
90
expect(cache.has('key')).toBe(false);
91
});
92
93
it('supports per-entry TTL override', () => {
94
const cache = new TtlCache<string>(5000);
95
cache.set('default', 'value1');
96
cache.set('short', 'value2', 1000);
97
98
vi.advanceTimersByTime(999);
99
expect(cache.get('default')).toBe('value1');
100
expect(cache.get('short')).toBe('value2');
101
102
vi.advanceTimersByTime(1);
103
expect(cache.get('default')).toBe('value1');
104
expect(cache.get('short')).toBeUndefined(); // expired at 1000ms
105
106
vi.advanceTimersByTime(4000);
107
expect(cache.get('default')).toBeUndefined(); // expired at 5000ms
108
});
109
});
110
111
describe('SingleSlotTtlCache', () => {
112
beforeEach(() => {
113
vi.useFakeTimers();
114
});
115
116
afterEach(() => {
117
vi.useRealTimers();
118
});
119
120
it('returns undefined when empty', () => {
121
const cache = new SingleSlotTtlCache<string>(1000);
122
expect(cache.get('any')).toBeUndefined();
123
});
124
125
it('stores and retrieves a value within TTL', () => {
126
const cache = new SingleSlotTtlCache<number>(5000);
127
cache.set('key', 42);
128
expect(cache.get('key')).toBe(42);
129
});
130
131
it('returns undefined when key does not match', () => {
132
const cache = new SingleSlotTtlCache<string>(5000);
133
cache.set('key1', 'value');
134
expect(cache.get('key2')).toBeUndefined();
135
});
136
137
it('expires entry after TTL elapses', () => {
138
const cache = new SingleSlotTtlCache<string>(1000);
139
cache.set('key', 'value');
140
141
vi.advanceTimersByTime(999);
142
expect(cache.get('key')).toBe('value');
143
144
vi.advanceTimersByTime(1);
145
expect(cache.get('key')).toBeUndefined();
146
});
147
148
it('replaces previous entry when set with new key', () => {
149
const cache = new SingleSlotTtlCache<string>(5000);
150
cache.set('key1', 'a');
151
cache.set('key2', 'b');
152
153
expect(cache.get('key1')).toBeUndefined();
154
expect(cache.get('key2')).toBe('b');
155
});
156
157
it('replaces and resets TTL on same key', () => {
158
const cache = new SingleSlotTtlCache<string>(1000);
159
cache.set('key', 'old');
160
161
vi.advanceTimersByTime(800);
162
cache.set('key', 'new');
163
164
vi.advanceTimersByTime(800);
165
expect(cache.get('key')).toBe('new');
166
});
167
168
it('clear removes entry', () => {
169
const cache = new SingleSlotTtlCache<string>(5000);
170
cache.set('key', 'value');
171
cache.clear();
172
expect(cache.get('key')).toBeUndefined();
173
});
174
175
it('has returns true for non-expired matching key', () => {
176
const cache = new SingleSlotTtlCache<string>(1000);
177
expect(cache.has('key')).toBe(false);
178
179
cache.set('key', 'value');
180
expect(cache.has('key')).toBe(true);
181
expect(cache.has('other')).toBe(false);
182
183
vi.advanceTimersByTime(1000);
184
expect(cache.has('key')).toBe(false);
185
});
186
});
187
188