@t1mmen/srtd 0.4.2 → 0.4.4
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/README.md +1 -1
- package/dist/__tests__/apply.test.js +2 -2
- package/dist/__tests__/build.test.js +4 -4
- package/dist/__tests__/build.test.js.map +1 -1
- package/dist/__tests__/clear.test.d.ts +1 -0
- package/dist/__tests__/clear.test.js +11 -0
- package/dist/__tests__/clear.test.js.map +1 -0
- package/dist/__tests__/init.test.d.ts +1 -0
- package/dist/__tests__/init.test.js +28 -0
- package/dist/__tests__/init.test.js.map +1 -0
- package/dist/__tests__/register.test.d.ts +1 -0
- package/dist/__tests__/register.test.js +9 -0
- package/dist/__tests__/register.test.js.map +1 -0
- package/dist/__tests__/vitest.setup.js +2 -1
- package/dist/__tests__/vitest.setup.js.map +1 -1
- package/dist/__tests__/watch.test.js +3 -6
- package/dist/__tests__/watch.test.js.map +1 -1
- package/dist/commands/_app.js +1 -9
- package/dist/commands/_app.js.map +1 -1
- package/dist/commands/apply.js +3 -5
- package/dist/commands/apply.js.map +1 -1
- package/dist/commands/build.js +5 -6
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/clear.js +12 -5
- package/dist/commands/clear.js.map +1 -1
- package/dist/commands/index.js +6 -12
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/register.d.ts +1 -1
- package/dist/commands/register.js +62 -16
- package/dist/commands/register.js.map +1 -1
- package/dist/commands/watch.js +25 -28
- package/dist/commands/watch.js.map +1 -1
- package/dist/components/Branding.js +1 -1
- package/dist/components/Branding.js.map +1 -1
- package/dist/components/ProcessingResults.js +26 -14
- package/dist/components/ProcessingResults.js.map +1 -1
- package/dist/components/Quittable.js +6 -4
- package/dist/components/Quittable.js.map +1 -1
- package/dist/components/StatBadge.d.ts +6 -0
- package/dist/components/StatBadge.js +14 -0
- package/dist/components/StatBadge.js.map +1 -0
- package/dist/components/TimeSince.js +9 -5
- package/dist/components/TimeSince.js.map +1 -1
- package/dist/hooks/useDatabaseConnection.js +2 -1
- package/dist/hooks/useDatabaseConnection.js.map +1 -1
- package/dist/hooks/useFullscreen.d.ts +1 -0
- package/dist/hooks/useFullscreen.js +18 -0
- package/dist/hooks/useFullscreen.js.map +1 -0
- package/dist/hooks/useTemplateProcessor.js +0 -6
- package/dist/hooks/useTemplateProcessor.js.map +1 -1
- package/dist/lib/templateManager.js +41 -26
- package/dist/lib/templateManager.js.map +1 -1
- package/dist/lib/templateManager.test.js +821 -505
- package/dist/lib/templateManager.test.js.map +1 -1
- package/dist/utils/applyMigrations.test.js +4 -1
- package/dist/utils/applyMigrations.test.js.map +1 -1
- package/dist/utils/databaseConnection.js +21 -19
- package/dist/utils/databaseConnection.js.map +1 -1
- package/dist/utils/databaseConnection.test.js +1 -4
- package/dist/utils/databaseConnection.test.js.map +1 -1
- package/dist/utils/logger.js +6 -5
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/registerTemplate.js +1 -2
- package/dist/utils/registerTemplate.js.map +1 -1
- package/package.json +2 -1
|
@@ -56,27 +56,22 @@ import { default as path, join, relative } from 'node:path';
|
|
|
56
56
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
57
57
|
import { TEST_FN_PREFIX } from '../__tests__/vitest.setup.js';
|
|
58
58
|
import { calculateMD5 } from '../utils/calculateMD5.js';
|
|
59
|
-
import { connect
|
|
59
|
+
import { connect } from '../utils/databaseConnection.js';
|
|
60
60
|
import { ensureDirectories } from '../utils/ensureDirectories.js';
|
|
61
61
|
import { TemplateManager } from './templateManager.js';
|
|
62
|
-
const
|
|
63
|
-
const start = Date.now();
|
|
64
|
-
while (Date.now() - start < timeout) {
|
|
65
|
-
if (await condition())
|
|
66
|
-
return true;
|
|
67
|
-
await new Promise(resolve => setTimeout(resolve, interval));
|
|
68
|
-
}
|
|
69
|
-
return false;
|
|
70
|
-
};
|
|
62
|
+
const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
71
63
|
describe('TemplateManager', () => {
|
|
72
64
|
const testContext = {
|
|
73
|
-
|
|
74
|
-
testDir:
|
|
75
|
-
testFunctionName:
|
|
65
|
+
testId: 0,
|
|
66
|
+
testDir: tmpdir(),
|
|
67
|
+
testFunctionName: TEST_FN_PREFIX,
|
|
68
|
+
templateCounter: 0,
|
|
76
69
|
};
|
|
77
70
|
beforeEach(async () => {
|
|
78
|
-
testContext.
|
|
79
|
-
testContext.
|
|
71
|
+
testContext.testId = Math.floor(Math.random() * 1000000);
|
|
72
|
+
testContext.testDir = join(tmpdir(), `srtd-test`);
|
|
73
|
+
testContext.testFunctionName = `${TEST_FN_PREFIX}`;
|
|
74
|
+
testContext.templateCounter = 0;
|
|
80
75
|
await ensureDirectories(testContext.testDir);
|
|
81
76
|
const client = await connect();
|
|
82
77
|
try {
|
|
@@ -106,190 +101,316 @@ describe('TemplateManager', () => {
|
|
|
106
101
|
client.release();
|
|
107
102
|
}
|
|
108
103
|
await fs.rm(testContext.testDir, { recursive: true, force: true });
|
|
109
|
-
disconnect();
|
|
110
104
|
});
|
|
105
|
+
// Helper to generate unique template names
|
|
106
|
+
const getNextTemplateName = (prefix = 'template') => {
|
|
107
|
+
testContext.templateCounter++;
|
|
108
|
+
return `${prefix}_${testContext.testId}_${testContext.templateCounter}`;
|
|
109
|
+
};
|
|
111
110
|
const createTemplate = async (name, content, dir) => {
|
|
112
111
|
const fullPath = dir
|
|
113
112
|
? join(testContext.testDir, 'test-templates', dir, name)
|
|
114
113
|
: join(testContext.testDir, 'test-templates', name);
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
try {
|
|
115
|
+
await fs.mkdir(path.dirname(fullPath), { recursive: true });
|
|
116
|
+
await fs.writeFile(fullPath, content);
|
|
117
|
+
return fullPath;
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
console.error('Error creating template:', error);
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
118
123
|
};
|
|
119
|
-
const createTemplateWithFunc = async (
|
|
124
|
+
const createTemplateWithFunc = async (prefix, funcSuffix = '', dir) => {
|
|
125
|
+
const name = `${getNextTemplateName(prefix)}.sql`;
|
|
120
126
|
const funcName = `${testContext.testFunctionName}${funcSuffix}`;
|
|
121
127
|
const content = `CREATE OR REPLACE FUNCTION ${funcName}() RETURNS void AS $$ BEGIN NULL; END; $$ LANGUAGE plpgsql;`;
|
|
122
128
|
return createTemplate(name, content, dir);
|
|
123
129
|
};
|
|
124
130
|
it('should create migration file when template changes', async () => {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
132
|
+
try {
|
|
133
|
+
await createTemplateWithFunc('basic', '_file_change');
|
|
134
|
+
const manager = __addDisposableResource(env_1, await TemplateManager.create(testContext.testDir), false);
|
|
135
|
+
await manager.processTemplates({ generateFiles: true });
|
|
136
|
+
const migrations = await fs.readdir(join(testContext.testDir, 'test-migrations'));
|
|
137
|
+
expect(migrations.length).toBe(1);
|
|
138
|
+
}
|
|
139
|
+
catch (e_1) {
|
|
140
|
+
env_1.error = e_1;
|
|
141
|
+
env_1.hasError = true;
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
__disposeResources(env_1);
|
|
145
|
+
}
|
|
131
146
|
});
|
|
132
147
|
it('should not allow building WIP templates', async () => {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
148
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
149
|
+
try {
|
|
150
|
+
await createTemplateWithFunc('file.wip', '_wip_wont_build');
|
|
151
|
+
const manager = __addDisposableResource(env_2, await TemplateManager.create(testContext.testDir), false);
|
|
152
|
+
await manager.processTemplates({ generateFiles: true });
|
|
153
|
+
const migrations = await fs.readdir(join(testContext.testDir, 'test-migrations'));
|
|
154
|
+
expect(migrations.filter(m => m.includes(`wip`))).toHaveLength(0);
|
|
155
|
+
}
|
|
156
|
+
catch (e_2) {
|
|
157
|
+
env_2.error = e_2;
|
|
158
|
+
env_2.hasError = true;
|
|
159
|
+
}
|
|
160
|
+
finally {
|
|
161
|
+
__disposeResources(env_2);
|
|
162
|
+
}
|
|
138
163
|
});
|
|
139
164
|
it('should maintain separate build and local logs', async () => {
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
165
|
+
const env_3 = { stack: [], error: void 0, hasError: false };
|
|
166
|
+
try {
|
|
167
|
+
const templatePath = join(testContext.testDir, 'test-templates', `template_${testContext.testId}_1.sql`);
|
|
168
|
+
const templateContent = `CREATE FUNCTION ${testContext.testFunctionName}() RETURNS void AS $$ BEGIN NULL; END; $$ LANGUAGE plpgsql;`;
|
|
169
|
+
await fs.writeFile(templatePath, templateContent);
|
|
170
|
+
const manager = __addDisposableResource(env_3, await TemplateManager.create(testContext.testDir), false);
|
|
171
|
+
// Build writes to build log
|
|
172
|
+
await manager.processTemplates({ generateFiles: true });
|
|
173
|
+
const buildLog = JSON.parse(await fs.readFile(join(testContext.testDir, '.buildlog-test.json'), 'utf-8'));
|
|
174
|
+
const relPath = relative(testContext.testDir, templatePath);
|
|
175
|
+
expect(buildLog.templates[relPath].lastBuildHash).toBeDefined();
|
|
176
|
+
// Apply writes to local log
|
|
177
|
+
await manager.processTemplates({ apply: true });
|
|
178
|
+
const localLog = JSON.parse(await fs.readFile(join(testContext.testDir, '.buildlog-test.local.json'), 'utf-8'));
|
|
179
|
+
expect(localLog.templates[relPath].lastAppliedHash).toBeDefined();
|
|
180
|
+
}
|
|
181
|
+
catch (e_3) {
|
|
182
|
+
env_3.error = e_3;
|
|
183
|
+
env_3.hasError = true;
|
|
184
|
+
}
|
|
185
|
+
finally {
|
|
186
|
+
__disposeResources(env_3);
|
|
187
|
+
}
|
|
153
188
|
});
|
|
154
189
|
it('should track template state correctly', async () => {
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
190
|
+
const env_4 = { stack: [], error: void 0, hasError: false };
|
|
191
|
+
try {
|
|
192
|
+
const templatePath = join(testContext.testDir, 'test-templates', `template_${testContext.testId}_1.sql`);
|
|
193
|
+
const templateContent = `CREATE FUNCTION ${testContext.testFunctionName}() RETURNS void AS $$ BEGIN NULL; END; $$ LANGUAGE plpgsql;`;
|
|
194
|
+
await fs.writeFile(templatePath, templateContent);
|
|
195
|
+
const manager = __addDisposableResource(env_4, await TemplateManager.create(testContext.testDir), false);
|
|
196
|
+
// Initially no state
|
|
197
|
+
let status = await manager.getTemplateStatus(templatePath);
|
|
198
|
+
expect(status.buildState.lastBuildHash).toBeUndefined();
|
|
199
|
+
expect(status.buildState.lastAppliedHash).toBeUndefined();
|
|
200
|
+
// After build
|
|
201
|
+
await manager.processTemplates({ generateFiles: true });
|
|
202
|
+
status = await manager.getTemplateStatus(templatePath);
|
|
203
|
+
expect(status.buildState.lastBuildHash).toBeDefined();
|
|
204
|
+
expect(status.buildState.lastBuildDate).toBeDefined();
|
|
205
|
+
// After apply
|
|
206
|
+
await manager.processTemplates({ apply: true });
|
|
207
|
+
status = await manager.getTemplateStatus(templatePath);
|
|
208
|
+
expect(status.buildState.lastAppliedHash).toBeDefined();
|
|
209
|
+
expect(status.buildState.lastAppliedDate).toBeDefined();
|
|
210
|
+
}
|
|
211
|
+
catch (e_4) {
|
|
212
|
+
env_4.error = e_4;
|
|
213
|
+
env_4.hasError = true;
|
|
214
|
+
}
|
|
215
|
+
finally {
|
|
216
|
+
__disposeResources(env_4);
|
|
217
|
+
}
|
|
173
218
|
});
|
|
174
219
|
it('should handle rapid template changes', async () => {
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
changes
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
220
|
+
const env_5 = { stack: [], error: void 0, hasError: false };
|
|
221
|
+
try {
|
|
222
|
+
const templatePath = join(testContext.testDir, 'test-templates', `template_${testContext.testId}_1.sql`);
|
|
223
|
+
const baseContent = `CREATE OR REPLACE FUNCTION ${testContext.testFunctionName}() RETURNS void AS $$ BEGIN NULL; END; $$ LANGUAGE plpgsql;`;
|
|
224
|
+
await fs.writeFile(templatePath, baseContent);
|
|
225
|
+
const manager = __addDisposableResource(env_5, await TemplateManager.create(testContext.testDir), false);
|
|
226
|
+
const changes = [];
|
|
227
|
+
manager.on('templateChanged', async (template) => {
|
|
228
|
+
changes.push(template.currentHash);
|
|
229
|
+
});
|
|
230
|
+
const watcher = await manager.watch();
|
|
231
|
+
await wait(100);
|
|
232
|
+
// Make rapid changes
|
|
233
|
+
for (let i = 0; i < 5; i++) {
|
|
234
|
+
await fs.writeFile(templatePath, `${baseContent}\n-- Change ${i}`);
|
|
235
|
+
await wait(100);
|
|
236
|
+
}
|
|
237
|
+
await wait(500);
|
|
238
|
+
watcher.close();
|
|
239
|
+
expect(changes.length).toBeGreaterThanOrEqual(1);
|
|
240
|
+
expect(new Set(changes).size).toBe(changes.length); // All changes should be unique
|
|
241
|
+
}
|
|
242
|
+
catch (e_5) {
|
|
243
|
+
env_5.error = e_5;
|
|
244
|
+
env_5.hasError = true;
|
|
245
|
+
}
|
|
246
|
+
finally {
|
|
247
|
+
__disposeResources(env_5);
|
|
248
|
+
}
|
|
194
249
|
}, 10000);
|
|
195
250
|
it('should apply WIP templates directly to database', async () => {
|
|
196
|
-
const
|
|
197
|
-
const templateContent = `CREATE FUNCTION ${testContext.testFunctionName}() RETURNS void AS $$ BEGIN NULL; END; $$ LANGUAGE plpgsql;`;
|
|
198
|
-
await fs.writeFile(templatePath, templateContent);
|
|
199
|
-
const manager = await TemplateManager.create(testContext.testDir);
|
|
200
|
-
const result = await manager.processTemplates({ apply: true });
|
|
201
|
-
expect(result.errors).toHaveLength(0);
|
|
202
|
-
const client = await connect();
|
|
251
|
+
const env_6 = { stack: [], error: void 0, hasError: false };
|
|
203
252
|
try {
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
253
|
+
const templatePath = join(testContext.testDir, 'test-templates', `template_${testContext.testId}_1.wip.sql`);
|
|
254
|
+
const templateContent = `CREATE FUNCTION ${testContext.testFunctionName}() RETURNS void AS $$ BEGIN NULL; END; $$ LANGUAGE plpgsql;`;
|
|
255
|
+
await fs.writeFile(templatePath, templateContent);
|
|
256
|
+
const manager = __addDisposableResource(env_6, await TemplateManager.create(testContext.testDir), false);
|
|
257
|
+
const result = await manager.processTemplates({ apply: true });
|
|
258
|
+
expect(result.errors).toHaveLength(0);
|
|
259
|
+
const client = await connect();
|
|
260
|
+
try {
|
|
261
|
+
const res = await client.query(`SELECT COUNT(*) FROM pg_proc WHERE proname = $1`, [
|
|
262
|
+
testContext.testFunctionName,
|
|
263
|
+
]);
|
|
264
|
+
expect(Number.parseInt(res.rows[0].count)).toBe(1);
|
|
265
|
+
}
|
|
266
|
+
finally {
|
|
267
|
+
client.release();
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
catch (e_6) {
|
|
271
|
+
env_6.error = e_6;
|
|
272
|
+
env_6.hasError = true;
|
|
208
273
|
}
|
|
209
274
|
finally {
|
|
210
|
-
|
|
275
|
+
__disposeResources(env_6);
|
|
211
276
|
}
|
|
212
277
|
});
|
|
213
278
|
it('should handle sequential template operations', async () => {
|
|
214
|
-
const
|
|
215
|
-
const manager = await TemplateManager.create(testContext.testDir);
|
|
216
|
-
const client = await connect();
|
|
279
|
+
const env_7 = { stack: [], error: void 0, hasError: false };
|
|
217
280
|
try {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
281
|
+
const tmpls = await Promise.all([...Array(5)].map((_, i) => createTemplateWithFunc(`sequencetest_${i}`, `_sequence_test_${i}`)));
|
|
282
|
+
expect(tmpls).toHaveLength(5);
|
|
283
|
+
const manager = __addDisposableResource(env_7, await TemplateManager.create(testContext.testDir), false);
|
|
284
|
+
const client = await connect();
|
|
285
|
+
await wait(100);
|
|
286
|
+
try {
|
|
287
|
+
// Start transaction
|
|
288
|
+
await client.query('BEGIN');
|
|
289
|
+
const result = await manager.processTemplates({ apply: true, force: true });
|
|
290
|
+
// Add retry logic for verification
|
|
291
|
+
const verifyFunctions = async (retries = 3, delay = 200) => {
|
|
292
|
+
try {
|
|
293
|
+
const allFunctions = await client.query(`SELECT proname FROM pg_proc WHERE proname LIKE $1`, [`${testContext.testFunctionName}_sequence_test_%`]);
|
|
294
|
+
expect(allFunctions.rows).toHaveLength(5);
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
console.log('Flakey test failed verifying functions:', error, 'retries', retries);
|
|
298
|
+
if (retries === 0)
|
|
299
|
+
throw error;
|
|
300
|
+
await wait(delay);
|
|
301
|
+
await verifyFunctions(retries - 1, delay * 2);
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
await verifyFunctions();
|
|
305
|
+
await client.query('COMMIT');
|
|
223
306
|
expect(result.errors).toHaveLength(0);
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
307
|
+
expect(result.applied).toHaveLength(5);
|
|
308
|
+
}
|
|
309
|
+
catch (error) {
|
|
310
|
+
await client.query('ROLLBACK');
|
|
311
|
+
throw error;
|
|
312
|
+
}
|
|
313
|
+
finally {
|
|
314
|
+
client.release();
|
|
232
315
|
}
|
|
233
|
-
// Verify final state
|
|
234
|
-
const allFunctions = await client.query(`SELECT proname FROM pg_proc WHERE proname LIKE $1`, [
|
|
235
|
-
`${testContext.testFunctionName}_sequence_test_%`,
|
|
236
|
-
]);
|
|
237
|
-
expect(allFunctions.rows).toHaveLength(5);
|
|
238
316
|
}
|
|
239
|
-
catch (
|
|
240
|
-
|
|
241
|
-
|
|
317
|
+
catch (e_7) {
|
|
318
|
+
env_7.error = e_7;
|
|
319
|
+
env_7.hasError = true;
|
|
242
320
|
}
|
|
243
321
|
finally {
|
|
244
|
-
|
|
245
|
-
await client.query('ROLLBACK');
|
|
246
|
-
client.release();
|
|
322
|
+
__disposeResources(env_7);
|
|
247
323
|
}
|
|
248
324
|
});
|
|
249
325
|
it('should generate unique timestamps for multiple templates', async () => {
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
326
|
+
const env_8 = { stack: [], error: void 0, hasError: false };
|
|
327
|
+
try {
|
|
328
|
+
const templates = await Promise.all([...Array(10)].map((_, i) => createTemplateWithFunc(`timestamptest_${i}`, `_unique_timestamps_${i}`)));
|
|
329
|
+
const manager = __addDisposableResource(env_8, await TemplateManager.create(testContext.testDir), false);
|
|
330
|
+
await manager.processTemplates({ generateFiles: true });
|
|
331
|
+
const migrations = await fs.readdir(join(testContext.testDir, 'test-migrations'));
|
|
332
|
+
const timestamps = migrations.map(m => m.split('_')[0]);
|
|
333
|
+
const uniqueTimestamps = new Set(timestamps);
|
|
334
|
+
expect(uniqueTimestamps.size).toBe(templates.length);
|
|
335
|
+
expect(timestamps).toEqual([...timestamps].sort());
|
|
336
|
+
}
|
|
337
|
+
catch (e_8) {
|
|
338
|
+
env_8.error = e_8;
|
|
339
|
+
env_8.hasError = true;
|
|
340
|
+
}
|
|
341
|
+
finally {
|
|
342
|
+
__disposeResources(env_8);
|
|
343
|
+
}
|
|
258
344
|
});
|
|
259
345
|
it('should handle mix of working and broken templates', async () => {
|
|
260
|
-
|
|
261
|
-
await createTemplate(`a-test-bad-${testContext.timestamp}.sql`, 'INVALID SQL SYNTAX;');
|
|
262
|
-
const manager = await TemplateManager.create(testContext.testDir);
|
|
263
|
-
const result = await manager.processTemplates({ apply: true });
|
|
264
|
-
expect(result.errors).toHaveLength(1);
|
|
265
|
-
expect(result.applied).toHaveLength(1);
|
|
266
|
-
const client = await connect();
|
|
346
|
+
const env_9 = { stack: [], error: void 0, hasError: false };
|
|
267
347
|
try {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
348
|
+
await createTemplateWithFunc(`a-test-good`, '_good_and_broken_mix');
|
|
349
|
+
await createTemplate(`a-test-bad.sql`, 'INVALID SQL SYNTAX;');
|
|
350
|
+
const manager = __addDisposableResource(env_9, await TemplateManager.create(testContext.testDir), false);
|
|
351
|
+
const result = await manager.processTemplates({ apply: true });
|
|
352
|
+
expect(result.errors).toHaveLength(1);
|
|
353
|
+
expect(result.applied).toHaveLength(1);
|
|
354
|
+
const client = await connect();
|
|
355
|
+
try {
|
|
356
|
+
const res = await client.query(`SELECT COUNT(*) FROM pg_proc WHERE proname = $1`, [
|
|
357
|
+
`${testContext.testFunctionName}_good_and_broken_mix`,
|
|
358
|
+
]);
|
|
359
|
+
expect(Number.parseInt(res.rows[0].count)).toBe(1);
|
|
360
|
+
}
|
|
361
|
+
finally {
|
|
362
|
+
client.release();
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
catch (e_9) {
|
|
366
|
+
env_9.error = e_9;
|
|
367
|
+
env_9.hasError = true;
|
|
272
368
|
}
|
|
273
369
|
finally {
|
|
274
|
-
|
|
370
|
+
__disposeResources(env_9);
|
|
275
371
|
}
|
|
276
372
|
});
|
|
277
373
|
it('should handle database errors gracefully', async () => {
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
374
|
+
const env_10 = { stack: [], error: void 0, hasError: false };
|
|
375
|
+
try {
|
|
376
|
+
const manager = __addDisposableResource(env_10, await TemplateManager.create(testContext.testDir), false);
|
|
377
|
+
await createTemplate(`test-error.sql`, 'SELECT 1/0;'); // Division by zero error
|
|
378
|
+
const result = await manager.processTemplates({ apply: true });
|
|
379
|
+
expect(result.errors).toHaveLength(1);
|
|
380
|
+
expect(result.errors[0]?.error).toMatch(/division by zero/i);
|
|
381
|
+
}
|
|
382
|
+
catch (e_10) {
|
|
383
|
+
env_10.error = e_10;
|
|
384
|
+
env_10.hasError = true;
|
|
385
|
+
}
|
|
386
|
+
finally {
|
|
387
|
+
__disposeResources(env_10);
|
|
388
|
+
}
|
|
283
389
|
});
|
|
284
390
|
it('should handle file system errors', async () => {
|
|
285
|
-
const errorPath = join(testContext.testDir, 'test-templates', `test-error
|
|
391
|
+
const errorPath = join(testContext.testDir, 'test-templates', `test-error.sql`);
|
|
286
392
|
try {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
393
|
+
const env_11 = { stack: [], error: void 0, hasError: false };
|
|
394
|
+
try {
|
|
395
|
+
await createTemplate(`test-error.sql`, 'SELECT 1;');
|
|
396
|
+
await fs.chmod(errorPath, 0o000);
|
|
397
|
+
const manager = __addDisposableResource(env_11, await TemplateManager.create(testContext.testDir), false);
|
|
398
|
+
try {
|
|
399
|
+
await manager.processTemplates({ generateFiles: true });
|
|
400
|
+
}
|
|
401
|
+
catch (error) {
|
|
402
|
+
expect(error).toBeDefined();
|
|
403
|
+
}
|
|
404
|
+
// Cleanup for afterEach
|
|
405
|
+
await fs.chmod(errorPath, 0o644);
|
|
406
|
+
}
|
|
407
|
+
catch (e_11) {
|
|
408
|
+
env_11.error = e_11;
|
|
409
|
+
env_11.hasError = true;
|
|
410
|
+
}
|
|
411
|
+
finally {
|
|
412
|
+
__disposeResources(env_11);
|
|
413
|
+
}
|
|
293
414
|
}
|
|
294
415
|
catch (error) {
|
|
295
416
|
expect(error).toBeDefined();
|
|
@@ -303,17 +424,30 @@ describe('TemplateManager', () => {
|
|
|
303
424
|
}
|
|
304
425
|
});
|
|
305
426
|
it('should handle large batches of templates', async () => {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
427
|
+
const env_12 = { stack: [], error: void 0, hasError: false };
|
|
428
|
+
try {
|
|
429
|
+
// Create 50 templates
|
|
430
|
+
await Promise.all([...Array(50)].map((_, i) => createTemplateWithFunc(`test_${i}`, `_large_batch_${i}`)));
|
|
431
|
+
const manager = __addDisposableResource(env_12, await TemplateManager.create(testContext.testDir), false);
|
|
432
|
+
const result = await manager.processTemplates({ generateFiles: true });
|
|
433
|
+
expect(result.errors).toHaveLength(0);
|
|
434
|
+
const migrations = await fs.readdir(join(testContext.testDir, 'test-migrations'));
|
|
435
|
+
expect(migrations.length).toBe(50);
|
|
436
|
+
}
|
|
437
|
+
catch (e_12) {
|
|
438
|
+
env_12.error = e_12;
|
|
439
|
+
env_12.hasError = true;
|
|
440
|
+
}
|
|
441
|
+
finally {
|
|
442
|
+
__disposeResources(env_12);
|
|
443
|
+
}
|
|
313
444
|
});
|
|
314
445
|
it('should handle templates with complex SQL', async () => {
|
|
315
|
-
const
|
|
316
|
-
|
|
446
|
+
const env_13 = { stack: [], error: void 0, hasError: false };
|
|
447
|
+
try {
|
|
448
|
+
const testFunctionName = `${testContext.testFunctionName}_complex`;
|
|
449
|
+
const complexSQL = `
|
|
450
|
+
CREATE OR REPLACE FUNCTION ${testFunctionName}(
|
|
317
451
|
param1 integer DEFAULT 100,
|
|
318
452
|
OUT result1 integer,
|
|
319
453
|
OUT result2 text
|
|
@@ -337,413 +471,595 @@ describe('TemplateManager', () => {
|
|
|
337
471
|
END;
|
|
338
472
|
$$ LANGUAGE plpgsql;
|
|
339
473
|
`;
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
474
|
+
await createTemplate(`test-complex.sql`, complexSQL);
|
|
475
|
+
const manager = __addDisposableResource(env_13, await TemplateManager.create(testContext.testDir), false);
|
|
476
|
+
const result = await manager.processTemplates({ apply: true });
|
|
477
|
+
expect(result.errors).toHaveLength(0);
|
|
478
|
+
const client = await connect();
|
|
479
|
+
try {
|
|
480
|
+
const res = await client.query(`
|
|
347
481
|
SELECT proname, pronargs, prorettype::regtype::text as return_type
|
|
348
482
|
FROM pg_proc
|
|
349
483
|
WHERE proname = $1
|
|
350
|
-
`, [
|
|
351
|
-
|
|
352
|
-
|
|
484
|
+
`, [testFunctionName]);
|
|
485
|
+
expect(res.rows).toHaveLength(1);
|
|
486
|
+
expect(res.rows[0].return_type).toBe('record');
|
|
487
|
+
}
|
|
488
|
+
finally {
|
|
489
|
+
client.release();
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
catch (e_13) {
|
|
493
|
+
env_13.error = e_13;
|
|
494
|
+
env_13.hasError = true;
|
|
353
495
|
}
|
|
354
496
|
finally {
|
|
355
|
-
|
|
497
|
+
__disposeResources(env_13);
|
|
356
498
|
}
|
|
357
499
|
});
|
|
358
500
|
it('should maintain template state across manager instances', async () => {
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
501
|
+
const env_14 = { stack: [], error: void 0, hasError: false };
|
|
502
|
+
try {
|
|
503
|
+
const template = await createTemplateWithFunc(`test`, 'maintain_state');
|
|
504
|
+
// First manager instance
|
|
505
|
+
const manager1 = __addDisposableResource(env_14, await TemplateManager.create(testContext.testDir), false);
|
|
506
|
+
await manager1.processTemplates({ generateFiles: true });
|
|
507
|
+
// Second manager instance should see the state
|
|
508
|
+
const manager2 = __addDisposableResource(env_14, await TemplateManager.create(testContext.testDir), false);
|
|
509
|
+
const status = await manager2.getTemplateStatus(template);
|
|
510
|
+
expect(status.buildState.lastBuildHash).toBeDefined();
|
|
511
|
+
}
|
|
512
|
+
catch (e_14) {
|
|
513
|
+
env_14.error = e_14;
|
|
514
|
+
env_14.hasError = true;
|
|
515
|
+
}
|
|
516
|
+
finally {
|
|
517
|
+
__disposeResources(env_14);
|
|
518
|
+
}
|
|
367
519
|
});
|
|
368
520
|
it('should handle template additions in watch mode', async () => {
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
changes
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
521
|
+
const env_15 = { stack: [], error: void 0, hasError: false };
|
|
522
|
+
try {
|
|
523
|
+
const manager = __addDisposableResource(env_15, await TemplateManager.create(testContext.testDir), false);
|
|
524
|
+
const changes = [];
|
|
525
|
+
manager.on('templateChanged', template => {
|
|
526
|
+
changes.push(template.name);
|
|
527
|
+
});
|
|
528
|
+
const watcher = await manager.watch();
|
|
529
|
+
// Add new template after watch started
|
|
530
|
+
await createTemplateWithFunc('new', '_watch_addition');
|
|
531
|
+
await wait(150);
|
|
532
|
+
watcher.close();
|
|
533
|
+
expect(changes).toContain(`new_${testContext.testId}_1`);
|
|
534
|
+
}
|
|
535
|
+
catch (e_15) {
|
|
536
|
+
env_15.error = e_15;
|
|
537
|
+
env_15.hasError = true;
|
|
538
|
+
}
|
|
539
|
+
finally {
|
|
540
|
+
__disposeResources(env_15);
|
|
541
|
+
}
|
|
380
542
|
});
|
|
381
543
|
it('should handle templates in deep subdirectories', async () => {
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
const
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
changes
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
544
|
+
const env_16 = { stack: [], error: void 0, hasError: false };
|
|
545
|
+
try {
|
|
546
|
+
// Create nested directory structure
|
|
547
|
+
const depth = 5;
|
|
548
|
+
const templatePaths = [];
|
|
549
|
+
for (let i = 1; i <= depth; i++) {
|
|
550
|
+
const dir = [...Array(i)].map((_, idx) => `level${idx + 1}`).join('/');
|
|
551
|
+
const templatePath = await createTemplateWithFunc(`depth-test_${i}`, `_depth_${i}`, dir);
|
|
552
|
+
templatePaths.push(templatePath);
|
|
553
|
+
}
|
|
554
|
+
const manager = __addDisposableResource(env_16, await TemplateManager.create(testContext.testDir), false);
|
|
555
|
+
const changes = [];
|
|
556
|
+
manager.on('templateChanged', template => {
|
|
557
|
+
changes.push(template.name);
|
|
558
|
+
});
|
|
559
|
+
const watcher = await manager.watch();
|
|
560
|
+
await wait(depth * 100 * 1.1);
|
|
561
|
+
watcher.close();
|
|
562
|
+
expect(changes.length).toBe(depth);
|
|
563
|
+
// Verify each template was detected
|
|
564
|
+
for (let i = 1; i <= depth; i++) {
|
|
565
|
+
expect(changes).toContain(`depth-test_${i}_${testContext.testId}_${i}`);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
catch (e_16) {
|
|
569
|
+
env_16.error = e_16;
|
|
570
|
+
env_16.hasError = true;
|
|
571
|
+
}
|
|
572
|
+
finally {
|
|
573
|
+
__disposeResources(env_16);
|
|
402
574
|
}
|
|
403
575
|
});
|
|
404
576
|
it('should only watch SQL files', async () => {
|
|
405
|
-
const
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
changes
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
577
|
+
const env_17 = { stack: [], error: void 0, hasError: false };
|
|
578
|
+
try {
|
|
579
|
+
const manager = __addDisposableResource(env_17, await TemplateManager.create(testContext.testDir), false);
|
|
580
|
+
const changes = [];
|
|
581
|
+
manager.on('templateChanged', template => {
|
|
582
|
+
changes.push(template.name);
|
|
583
|
+
});
|
|
584
|
+
const watcher = await manager.watch();
|
|
585
|
+
await wait(100);
|
|
586
|
+
// Create various file types
|
|
587
|
+
await fs.writeFile(join(testContext.testDir, 'test-templates/test.txt'), 'not sql');
|
|
588
|
+
await fs.writeFile(join(testContext.testDir, 'test-templates/test.md'), 'not sql');
|
|
589
|
+
await createTemplateWithFunc(`sql`, '_watch_sql_only');
|
|
590
|
+
await wait(500);
|
|
591
|
+
watcher.close();
|
|
592
|
+
expect(changes).toHaveLength(1);
|
|
593
|
+
expect(changes[0]).toBe(`sql_${testContext.testId}_1`);
|
|
594
|
+
}
|
|
595
|
+
catch (e_17) {
|
|
596
|
+
env_17.error = e_17;
|
|
597
|
+
env_17.hasError = true;
|
|
598
|
+
}
|
|
599
|
+
finally {
|
|
600
|
+
__disposeResources(env_17);
|
|
601
|
+
}
|
|
420
602
|
});
|
|
421
603
|
it('should handle multiple template changes simultaneously', async () => {
|
|
422
|
-
const
|
|
423
|
-
const changes = new Set();
|
|
424
|
-
const count = 5;
|
|
425
|
-
manager.on('templateChanged', template => {
|
|
426
|
-
changes.add(template.name);
|
|
427
|
-
});
|
|
428
|
-
const watcher = await manager.watch();
|
|
429
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
430
|
-
// Create multiple templates simultaneously
|
|
431
|
-
await Promise.all([
|
|
432
|
-
createTemplateWithFunc(`rapid_test-1-${testContext.timestamp}.sql`, '_batch_changes_1'),
|
|
433
|
-
createTemplateWithFunc(`rapid_test-2-${testContext.timestamp}.sql`, '_batch_changes_2'),
|
|
434
|
-
createTemplateWithFunc(`rapid_test-3-${testContext.timestamp}.sql`, '_batch_changes_3'),
|
|
435
|
-
createTemplateWithFunc(`rapid_test-4-${testContext.timestamp}.sql`, '_batch_changes_4', 'deep'),
|
|
436
|
-
createTemplateWithFunc(`rapid_test-5-${testContext.timestamp}.sql`, '_batch_changes_5', 'deep/nested'),
|
|
437
|
-
]);
|
|
438
|
-
// Give enough time for all changes to be detected
|
|
439
|
-
await new Promise(resolve => setTimeout(resolve, count * 100 * 1.1));
|
|
440
|
-
watcher.close();
|
|
441
|
-
expect(changes.size).toBe(count); // Should detect all 5 templates
|
|
442
|
-
for (let i = 1; i <= count; i++) {
|
|
443
|
-
expect(changes.has(`rapid_test-${i}-${testContext.timestamp}`)).toBe(true);
|
|
444
|
-
}
|
|
445
|
-
// Verify all templates were processed
|
|
446
|
-
const client = await connect();
|
|
604
|
+
const env_18 = { stack: [], error: void 0, hasError: false };
|
|
447
605
|
try {
|
|
606
|
+
const client = await connect();
|
|
607
|
+
const manager = __addDisposableResource(env_18, await TemplateManager.create(testContext.testDir), false);
|
|
608
|
+
const changes = new Set();
|
|
609
|
+
const count = 5;
|
|
610
|
+
const watcher = await manager.watch();
|
|
611
|
+
await wait(100);
|
|
612
|
+
manager.on('templateChanged', template => {
|
|
613
|
+
changes.add(template.name);
|
|
614
|
+
});
|
|
615
|
+
// Create multiple templates simultaneously
|
|
616
|
+
try {
|
|
617
|
+
await createTemplateWithFunc(`rapid_test_1`, '_batch_changes_1');
|
|
618
|
+
await createTemplateWithFunc(`rapid_test_2`, '_batch_changes_2');
|
|
619
|
+
await createTemplateWithFunc(`rapid_test_3`, '_batch_changes_3');
|
|
620
|
+
await createTemplateWithFunc(`rapid_test_4`, '_batch_changes_4', 'deep');
|
|
621
|
+
await createTemplateWithFunc(`rapid_test_5`, '_batch_changes_5', 'deep/nested');
|
|
622
|
+
}
|
|
623
|
+
catch (error) {
|
|
624
|
+
console.error('Error creating templates:', error);
|
|
625
|
+
throw error;
|
|
626
|
+
}
|
|
627
|
+
// Give enough time for all changes to be detected
|
|
628
|
+
await wait(count * 100 * 1.1);
|
|
629
|
+
watcher.close();
|
|
630
|
+
expect(changes.size).toBe(count); // Should detect all 5 templates
|
|
448
631
|
for (let i = 1; i <= count; i++) {
|
|
449
|
-
|
|
450
|
-
|
|
632
|
+
expect(changes.has(`rapid_test_${i}_${testContext.testId}_${i}`)).toBe(true);
|
|
633
|
+
}
|
|
634
|
+
// Verify all templates were processed
|
|
635
|
+
await wait(100);
|
|
636
|
+
try {
|
|
637
|
+
const res = await client.query(`SELECT proname FROM pg_proc WHERE proname LIKE $1`, [
|
|
638
|
+
`${testContext.testFunctionName}_batch_changes_%`,
|
|
451
639
|
]);
|
|
452
|
-
expect(res
|
|
640
|
+
// expect(res).toBe('');
|
|
641
|
+
expect(res.rows).toHaveLength(count);
|
|
642
|
+
}
|
|
643
|
+
catch (error) {
|
|
644
|
+
console.error('Error querying functions:', error);
|
|
645
|
+
}
|
|
646
|
+
finally {
|
|
647
|
+
client.release();
|
|
453
648
|
}
|
|
454
649
|
}
|
|
650
|
+
catch (e_18) {
|
|
651
|
+
env_18.error = e_18;
|
|
652
|
+
env_18.hasError = true;
|
|
653
|
+
}
|
|
455
654
|
finally {
|
|
456
|
-
|
|
655
|
+
__disposeResources(env_18);
|
|
457
656
|
}
|
|
458
657
|
}, 15000);
|
|
459
658
|
it('should handle rapid bulk template creation realistically', async () => {
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
resolveProcessing
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
659
|
+
const env_19 = { stack: [], error: void 0, hasError: false };
|
|
660
|
+
try {
|
|
661
|
+
const TEMPLATE_COUNT = 50;
|
|
662
|
+
const manager = __addDisposableResource(env_19, await TemplateManager.create(testContext.testDir), false);
|
|
663
|
+
const processed = new Set();
|
|
664
|
+
const failed = new Set();
|
|
665
|
+
const inProgress = new Set();
|
|
666
|
+
const events = [];
|
|
667
|
+
let resolveProcessing;
|
|
668
|
+
const processingComplete = new Promise(resolve => {
|
|
669
|
+
resolveProcessing = resolve;
|
|
670
|
+
});
|
|
671
|
+
manager.on('templateChanged', ({ name }) => {
|
|
672
|
+
events.push({ event: 'changed', template: name, time: Date.now() });
|
|
673
|
+
inProgress.add(name);
|
|
674
|
+
});
|
|
675
|
+
manager.on('templateApplied', ({ name }) => {
|
|
676
|
+
events.push({ event: 'applied', template: name, time: Date.now() });
|
|
677
|
+
processed.add(name);
|
|
678
|
+
inProgress.delete(name);
|
|
679
|
+
if (processed.size + failed.size === TEMPLATE_COUNT) {
|
|
680
|
+
resolveProcessing();
|
|
681
|
+
}
|
|
682
|
+
});
|
|
683
|
+
manager.on('templateError', ({ template: { name }, error }) => {
|
|
684
|
+
events.push({ event: 'error', template: name, time: Date.now() });
|
|
685
|
+
failed.add(name);
|
|
686
|
+
inProgress.delete(name);
|
|
687
|
+
console.error('Template error:', { name, error });
|
|
688
|
+
if (processed.size + failed.size === TEMPLATE_COUNT) {
|
|
689
|
+
resolveProcessing();
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
const watcher = await manager.watch();
|
|
693
|
+
// Create all templates
|
|
694
|
+
await Promise.all(Array.from({ length: TEMPLATE_COUNT }, (_, i) => createTemplateWithFunc(`bulk_${i + 1}`, `_bulk_${i + 1}`)));
|
|
695
|
+
await processingComplete;
|
|
696
|
+
watcher.close();
|
|
697
|
+
expect(processed.size + failed.size).toBe(TEMPLATE_COUNT);
|
|
698
|
+
expect(inProgress.size).toBe(0);
|
|
699
|
+
expect(failed.size).toBe(0);
|
|
700
|
+
}
|
|
701
|
+
catch (e_19) {
|
|
702
|
+
env_19.error = e_19;
|
|
703
|
+
env_19.hasError = true;
|
|
704
|
+
}
|
|
705
|
+
finally {
|
|
706
|
+
__disposeResources(env_19);
|
|
707
|
+
}
|
|
499
708
|
});
|
|
500
709
|
it('should cleanup resources when disposed', async () => {
|
|
501
|
-
const
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
changes
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
710
|
+
const env_20 = { stack: [], error: void 0, hasError: false };
|
|
711
|
+
try {
|
|
712
|
+
const manager = __addDisposableResource(env_20, await TemplateManager.create(testContext.testDir), false);
|
|
713
|
+
const changes = [];
|
|
714
|
+
manager.on('templateChanged', template => {
|
|
715
|
+
changes.push(template.name);
|
|
716
|
+
});
|
|
717
|
+
await manager.watch();
|
|
718
|
+
// Create template before disposal
|
|
719
|
+
await createTemplateWithFunc(`before-dispose`, 'before_dispose');
|
|
720
|
+
await wait(100);
|
|
721
|
+
// Dispose and verify cleanup
|
|
722
|
+
manager[Symbol.dispose]();
|
|
723
|
+
// Try creating template after disposal
|
|
724
|
+
await createTemplateWithFunc(`after-dispose`, 'after_dispose');
|
|
725
|
+
await wait(100);
|
|
726
|
+
expect(changes).toHaveLength(1);
|
|
727
|
+
expect(changes[0]).toBe(`before-dispose_${testContext.testId}_1`);
|
|
728
|
+
}
|
|
729
|
+
catch (e_20) {
|
|
730
|
+
env_20.error = e_20;
|
|
731
|
+
env_20.hasError = true;
|
|
732
|
+
}
|
|
733
|
+
finally {
|
|
734
|
+
__disposeResources(env_20);
|
|
735
|
+
}
|
|
517
736
|
});
|
|
518
737
|
it('should auto-cleanup with using statement', async () => {
|
|
519
738
|
const changes = [];
|
|
520
739
|
await (async () => {
|
|
521
|
-
const
|
|
740
|
+
const env_21 = { stack: [], error: void 0, hasError: false };
|
|
522
741
|
try {
|
|
523
|
-
const manager = __addDisposableResource(
|
|
742
|
+
const manager = __addDisposableResource(env_21, await TemplateManager.create(testContext.testDir), false);
|
|
524
743
|
manager.on('templateChanged', template => {
|
|
525
744
|
changes.push(template.name);
|
|
526
745
|
});
|
|
527
746
|
await manager.watch();
|
|
528
|
-
await createTemplateWithFunc(`
|
|
529
|
-
await
|
|
747
|
+
await createTemplateWithFunc(`during-scope`, 'during_scope');
|
|
748
|
+
await wait(100);
|
|
530
749
|
}
|
|
531
|
-
catch (
|
|
532
|
-
|
|
533
|
-
|
|
750
|
+
catch (e_21) {
|
|
751
|
+
env_21.error = e_21;
|
|
752
|
+
env_21.hasError = true;
|
|
534
753
|
}
|
|
535
754
|
finally {
|
|
536
|
-
__disposeResources(
|
|
755
|
+
__disposeResources(env_21);
|
|
537
756
|
}
|
|
538
757
|
})();
|
|
539
758
|
// After scope exit, create another template
|
|
540
|
-
await createTemplateWithFunc(`
|
|
541
|
-
await
|
|
759
|
+
await createTemplateWithFunc(`after-scope`, 'after_scope');
|
|
760
|
+
await wait(100);
|
|
761
|
+
expect(changes[0]).toBe(`during-scope_${testContext.testId}_1`);
|
|
542
762
|
expect(changes).toHaveLength(1);
|
|
543
|
-
expect(changes[0]).toBe(`test-during-scope-${testContext.timestamp}`);
|
|
544
763
|
});
|
|
545
764
|
it('should not process unchanged templates', async () => {
|
|
546
|
-
const
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
changes
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
765
|
+
const env_22 = { stack: [], error: void 0, hasError: false };
|
|
766
|
+
try {
|
|
767
|
+
const templatePath = await createTemplateWithFunc(`initial_will_remain_unchanged`, 'unchanged_tmpl');
|
|
768
|
+
const manager = __addDisposableResource(env_22, await TemplateManager.create(testContext.testDir), false);
|
|
769
|
+
await manager.watch();
|
|
770
|
+
// First processing
|
|
771
|
+
await manager.processTemplates({ apply: true });
|
|
772
|
+
// Get the status after first processing
|
|
773
|
+
const statusAfterFirstRun = await manager.getTemplateStatus(templatePath);
|
|
774
|
+
const changes = [];
|
|
775
|
+
manager.on('templateChanged', template => {
|
|
776
|
+
changes.push(template.name);
|
|
777
|
+
});
|
|
778
|
+
// Process again without changes
|
|
779
|
+
await manager.processTemplates({ apply: true });
|
|
780
|
+
// Get status after second run
|
|
781
|
+
const statusAfterSecondRun = await manager.getTemplateStatus(templatePath);
|
|
782
|
+
expect(changes).toHaveLength(0);
|
|
783
|
+
expect(statusAfterSecondRun.buildState.lastBuildHash).toBe(statusAfterFirstRun.buildState.lastBuildHash);
|
|
784
|
+
expect(statusAfterSecondRun.buildState.lastAppliedHash).toBe(statusAfterFirstRun.buildState.lastAppliedHash);
|
|
785
|
+
}
|
|
786
|
+
catch (e_22) {
|
|
787
|
+
env_22.error = e_22;
|
|
788
|
+
env_22.hasError = true;
|
|
789
|
+
}
|
|
790
|
+
finally {
|
|
791
|
+
__disposeResources(env_22);
|
|
792
|
+
}
|
|
564
793
|
});
|
|
565
794
|
it('should only process modified templates in batch', async () => {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
changes
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
795
|
+
const env_23 = { stack: [], error: void 0, hasError: false };
|
|
796
|
+
try {
|
|
797
|
+
// Create two templates
|
|
798
|
+
const template1 = await createTemplateWithFunc(`modified_tmpl_1`, 'mod_1');
|
|
799
|
+
await createTemplateWithFunc(`modified_tmpl_2`, 'mod_2');
|
|
800
|
+
const manager = __addDisposableResource(env_23, await TemplateManager.create(testContext.testDir), false);
|
|
801
|
+
// First processing of both
|
|
802
|
+
await manager.processTemplates({ apply: true });
|
|
803
|
+
const changes = [];
|
|
804
|
+
manager.on('templateChanged', template => {
|
|
805
|
+
changes.push(template.name);
|
|
806
|
+
});
|
|
807
|
+
// Modify only template1
|
|
808
|
+
try {
|
|
809
|
+
const tmpl1content = await fs.readFile(template1, 'utf-8');
|
|
810
|
+
await fs.writeFile(template1, `${tmpl1content}\n-- Modified`);
|
|
811
|
+
}
|
|
812
|
+
catch (error) {
|
|
813
|
+
console.error('Test: Error modifying template:', error);
|
|
814
|
+
throw error;
|
|
815
|
+
}
|
|
816
|
+
// Process both templates again
|
|
817
|
+
await manager.processTemplates({ apply: true });
|
|
818
|
+
expect(changes).toHaveLength(1);
|
|
819
|
+
expect(changes[0]).toBe(`modified_tmpl_1_${testContext.testId}_1`);
|
|
820
|
+
}
|
|
821
|
+
catch (e_23) {
|
|
822
|
+
env_23.error = e_23;
|
|
823
|
+
env_23.hasError = true;
|
|
824
|
+
}
|
|
825
|
+
finally {
|
|
826
|
+
__disposeResources(env_23);
|
|
827
|
+
}
|
|
582
828
|
});
|
|
583
829
|
it('should correctly update local buildlog on apply', async () => {
|
|
584
|
-
const
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
830
|
+
const env_24 = { stack: [], error: void 0, hasError: false };
|
|
831
|
+
try {
|
|
832
|
+
const templatePath = await createTemplateWithFunc(`buildlog`, '_buildlog');
|
|
833
|
+
const manager = __addDisposableResource(env_24, await TemplateManager.create(testContext.testDir), false);
|
|
834
|
+
const localBuildlogPath = join(testContext.testDir, '.buildlog-test.local.json');
|
|
835
|
+
// Initial apply
|
|
836
|
+
await manager.processTemplates({ apply: true });
|
|
837
|
+
const initialLog = JSON.parse(await fs.readFile(localBuildlogPath, 'utf-8'));
|
|
838
|
+
const relPath = relative(testContext.testDir, templatePath);
|
|
839
|
+
const initialHash = initialLog.templates[relPath].lastAppliedHash;
|
|
840
|
+
const initialContent = await fs.readFile(templatePath, 'utf-8');
|
|
841
|
+
expect(initialHash).toBeDefined();
|
|
842
|
+
// Modify template
|
|
843
|
+
await fs.writeFile(templatePath, `${initialContent}\n-- Modified`);
|
|
844
|
+
await wait(100);
|
|
845
|
+
const changedContent = await fs.readFile(templatePath, 'utf-8');
|
|
846
|
+
// Second apply
|
|
847
|
+
await manager.processTemplates({ apply: true });
|
|
848
|
+
await wait(100);
|
|
849
|
+
const updatedLog = JSON.parse(await fs.readFile(localBuildlogPath, 'utf-8'));
|
|
850
|
+
const newHash = updatedLog.templates[relPath].lastAppliedHash;
|
|
851
|
+
const manualMd5 = await calculateMD5(changedContent);
|
|
852
|
+
expect(newHash).toBeDefined();
|
|
853
|
+
expect(newHash).toBe(manualMd5);
|
|
854
|
+
expect(newHash).not.toBe(initialHash);
|
|
855
|
+
}
|
|
856
|
+
catch (e_24) {
|
|
857
|
+
env_24.error = e_24;
|
|
858
|
+
env_24.hasError = true;
|
|
859
|
+
}
|
|
860
|
+
finally {
|
|
861
|
+
__disposeResources(env_24);
|
|
862
|
+
}
|
|
607
863
|
});
|
|
608
864
|
it('should skip apply if template hash matches local buildlog', async () => {
|
|
609
|
-
const
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
865
|
+
const env_25 = { stack: [], error: void 0, hasError: false };
|
|
866
|
+
try {
|
|
867
|
+
const templatePath = await createTemplateWithFunc(`skip`, '_skip_apply');
|
|
868
|
+
const manager = __addDisposableResource(env_25, await TemplateManager.create(testContext.testDir), false);
|
|
869
|
+
const localBuildlogPath = join(testContext.testDir, '.buildlog-test.local.json');
|
|
870
|
+
// Initial apply
|
|
871
|
+
await manager.processTemplates({ apply: true });
|
|
872
|
+
const initialLog = JSON.parse(await fs.readFile(localBuildlogPath, 'utf-8'));
|
|
873
|
+
const relPath = relative(testContext.testDir, templatePath);
|
|
874
|
+
const initialHash = initialLog.templates[relPath].lastAppliedHash;
|
|
875
|
+
const initialDate = initialLog.templates[relPath].lastAppliedDate;
|
|
876
|
+
// Wait a bit to ensure timestamp would be different
|
|
877
|
+
await wait(100);
|
|
878
|
+
// Apply again without changes
|
|
879
|
+
await manager.processTemplates({ apply: true });
|
|
880
|
+
const updatedLog = JSON.parse(await fs.readFile(localBuildlogPath, 'utf-8'));
|
|
881
|
+
// Hash and date should remain exactly the same since no changes were made
|
|
882
|
+
expect(updatedLog.templates[relPath].lastAppliedHash).toBe(initialHash);
|
|
883
|
+
expect(updatedLog.templates[relPath].lastAppliedDate).toBe(initialDate);
|
|
884
|
+
}
|
|
885
|
+
catch (e_25) {
|
|
886
|
+
env_25.error = e_25;
|
|
887
|
+
env_25.hasError = true;
|
|
888
|
+
}
|
|
889
|
+
finally {
|
|
890
|
+
__disposeResources(env_25);
|
|
891
|
+
}
|
|
626
892
|
});
|
|
627
893
|
it('should not reapply unchanged templates in watch mode', async () => {
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
changed
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
const
|
|
664
|
-
const
|
|
665
|
-
|
|
666
|
-
|
|
894
|
+
const env_26 = { stack: [], error: void 0, hasError: false };
|
|
895
|
+
try {
|
|
896
|
+
// Create multiple templates
|
|
897
|
+
const templates = await Promise.all([
|
|
898
|
+
createTemplateWithFunc(`watch-stable_1`, '_watch_1'),
|
|
899
|
+
createTemplateWithFunc(`watch-stable_2`, '_watch_2'),
|
|
900
|
+
]);
|
|
901
|
+
const manager = __addDisposableResource(env_26, await TemplateManager.create(testContext.testDir), false);
|
|
902
|
+
const applied = [];
|
|
903
|
+
const changed = [];
|
|
904
|
+
manager.on('templateChanged', template => {
|
|
905
|
+
changed.push(template.name);
|
|
906
|
+
});
|
|
907
|
+
manager.on('templateApplied', template => {
|
|
908
|
+
applied.push(template.name);
|
|
909
|
+
});
|
|
910
|
+
// First watch session
|
|
911
|
+
const watcher1 = await manager.watch();
|
|
912
|
+
await wait(100);
|
|
913
|
+
await watcher1.close();
|
|
914
|
+
// Record initial state
|
|
915
|
+
const initialApplied = [...applied];
|
|
916
|
+
const initialChanged = [...changed];
|
|
917
|
+
applied.length = 0;
|
|
918
|
+
changed.length = 0;
|
|
919
|
+
// Second watch session without any changes
|
|
920
|
+
const watcher2 = await manager.watch();
|
|
921
|
+
await wait(100);
|
|
922
|
+
await watcher2.close();
|
|
923
|
+
expect(initialApplied).toHaveLength(2); // First run should apply both
|
|
924
|
+
expect(initialChanged).toHaveLength(2); // First run should detect both
|
|
925
|
+
expect(applied).toHaveLength(0); // Second run should apply none
|
|
926
|
+
expect(changed).toHaveLength(0); // Second run should detect none
|
|
927
|
+
// Verify the buildlog state
|
|
928
|
+
const localBuildlogPath = join(testContext.testDir, '.buildlog-test.local.json');
|
|
929
|
+
const buildLog = JSON.parse(await fs.readFile(localBuildlogPath, 'utf-8'));
|
|
930
|
+
for (const templatePath of templates) {
|
|
931
|
+
const relPath = relative(testContext.testDir, templatePath);
|
|
932
|
+
const content = await fs.readFile(templatePath, 'utf-8');
|
|
933
|
+
const hash = await calculateMD5(content);
|
|
934
|
+
expect(buildLog.templates[relPath].lastAppliedHash).toBe(hash);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
catch (e_26) {
|
|
938
|
+
env_26.error = e_26;
|
|
939
|
+
env_26.hasError = true;
|
|
940
|
+
}
|
|
941
|
+
finally {
|
|
942
|
+
__disposeResources(env_26);
|
|
667
943
|
}
|
|
668
944
|
});
|
|
669
945
|
it('should process unapplied templates on startup', async () => {
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
946
|
+
const env_27 = { stack: [], error: void 0, hasError: false };
|
|
947
|
+
try {
|
|
948
|
+
// Create template but don't process it
|
|
949
|
+
await createTemplateWithFunc(`startup-test`, '_startup_test');
|
|
950
|
+
// Create a new manager instance
|
|
951
|
+
const manager = __addDisposableResource(env_27, await TemplateManager.create(testContext.testDir), false);
|
|
952
|
+
const changes = [];
|
|
953
|
+
const applied = [];
|
|
954
|
+
manager.on('templateChanged', t => changes.push(t.name));
|
|
955
|
+
manager.on('templateApplied', t => applied.push(t.name));
|
|
956
|
+
// Start watching - this should process the template
|
|
957
|
+
await manager.watch();
|
|
958
|
+
await wait(100);
|
|
959
|
+
expect(changes).toHaveLength(1);
|
|
960
|
+
expect(applied).toHaveLength(1);
|
|
961
|
+
expect(changes[0]).toBe(`startup-test_${testContext.testId}_1`);
|
|
962
|
+
expect(applied[0]).toBe(`startup-test_${testContext.testId}_1`);
|
|
963
|
+
}
|
|
964
|
+
catch (e_27) {
|
|
965
|
+
env_27.error = e_27;
|
|
966
|
+
env_27.hasError = true;
|
|
967
|
+
}
|
|
968
|
+
finally {
|
|
969
|
+
__disposeResources(env_27);
|
|
970
|
+
}
|
|
685
971
|
});
|
|
686
972
|
it('should handle error state transitions correctly', async () => {
|
|
687
|
-
const
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
{
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
973
|
+
const env_28 = { stack: [], error: void 0, hasError: false };
|
|
974
|
+
try {
|
|
975
|
+
const templatePath = await createTemplateWithFunc(`error-state`, '_error_test');
|
|
976
|
+
const manager = __addDisposableResource(env_28, await TemplateManager.create(testContext.testDir), false);
|
|
977
|
+
const states = [];
|
|
978
|
+
manager.on('templateChanged', () => states.push({ type: 'changed' }));
|
|
979
|
+
manager.on('templateApplied', () => states.push({ type: 'applied' }));
|
|
980
|
+
manager.on('templateError', ({ error }) => states.push({ type: 'error', error: String(error) }));
|
|
981
|
+
// First apply should succeed
|
|
982
|
+
await manager.processTemplates({ apply: true });
|
|
983
|
+
// Modify template to be invalid
|
|
984
|
+
await fs.writeFile(templatePath, 'INVALID SQL;');
|
|
985
|
+
await manager.processTemplates({ apply: true });
|
|
986
|
+
// Fix template with valid SQL
|
|
987
|
+
await fs.writeFile(templatePath, `CREATE OR REPLACE FUNCTION ${testContext.testFunctionName}() RETURNS void AS $$ BEGIN NULL; END; $$ LANGUAGE plpgsql;`);
|
|
988
|
+
await manager.processTemplates({ apply: true });
|
|
989
|
+
expect(states).toEqual([
|
|
990
|
+
{ type: 'changed' },
|
|
991
|
+
{ type: 'applied' },
|
|
992
|
+
{ type: 'changed' },
|
|
993
|
+
{ type: 'error', error: expect.stringMatching(/syntax error/) },
|
|
994
|
+
{ type: 'changed' },
|
|
995
|
+
{ type: 'applied' },
|
|
996
|
+
]);
|
|
997
|
+
}
|
|
998
|
+
catch (e_28) {
|
|
999
|
+
env_28.error = e_28;
|
|
1000
|
+
env_28.hasError = true;
|
|
1001
|
+
}
|
|
1002
|
+
finally {
|
|
1003
|
+
__disposeResources(env_28);
|
|
1004
|
+
}
|
|
709
1005
|
});
|
|
710
1006
|
it('should maintain correct state through manager restarts', async () => {
|
|
711
|
-
const
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
1007
|
+
const env_29 = { stack: [], error: void 0, hasError: false };
|
|
1008
|
+
try {
|
|
1009
|
+
const templatePath = await createTemplateWithFunc(`restart-test`, 'restart_test');
|
|
1010
|
+
// First manager instance
|
|
1011
|
+
const manager1 = __addDisposableResource(env_29, await TemplateManager.create(testContext.testDir), false);
|
|
1012
|
+
await manager1.processTemplates({ apply: true });
|
|
1013
|
+
// Get initial state
|
|
1014
|
+
const status1 = await manager1.getTemplateStatus(templatePath);
|
|
1015
|
+
const initialHash = status1.buildState.lastAppliedHash;
|
|
1016
|
+
// Modify template
|
|
1017
|
+
await fs.writeFile(templatePath, `${await fs.readFile(templatePath, 'utf-8')}\n-- Modified`);
|
|
1018
|
+
// Create new manager instance
|
|
1019
|
+
const manager2 = __addDisposableResource(env_29, await TemplateManager.create(testContext.testDir), false);
|
|
1020
|
+
const changes = [];
|
|
1021
|
+
const applied = [];
|
|
1022
|
+
manager2.on('templateChanged', t => changes.push(t.name));
|
|
1023
|
+
manager2.on('templateApplied', t => applied.push(t.name));
|
|
1024
|
+
await manager2.watch();
|
|
1025
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
1026
|
+
// Verify state was maintained and change was detected
|
|
1027
|
+
const status2 = await manager2.getTemplateStatus(templatePath);
|
|
1028
|
+
expect(status2.buildState.lastAppliedHash).not.toBe(initialHash);
|
|
1029
|
+
expect(changes).toContain(`restart-test_${testContext.testId}_1`);
|
|
1030
|
+
expect(applied).toContain(`restart-test_${testContext.testId}_1`);
|
|
1031
|
+
}
|
|
1032
|
+
catch (e_29) {
|
|
1033
|
+
env_29.error = e_29;
|
|
1034
|
+
env_29.hasError = true;
|
|
1035
|
+
}
|
|
1036
|
+
finally {
|
|
1037
|
+
__disposeResources(env_29);
|
|
1038
|
+
}
|
|
733
1039
|
});
|
|
734
1040
|
it('should properly format and propagate error messages', async () => {
|
|
735
|
-
const
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
1041
|
+
const env_30 = { stack: [], error: void 0, hasError: false };
|
|
1042
|
+
try {
|
|
1043
|
+
const templatePath = await createTemplateWithFunc(`error-format`, 'error_format');
|
|
1044
|
+
const manager = __addDisposableResource(env_30, await TemplateManager.create(testContext.testDir), false);
|
|
1045
|
+
const errors = [];
|
|
1046
|
+
manager.on('templateError', err => errors.push(err));
|
|
1047
|
+
// Create invalid SQL
|
|
1048
|
+
await fs.writeFile(templatePath, 'SELECT * FROM nonexistent_table;');
|
|
1049
|
+
await manager.processTemplates({ apply: true });
|
|
1050
|
+
expect(errors).toHaveLength(1);
|
|
1051
|
+
const error = errors[0]?.error;
|
|
1052
|
+
expect(typeof error).toBe('string');
|
|
1053
|
+
expect(error).not.toMatch(/\[object Object\]/);
|
|
1054
|
+
expect(error).toMatch(/relation.*does not exist/i);
|
|
1055
|
+
}
|
|
1056
|
+
catch (e_30) {
|
|
1057
|
+
env_30.error = e_30;
|
|
1058
|
+
env_30.hasError = true;
|
|
1059
|
+
}
|
|
1060
|
+
finally {
|
|
1061
|
+
__disposeResources(env_30);
|
|
1062
|
+
}
|
|
747
1063
|
});
|
|
748
1064
|
});
|
|
749
1065
|
//# sourceMappingURL=templateManager.test.js.map
|