cabloy 5.1.220 → 5.1.221
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/.cabloy-version +1 -1
- package/.github/workflows/agent-governance.yml +2 -2
- package/.github/workflows/create-cabloy.yml +2 -2
- package/.github/workflows/docs-pages.yml +2 -2
- package/.github/workflows/playwright-e2e.yml +4 -4
- package/.github/workflows/vona-cov-pg.yml +2 -2
- package/.github/workflows/vona-test-crud.yml +2 -2
- package/.github/workflows/vona-test-mysql.yml +2 -2
- package/.github/workflows/vona-test-pg.yml +2 -2
- package/.github/workflows/vona-test-sqlite3.yml +2 -2
- package/.github/workflows/vona-tsc.yml +2 -2
- package/.github/workflows/zova-ui.yml +2 -2
- package/CHANGELOG.md +11 -0
- package/package.json +4 -3
- package/repo-docs/frontend/openapi-sdk-guide.md +2 -0
- package/repo-docs/reference/repo-scripts.md +5 -1
- package/scripts/generateOpenapiIsolated.ts +18 -1
- package/scripts/runIsolatedTest.test.ts +9 -1
- package/scripts/runIsolatedTest.ts +81 -18
- package/scripts/strictGenerationDiagnostics.test.ts +1009 -0
- package/scripts/strictGenerationDiagnostics.ts +61 -0
- package/vona/package.original.json +3 -2
- package/vona/packages-cli/cli/package.json +1 -1
- package/vona/packages-cli/cli-set-api/package.json +1 -1
- package/vona/packages-cli/cli-set-api/src/lib/bean/cli.bin.dev.ts +14 -4
- package/vona/packages-cli/cli-set-api/src/lib/bean/toolsBin/generateEntryFiles.ts +6 -1
- package/vona/packages-cli/cli-set-api/src/lib/bean/toolsBin/generateVonaMeta.ts +2 -10
- package/vona/packages-cli/cli-set-api/src/lib/bean/toolsBin/validateGenerationPaths.ts +27 -0
- package/vona/packages-cli/cli-set-api/test/binDevLifecycle.test.ts +1 -1
- package/vona/packages-cli/cli-set-api/test/strictGenerationPrivacy.test.ts +439 -0
- package/vona/packages-vona/vona/package.json +1 -1
- package/vona/packages-vona/vona-core/package.json +1 -1
- package/vona/packages-vona/vona-core/src/lib/core/logger/appLogger.ts +10 -2
- package/vona/packages-vona/vona-core/src/lib/core/logger/diagnosticLogger.test.ts +268 -68
- package/vona/packages-vona/vona-core/src/lib/core/testFreshness.ts +3 -9
- package/vona/packages-vona/vona-core/src/lib/core/testStrictMode.ts +9 -0
- package/vona/packages-vona/vona-mock/package.json +1 -1
- package/vona/pnpm-lock.yaml +542 -236
- package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-ormdialect/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-ormdialect/src/index.ts +11 -0
- package/vona/src/suite-vendor/a-vona/modules/a-ormdialect/src/lib/protectedSqliteRegistry.ts +356 -0
- package/vona/src/suite-vendor/a-vona/package.json +1 -1
- package/zova/package.original.json +3 -2
- package/zova/packages-cli/cli/package.json +2 -2
- package/zova/packages-cli/cli-set-front/package.json +1 -1
- package/zova/packages-cli/cli-set-front/src/lib/common/restDependencyVersions.ts +22 -1
- package/zova/packages-cli/cli-set-front/test/restDependencies.test.ts +137 -0
- package/zova/pnpm-lock.yaml +442 -564
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vona",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.112",
|
|
4
4
|
"gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
|
|
5
5
|
"description": "Vona is an intuitive, elegant and powerful Node.js framework for rapidly developing enterprise applications of any size",
|
|
6
6
|
"keywords": [
|
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
import { BeanSimple } from '../../bean/beanSimple.ts';
|
|
15
15
|
import { deepExtend } from '../../utils/util.ts';
|
|
16
16
|
import { getRequestBoundary } from '../requestBoundary.ts';
|
|
17
|
+
import { requiresFreshTestResources } from '../testStrictMode.ts';
|
|
17
18
|
import { createDiagnosticLogger, getSuppressedDiagnosticLogger } from './diagnosticLogger.ts';
|
|
18
19
|
|
|
19
20
|
const SymbolLoggerInstances = Symbol('SymbolLoggerInstances');
|
|
@@ -31,7 +32,9 @@ export class AppLogger extends BeanSimple {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
get(clientName?: keyof ILoggerClientRecord) {
|
|
34
|
-
if (
|
|
35
|
+
if (requiresFreshTestResources() || getRequestBoundary()) {
|
|
36
|
+
return getSuppressedDiagnosticLogger();
|
|
37
|
+
}
|
|
35
38
|
clientName = clientName || 'default';
|
|
36
39
|
if (!this[SymbolLoggerInstances][clientName]) {
|
|
37
40
|
const raw = this._createClient(clientName);
|
|
@@ -42,7 +45,9 @@ export class AppLogger extends BeanSimple {
|
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
child(childName?: keyof ILoggerChildRecord, clientName?: keyof ILoggerClientRecord) {
|
|
45
|
-
if (
|
|
48
|
+
if (requiresFreshTestResources() || getRequestBoundary()) {
|
|
49
|
+
return getSuppressedDiagnosticLogger();
|
|
50
|
+
}
|
|
46
51
|
const logger = this.get(clientName);
|
|
47
52
|
if (!childName) return logger;
|
|
48
53
|
return logger.child({ name: childName });
|
|
@@ -120,6 +125,9 @@ export class AppLogger extends BeanSimple {
|
|
|
120
125
|
| Winston.transports.FileTransportOptions
|
|
121
126
|
| DailyRotateFile.DailyRotateFileTransportOptions,
|
|
122
127
|
) {
|
|
128
|
+
if (requiresFreshTestResources()) {
|
|
129
|
+
throw new Error('Strict test file logger transport is disabled');
|
|
130
|
+
}
|
|
123
131
|
const dirname = this.app.config.logger.baseDir;
|
|
124
132
|
if (!fse.existsSync(dirname)) {
|
|
125
133
|
const [_, err] = catchErrorSync(() => {
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
|
-
import { test } from 'node:test';
|
|
2
|
+
import { afterEach, beforeEach, test } from 'node:test';
|
|
3
3
|
import * as Winston from 'winston';
|
|
4
4
|
import Transport from 'winston-transport';
|
|
5
5
|
|
|
6
6
|
import { createRequestBoundary, runWithRequestBoundary } from '../requestBoundary.ts';
|
|
7
|
+
import { requiresFreshTestResources, TEST_REQUIRE_FRESH_RESOURCES_ENV } from '../testStrictMode.ts';
|
|
7
8
|
import { AppLogger } from './appLogger.ts';
|
|
9
|
+
import { getSuppressedDiagnosticLogger } from './diagnosticLogger.ts';
|
|
10
|
+
|
|
11
|
+
let previousStrictFlag: string | undefined;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
previousStrictFlag = process.env[TEST_REQUIRE_FRESH_RESOURCES_ENV];
|
|
14
|
+
delete process.env[TEST_REQUIRE_FRESH_RESOURCES_ENV];
|
|
15
|
+
});
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
if (previousStrictFlag === undefined) delete process.env[TEST_REQUIRE_FRESH_RESOURCES_ENV];
|
|
18
|
+
else process.env[TEST_REQUIRE_FRESH_RESOURCES_ENV] = previousStrictFlag;
|
|
19
|
+
});
|
|
8
20
|
|
|
9
21
|
class MemoryTransport extends Transport {
|
|
10
22
|
count = 0;
|
|
@@ -58,87 +70,275 @@ function payloadProbe() {
|
|
|
58
70
|
};
|
|
59
71
|
}
|
|
60
72
|
|
|
61
|
-
|
|
73
|
+
function throwingProbe() {
|
|
74
|
+
let reads = 0;
|
|
75
|
+
const read = () => {
|
|
76
|
+
reads++;
|
|
77
|
+
throw new Error('Synthetic logger input must not be evaluated');
|
|
78
|
+
};
|
|
79
|
+
return {
|
|
80
|
+
value: new Proxy({}, { get: read, ownKeys: read }),
|
|
81
|
+
read,
|
|
82
|
+
reads: () => reads,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
test(
|
|
87
|
+
'cached diagnostic handlers never expose raw Winston to a request boundary',
|
|
88
|
+
{ concurrency: false },
|
|
89
|
+
async () => {
|
|
90
|
+
const local = fixture();
|
|
91
|
+
const { raw, logger, sink } = local;
|
|
92
|
+
const exceptions = logger.exceptions;
|
|
93
|
+
const rejections = logger.rejections;
|
|
94
|
+
const probe = payloadProbe();
|
|
95
|
+
try {
|
|
96
|
+
assert.equal(local.factory.get(), logger);
|
|
97
|
+
assert.equal(local.creations(), 1);
|
|
98
|
+
assert.equal(logger.exceptions, exceptions);
|
|
99
|
+
assert.equal(logger.rejections, rejections);
|
|
100
|
+
for (const handler of [exceptions, rejections]) {
|
|
101
|
+
assert.equal(handler.logger, logger);
|
|
102
|
+
assert.equal(Reflect.set(handler, 'logger', raw), false);
|
|
103
|
+
}
|
|
104
|
+
assert.equal(raw.exceptions.logger, raw);
|
|
105
|
+
assert.equal(raw.rejections.logger, raw);
|
|
106
|
+
runWithRequestBoundary(createRequestBoundary(), () => {
|
|
107
|
+
assert.equal(local.factory.get(), getSuppressedDiagnosticLogger());
|
|
108
|
+
assert.equal(local.factory.get('unconfigured' as any), getSuppressedDiagnosticLogger());
|
|
109
|
+
assert.equal(local.factory.child('synthetic' as any), getSuppressedDiagnosticLogger());
|
|
110
|
+
logger.error(probe.payload);
|
|
111
|
+
logger.exceptions.logger.error(probe.payload);
|
|
112
|
+
logger.rejections.logger.error(probe.payload);
|
|
113
|
+
exceptions.logger.error(probe.payload);
|
|
114
|
+
rejections.logger.error(probe.payload);
|
|
115
|
+
});
|
|
116
|
+
assert.equal(probe.reads(), 0);
|
|
117
|
+
assert.equal(sink.count, 0);
|
|
118
|
+
for (const handler of [exceptions, rejections]) {
|
|
119
|
+
const before = probe.reads();
|
|
120
|
+
handler.logger.error(probe.payload);
|
|
121
|
+
assert.ok(probe.reads() > before);
|
|
122
|
+
}
|
|
123
|
+
assert.equal(sink.count, 2);
|
|
124
|
+
const before = probe.reads();
|
|
125
|
+
raw.error(probe.payload);
|
|
126
|
+
assert.ok(probe.reads() > before);
|
|
127
|
+
assert.equal(sink.count, 3);
|
|
128
|
+
} finally {
|
|
129
|
+
await local.close();
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
test(
|
|
135
|
+
'diagnostic handler methods keep their raw receiver and map fluent returns',
|
|
136
|
+
{ concurrency: false },
|
|
137
|
+
async () => {
|
|
138
|
+
const local = fixture();
|
|
139
|
+
try {
|
|
140
|
+
for (const key of ['exceptions', 'rejections'] as const) {
|
|
141
|
+
const rawHandler = local.raw[key];
|
|
142
|
+
const handler = local.logger[key];
|
|
143
|
+
const marker = {};
|
|
144
|
+
const original = rawHandler.getAllInfo;
|
|
145
|
+
Object.defineProperty(rawHandler, 'getAllInfo', {
|
|
146
|
+
configurable: true,
|
|
147
|
+
value(this: typeof rawHandler, value: unknown) {
|
|
148
|
+
assert.equal(this, rawHandler);
|
|
149
|
+
assert.equal(value, marker);
|
|
150
|
+
return this;
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
try {
|
|
154
|
+
assert.equal(handler.handlers, rawHandler.handlers);
|
|
155
|
+
assert.equal(handler.getAllInfo(marker as any), handler);
|
|
156
|
+
assert.equal(handler.logger, local.logger);
|
|
157
|
+
} finally {
|
|
158
|
+
Object.defineProperty(rawHandler, 'getAllInfo', {
|
|
159
|
+
configurable: true,
|
|
160
|
+
value: original,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const exceptions = local.logger.exceptions;
|
|
165
|
+
const rejections = local.logger.rejections;
|
|
166
|
+
local.logger.configure({ transports: [local.sink] });
|
|
167
|
+
assert.notEqual(local.logger.exceptions, exceptions);
|
|
168
|
+
assert.notEqual(local.logger.rejections, rejections);
|
|
169
|
+
assert.equal(local.logger.exceptions.logger, local.logger);
|
|
170
|
+
assert.equal(local.logger.rejections.logger, local.logger);
|
|
171
|
+
assert.equal(exceptions.logger, local.logger);
|
|
172
|
+
assert.equal(rejections.logger, local.logger);
|
|
173
|
+
runWithRequestBoundary(createRequestBoundary(), () => {
|
|
174
|
+
exceptions.logger.error('local');
|
|
175
|
+
rejections.logger.error('local');
|
|
176
|
+
});
|
|
177
|
+
assert.equal(local.sink.count, 0);
|
|
178
|
+
} finally {
|
|
179
|
+
await local.close();
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
test('strict logger bypasses cached clients and payloads', { concurrency: false }, async () => {
|
|
62
185
|
const local = fixture();
|
|
63
|
-
const
|
|
64
|
-
const exceptions = logger.exceptions;
|
|
65
|
-
const rejections = logger.rejections;
|
|
66
|
-
const probe = payloadProbe();
|
|
186
|
+
const probe = throwingProbe();
|
|
67
187
|
try {
|
|
68
|
-
|
|
188
|
+
process.env[TEST_REQUIRE_FRESH_RESOURCES_ENV] = 'true';
|
|
189
|
+
const suppressed = getSuppressedDiagnosticLogger();
|
|
190
|
+
assert.equal(local.factory.get(), suppressed);
|
|
191
|
+
assert.equal(local.factory.get('unconfigured' as any), suppressed);
|
|
192
|
+
assert.equal(local.factory.child('synthetic' as any), suppressed);
|
|
193
|
+
assert.equal(local.factory.child('synthetic' as any, 'unconfigured' as any), suppressed);
|
|
194
|
+
assert.notEqual(suppressed, local.logger);
|
|
195
|
+
assert.equal(suppressed.error(probe.value), suppressed);
|
|
196
|
+
assert.equal(suppressed.info(probe.value), suppressed);
|
|
197
|
+
assert.equal(suppressed.log(probe.value as any), suppressed);
|
|
198
|
+
assert.equal(suppressed.child(probe.value), suppressed);
|
|
199
|
+
assert.equal(suppressed.startTimer().done(probe.value), suppressed);
|
|
200
|
+
let completions = 0;
|
|
201
|
+
assert.equal(
|
|
202
|
+
suppressed.write(probe.value, () => completions++),
|
|
203
|
+
true,
|
|
204
|
+
);
|
|
205
|
+
assert.equal(completions, 1);
|
|
206
|
+
assert.equal(probe.reads(), 0);
|
|
69
207
|
assert.equal(local.creations(), 1);
|
|
70
|
-
assert.equal(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
208
|
+
assert.equal(local.sink.count, 0);
|
|
209
|
+
delete process.env[TEST_REQUIRE_FRESH_RESOURCES_ENV];
|
|
210
|
+
assert.equal(local.factory.get(), local.logger);
|
|
211
|
+
local.factory.child().info('ordinary logging remains available');
|
|
212
|
+
assert.equal(local.sink.count, 1);
|
|
213
|
+
} finally {
|
|
214
|
+
await local.close();
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
test('strict entry guards precede cache and app access', { concurrency: false }, async () => {
|
|
219
|
+
const local = fixture();
|
|
220
|
+
const probe = throwingProbe();
|
|
221
|
+
const descriptors = Object.getOwnPropertyDescriptors(local.factory);
|
|
222
|
+
const cacheKeys = Object.getOwnPropertySymbols(local.factory);
|
|
223
|
+
try {
|
|
224
|
+
assert.equal(cacheKeys.length, 2);
|
|
225
|
+
for (const key of cacheKeys) {
|
|
226
|
+
Object.defineProperty(local.factory, key, { configurable: true, get: probe.read });
|
|
75
227
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
228
|
+
Object.defineProperty(local.factory, 'app', { configurable: true, get: probe.read });
|
|
229
|
+
process.env[TEST_REQUIRE_FRESH_RESOURCES_ENV] = 'true';
|
|
230
|
+
assert.equal(local.factory.get(), getSuppressedDiagnosticLogger());
|
|
231
|
+
assert.equal(local.factory.get(probe.value as any), getSuppressedDiagnosticLogger());
|
|
232
|
+
Object.defineProperty(local.factory, 'get', { configurable: true, get: probe.read });
|
|
233
|
+
assert.equal(local.factory.child(), getSuppressedDiagnosticLogger());
|
|
234
|
+
assert.equal(
|
|
235
|
+
local.factory.child(probe.value as any, probe.value as any),
|
|
236
|
+
getSuppressedDiagnosticLogger(),
|
|
237
|
+
);
|
|
238
|
+
assert.equal(local.creations(), 1);
|
|
85
239
|
assert.equal(probe.reads(), 0);
|
|
86
|
-
assert.equal(sink.count, 0);
|
|
87
|
-
for (const handler of [exceptions, rejections]) {
|
|
88
|
-
const before = probe.reads();
|
|
89
|
-
handler.logger.error(probe.payload);
|
|
90
|
-
assert.ok(probe.reads() > before);
|
|
91
|
-
}
|
|
92
|
-
assert.equal(sink.count, 2);
|
|
93
|
-
const before = probe.reads();
|
|
94
|
-
raw.error(probe.payload);
|
|
95
|
-
assert.ok(probe.reads() > before);
|
|
96
|
-
assert.equal(sink.count, 3);
|
|
240
|
+
assert.equal(local.sink.count, 0);
|
|
97
241
|
} finally {
|
|
242
|
+
delete (local.factory as any).get;
|
|
243
|
+
delete (local.factory as any).app;
|
|
244
|
+
Object.defineProperties(local.factory, descriptors);
|
|
98
245
|
await local.close();
|
|
99
246
|
}
|
|
100
247
|
});
|
|
101
248
|
|
|
102
|
-
test('
|
|
249
|
+
test('strict logger skips real configuration factories', { concurrency: false }, async () => {
|
|
250
|
+
const factory = new AppLogger();
|
|
251
|
+
const probe = throwingProbe();
|
|
252
|
+
let configurations = 0;
|
|
253
|
+
Object.defineProperty(factory, 'app', {
|
|
254
|
+
value: {
|
|
255
|
+
config: {
|
|
256
|
+
logger: {
|
|
257
|
+
base() {
|
|
258
|
+
configurations++;
|
|
259
|
+
return probe.read();
|
|
260
|
+
},
|
|
261
|
+
clients: {
|
|
262
|
+
default() {
|
|
263
|
+
configurations++;
|
|
264
|
+
return probe.read();
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
get baseDir() {
|
|
268
|
+
return probe.read();
|
|
269
|
+
},
|
|
270
|
+
get rotate() {
|
|
271
|
+
return probe.read();
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
});
|
|
277
|
+
try {
|
|
278
|
+
process.env[TEST_REQUIRE_FRESH_RESOURCES_ENV] = 'true';
|
|
279
|
+
assert.equal(factory.get(), getSuppressedDiagnosticLogger());
|
|
280
|
+
assert.equal(factory.child('synthetic' as any), getSuppressedDiagnosticLogger());
|
|
281
|
+
assert.equal(configurations, 0);
|
|
282
|
+
assert.equal(probe.reads(), 0);
|
|
283
|
+
} finally {
|
|
284
|
+
await factory.dispose();
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
test('strict file transport fails before any input access', { concurrency: false }, () => {
|
|
289
|
+
const factory = new AppLogger();
|
|
290
|
+
const probe = throwingProbe();
|
|
291
|
+
const args = [probe.value, probe.value, probe.value] as unknown as Parameters<
|
|
292
|
+
AppLogger['createTransportFile']
|
|
293
|
+
>;
|
|
294
|
+
Object.defineProperty(factory, 'app', { get: probe.read });
|
|
295
|
+
process.env[TEST_REQUIRE_FRESH_RESOURCES_ENV] = 'true';
|
|
296
|
+
assert.throws(() => factory.createTransportFile(...args), {
|
|
297
|
+
message: 'Strict test file logger transport is disabled',
|
|
298
|
+
});
|
|
299
|
+
runWithRequestBoundary(createRequestBoundary(), () => {
|
|
300
|
+
assert.throws(() => factory.createTransportFile(...args), {
|
|
301
|
+
message: 'Strict test file logger transport is disabled',
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
assert.equal(probe.reads(), 0);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
test('invalid strict flags never fall back to loggers', { concurrency: false }, async () => {
|
|
103
308
|
const local = fixture();
|
|
309
|
+
const probe = throwingProbe();
|
|
310
|
+
Object.defineProperty(local.factory, 'app', { get: probe.read });
|
|
311
|
+
const args = [probe.value, probe.value, probe.value] as unknown as Parameters<
|
|
312
|
+
AppLogger['createTransportFile']
|
|
313
|
+
>;
|
|
104
314
|
try {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
315
|
+
const env: NodeJS.ProcessEnv = { NODE_ENV: 'test', META_FLAVOR: 'normal', META_MODE: 'test' };
|
|
316
|
+
assert.equal(requiresFreshTestResources(), false);
|
|
317
|
+
assert.equal(requiresFreshTestResources(env), false);
|
|
318
|
+
assert.equal(
|
|
319
|
+
requiresFreshTestResources({ ...env, [TEST_REQUIRE_FRESH_RESOURCES_ENV]: 'true' }),
|
|
320
|
+
true,
|
|
321
|
+
);
|
|
322
|
+
for (const flag of ['', 'false', 'TRUE', 'synthetic-invalid-flag']) {
|
|
323
|
+
process.env[TEST_REQUIRE_FRESH_RESOURCES_ENV] = flag;
|
|
324
|
+
const expected = { message: 'Invalid strict test resource freshness flag' };
|
|
325
|
+
assert.throws(() => requiresFreshTestResources(), expected);
|
|
326
|
+
assert.throws(
|
|
327
|
+
() => requiresFreshTestResources({ ...env, [TEST_REQUIRE_FRESH_RESOURCES_ENV]: flag }),
|
|
328
|
+
expected,
|
|
329
|
+
);
|
|
330
|
+
const calls = [
|
|
331
|
+
() => local.factory.get(),
|
|
332
|
+
() => local.factory.child('synthetic' as any),
|
|
333
|
+
() => local.factory.createTransportFile(...args),
|
|
334
|
+
];
|
|
335
|
+
for (const call of calls) {
|
|
336
|
+
assert.throws(call, expected);
|
|
337
|
+
runWithRequestBoundary(createRequestBoundary(), () => assert.throws(call, expected));
|
|
127
338
|
}
|
|
128
339
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
local.logger.configure({ transports: [local.sink] });
|
|
132
|
-
assert.notEqual(local.logger.exceptions, exceptions);
|
|
133
|
-
assert.notEqual(local.logger.rejections, rejections);
|
|
134
|
-
assert.equal(local.logger.exceptions.logger, local.logger);
|
|
135
|
-
assert.equal(local.logger.rejections.logger, local.logger);
|
|
136
|
-
assert.equal(exceptions.logger, local.logger);
|
|
137
|
-
assert.equal(rejections.logger, local.logger);
|
|
138
|
-
runWithRequestBoundary(createRequestBoundary(), () => {
|
|
139
|
-
exceptions.logger.error('local');
|
|
140
|
-
rejections.logger.error('local');
|
|
141
|
-
});
|
|
340
|
+
assert.equal(probe.reads(), 0);
|
|
341
|
+
assert.equal(local.creations(), 1);
|
|
142
342
|
assert.equal(local.sink.count, 0);
|
|
143
343
|
} finally {
|
|
144
344
|
await local.close();
|
|
@@ -12,17 +12,11 @@ import {
|
|
|
12
12
|
mergeTestClaimRedisOptions,
|
|
13
13
|
} from './testClaim.ts';
|
|
14
14
|
import { resolveVonaLocalPaths } from './testIsolation.ts';
|
|
15
|
+
import { requiresFreshTestResources } from './testStrictMode.ts';
|
|
15
16
|
|
|
16
|
-
export
|
|
17
|
-
const freshApps = new WeakSet<VonaApplication>();
|
|
17
|
+
export { requiresFreshTestResources, TEST_REQUIRE_FRESH_RESOURCES_ENV } from './testStrictMode.ts';
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
const value = process.env[TEST_REQUIRE_FRESH_RESOURCES_ENV];
|
|
21
|
-
if (value !== undefined && value !== 'true') {
|
|
22
|
-
throw new Error('Invalid strict test resource freshness flag');
|
|
23
|
-
}
|
|
24
|
-
return value === 'true';
|
|
25
|
-
}
|
|
19
|
+
const freshApps = new WeakSet<VonaApplication>();
|
|
26
20
|
|
|
27
21
|
export function assertFreshTestResourcesReady(app: VonaApplication) {
|
|
28
22
|
if (!requiresFreshTestResources()) return;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const TEST_REQUIRE_FRESH_RESOURCES_ENV = 'VONA_TEST_REQUIRE_FRESH_RESOURCES';
|
|
2
|
+
|
|
3
|
+
export function requiresFreshTestResources(env: NodeJS.ProcessEnv = process.env) {
|
|
4
|
+
const value = env[TEST_REQUIRE_FRESH_RESOURCES_ENV];
|
|
5
|
+
if (value !== undefined && value !== 'true') {
|
|
6
|
+
throw new Error('Invalid strict test resource freshness flag');
|
|
7
|
+
}
|
|
8
|
+
return value === 'true';
|
|
9
|
+
}
|