@friggframework/admin-scripts 2.0.0--canary.517.7e78259.0 → 2.0.0--canary.517.2239974.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/package.json +6 -6
- package/src/application/__tests__/admin-frigg-commands.test.js +81 -295
- package/src/application/__tests__/admin-script-base.test.js +0 -91
- package/src/application/__tests__/script-runner.test.js +0 -133
- package/src/application/__tests__/validate-script-input.test.js +196 -0
- package/src/application/admin-frigg-commands.js +15 -78
- package/src/application/admin-script-base.js +0 -20
- package/src/application/script-runner.js +1 -111
- package/src/application/validate-script-input.js +116 -0
- package/src/builtins/__tests__/integration-health-check.test.js +27 -25
- package/src/builtins/__tests__/oauth-token-refresh.test.js +17 -15
- package/src/builtins/integration-health-check.js +3 -3
- package/src/builtins/oauth-token-refresh.js +2 -2
- package/src/infrastructure/__tests__/admin-script-router.test.js +2 -2
- package/src/infrastructure/admin-script-router.js +28 -14
- package/src/infrastructure/script-executor-handler.js +18 -35
|
@@ -5,22 +5,18 @@ jest.mock('@friggframework/core/integrations/repositories/integration-repository
|
|
|
5
5
|
jest.mock('@friggframework/core/user/repositories/user-repository-factory');
|
|
6
6
|
jest.mock('@friggframework/core/modules/repositories/module-repository-factory');
|
|
7
7
|
jest.mock('@friggframework/core/credential/repositories/credential-repository-factory');
|
|
8
|
-
jest.mock('@friggframework/core/admin-scripts/repositories/admin-process-repository-factory');
|
|
9
8
|
jest.mock('@friggframework/core/queues');
|
|
10
9
|
|
|
11
|
-
describe('
|
|
10
|
+
describe('AdminScriptContext', () => {
|
|
12
11
|
let mockIntegrationRepo;
|
|
13
12
|
let mockUserRepo;
|
|
14
13
|
let mockModuleRepo;
|
|
15
14
|
let mockCredentialRepo;
|
|
16
|
-
let mockAdminProcessRepo;
|
|
17
15
|
let mockQueuerUtil;
|
|
18
16
|
|
|
19
17
|
beforeEach(() => {
|
|
20
|
-
// Reset all mocks
|
|
21
18
|
jest.clearAllMocks();
|
|
22
19
|
|
|
23
|
-
// Create mock repositories
|
|
24
20
|
mockIntegrationRepo = {
|
|
25
21
|
findIntegrations: jest.fn(),
|
|
26
22
|
findIntegrationById: jest.fn(),
|
|
@@ -46,300 +42,116 @@ describe('AdminFriggCommands', () => {
|
|
|
46
42
|
updateCredential: jest.fn(),
|
|
47
43
|
};
|
|
48
44
|
|
|
49
|
-
mockAdminProcessRepo = {
|
|
50
|
-
appendProcessLog: jest.fn().mockResolvedValue(undefined),
|
|
51
|
-
};
|
|
52
|
-
|
|
53
45
|
mockQueuerUtil = {
|
|
54
46
|
send: jest.fn().mockResolvedValue(undefined),
|
|
55
47
|
batchSend: jest.fn().mockResolvedValue(undefined),
|
|
56
48
|
};
|
|
57
49
|
|
|
58
|
-
// Mock factory functions
|
|
59
50
|
const { createIntegrationRepository } = require('@friggframework/core/integrations/repositories/integration-repository-factory');
|
|
60
51
|
const { createUserRepository } = require('@friggframework/core/user/repositories/user-repository-factory');
|
|
61
52
|
const { createModuleRepository } = require('@friggframework/core/modules/repositories/module-repository-factory');
|
|
62
53
|
const { createCredentialRepository } = require('@friggframework/core/credential/repositories/credential-repository-factory');
|
|
63
|
-
const { createAdminProcessRepository } = require('@friggframework/core/admin-scripts/repositories/admin-process-repository-factory');
|
|
64
54
|
const { QueuerUtil } = require('@friggframework/core/queues');
|
|
65
55
|
|
|
66
56
|
createIntegrationRepository.mockReturnValue(mockIntegrationRepo);
|
|
67
57
|
createUserRepository.mockReturnValue(mockUserRepo);
|
|
68
58
|
createModuleRepository.mockReturnValue(mockModuleRepo);
|
|
69
59
|
createCredentialRepository.mockReturnValue(mockCredentialRepo);
|
|
70
|
-
createAdminProcessRepository.mockReturnValue(mockAdminProcessRepo);
|
|
71
60
|
|
|
72
|
-
// Mock QueuerUtil methods
|
|
73
61
|
QueuerUtil.send = mockQueuerUtil.send;
|
|
74
62
|
QueuerUtil.batchSend = mockQueuerUtil.batchSend;
|
|
75
63
|
});
|
|
76
64
|
|
|
77
65
|
describe('Constructor', () => {
|
|
78
66
|
it('creates with executionId', () => {
|
|
79
|
-
const
|
|
67
|
+
const ctx = new AdminFriggCommands({ executionId: 'exec_123' });
|
|
80
68
|
|
|
81
|
-
expect(
|
|
82
|
-
expect(
|
|
83
|
-
expect(
|
|
69
|
+
expect(ctx.executionId).toBe('exec_123');
|
|
70
|
+
expect(ctx.logs).toEqual([]);
|
|
71
|
+
expect(ctx.integrationFactory).toBeNull();
|
|
84
72
|
});
|
|
85
73
|
|
|
86
74
|
it('creates with integrationFactory', () => {
|
|
87
75
|
const mockFactory = { getInstanceFromIntegrationId: jest.fn() };
|
|
88
|
-
const
|
|
76
|
+
const ctx = new AdminFriggCommands({ integrationFactory: mockFactory });
|
|
89
77
|
|
|
90
|
-
expect(
|
|
78
|
+
expect(ctx.integrationFactory).toBe(mockFactory);
|
|
91
79
|
});
|
|
92
80
|
|
|
93
81
|
it('creates without params (defaults)', () => {
|
|
94
|
-
const
|
|
82
|
+
const ctx = new AdminFriggCommands();
|
|
95
83
|
|
|
96
|
-
expect(
|
|
97
|
-
expect(
|
|
98
|
-
expect(
|
|
84
|
+
expect(ctx.executionId).toBeNull();
|
|
85
|
+
expect(ctx.logs).toEqual([]);
|
|
86
|
+
expect(ctx.integrationFactory).toBeNull();
|
|
99
87
|
});
|
|
100
88
|
});
|
|
101
89
|
|
|
102
90
|
describe('Lazy Repository Loading', () => {
|
|
103
91
|
it('creates integrationRepository on first access', () => {
|
|
104
|
-
const
|
|
92
|
+
const ctx = new AdminFriggCommands();
|
|
105
93
|
const { createIntegrationRepository } = require('@friggframework/core/integrations/repositories/integration-repository-factory');
|
|
106
94
|
|
|
107
95
|
expect(createIntegrationRepository).not.toHaveBeenCalled();
|
|
108
96
|
|
|
109
|
-
const repo =
|
|
97
|
+
const repo = ctx.integrationRepository;
|
|
110
98
|
|
|
111
99
|
expect(createIntegrationRepository).toHaveBeenCalledTimes(1);
|
|
112
100
|
expect(repo).toBe(mockIntegrationRepo);
|
|
113
101
|
});
|
|
114
102
|
|
|
115
103
|
it('returns same instance on subsequent access', () => {
|
|
116
|
-
const
|
|
104
|
+
const ctx = new AdminFriggCommands();
|
|
117
105
|
|
|
118
|
-
const repo1 =
|
|
119
|
-
const repo2 =
|
|
106
|
+
const repo1 = ctx.integrationRepository;
|
|
107
|
+
const repo2 = ctx.integrationRepository;
|
|
120
108
|
|
|
121
109
|
expect(repo1).toBe(repo2);
|
|
122
110
|
expect(repo1).toBe(mockIntegrationRepo);
|
|
123
111
|
});
|
|
124
112
|
|
|
125
113
|
it('creates userRepository on first access', () => {
|
|
126
|
-
const
|
|
114
|
+
const ctx = new AdminFriggCommands();
|
|
127
115
|
const { createUserRepository } = require('@friggframework/core/user/repositories/user-repository-factory');
|
|
128
116
|
|
|
129
117
|
expect(createUserRepository).not.toHaveBeenCalled();
|
|
130
118
|
|
|
131
|
-
const repo =
|
|
119
|
+
const repo = ctx.userRepository;
|
|
132
120
|
|
|
133
121
|
expect(createUserRepository).toHaveBeenCalledTimes(1);
|
|
134
122
|
expect(repo).toBe(mockUserRepo);
|
|
135
123
|
});
|
|
136
124
|
|
|
137
125
|
it('creates moduleRepository on first access', () => {
|
|
138
|
-
const
|
|
126
|
+
const ctx = new AdminFriggCommands();
|
|
139
127
|
const { createModuleRepository } = require('@friggframework/core/modules/repositories/module-repository-factory');
|
|
140
128
|
|
|
141
129
|
expect(createModuleRepository).not.toHaveBeenCalled();
|
|
142
130
|
|
|
143
|
-
const repo =
|
|
131
|
+
const repo = ctx.moduleRepository;
|
|
144
132
|
|
|
145
133
|
expect(createModuleRepository).toHaveBeenCalledTimes(1);
|
|
146
134
|
expect(repo).toBe(mockModuleRepo);
|
|
147
135
|
});
|
|
148
136
|
|
|
149
137
|
it('creates credentialRepository on first access', () => {
|
|
150
|
-
const
|
|
138
|
+
const ctx = new AdminFriggCommands();
|
|
151
139
|
const { createCredentialRepository } = require('@friggframework/core/credential/repositories/credential-repository-factory');
|
|
152
140
|
|
|
153
141
|
expect(createCredentialRepository).not.toHaveBeenCalled();
|
|
154
142
|
|
|
155
|
-
const repo =
|
|
143
|
+
const repo = ctx.credentialRepository;
|
|
156
144
|
|
|
157
145
|
expect(createCredentialRepository).toHaveBeenCalledTimes(1);
|
|
158
146
|
expect(repo).toBe(mockCredentialRepo);
|
|
159
147
|
});
|
|
160
|
-
|
|
161
|
-
it('creates adminProcessRepository on first access', () => {
|
|
162
|
-
const commands = new AdminFriggCommands();
|
|
163
|
-
const { createAdminProcessRepository } = require('@friggframework/core/admin-scripts/repositories/admin-process-repository-factory');
|
|
164
|
-
|
|
165
|
-
expect(createAdminProcessRepository).not.toHaveBeenCalled();
|
|
166
|
-
|
|
167
|
-
const repo = commands.adminProcessRepository;
|
|
168
|
-
|
|
169
|
-
expect(createAdminProcessRepository).toHaveBeenCalledTimes(1);
|
|
170
|
-
expect(repo).toBe(mockAdminProcessRepo);
|
|
171
|
-
});
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
describe('Integration Queries', () => {
|
|
175
|
-
it('listIntegrations with userId filter calls findIntegrationsByUserId', async () => {
|
|
176
|
-
const commands = new AdminFriggCommands();
|
|
177
|
-
const mockIntegrations = [{ id: '1' }, { id: '2' }];
|
|
178
|
-
mockIntegrationRepo.findIntegrationsByUserId.mockResolvedValue(mockIntegrations);
|
|
179
|
-
|
|
180
|
-
const result = await commands.listIntegrations({ userId: 'user_123' });
|
|
181
|
-
|
|
182
|
-
expect(result).toEqual(mockIntegrations);
|
|
183
|
-
expect(mockIntegrationRepo.findIntegrationsByUserId).toHaveBeenCalledWith('user_123');
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it('listIntegrations without userId calls findIntegrations', async () => {
|
|
187
|
-
const commands = new AdminFriggCommands();
|
|
188
|
-
const mockIntegrations = [{ id: '1' }];
|
|
189
|
-
mockIntegrationRepo.findIntegrations.mockResolvedValue(mockIntegrations);
|
|
190
|
-
|
|
191
|
-
const result = await commands.listIntegrations({ status: 'active' });
|
|
192
|
-
|
|
193
|
-
expect(result).toEqual(mockIntegrations);
|
|
194
|
-
expect(mockIntegrationRepo.findIntegrations).toHaveBeenCalledWith({ status: 'active' });
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
it('findIntegrationById calls repository', async () => {
|
|
198
|
-
const commands = new AdminFriggCommands();
|
|
199
|
-
const mockIntegration = { id: 'int_123', name: 'Test' };
|
|
200
|
-
mockIntegrationRepo.findIntegrationById.mockResolvedValue(mockIntegration);
|
|
201
|
-
|
|
202
|
-
const result = await commands.findIntegrationById('int_123');
|
|
203
|
-
|
|
204
|
-
expect(result).toEqual(mockIntegration);
|
|
205
|
-
expect(mockIntegrationRepo.findIntegrationById).toHaveBeenCalledWith('int_123');
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
it('findIntegrationsByUserId calls repository', async () => {
|
|
209
|
-
const commands = new AdminFriggCommands();
|
|
210
|
-
const mockIntegrations = [{ id: '1' }, { id: '2' }];
|
|
211
|
-
mockIntegrationRepo.findIntegrationsByUserId.mockResolvedValue(mockIntegrations);
|
|
212
|
-
|
|
213
|
-
const result = await commands.findIntegrationsByUserId('user_123');
|
|
214
|
-
|
|
215
|
-
expect(result).toEqual(mockIntegrations);
|
|
216
|
-
expect(mockIntegrationRepo.findIntegrationsByUserId).toHaveBeenCalledWith('user_123');
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
it('updateIntegrationConfig calls repository', async () => {
|
|
220
|
-
const commands = new AdminFriggCommands();
|
|
221
|
-
const newConfig = { setting: 'value' };
|
|
222
|
-
const updatedIntegration = { id: 'int_123', config: newConfig };
|
|
223
|
-
mockIntegrationRepo.updateIntegrationConfig.mockResolvedValue(updatedIntegration);
|
|
224
|
-
|
|
225
|
-
const result = await commands.updateIntegrationConfig('int_123', newConfig);
|
|
226
|
-
|
|
227
|
-
expect(result).toEqual(updatedIntegration);
|
|
228
|
-
expect(mockIntegrationRepo.updateIntegrationConfig).toHaveBeenCalledWith('int_123', newConfig);
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
it('updateIntegrationStatus calls repository', async () => {
|
|
232
|
-
const commands = new AdminFriggCommands();
|
|
233
|
-
const updatedIntegration = { id: 'int_123', status: 'active' };
|
|
234
|
-
mockIntegrationRepo.updateIntegrationStatus.mockResolvedValue(updatedIntegration);
|
|
235
|
-
|
|
236
|
-
const result = await commands.updateIntegrationStatus('int_123', 'active');
|
|
237
|
-
|
|
238
|
-
expect(result).toEqual(updatedIntegration);
|
|
239
|
-
expect(mockIntegrationRepo.updateIntegrationStatus).toHaveBeenCalledWith('int_123', 'active');
|
|
240
|
-
});
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
describe('User Queries', () => {
|
|
244
|
-
it('findUserById calls repository', async () => {
|
|
245
|
-
const commands = new AdminFriggCommands();
|
|
246
|
-
const mockUser = { id: 'user_123', email: 'test@example.com' };
|
|
247
|
-
mockUserRepo.findIndividualUserById.mockResolvedValue(mockUser);
|
|
248
|
-
|
|
249
|
-
const result = await commands.findUserById('user_123');
|
|
250
|
-
|
|
251
|
-
expect(result).toEqual(mockUser);
|
|
252
|
-
expect(mockUserRepo.findIndividualUserById).toHaveBeenCalledWith('user_123');
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
it('findUserByAppUserId calls repository', async () => {
|
|
256
|
-
const commands = new AdminFriggCommands();
|
|
257
|
-
const mockUser = { id: 'user_123', appUserId: 'app_456' };
|
|
258
|
-
mockUserRepo.findIndividualUserByAppUserId.mockResolvedValue(mockUser);
|
|
259
|
-
|
|
260
|
-
const result = await commands.findUserByAppUserId('app_456');
|
|
261
|
-
|
|
262
|
-
expect(result).toEqual(mockUser);
|
|
263
|
-
expect(mockUserRepo.findIndividualUserByAppUserId).toHaveBeenCalledWith('app_456');
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
it('findUserByUsername calls repository', async () => {
|
|
267
|
-
const commands = new AdminFriggCommands();
|
|
268
|
-
const mockUser = { id: 'user_123', username: 'testuser' };
|
|
269
|
-
mockUserRepo.findIndividualUserByUsername.mockResolvedValue(mockUser);
|
|
270
|
-
|
|
271
|
-
const result = await commands.findUserByUsername('testuser');
|
|
272
|
-
|
|
273
|
-
expect(result).toEqual(mockUser);
|
|
274
|
-
expect(mockUserRepo.findIndividualUserByUsername).toHaveBeenCalledWith('testuser');
|
|
275
|
-
});
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
describe('Entity Queries', () => {
|
|
279
|
-
it('listEntities with userId filter calls findEntitiesByUserId', async () => {
|
|
280
|
-
const commands = new AdminFriggCommands();
|
|
281
|
-
const mockEntities = [{ id: 'ent_1' }, { id: 'ent_2' }];
|
|
282
|
-
mockModuleRepo.findEntitiesByUserId.mockResolvedValue(mockEntities);
|
|
283
|
-
|
|
284
|
-
const result = await commands.listEntities({ userId: 'user_123' });
|
|
285
|
-
|
|
286
|
-
expect(result).toEqual(mockEntities);
|
|
287
|
-
expect(mockModuleRepo.findEntitiesByUserId).toHaveBeenCalledWith('user_123');
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
it('listEntities without userId calls findEntity', async () => {
|
|
291
|
-
const commands = new AdminFriggCommands();
|
|
292
|
-
const mockEntities = [{ id: 'ent_1' }];
|
|
293
|
-
mockModuleRepo.findEntity.mockResolvedValue(mockEntities);
|
|
294
|
-
|
|
295
|
-
const result = await commands.listEntities({ type: 'account' });
|
|
296
|
-
|
|
297
|
-
expect(result).toEqual(mockEntities);
|
|
298
|
-
expect(mockModuleRepo.findEntity).toHaveBeenCalledWith({ type: 'account' });
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
it('findEntityById calls repository', async () => {
|
|
302
|
-
const commands = new AdminFriggCommands();
|
|
303
|
-
const mockEntity = { id: 'ent_123', name: 'Test Entity' };
|
|
304
|
-
mockModuleRepo.findEntityById.mockResolvedValue(mockEntity);
|
|
305
|
-
|
|
306
|
-
const result = await commands.findEntityById('ent_123');
|
|
307
|
-
|
|
308
|
-
expect(result).toEqual(mockEntity);
|
|
309
|
-
expect(mockModuleRepo.findEntityById).toHaveBeenCalledWith('ent_123');
|
|
310
|
-
});
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
describe('Credential Queries', () => {
|
|
314
|
-
it('findCredential calls repository', async () => {
|
|
315
|
-
const commands = new AdminFriggCommands();
|
|
316
|
-
const mockCredential = { id: 'cred_123', userId: 'user_123' };
|
|
317
|
-
mockCredentialRepo.findCredential.mockResolvedValue(mockCredential);
|
|
318
|
-
|
|
319
|
-
const result = await commands.findCredential({ userId: 'user_123' });
|
|
320
|
-
|
|
321
|
-
expect(result).toEqual(mockCredential);
|
|
322
|
-
expect(mockCredentialRepo.findCredential).toHaveBeenCalledWith({ userId: 'user_123' });
|
|
323
|
-
});
|
|
324
|
-
|
|
325
|
-
it('updateCredential calls repository', async () => {
|
|
326
|
-
const commands = new AdminFriggCommands();
|
|
327
|
-
const updates = { data: { newToken: 'xyz' } };
|
|
328
|
-
const updatedCredential = { id: 'cred_123', ...updates };
|
|
329
|
-
mockCredentialRepo.updateCredential.mockResolvedValue(updatedCredential);
|
|
330
|
-
|
|
331
|
-
const result = await commands.updateCredential('cred_123', updates);
|
|
332
|
-
|
|
333
|
-
expect(result).toEqual(updatedCredential);
|
|
334
|
-
expect(mockCredentialRepo.updateCredential).toHaveBeenCalledWith('cred_123', updates);
|
|
335
|
-
});
|
|
336
148
|
});
|
|
337
149
|
|
|
338
150
|
describe('instantiate()', () => {
|
|
339
151
|
it('throws if no integrationFactory', async () => {
|
|
340
|
-
const
|
|
152
|
+
const ctx = new AdminFriggCommands();
|
|
341
153
|
|
|
342
|
-
await expect(
|
|
154
|
+
await expect(ctx.instantiate('int_123')).rejects.toThrow(
|
|
343
155
|
'instantiate() requires integrationFactory. ' +
|
|
344
156
|
'Set Definition.config.requireIntegrationInstance = true'
|
|
345
157
|
);
|
|
@@ -350,9 +162,9 @@ describe('AdminFriggCommands', () => {
|
|
|
350
162
|
const mockFactory = {
|
|
351
163
|
getInstanceFromIntegrationId: jest.fn().mockResolvedValue(mockInstance),
|
|
352
164
|
};
|
|
353
|
-
const
|
|
165
|
+
const ctx = new AdminFriggCommands({ integrationFactory: mockFactory });
|
|
354
166
|
|
|
355
|
-
const result = await
|
|
167
|
+
const result = await ctx.instantiate('int_123');
|
|
356
168
|
|
|
357
169
|
expect(result).toEqual(mockInstance);
|
|
358
170
|
expect(mockFactory.getInstanceFromIntegrationId).toHaveBeenCalledWith({
|
|
@@ -366,9 +178,9 @@ describe('AdminFriggCommands', () => {
|
|
|
366
178
|
const mockFactory = {
|
|
367
179
|
getInstanceFromIntegrationId: jest.fn().mockResolvedValue(mockInstance),
|
|
368
180
|
};
|
|
369
|
-
const
|
|
181
|
+
const ctx = new AdminFriggCommands({ integrationFactory: mockFactory });
|
|
370
182
|
|
|
371
|
-
await
|
|
183
|
+
await ctx.instantiate('int_123');
|
|
372
184
|
|
|
373
185
|
const callArgs = mockFactory.getInstanceFromIntegrationId.mock.calls[0][0];
|
|
374
186
|
expect(callArgs._isAdminContext).toBe(true);
|
|
@@ -388,19 +200,19 @@ describe('AdminFriggCommands', () => {
|
|
|
388
200
|
|
|
389
201
|
it('throws if ADMIN_SCRIPT_QUEUE_URL not set', async () => {
|
|
390
202
|
delete process.env.ADMIN_SCRIPT_QUEUE_URL;
|
|
391
|
-
const
|
|
203
|
+
const ctx = new AdminFriggCommands();
|
|
392
204
|
|
|
393
|
-
await expect(
|
|
205
|
+
await expect(ctx.queueScript('test-script', {})).rejects.toThrow(
|
|
394
206
|
'ADMIN_SCRIPT_QUEUE_URL environment variable not set'
|
|
395
207
|
);
|
|
396
208
|
});
|
|
397
209
|
|
|
398
210
|
it('calls QueuerUtil.send with correct params', async () => {
|
|
399
211
|
process.env.ADMIN_SCRIPT_QUEUE_URL = 'https://sqs.us-east-1.amazonaws.com/123456789012/admin-scripts';
|
|
400
|
-
const
|
|
212
|
+
const ctx = new AdminFriggCommands({ executionId: 'exec_123' });
|
|
401
213
|
const params = { integrationId: 'int_456' };
|
|
402
214
|
|
|
403
|
-
await
|
|
215
|
+
await ctx.queueScript('test-script', params);
|
|
404
216
|
|
|
405
217
|
expect(mockQueuerUtil.send).toHaveBeenCalledWith(
|
|
406
218
|
{
|
|
@@ -415,9 +227,9 @@ describe('AdminFriggCommands', () => {
|
|
|
415
227
|
|
|
416
228
|
it('includes parentExecutionId from constructor', async () => {
|
|
417
229
|
process.env.ADMIN_SCRIPT_QUEUE_URL = 'https://sqs.example.com/queue';
|
|
418
|
-
const
|
|
230
|
+
const ctx = new AdminFriggCommands({ executionId: 'exec_parent' });
|
|
419
231
|
|
|
420
|
-
await
|
|
232
|
+
await ctx.queueScript('my-script', {});
|
|
421
233
|
|
|
422
234
|
const callArgs = mockQueuerUtil.send.mock.calls[0][0];
|
|
423
235
|
expect(callArgs.parentExecutionId).toBe('exec_parent');
|
|
@@ -425,12 +237,12 @@ describe('AdminFriggCommands', () => {
|
|
|
425
237
|
|
|
426
238
|
it('logs queuing operation', async () => {
|
|
427
239
|
process.env.ADMIN_SCRIPT_QUEUE_URL = 'https://sqs.example.com/queue';
|
|
428
|
-
const
|
|
240
|
+
const ctx = new AdminFriggCommands();
|
|
429
241
|
const params = { batchId: 'batch_1' };
|
|
430
242
|
|
|
431
|
-
await
|
|
243
|
+
await ctx.queueScript('test-script', params);
|
|
432
244
|
|
|
433
|
-
const logs =
|
|
245
|
+
const logs = ctx.getLogs();
|
|
434
246
|
expect(logs).toHaveLength(1);
|
|
435
247
|
expect(logs[0].level).toBe('info');
|
|
436
248
|
expect(logs[0].message).toBe('Queued continuation for test-script');
|
|
@@ -451,22 +263,22 @@ describe('AdminFriggCommands', () => {
|
|
|
451
263
|
|
|
452
264
|
it('throws if ADMIN_SCRIPT_QUEUE_URL not set', async () => {
|
|
453
265
|
delete process.env.ADMIN_SCRIPT_QUEUE_URL;
|
|
454
|
-
const
|
|
266
|
+
const ctx = new AdminFriggCommands();
|
|
455
267
|
|
|
456
|
-
await expect(
|
|
268
|
+
await expect(ctx.queueScriptBatch([])).rejects.toThrow(
|
|
457
269
|
'ADMIN_SCRIPT_QUEUE_URL environment variable not set'
|
|
458
270
|
);
|
|
459
271
|
});
|
|
460
272
|
|
|
461
273
|
it('calls QueuerUtil.batchSend', async () => {
|
|
462
274
|
process.env.ADMIN_SCRIPT_QUEUE_URL = 'https://sqs.example.com/queue';
|
|
463
|
-
const
|
|
275
|
+
const ctx = new AdminFriggCommands({ executionId: 'exec_123' });
|
|
464
276
|
const entries = [
|
|
465
277
|
{ scriptName: 'script-1', params: { id: '1' } },
|
|
466
278
|
{ scriptName: 'script-2', params: { id: '2' } },
|
|
467
279
|
];
|
|
468
280
|
|
|
469
|
-
await
|
|
281
|
+
await ctx.queueScriptBatch(entries);
|
|
470
282
|
|
|
471
283
|
expect(mockQueuerUtil.batchSend).toHaveBeenCalledWith(
|
|
472
284
|
[
|
|
@@ -489,12 +301,12 @@ describe('AdminFriggCommands', () => {
|
|
|
489
301
|
|
|
490
302
|
it('maps entries correctly', async () => {
|
|
491
303
|
process.env.ADMIN_SCRIPT_QUEUE_URL = 'https://sqs.example.com/queue';
|
|
492
|
-
const
|
|
304
|
+
const ctx = new AdminFriggCommands();
|
|
493
305
|
const entries = [
|
|
494
306
|
{ scriptName: 'test-script', params: { value: 'abc' } },
|
|
495
307
|
];
|
|
496
308
|
|
|
497
|
-
await
|
|
309
|
+
await ctx.queueScriptBatch(entries);
|
|
498
310
|
|
|
499
311
|
const callArgs = mockQueuerUtil.batchSend.mock.calls[0][0];
|
|
500
312
|
expect(callArgs).toHaveLength(1);
|
|
@@ -505,12 +317,12 @@ describe('AdminFriggCommands', () => {
|
|
|
505
317
|
|
|
506
318
|
it('handles entries without params', async () => {
|
|
507
319
|
process.env.ADMIN_SCRIPT_QUEUE_URL = 'https://sqs.example.com/queue';
|
|
508
|
-
const
|
|
320
|
+
const ctx = new AdminFriggCommands();
|
|
509
321
|
const entries = [
|
|
510
322
|
{ scriptName: 'no-params-script' },
|
|
511
323
|
];
|
|
512
324
|
|
|
513
|
-
await
|
|
325
|
+
await ctx.queueScriptBatch(entries);
|
|
514
326
|
|
|
515
327
|
const callArgs = mockQueuerUtil.batchSend.mock.calls[0][0];
|
|
516
328
|
expect(callArgs[0].params).toEqual({});
|
|
@@ -518,16 +330,16 @@ describe('AdminFriggCommands', () => {
|
|
|
518
330
|
|
|
519
331
|
it('logs batch queuing operation', async () => {
|
|
520
332
|
process.env.ADMIN_SCRIPT_QUEUE_URL = 'https://sqs.example.com/queue';
|
|
521
|
-
const
|
|
333
|
+
const ctx = new AdminFriggCommands();
|
|
522
334
|
const entries = [
|
|
523
335
|
{ scriptName: 'script-1', params: {} },
|
|
524
336
|
{ scriptName: 'script-2', params: {} },
|
|
525
337
|
{ scriptName: 'script-3', params: {} },
|
|
526
338
|
];
|
|
527
339
|
|
|
528
|
-
await
|
|
340
|
+
await ctx.queueScriptBatch(entries);
|
|
529
341
|
|
|
530
|
-
const logs =
|
|
342
|
+
const logs = ctx.getLogs();
|
|
531
343
|
expect(logs).toHaveLength(1);
|
|
532
344
|
expect(logs[0].level).toBe('info');
|
|
533
345
|
expect(logs[0].message).toBe('Queued 3 script continuations');
|
|
@@ -536,63 +348,37 @@ describe('AdminFriggCommands', () => {
|
|
|
536
348
|
|
|
537
349
|
describe('Logging', () => {
|
|
538
350
|
it('log() adds entry to logs array', () => {
|
|
539
|
-
const
|
|
351
|
+
const ctx = new AdminFriggCommands();
|
|
540
352
|
|
|
541
|
-
const entry =
|
|
353
|
+
const entry = ctx.log('info', 'Test message', { key: 'value' });
|
|
542
354
|
|
|
543
355
|
expect(entry.level).toBe('info');
|
|
544
356
|
expect(entry.message).toBe('Test message');
|
|
545
357
|
expect(entry.data).toEqual({ key: 'value' });
|
|
546
358
|
expect(entry.timestamp).toBeDefined();
|
|
547
|
-
expect(
|
|
548
|
-
expect(
|
|
359
|
+
expect(ctx.logs).toHaveLength(1);
|
|
360
|
+
expect(ctx.logs[0]).toBe(entry);
|
|
549
361
|
});
|
|
550
362
|
|
|
551
|
-
it('log()
|
|
552
|
-
const
|
|
553
|
-
// Force repository creation
|
|
554
|
-
commands.adminProcessRepository;
|
|
555
|
-
|
|
556
|
-
commands.log('warn', 'Warning message', { detail: 'xyz' });
|
|
557
|
-
|
|
558
|
-
// Give async operation a chance to execute
|
|
559
|
-
await new Promise(resolve => setImmediate(resolve));
|
|
560
|
-
|
|
561
|
-
expect(mockAdminProcessRepo.appendProcessLog).toHaveBeenCalled();
|
|
562
|
-
const callArgs = mockAdminProcessRepo.appendProcessLog.mock.calls[0];
|
|
563
|
-
expect(callArgs[0]).toBe('exec_123');
|
|
564
|
-
expect(callArgs[1].level).toBe('warn');
|
|
565
|
-
expect(callArgs[1].message).toBe('Warning message');
|
|
566
|
-
});
|
|
567
|
-
|
|
568
|
-
it('log() does not persist if no executionId', async () => {
|
|
569
|
-
const commands = new AdminFriggCommands();
|
|
570
|
-
|
|
571
|
-
commands.log('info', 'Test');
|
|
572
|
-
|
|
573
|
-
await new Promise(resolve => setImmediate(resolve));
|
|
574
|
-
|
|
575
|
-
expect(mockAdminProcessRepo.appendProcessLog).not.toHaveBeenCalled();
|
|
576
|
-
});
|
|
363
|
+
it('log() is in-memory only (no DB persistence)', () => {
|
|
364
|
+
const ctx = new AdminFriggCommands({ executionId: 'exec_123' });
|
|
577
365
|
|
|
578
|
-
|
|
579
|
-
const commands = new AdminFriggCommands({ executionId: 'exec_123' });
|
|
580
|
-
// Force repository creation
|
|
581
|
-
commands.adminProcessRepository;
|
|
582
|
-
mockAdminProcessRepo.appendProcessLog.mockRejectedValue(new Error('DB Error'));
|
|
366
|
+
ctx.log('warn', 'Warning message', { detail: 'xyz' });
|
|
583
367
|
|
|
584
|
-
//
|
|
585
|
-
expect(
|
|
368
|
+
// Verify entry was added to in-memory logs
|
|
369
|
+
expect(ctx.logs).toHaveLength(1);
|
|
370
|
+
expect(ctx.logs[0].level).toBe('warn');
|
|
371
|
+
expect(ctx.logs[0].message).toBe('Warning message');
|
|
586
372
|
});
|
|
587
373
|
|
|
588
374
|
it('getLogs() returns all logs', () => {
|
|
589
|
-
const
|
|
375
|
+
const ctx = new AdminFriggCommands();
|
|
590
376
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
377
|
+
ctx.log('info', 'First');
|
|
378
|
+
ctx.log('warn', 'Second');
|
|
379
|
+
ctx.log('error', 'Third');
|
|
594
380
|
|
|
595
|
-
const logs =
|
|
381
|
+
const logs = ctx.getLogs();
|
|
596
382
|
|
|
597
383
|
expect(logs).toHaveLength(3);
|
|
598
384
|
expect(logs[0].message).toBe('First');
|
|
@@ -601,43 +387,43 @@ describe('AdminFriggCommands', () => {
|
|
|
601
387
|
});
|
|
602
388
|
|
|
603
389
|
it('clearLogs() clears logs array', () => {
|
|
604
|
-
const
|
|
390
|
+
const ctx = new AdminFriggCommands();
|
|
605
391
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
expect(
|
|
392
|
+
ctx.log('info', 'First');
|
|
393
|
+
ctx.log('info', 'Second');
|
|
394
|
+
expect(ctx.logs).toHaveLength(2);
|
|
609
395
|
|
|
610
|
-
|
|
396
|
+
ctx.clearLogs();
|
|
611
397
|
|
|
612
|
-
expect(
|
|
398
|
+
expect(ctx.logs).toHaveLength(0);
|
|
613
399
|
});
|
|
614
400
|
|
|
615
401
|
it('getExecutionId() returns executionId', () => {
|
|
616
|
-
const
|
|
402
|
+
const ctx = new AdminFriggCommands({ executionId: 'exec_789' });
|
|
617
403
|
|
|
618
|
-
expect(
|
|
404
|
+
expect(ctx.getExecutionId()).toBe('exec_789');
|
|
619
405
|
});
|
|
620
406
|
|
|
621
407
|
it('getExecutionId() returns null if not set', () => {
|
|
622
|
-
const
|
|
408
|
+
const ctx = new AdminFriggCommands();
|
|
623
409
|
|
|
624
|
-
expect(
|
|
410
|
+
expect(ctx.getExecutionId()).toBeNull();
|
|
625
411
|
});
|
|
626
412
|
});
|
|
627
413
|
|
|
628
414
|
describe('createAdminFriggCommands factory', () => {
|
|
629
|
-
it('creates
|
|
630
|
-
const
|
|
415
|
+
it('creates AdminScriptContext instance', () => {
|
|
416
|
+
const ctx = createAdminFriggCommands({ executionId: 'exec_123' });
|
|
631
417
|
|
|
632
|
-
expect(
|
|
633
|
-
expect(
|
|
418
|
+
expect(ctx).toBeInstanceOf(AdminFriggCommands);
|
|
419
|
+
expect(ctx.executionId).toBe('exec_123');
|
|
634
420
|
});
|
|
635
421
|
|
|
636
422
|
it('creates with default params', () => {
|
|
637
|
-
const
|
|
423
|
+
const ctx = createAdminFriggCommands();
|
|
638
424
|
|
|
639
|
-
expect(
|
|
640
|
-
expect(
|
|
425
|
+
expect(ctx).toBeInstanceOf(AdminFriggCommands);
|
|
426
|
+
expect(ctx.executionId).toBeNull();
|
|
641
427
|
});
|
|
642
428
|
});
|
|
643
429
|
});
|