@friggframework/devtools 2.0.0--canary.463.62579dd.0 → 2.0.0--canary.461.ec909cf.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.
@@ -0,0 +1,482 @@
1
+ /**
2
+ * Tests for Aurora Builder
3
+ *
4
+ * Tests Aurora PostgreSQL cluster configuration
5
+ */
6
+
7
+ const { AuroraBuilder } = require('./aurora-builder');
8
+ const { ValidationResult } = require('../shared/base-builder');
9
+
10
+ describe('AuroraBuilder', () => {
11
+ let auroraBuilder;
12
+
13
+ beforeEach(() => {
14
+ auroraBuilder = new AuroraBuilder();
15
+ // Clean up env vars
16
+ delete process.env.FRIGG_SKIP_AWS_DISCOVERY;
17
+ });
18
+
19
+ afterEach(() => {
20
+ // Clean up env vars
21
+ delete process.env.FRIGG_SKIP_AWS_DISCOVERY;
22
+ });
23
+
24
+ describe('shouldExecute()', () => {
25
+ it('should return true when Postgres is enabled', () => {
26
+ const appDefinition = {
27
+ database: {
28
+ postgres: { enable: true },
29
+ },
30
+ };
31
+
32
+ expect(auroraBuilder.shouldExecute(appDefinition)).toBe(true);
33
+ });
34
+
35
+ it('should return false when Postgres is disabled', () => {
36
+ const appDefinition = {
37
+ database: {
38
+ postgres: { enable: false },
39
+ },
40
+ };
41
+
42
+ expect(auroraBuilder.shouldExecute(appDefinition)).toBe(false);
43
+ });
44
+
45
+ it('should return false when database is not defined', () => {
46
+ const appDefinition = {};
47
+
48
+ expect(auroraBuilder.shouldExecute(appDefinition)).toBe(false);
49
+ });
50
+
51
+ it('should return false when postgres is not defined', () => {
52
+ const appDefinition = {
53
+ database: {},
54
+ };
55
+
56
+ expect(auroraBuilder.shouldExecute(appDefinition)).toBe(false);
57
+ });
58
+
59
+ it('should return false when FRIGG_SKIP_AWS_DISCOVERY is set (local mode)', () => {
60
+ process.env.FRIGG_SKIP_AWS_DISCOVERY = 'true';
61
+
62
+ const appDefinition = {
63
+ database: {
64
+ postgres: { enable: true },
65
+ },
66
+ };
67
+
68
+ expect(auroraBuilder.shouldExecute(appDefinition)).toBe(false);
69
+ });
70
+
71
+ it('should return true when FRIGG_SKIP_AWS_DISCOVERY is not set and Postgres is enabled', () => {
72
+ delete process.env.FRIGG_SKIP_AWS_DISCOVERY;
73
+
74
+ const appDefinition = {
75
+ database: {
76
+ postgres: { enable: true },
77
+ },
78
+ };
79
+
80
+ expect(auroraBuilder.shouldExecute(appDefinition)).toBe(true);
81
+ });
82
+ });
83
+
84
+ describe('getDependencies()', () => {
85
+ it('should depend on VpcBuilder', () => {
86
+ const deps = auroraBuilder.getDependencies();
87
+
88
+ expect(deps).toEqual(['VpcBuilder']);
89
+ });
90
+ });
91
+
92
+ describe('validate()', () => {
93
+ it('should pass validation for valid discover mode config', () => {
94
+ const appDefinition = {
95
+ database: {
96
+ postgres: {
97
+ enable: true,
98
+ management: 'discover',
99
+ },
100
+ },
101
+ };
102
+
103
+ const result = auroraBuilder.validate(appDefinition);
104
+
105
+ expect(result).toBeInstanceOf(ValidationResult);
106
+ expect(result.valid).toBe(true);
107
+ expect(result.errors).toEqual([]);
108
+ });
109
+
110
+ it('should pass validation for create-new mode', () => {
111
+ const appDefinition = {
112
+ database: {
113
+ postgres: {
114
+ enable: true,
115
+ management: 'create-new',
116
+ },
117
+ },
118
+ };
119
+
120
+ const result = auroraBuilder.validate(appDefinition);
121
+
122
+ expect(result.valid).toBe(true);
123
+ });
124
+
125
+ it('should error when database config is missing', () => {
126
+ const appDefinition = {};
127
+
128
+ const result = auroraBuilder.validate(appDefinition);
129
+
130
+ expect(result.valid).toBe(false);
131
+ expect(result.errors).toContain('PostgreSQL database configuration is missing');
132
+ });
133
+
134
+ it('should error for invalid management mode', () => {
135
+ const appDefinition = {
136
+ database: {
137
+ postgres: {
138
+ enable: true,
139
+ management: 'invalid-mode',
140
+ },
141
+ },
142
+ };
143
+
144
+ const result = auroraBuilder.validate(appDefinition);
145
+
146
+ expect(result.valid).toBe(false);
147
+ expect(result.errors).toContain(
148
+ expect.stringContaining('Invalid database.postgres.management')
149
+ );
150
+ });
151
+
152
+ it('should error when use-existing without endpoint', () => {
153
+ const appDefinition = {
154
+ database: {
155
+ postgres: {
156
+ enable: true,
157
+ management: 'use-existing',
158
+ },
159
+ },
160
+ };
161
+
162
+ const result = auroraBuilder.validate(appDefinition);
163
+
164
+ expect(result.valid).toBe(false);
165
+ expect(result.errors).toContain(
166
+ 'database.postgres.endpoint is required when management="use-existing"'
167
+ );
168
+ });
169
+
170
+ it('should pass when use-existing with endpoint', () => {
171
+ const appDefinition = {
172
+ database: {
173
+ postgres: {
174
+ enable: true,
175
+ management: 'use-existing',
176
+ endpoint: 'db.example.com',
177
+ },
178
+ },
179
+ };
180
+
181
+ const result = auroraBuilder.validate(appDefinition);
182
+
183
+ expect(result.valid).toBe(true);
184
+ });
185
+
186
+ it('should error when minCapacity is out of range', () => {
187
+ const appDefinition = {
188
+ database: {
189
+ postgres: {
190
+ enable: true,
191
+ minCapacity: 0.25, // Too low
192
+ },
193
+ },
194
+ };
195
+
196
+ const result = auroraBuilder.validate(appDefinition);
197
+
198
+ expect(result.valid).toBe(false);
199
+ expect(result.errors).toContain(
200
+ expect.stringContaining('minCapacity must be between 0.5 and 128')
201
+ );
202
+ });
203
+
204
+ it('should error when maxCapacity is out of range', () => {
205
+ const appDefinition = {
206
+ database: {
207
+ postgres: {
208
+ enable: true,
209
+ maxCapacity: 256, // Too high
210
+ },
211
+ },
212
+ };
213
+
214
+ const result = auroraBuilder.validate(appDefinition);
215
+
216
+ expect(result.valid).toBe(false);
217
+ expect(result.errors).toContain(
218
+ expect.stringContaining('maxCapacity must be between 0.5 and 128')
219
+ );
220
+ });
221
+
222
+ it('should pass with valid capacity values', () => {
223
+ const appDefinition = {
224
+ database: {
225
+ postgres: {
226
+ enable: true,
227
+ minCapacity: 0.5,
228
+ maxCapacity: 16,
229
+ },
230
+ },
231
+ };
232
+
233
+ const result = auroraBuilder.validate(appDefinition);
234
+
235
+ expect(result.valid).toBe(true);
236
+ });
237
+
238
+ it('should warn about public accessibility', () => {
239
+ const appDefinition = {
240
+ database: {
241
+ postgres: {
242
+ enable: true,
243
+ publiclyAccessible: true,
244
+ },
245
+ },
246
+ };
247
+
248
+ const result = auroraBuilder.validate(appDefinition);
249
+
250
+ expect(result.warnings).toContain(
251
+ expect.stringContaining('publiclyAccessible=true is not recommended for production')
252
+ );
253
+ });
254
+
255
+ it('should not warn when publiclyAccessible is false', () => {
256
+ const appDefinition = {
257
+ database: {
258
+ postgres: {
259
+ enable: true,
260
+ publiclyAccessible: false,
261
+ },
262
+ },
263
+ };
264
+
265
+ const result = auroraBuilder.validate(appDefinition);
266
+
267
+ expect(result.warnings).toEqual([]);
268
+ });
269
+ });
270
+
271
+ describe('build() - discover mode', () => {
272
+ it('should use discovered database endpoint', async () => {
273
+ const appDefinition = {
274
+ database: {
275
+ postgres: {
276
+ enable: true,
277
+ management: 'discover',
278
+ },
279
+ },
280
+ };
281
+
282
+ const discoveredResources = {
283
+ auroraClusterEndpoint: 'cluster.abc.us-east-1.rds.amazonaws.com',
284
+ auroraPort: 5432,
285
+ databaseSecretArn: 'arn:aws:secretsmanager:us-east-1:123:secret:db',
286
+ };
287
+
288
+ const result = await auroraBuilder.build(appDefinition, discoveredResources);
289
+
290
+ expect(result.environment.DATABASE_URL).toContain('cluster.abc.us-east-1.rds.amazonaws.com');
291
+ expect(result.environment.DATABASE_URL).toContain('5432');
292
+ });
293
+
294
+ it('should add IAM permissions for Secrets Manager', async () => {
295
+ const appDefinition = {
296
+ database: {
297
+ postgres: {
298
+ enable: true,
299
+ management: 'discover',
300
+ },
301
+ },
302
+ };
303
+
304
+ const discoveredResources = {
305
+ auroraClusterEndpoint: 'cluster.abc.us-east-1.rds.amazonaws.com',
306
+ auroraPort: 5432,
307
+ databaseSecretArn: 'arn:aws:secretsmanager:us-east-1:123:secret:db',
308
+ };
309
+
310
+ const result = await auroraBuilder.build(appDefinition, discoveredResources);
311
+
312
+ const secretPermission = result.iamStatements.find(stmt =>
313
+ stmt.Action.includes('secretsmanager:GetSecretValue')
314
+ );
315
+
316
+ expect(secretPermission).toBeDefined();
317
+ expect(secretPermission.Resource).toBe('arn:aws:secretsmanager:us-east-1:123:secret:db');
318
+ });
319
+ });
320
+
321
+ describe('build() - create-new mode', () => {
322
+ it('should create Aurora cluster resources', async () => {
323
+ const appDefinition = {
324
+ database: {
325
+ postgres: {
326
+ enable: true,
327
+ management: 'create-new',
328
+ },
329
+ },
330
+ };
331
+
332
+ const discoveredResources = {
333
+ defaultVpcId: 'vpc-123',
334
+ privateSubnetId1: 'subnet-1',
335
+ privateSubnetId2: 'subnet-2',
336
+ };
337
+
338
+ const result = await auroraBuilder.build(appDefinition, discoveredResources);
339
+
340
+ expect(result.resources.FriggAuroraCluster).toBeDefined();
341
+ expect(result.resources.FriggAuroraCluster.Type).toBe('AWS::RDS::DBCluster');
342
+ });
343
+
344
+ it('should create database subnet group', async () => {
345
+ const appDefinition = {
346
+ database: {
347
+ postgres: {
348
+ enable: true,
349
+ management: 'create-new',
350
+ },
351
+ },
352
+ };
353
+
354
+ const discoveredResources = {
355
+ defaultVpcId: 'vpc-123',
356
+ privateSubnetId1: 'subnet-1',
357
+ privateSubnetId2: 'subnet-2',
358
+ };
359
+
360
+ const result = await auroraBuilder.build(appDefinition, discoveredResources);
361
+
362
+ expect(result.resources.FriggDBSubnetGroup).toBeDefined();
363
+ expect(result.resources.FriggDBSubnetGroup.Type).toBe('AWS::RDS::DBSubnetGroup');
364
+ });
365
+
366
+ it('should create Secrets Manager secret for credentials', async () => {
367
+ const appDefinition = {
368
+ database: {
369
+ postgres: {
370
+ enable: true,
371
+ management: 'create-new',
372
+ },
373
+ },
374
+ };
375
+
376
+ const discoveredResources = {
377
+ defaultVpcId: 'vpc-123',
378
+ };
379
+
380
+ const result = await auroraBuilder.build(appDefinition, discoveredResources);
381
+
382
+ expect(result.resources.FriggDatabaseSecret).toBeDefined();
383
+ expect(result.resources.FriggDatabaseSecret.Type).toBe('AWS::SecretsManager::Secret');
384
+ });
385
+
386
+ it('should configure Aurora Serverless v2', async () => {
387
+ const appDefinition = {
388
+ database: {
389
+ postgres: {
390
+ enable: true,
391
+ management: 'create-new',
392
+ },
393
+ },
394
+ };
395
+
396
+ const result = await auroraBuilder.build(appDefinition, {});
397
+
398
+ expect(result.resources.FriggAuroraCluster.Properties.EngineMode).toBe('provisioned');
399
+ expect(result.resources.FriggAuroraCluster.Properties.ServerlessV2ScalingConfiguration).toBeDefined();
400
+ });
401
+
402
+ it('should use custom capacity settings', async () => {
403
+ const appDefinition = {
404
+ database: {
405
+ postgres: {
406
+ enable: true,
407
+ management: 'create-new',
408
+ minCapacity: 1,
409
+ maxCapacity: 8,
410
+ },
411
+ },
412
+ };
413
+
414
+ const result = await auroraBuilder.build(appDefinition, {});
415
+
416
+ const scaling = result.resources.FriggAuroraCluster.Properties.ServerlessV2ScalingConfiguration;
417
+ expect(scaling.MinCapacity).toBe(1);
418
+ expect(scaling.MaxCapacity).toBe(8);
419
+ });
420
+
421
+ it('should default to sensible capacity values', async () => {
422
+ const appDefinition = {
423
+ database: {
424
+ postgres: {
425
+ enable: true,
426
+ management: 'create-new',
427
+ },
428
+ },
429
+ };
430
+
431
+ const result = await auroraBuilder.build(appDefinition, {});
432
+
433
+ const scaling = result.resources.FriggAuroraCluster.Properties.ServerlessV2ScalingConfiguration;
434
+ expect(scaling.MinCapacity).toBeGreaterThanOrEqual(0.5);
435
+ expect(scaling.MaxCapacity).toBeLessThanOrEqual(128);
436
+ });
437
+ });
438
+
439
+ describe('build() - use-existing mode', () => {
440
+ it('should use provided database endpoint', async () => {
441
+ const appDefinition = {
442
+ database: {
443
+ postgres: {
444
+ enable: true,
445
+ management: 'use-existing',
446
+ endpoint: 'custom-db.example.com',
447
+ port: 5432,
448
+ },
449
+ },
450
+ };
451
+
452
+ const result = await auroraBuilder.build(appDefinition, {});
453
+
454
+ expect(result.environment.DATABASE_URL).toContain('custom-db.example.com');
455
+ expect(result.environment.DATABASE_URL).toContain('5432');
456
+ });
457
+
458
+ it('should not create Aurora resources in use-existing mode', async () => {
459
+ const appDefinition = {
460
+ database: {
461
+ postgres: {
462
+ enable: true,
463
+ management: 'use-existing',
464
+ endpoint: 'db.example.com',
465
+ },
466
+ },
467
+ };
468
+
469
+ const result = await auroraBuilder.build(appDefinition, {});
470
+
471
+ expect(result.resources.FriggAuroraCluster).toBeUndefined();
472
+ expect(result.resources.FriggDatabaseSecret).toBeUndefined();
473
+ });
474
+ });
475
+
476
+ describe('getName()', () => {
477
+ it('should return AuroraBuilder', () => {
478
+ expect(auroraBuilder.getName()).toBe('AuroraBuilder');
479
+ });
480
+ });
481
+ });
482
+