ai-evaluate 2.1.8 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/evaluate.d.ts.map +1 -1
- package/dist/evaluate.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/miniflare-pool.d.ts.map +1 -1
- package/dist/miniflare-pool.js.map +1 -1
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js.map +1 -1
- package/dist/static/index.d.ts +111 -0
- package/dist/static/index.d.ts.map +1 -0
- package/dist/static/index.js +347 -0
- package/dist/static/index.js.map +1 -0
- package/dist/type-guards.d.ts.map +1 -1
- package/dist/type-guards.js.map +1 -1
- package/dist/worker-template/core.d.ts.map +1 -1
- package/dist/worker-template/core.js +1 -1
- package/dist/worker-template/core.js.map +1 -1
- package/package.json +17 -4
- package/public/capnweb.mjs +220 -0
- package/public/index.mjs +426 -0
- package/public/scaffold.mjs +198 -0
- package/.turbo/turbo-build.log +0 -4
- package/.turbo/turbo-test.log +0 -54
- package/.turbo/turbo-typecheck.log +0 -4
- package/CHANGELOG.md +0 -48
- package/example/package.json +0 -20
- package/example/src/index.ts +0 -221
- package/example/wrangler.jsonc +0 -25
- package/src/capnweb-bundle.ts +0 -2596
- package/src/evaluate.ts +0 -329
- package/src/index.ts +0 -23
- package/src/miniflare-pool.ts +0 -395
- package/src/node.ts +0 -245
- package/src/repl.ts +0 -228
- package/src/shared.ts +0 -186
- package/src/type-guards.ts +0 -323
- package/src/types.ts +0 -196
- package/src/validation.ts +0 -120
- package/src/worker-template/code-transforms.ts +0 -32
- package/src/worker-template/core.ts +0 -557
- package/src/worker-template/helpers.ts +0 -90
- package/src/worker-template/index.ts +0 -23
- package/src/worker-template/sdk-generator.ts +0 -2515
- package/src/worker-template/test-generator.ts +0 -358
- package/test/evaluate-extended.test.js +0 -429
- package/test/evaluate-extended.test.ts +0 -469
- package/test/evaluate.test.js +0 -235
- package/test/evaluate.test.ts +0 -253
- package/test/index.test.js +0 -77
- package/test/index.test.ts +0 -95
- package/test/miniflare-pool.test.ts +0 -246
- package/test/node.test.ts +0 -467
- package/test/security.test.ts +0 -1009
- package/test/shared.test.ts +0 -105
- package/test/type-guards.test.ts +0 -303
- package/test/validation.test.ts +0 -240
- package/test/worker-template.test.js +0 -365
- package/test/worker-template.test.ts +0 -432
- package/tsconfig.json +0 -22
- package/vitest.config.js +0 -21
- package/vitest.config.ts +0 -28
package/test/evaluate.test.ts
DELETED
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
|
|
2
|
-
import { evaluate } from '../src/index.js'
|
|
3
|
-
|
|
4
|
-
describe('evaluate', () => {
|
|
5
|
-
describe('script execution', () => {
|
|
6
|
-
it('executes simple expressions', async () => {
|
|
7
|
-
const result = await evaluate({
|
|
8
|
-
script: 'return 1 + 1'
|
|
9
|
-
})
|
|
10
|
-
expect(result.success).toBe(true)
|
|
11
|
-
expect(result.value).toBe(2)
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
it('captures console output', async () => {
|
|
15
|
-
const result = await evaluate({
|
|
16
|
-
script: `
|
|
17
|
-
console.log('hello');
|
|
18
|
-
console.warn('warning');
|
|
19
|
-
console.error('error');
|
|
20
|
-
return 'done';
|
|
21
|
-
`
|
|
22
|
-
})
|
|
23
|
-
expect(result.success).toBe(true)
|
|
24
|
-
expect(result.value).toBe('done')
|
|
25
|
-
expect(result.logs).toHaveLength(3)
|
|
26
|
-
expect(result.logs[0].level).toBe('log')
|
|
27
|
-
expect(result.logs[0].message).toBe('hello')
|
|
28
|
-
expect(result.logs[1].level).toBe('warn')
|
|
29
|
-
expect(result.logs[2].level).toBe('error')
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
it('handles script errors', async () => {
|
|
33
|
-
const result = await evaluate({
|
|
34
|
-
script: 'throw new Error("test error")'
|
|
35
|
-
})
|
|
36
|
-
expect(result.success).toBe(false)
|
|
37
|
-
expect(result.error).toContain('test error')
|
|
38
|
-
})
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
describe('module exports', () => {
|
|
42
|
-
it('exposes exports to script', async () => {
|
|
43
|
-
const result = await evaluate({
|
|
44
|
-
module: `
|
|
45
|
-
exports.add = (a, b) => a + b;
|
|
46
|
-
exports.multiply = (a, b) => a * b;
|
|
47
|
-
`,
|
|
48
|
-
script: 'return add(2, 3) + multiply(4, 5)'
|
|
49
|
-
})
|
|
50
|
-
expect(result.success).toBe(true)
|
|
51
|
-
expect(result.value).toBe(25) // 5 + 20
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
it('exposes exports to tests', async () => {
|
|
55
|
-
const result = await evaluate({
|
|
56
|
-
module: `
|
|
57
|
-
exports.double = (n) => n * 2;
|
|
58
|
-
`,
|
|
59
|
-
tests: `
|
|
60
|
-
describe('double', () => {
|
|
61
|
-
it('doubles a number', () => {
|
|
62
|
-
expect(double(5)).toBe(10);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
`
|
|
66
|
-
})
|
|
67
|
-
expect(result.success).toBe(true)
|
|
68
|
-
expect(result.testResults?.total).toBe(1)
|
|
69
|
-
expect(result.testResults?.passed).toBe(1)
|
|
70
|
-
})
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
describe('test framework', () => {
|
|
74
|
-
it('runs passing tests', async () => {
|
|
75
|
-
const result = await evaluate({
|
|
76
|
-
tests: `
|
|
77
|
-
describe('math', () => {
|
|
78
|
-
it('adds', () => {
|
|
79
|
-
expect(1 + 1).toBe(2);
|
|
80
|
-
});
|
|
81
|
-
it('subtracts', () => {
|
|
82
|
-
expect(5 - 3).toBe(2);
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
`
|
|
86
|
-
})
|
|
87
|
-
expect(result.success).toBe(true)
|
|
88
|
-
expect(result.testResults?.total).toBe(2)
|
|
89
|
-
expect(result.testResults?.passed).toBe(2)
|
|
90
|
-
expect(result.testResults?.failed).toBe(0)
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
it('reports failing tests', async () => {
|
|
94
|
-
const result = await evaluate({
|
|
95
|
-
tests: `
|
|
96
|
-
it('fails', () => {
|
|
97
|
-
expect(1).toBe(2);
|
|
98
|
-
});
|
|
99
|
-
`
|
|
100
|
-
})
|
|
101
|
-
expect(result.success).toBe(false)
|
|
102
|
-
expect(result.testResults?.total).toBe(1)
|
|
103
|
-
expect(result.testResults?.failed).toBe(1)
|
|
104
|
-
expect(result.testResults?.tests[0].error).toContain('Expected 2')
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
it('supports skipped tests', async () => {
|
|
108
|
-
const result = await evaluate({
|
|
109
|
-
tests: `
|
|
110
|
-
it.skip('skipped', () => {
|
|
111
|
-
expect(1).toBe(2);
|
|
112
|
-
});
|
|
113
|
-
it('runs', () => {
|
|
114
|
-
expect(1).toBe(1);
|
|
115
|
-
});
|
|
116
|
-
`
|
|
117
|
-
})
|
|
118
|
-
expect(result.success).toBe(true)
|
|
119
|
-
expect(result.testResults?.total).toBe(2)
|
|
120
|
-
expect(result.testResults?.passed).toBe(1)
|
|
121
|
-
expect(result.testResults?.skipped).toBe(1)
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
it('supports beforeEach hooks', async () => {
|
|
125
|
-
const result = await evaluate({
|
|
126
|
-
tests: `
|
|
127
|
-
let count = 0;
|
|
128
|
-
beforeEach(() => {
|
|
129
|
-
count++;
|
|
130
|
-
});
|
|
131
|
-
it('first', () => {
|
|
132
|
-
expect(count).toBe(1);
|
|
133
|
-
});
|
|
134
|
-
it('second', () => {
|
|
135
|
-
expect(count).toBe(2);
|
|
136
|
-
});
|
|
137
|
-
`
|
|
138
|
-
})
|
|
139
|
-
expect(result.success).toBe(true)
|
|
140
|
-
expect(result.testResults?.passed).toBe(2)
|
|
141
|
-
})
|
|
142
|
-
|
|
143
|
-
it('supports async tests', async () => {
|
|
144
|
-
const result = await evaluate({
|
|
145
|
-
tests: `
|
|
146
|
-
it('async test', async () => {
|
|
147
|
-
const value = await Promise.resolve(42);
|
|
148
|
-
expect(value).toBe(42);
|
|
149
|
-
});
|
|
150
|
-
`
|
|
151
|
-
})
|
|
152
|
-
expect(result.success).toBe(true)
|
|
153
|
-
expect(result.testResults?.passed).toBe(1)
|
|
154
|
-
})
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
describe('expect matchers', () => {
|
|
158
|
-
it('toBe', async () => {
|
|
159
|
-
const result = await evaluate({
|
|
160
|
-
tests: `
|
|
161
|
-
it('works', () => {
|
|
162
|
-
expect(1).toBe(1);
|
|
163
|
-
expect('a').toBe('a');
|
|
164
|
-
});
|
|
165
|
-
`
|
|
166
|
-
})
|
|
167
|
-
expect(result.success).toBe(true)
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
it('toEqual', async () => {
|
|
171
|
-
const result = await evaluate({
|
|
172
|
-
tests: `
|
|
173
|
-
it('works', () => {
|
|
174
|
-
expect({ a: 1 }).toEqual({ a: 1 });
|
|
175
|
-
expect([1, 2]).toEqual([1, 2]);
|
|
176
|
-
});
|
|
177
|
-
`
|
|
178
|
-
})
|
|
179
|
-
expect(result.success).toBe(true)
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
it('toContain', async () => {
|
|
183
|
-
const result = await evaluate({
|
|
184
|
-
tests: `
|
|
185
|
-
it('works', () => {
|
|
186
|
-
expect([1, 2, 3]).toContain(2);
|
|
187
|
-
expect('hello').toContain('ell');
|
|
188
|
-
});
|
|
189
|
-
`
|
|
190
|
-
})
|
|
191
|
-
expect(result.success).toBe(true)
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
it('toThrow', async () => {
|
|
195
|
-
const result = await evaluate({
|
|
196
|
-
tests: `
|
|
197
|
-
it('works', () => {
|
|
198
|
-
expect(() => { throw new Error('boom'); }).toThrow('boom');
|
|
199
|
-
expect(() => { throw new Error('boom'); }).toThrow(/boom/);
|
|
200
|
-
});
|
|
201
|
-
`
|
|
202
|
-
})
|
|
203
|
-
expect(result.success).toBe(true)
|
|
204
|
-
})
|
|
205
|
-
|
|
206
|
-
it('toHaveProperty', async () => {
|
|
207
|
-
const result = await evaluate({
|
|
208
|
-
tests: `
|
|
209
|
-
it('works', () => {
|
|
210
|
-
expect({ a: { b: 1 } }).toHaveProperty('a.b');
|
|
211
|
-
expect({ a: { b: 1 } }).toHaveProperty('a.b', 1);
|
|
212
|
-
});
|
|
213
|
-
`
|
|
214
|
-
})
|
|
215
|
-
expect(result.success).toBe(true)
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
it('toMatchObject', async () => {
|
|
219
|
-
const result = await evaluate({
|
|
220
|
-
tests: `
|
|
221
|
-
it('works', () => {
|
|
222
|
-
expect({ a: 1, b: 2 }).toMatchObject({ a: 1 });
|
|
223
|
-
});
|
|
224
|
-
`
|
|
225
|
-
})
|
|
226
|
-
expect(result.success).toBe(true)
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
it('not matchers', async () => {
|
|
230
|
-
const result = await evaluate({
|
|
231
|
-
tests: `
|
|
232
|
-
it('works', () => {
|
|
233
|
-
expect(1).not.toBe(2);
|
|
234
|
-
expect({ a: 1 }).not.toEqual({ a: 2 });
|
|
235
|
-
expect([1, 2]).not.toContain(3);
|
|
236
|
-
});
|
|
237
|
-
`
|
|
238
|
-
})
|
|
239
|
-
expect(result.success).toBe(true)
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
it('toBeCloseTo', async () => {
|
|
243
|
-
const result = await evaluate({
|
|
244
|
-
tests: `
|
|
245
|
-
it('works', () => {
|
|
246
|
-
expect(0.1 + 0.2).toBeCloseTo(0.3);
|
|
247
|
-
});
|
|
248
|
-
`
|
|
249
|
-
})
|
|
250
|
-
expect(result.success).toBe(true)
|
|
251
|
-
})
|
|
252
|
-
})
|
|
253
|
-
})
|
package/test/index.test.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
describe('index exports', () => {
|
|
3
|
-
it('exports evaluate function', async () => {
|
|
4
|
-
const { evaluate } = await import('../src/index.js');
|
|
5
|
-
expect(typeof evaluate).toBe('function');
|
|
6
|
-
});
|
|
7
|
-
it('exports createEvaluator function', async () => {
|
|
8
|
-
const { createEvaluator } = await import('../src/index.js');
|
|
9
|
-
expect(typeof createEvaluator).toBe('function');
|
|
10
|
-
});
|
|
11
|
-
it('exports types', async () => {
|
|
12
|
-
// Types are compile-time only, so we just check the module loads
|
|
13
|
-
await import('../src/index.js');
|
|
14
|
-
});
|
|
15
|
-
});
|
|
16
|
-
describe('types', () => {
|
|
17
|
-
it('EvaluateOptions interface is usable', async () => {
|
|
18
|
-
const { evaluate } = await import('../src/index.js');
|
|
19
|
-
// Test that options conform to EvaluateOptions
|
|
20
|
-
const options = {
|
|
21
|
-
module: 'exports.x = 1;',
|
|
22
|
-
tests: 'it("test", () => {});',
|
|
23
|
-
script: 'return 1;',
|
|
24
|
-
timeout: 5000,
|
|
25
|
-
env: { FOO: 'bar' },
|
|
26
|
-
fetch: null
|
|
27
|
-
};
|
|
28
|
-
const result = await evaluate(options);
|
|
29
|
-
expect(result).toHaveProperty('success');
|
|
30
|
-
});
|
|
31
|
-
it('EvaluateResult has correct shape', async () => {
|
|
32
|
-
const { evaluate } = await import('../src/index.js');
|
|
33
|
-
const result = await evaluate({ script: 'return 42;' });
|
|
34
|
-
expect(result).toHaveProperty('success');
|
|
35
|
-
expect(result).toHaveProperty('logs');
|
|
36
|
-
expect(result).toHaveProperty('duration');
|
|
37
|
-
expect(typeof result.success).toBe('boolean');
|
|
38
|
-
expect(Array.isArray(result.logs)).toBe(true);
|
|
39
|
-
expect(typeof result.duration).toBe('number');
|
|
40
|
-
});
|
|
41
|
-
it('LogEntry has correct shape', async () => {
|
|
42
|
-
const { evaluate } = await import('../src/index.js');
|
|
43
|
-
const result = await evaluate({
|
|
44
|
-
script: 'console.log("test"); return true;'
|
|
45
|
-
});
|
|
46
|
-
const log = result.logs[0];
|
|
47
|
-
expect(log).toHaveProperty('level');
|
|
48
|
-
expect(log).toHaveProperty('message');
|
|
49
|
-
expect(log).toHaveProperty('timestamp');
|
|
50
|
-
expect(['log', 'warn', 'error', 'info', 'debug']).toContain(log.level);
|
|
51
|
-
});
|
|
52
|
-
it('TestResults has correct shape when tests provided', async () => {
|
|
53
|
-
const { evaluate } = await import('../src/index.js');
|
|
54
|
-
const result = await evaluate({
|
|
55
|
-
tests: 'it("test", () => { expect(1).toBe(1); });'
|
|
56
|
-
});
|
|
57
|
-
expect(result.testResults).toBeDefined();
|
|
58
|
-
expect(result.testResults).toHaveProperty('total');
|
|
59
|
-
expect(result.testResults).toHaveProperty('passed');
|
|
60
|
-
expect(result.testResults).toHaveProperty('failed');
|
|
61
|
-
expect(result.testResults).toHaveProperty('skipped');
|
|
62
|
-
expect(result.testResults).toHaveProperty('tests');
|
|
63
|
-
expect(result.testResults).toHaveProperty('duration');
|
|
64
|
-
});
|
|
65
|
-
it('TestResult has correct shape', async () => {
|
|
66
|
-
const { evaluate } = await import('../src/index.js');
|
|
67
|
-
const result = await evaluate({
|
|
68
|
-
tests: 'it("my test", () => {});'
|
|
69
|
-
});
|
|
70
|
-
const test = result.testResults?.tests[0];
|
|
71
|
-
expect(test).toHaveProperty('name');
|
|
72
|
-
expect(test).toHaveProperty('passed');
|
|
73
|
-
expect(test).toHaveProperty('duration');
|
|
74
|
-
expect(test?.name).toBe('my test');
|
|
75
|
-
expect(test?.passed).toBe(true);
|
|
76
|
-
});
|
|
77
|
-
});
|
package/test/index.test.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
|
|
3
|
-
describe('index exports', () => {
|
|
4
|
-
it('exports evaluate function', async () => {
|
|
5
|
-
const { evaluate } = await import('../src/index.js')
|
|
6
|
-
expect(typeof evaluate).toBe('function')
|
|
7
|
-
})
|
|
8
|
-
|
|
9
|
-
it('exports createEvaluator function', async () => {
|
|
10
|
-
const { createEvaluator } = await import('../src/index.js')
|
|
11
|
-
expect(typeof createEvaluator).toBe('function')
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
it('exports types', async () => {
|
|
15
|
-
// Types are compile-time only, so we just check the module loads
|
|
16
|
-
await import('../src/index.js')
|
|
17
|
-
})
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
describe('types', () => {
|
|
21
|
-
it('EvaluateOptions interface is usable', async () => {
|
|
22
|
-
const { evaluate } = await import('../src/index.js')
|
|
23
|
-
|
|
24
|
-
// Test that options conform to EvaluateOptions
|
|
25
|
-
const options = {
|
|
26
|
-
module: 'exports.x = 1;',
|
|
27
|
-
tests: 'it("test", () => {});',
|
|
28
|
-
script: 'return 1;',
|
|
29
|
-
timeout: 5000,
|
|
30
|
-
env: { FOO: 'bar' },
|
|
31
|
-
fetch: null as null
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const result = await evaluate(options)
|
|
35
|
-
expect(result).toHaveProperty('success')
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
it('EvaluateResult has correct shape', async () => {
|
|
39
|
-
const { evaluate } = await import('../src/index.js')
|
|
40
|
-
|
|
41
|
-
const result = await evaluate({ script: 'return 42;' })
|
|
42
|
-
|
|
43
|
-
expect(result).toHaveProperty('success')
|
|
44
|
-
expect(result).toHaveProperty('logs')
|
|
45
|
-
expect(result).toHaveProperty('duration')
|
|
46
|
-
expect(typeof result.success).toBe('boolean')
|
|
47
|
-
expect(Array.isArray(result.logs)).toBe(true)
|
|
48
|
-
expect(typeof result.duration).toBe('number')
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
it('LogEntry has correct shape', async () => {
|
|
52
|
-
const { evaluate } = await import('../src/index.js')
|
|
53
|
-
|
|
54
|
-
const result = await evaluate({
|
|
55
|
-
script: 'console.log("test"); return true;'
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
const log = result.logs[0]
|
|
59
|
-
expect(log).toHaveProperty('level')
|
|
60
|
-
expect(log).toHaveProperty('message')
|
|
61
|
-
expect(log).toHaveProperty('timestamp')
|
|
62
|
-
expect(['log', 'warn', 'error', 'info', 'debug']).toContain(log.level)
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
it('TestResults has correct shape when tests provided', async () => {
|
|
66
|
-
const { evaluate } = await import('../src/index.js')
|
|
67
|
-
|
|
68
|
-
const result = await evaluate({
|
|
69
|
-
tests: 'it("test", () => { expect(1).toBe(1); });'
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
expect(result.testResults).toBeDefined()
|
|
73
|
-
expect(result.testResults).toHaveProperty('total')
|
|
74
|
-
expect(result.testResults).toHaveProperty('passed')
|
|
75
|
-
expect(result.testResults).toHaveProperty('failed')
|
|
76
|
-
expect(result.testResults).toHaveProperty('skipped')
|
|
77
|
-
expect(result.testResults).toHaveProperty('tests')
|
|
78
|
-
expect(result.testResults).toHaveProperty('duration')
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
it('TestResult has correct shape', async () => {
|
|
82
|
-
const { evaluate } = await import('../src/index.js')
|
|
83
|
-
|
|
84
|
-
const result = await evaluate({
|
|
85
|
-
tests: 'it("my test", () => {});'
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
const test = result.testResults?.tests[0]
|
|
89
|
-
expect(test).toHaveProperty('name')
|
|
90
|
-
expect(test).toHaveProperty('passed')
|
|
91
|
-
expect(test).toHaveProperty('duration')
|
|
92
|
-
expect(test?.name).toBe('my test')
|
|
93
|
-
expect(test?.passed).toBe(true)
|
|
94
|
-
})
|
|
95
|
-
})
|
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
|
2
|
-
import {
|
|
3
|
-
configurePool,
|
|
4
|
-
getPoolConfig,
|
|
5
|
-
getPoolStats,
|
|
6
|
-
warmPool,
|
|
7
|
-
disposePool,
|
|
8
|
-
resetPool,
|
|
9
|
-
} from '../src/miniflare-pool.js'
|
|
10
|
-
import { evaluate } from '../src/node.js'
|
|
11
|
-
|
|
12
|
-
describe('Miniflare Pool', () => {
|
|
13
|
-
// Reset pool state between tests
|
|
14
|
-
beforeEach(async () => {
|
|
15
|
-
await resetPool()
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
afterEach(async () => {
|
|
19
|
-
await disposePool()
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
describe('configurePool', () => {
|
|
23
|
-
it('sets pool size', () => {
|
|
24
|
-
configurePool({ size: 5 })
|
|
25
|
-
const config = getPoolConfig()
|
|
26
|
-
expect(config.size).toBe(5)
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
it('sets maxIdleTime', () => {
|
|
30
|
-
configurePool({ maxIdleTime: 60000 })
|
|
31
|
-
const config = getPoolConfig()
|
|
32
|
-
expect(config.maxIdleTime).toBe(60000)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
it('preserves existing values when not specified', () => {
|
|
36
|
-
configurePool({ size: 5 })
|
|
37
|
-
configurePool({ maxIdleTime: 60000 })
|
|
38
|
-
const config = getPoolConfig()
|
|
39
|
-
expect(config.size).toBe(5)
|
|
40
|
-
expect(config.maxIdleTime).toBe(60000)
|
|
41
|
-
})
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
describe('getPoolConfig', () => {
|
|
45
|
-
it('returns default configuration', () => {
|
|
46
|
-
const config = getPoolConfig()
|
|
47
|
-
expect(config.size).toBe(3)
|
|
48
|
-
expect(config.maxIdleTime).toBe(30000)
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
it('returns a copy of configuration', () => {
|
|
52
|
-
const config1 = getPoolConfig()
|
|
53
|
-
const config2 = getPoolConfig()
|
|
54
|
-
expect(config1).not.toBe(config2)
|
|
55
|
-
expect(config1).toEqual(config2)
|
|
56
|
-
})
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
describe('getPoolStats', () => {
|
|
60
|
-
it('returns initial empty stats', () => {
|
|
61
|
-
const stats = getPoolStats()
|
|
62
|
-
expect(stats.size).toBe(0)
|
|
63
|
-
expect(stats.available).toBe(0)
|
|
64
|
-
expect(stats.inUse).toBe(0)
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
it('shows correct stats after warming', async () => {
|
|
68
|
-
await warmPool(2)
|
|
69
|
-
const stats = getPoolStats()
|
|
70
|
-
expect(stats.size).toBe(2)
|
|
71
|
-
expect(stats.available).toBe(2)
|
|
72
|
-
expect(stats.inUse).toBe(0)
|
|
73
|
-
})
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
describe('warmPool', () => {
|
|
77
|
-
it('creates specified number of instances', async () => {
|
|
78
|
-
await warmPool(2)
|
|
79
|
-
const stats = getPoolStats()
|
|
80
|
-
expect(stats.size).toBe(2)
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it('respects pool size limit', async () => {
|
|
84
|
-
configurePool({ size: 2 })
|
|
85
|
-
await warmPool(5)
|
|
86
|
-
const stats = getPoolStats()
|
|
87
|
-
// warmPool creates up to the requested count, but pool won't grow beyond size
|
|
88
|
-
// when new instances are acquired
|
|
89
|
-
expect(stats.size).toBeLessThanOrEqual(5)
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
it('does not create duplicates when called multiple times', async () => {
|
|
93
|
-
await warmPool(2)
|
|
94
|
-
await warmPool(2)
|
|
95
|
-
const stats = getPoolStats()
|
|
96
|
-
expect(stats.size).toBe(2)
|
|
97
|
-
})
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
describe('disposePool', () => {
|
|
101
|
-
it('disposes all instances', async () => {
|
|
102
|
-
await warmPool(3)
|
|
103
|
-
await disposePool()
|
|
104
|
-
const stats = getPoolStats()
|
|
105
|
-
expect(stats.size).toBe(0)
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
it('can be called multiple times safely', async () => {
|
|
109
|
-
await warmPool(2)
|
|
110
|
-
await disposePool()
|
|
111
|
-
await disposePool()
|
|
112
|
-
const stats = getPoolStats()
|
|
113
|
-
expect(stats.size).toBe(0)
|
|
114
|
-
})
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
describe('resetPool', () => {
|
|
118
|
-
it('disposes instances and resets config', async () => {
|
|
119
|
-
configurePool({ size: 10, maxIdleTime: 60000 })
|
|
120
|
-
await warmPool(3)
|
|
121
|
-
await resetPool()
|
|
122
|
-
const stats = getPoolStats()
|
|
123
|
-
const config = getPoolConfig()
|
|
124
|
-
expect(stats.size).toBe(0)
|
|
125
|
-
expect(config.size).toBe(3)
|
|
126
|
-
expect(config.maxIdleTime).toBe(30000)
|
|
127
|
-
})
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
describe('pool integration with evaluate', () => {
|
|
131
|
-
it('reuses instances across evaluations', async () => {
|
|
132
|
-
// Warm the pool
|
|
133
|
-
await warmPool(1)
|
|
134
|
-
|
|
135
|
-
// Run multiple evaluations
|
|
136
|
-
const results = await Promise.all([
|
|
137
|
-
evaluate({ script: 'return 1' }),
|
|
138
|
-
evaluate({ script: 'return 2' }),
|
|
139
|
-
evaluate({ script: 'return 3' }),
|
|
140
|
-
])
|
|
141
|
-
|
|
142
|
-
expect(results[0].success).toBe(true)
|
|
143
|
-
expect(results[0].value).toBe(1)
|
|
144
|
-
expect(results[1].success).toBe(true)
|
|
145
|
-
expect(results[1].value).toBe(2)
|
|
146
|
-
expect(results[2].success).toBe(true)
|
|
147
|
-
expect(results[2].value).toBe(3)
|
|
148
|
-
|
|
149
|
-
// Pool should have created instances as needed
|
|
150
|
-
const stats = getPoolStats()
|
|
151
|
-
expect(stats.size).toBeGreaterThan(0)
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
it('returns instances to pool after evaluation', async () => {
|
|
155
|
-
// This test verifies the pool reuses instances by running multiple
|
|
156
|
-
// sequential evaluations. If pooling weren't working, each evaluation
|
|
157
|
-
// would be slower due to creating new Miniflare instances.
|
|
158
|
-
configurePool({ size: 1 })
|
|
159
|
-
|
|
160
|
-
// Run sequential evaluations with same pool size
|
|
161
|
-
const result1 = await evaluate({ script: 'return 1' })
|
|
162
|
-
expect(result1.success).toBe(true)
|
|
163
|
-
expect(result1.value).toBe(1)
|
|
164
|
-
|
|
165
|
-
const result2 = await evaluate({ script: 'return 2' })
|
|
166
|
-
expect(result2.success).toBe(true)
|
|
167
|
-
expect(result2.value).toBe(2)
|
|
168
|
-
|
|
169
|
-
const result3 = await evaluate({ script: 'return 3' })
|
|
170
|
-
expect(result3.success).toBe(true)
|
|
171
|
-
expect(result3.value).toBe(3)
|
|
172
|
-
|
|
173
|
-
// All evaluations should succeed, demonstrating instance reuse
|
|
174
|
-
// (If instances weren't being released, pool would exhaust quickly
|
|
175
|
-
// with size=1 and sequential evaluations would fail)
|
|
176
|
-
})
|
|
177
|
-
|
|
178
|
-
it('creates temporary instances when pool is exhausted', async () => {
|
|
179
|
-
configurePool({ size: 1 })
|
|
180
|
-
await warmPool(1)
|
|
181
|
-
|
|
182
|
-
// Start multiple concurrent evaluations
|
|
183
|
-
const evaluationPromises = [
|
|
184
|
-
evaluate({ script: 'return 1' }),
|
|
185
|
-
evaluate({ script: 'return 2' }),
|
|
186
|
-
evaluate({ script: 'return 3' }),
|
|
187
|
-
]
|
|
188
|
-
|
|
189
|
-
const results = await Promise.all(evaluationPromises)
|
|
190
|
-
|
|
191
|
-
// All should succeed (some using temporary instances)
|
|
192
|
-
expect(results.every((r) => r.success)).toBe(true)
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
it('handles errors without leaking instances', async () => {
|
|
196
|
-
configurePool({ size: 1 })
|
|
197
|
-
|
|
198
|
-
// Run an evaluation that throws
|
|
199
|
-
const result = await evaluate({
|
|
200
|
-
script: 'throw new Error("test error")',
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
expect(result.success).toBe(false)
|
|
204
|
-
expect(result.error).toContain('test error')
|
|
205
|
-
|
|
206
|
-
// Instance should still be returned to pool
|
|
207
|
-
const stats = getPoolStats()
|
|
208
|
-
expect(stats.inUse).toBe(0)
|
|
209
|
-
})
|
|
210
|
-
|
|
211
|
-
it('handles timeouts without leaking instances', async () => {
|
|
212
|
-
configurePool({ size: 1 })
|
|
213
|
-
|
|
214
|
-
// Run an evaluation that times out
|
|
215
|
-
const result = await evaluate({
|
|
216
|
-
script: 'while(true) {}',
|
|
217
|
-
timeout: 100,
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
expect(result.success).toBe(false)
|
|
221
|
-
expect(result.error).toContain('Timeout')
|
|
222
|
-
|
|
223
|
-
// Instance should still be returned to pool
|
|
224
|
-
const stats = getPoolStats()
|
|
225
|
-
expect(stats.inUse).toBe(0)
|
|
226
|
-
})
|
|
227
|
-
|
|
228
|
-
it('maintains isolation between evaluations', async () => {
|
|
229
|
-
configurePool({ size: 1 })
|
|
230
|
-
|
|
231
|
-
// First evaluation sets a global
|
|
232
|
-
const result1 = await evaluate({
|
|
233
|
-
script: 'globalThis.testValue = 42; return globalThis.testValue;',
|
|
234
|
-
})
|
|
235
|
-
expect(result1.success).toBe(true)
|
|
236
|
-
expect(result1.value).toBe(42)
|
|
237
|
-
|
|
238
|
-
// Second evaluation should not see the global (new worker script)
|
|
239
|
-
const result2 = await evaluate({
|
|
240
|
-
script: 'return globalThis.testValue;',
|
|
241
|
-
})
|
|
242
|
-
expect(result2.success).toBe(true)
|
|
243
|
-
expect(result2.value).toBeUndefined()
|
|
244
|
-
})
|
|
245
|
-
})
|
|
246
|
-
})
|