@friggframework/devtools 2.0.0--canary.474.898a56c.0 → 2.0.0--canary.474.a794ea3.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/infrastructure/domains/database/migration-builder.js +199 -1
- package/infrastructure/domains/database/migration-builder.test.js +73 -0
- package/infrastructure/domains/health/application/use-cases/__tests__/execute-resource-import-use-case.test.js +679 -0
- package/infrastructure/domains/health/application/use-cases/__tests__/repair-via-import-use-case.test.js +397 -29
- package/infrastructure/domains/health/application/use-cases/execute-resource-import-use-case.js +221 -0
- package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.js +6 -0
- package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.js +162 -9
- package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.js +19 -1
- package/infrastructure/domains/health/domain/entities/issue.js +50 -1
- package/infrastructure/domains/health/domain/entities/issue.test.js +111 -0
- package/infrastructure/domains/health/domain/services/__tests__/import-progress-monitor.test.js +971 -0
- package/infrastructure/domains/health/domain/services/__tests__/import-template-generator.test.js +1150 -0
- package/infrastructure/domains/health/domain/services/__tests__/logical-id-mapper.test.js +55 -28
- package/infrastructure/domains/health/domain/services/__tests__/update-progress-monitor.test.js +419 -0
- package/infrastructure/domains/health/domain/services/import-progress-monitor.js +195 -0
- package/infrastructure/domains/health/domain/services/import-template-generator.js +435 -0
- package/infrastructure/domains/health/domain/services/logical-id-mapper.js +21 -6
- package/infrastructure/domains/health/domain/services/property-mutability-config.js +382 -0
- package/infrastructure/domains/health/domain/services/update-progress-monitor.js +192 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.js +407 -20
- package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.test.js +698 -26
- package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.js +392 -1
- package/package.json +6 -6
|
@@ -120,19 +120,27 @@ describe('RepairViaImportUseCase - importWithLogicalIdMapping', () => {
|
|
|
120
120
|
|
|
121
121
|
const orphanedResources = [
|
|
122
122
|
{
|
|
123
|
-
physicalId: 'vpc-
|
|
123
|
+
physicalId: 'vpc-12345678',
|
|
124
124
|
resourceType: 'AWS::EC2::VPC',
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
125
|
+
properties: {
|
|
126
|
+
VpcId: 'vpc-12345678',
|
|
127
|
+
CidrBlock: '10.0.0.0/16',
|
|
128
|
+
tags: {
|
|
129
|
+
'aws:cloudformation:stack-name': 'acme-integrations-dev',
|
|
130
|
+
'aws:cloudformation:logical-id': 'FriggVPC',
|
|
131
|
+
},
|
|
132
|
+
},
|
|
129
133
|
},
|
|
130
134
|
{
|
|
131
|
-
physicalId: 'subnet-
|
|
135
|
+
physicalId: 'subnet-11111111',
|
|
132
136
|
resourceType: 'AWS::EC2::Subnet',
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
137
|
+
properties: {
|
|
138
|
+
SubnetId: 'subnet-11111111',
|
|
139
|
+
VpcId: 'vpc-12345678',
|
|
140
|
+
tags: {
|
|
141
|
+
'aws:cloudformation:stack-name': 'acme-integrations-dev',
|
|
142
|
+
},
|
|
143
|
+
},
|
|
136
144
|
},
|
|
137
145
|
];
|
|
138
146
|
|
|
@@ -150,7 +158,7 @@ describe('RepairViaImportUseCase - importWithLogicalIdMapping', () => {
|
|
|
150
158
|
Type: 'AWS::Lambda::Function',
|
|
151
159
|
Properties: {
|
|
152
160
|
VpcConfig: {
|
|
153
|
-
SubnetIds: ['subnet-
|
|
161
|
+
SubnetIds: ['subnet-11111111'],
|
|
154
162
|
},
|
|
155
163
|
},
|
|
156
164
|
},
|
|
@@ -160,14 +168,14 @@ describe('RepairViaImportUseCase - importWithLogicalIdMapping', () => {
|
|
|
160
168
|
const mappings = [
|
|
161
169
|
{
|
|
162
170
|
logicalId: 'FriggVPC',
|
|
163
|
-
physicalId: 'vpc-
|
|
171
|
+
physicalId: 'vpc-12345678',
|
|
164
172
|
resourceType: 'AWS::EC2::VPC',
|
|
165
173
|
matchMethod: 'tag',
|
|
166
174
|
confidence: 'high',
|
|
167
175
|
},
|
|
168
176
|
{
|
|
169
177
|
logicalId: 'FriggPrivateSubnet1',
|
|
170
|
-
physicalId: 'subnet-
|
|
178
|
+
physicalId: 'subnet-11111111',
|
|
171
179
|
resourceType: 'AWS::EC2::Subnet',
|
|
172
180
|
matchMethod: 'vpc-usage',
|
|
173
181
|
confidence: 'high',
|
|
@@ -219,9 +227,13 @@ describe('RepairViaImportUseCase - importWithLogicalIdMapping', () => {
|
|
|
219
227
|
|
|
220
228
|
const orphanedResources = [
|
|
221
229
|
{
|
|
222
|
-
physicalId: 'vpc-
|
|
230
|
+
physicalId: 'vpc-12345678',
|
|
223
231
|
resourceType: 'AWS::EC2::VPC',
|
|
224
|
-
|
|
232
|
+
properties: {
|
|
233
|
+
VpcId: 'vpc-12345678',
|
|
234
|
+
CidrBlock: '10.0.0.0/16',
|
|
235
|
+
tags: {},
|
|
236
|
+
},
|
|
225
237
|
},
|
|
226
238
|
];
|
|
227
239
|
|
|
@@ -231,7 +243,7 @@ describe('RepairViaImportUseCase - importWithLogicalIdMapping', () => {
|
|
|
231
243
|
const mappings = [
|
|
232
244
|
{
|
|
233
245
|
logicalId: 'FriggVPC',
|
|
234
|
-
physicalId: 'vpc-
|
|
246
|
+
physicalId: 'vpc-12345678',
|
|
235
247
|
resourceType: 'AWS::EC2::VPC',
|
|
236
248
|
matchMethod: 'tag',
|
|
237
249
|
confidence: 'high',
|
|
@@ -257,7 +269,7 @@ describe('RepairViaImportUseCase - importWithLogicalIdMapping', () => {
|
|
|
257
269
|
{
|
|
258
270
|
ResourceType: 'AWS::EC2::VPC',
|
|
259
271
|
LogicalResourceId: 'FriggVPC',
|
|
260
|
-
ResourceIdentifier: { VpcId: 'vpc-
|
|
272
|
+
ResourceIdentifier: { VpcId: 'vpc-12345678' },
|
|
261
273
|
},
|
|
262
274
|
]);
|
|
263
275
|
});
|
|
@@ -270,10 +282,41 @@ describe('RepairViaImportUseCase - importWithLogicalIdMapping', () => {
|
|
|
270
282
|
};
|
|
271
283
|
|
|
272
284
|
const orphanedResources = [
|
|
273
|
-
{
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
285
|
+
{
|
|
286
|
+
physicalId: 'vpc-123',
|
|
287
|
+
resourceType: 'AWS::EC2::VPC',
|
|
288
|
+
properties: {
|
|
289
|
+
VpcId: 'vpc-123',
|
|
290
|
+
CidrBlock: '10.0.0.0/16',
|
|
291
|
+
tags: {},
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
physicalId: 'subnet-456',
|
|
296
|
+
resourceType: 'AWS::EC2::Subnet',
|
|
297
|
+
properties: {
|
|
298
|
+
SubnetId: 'subnet-456',
|
|
299
|
+
VpcId: 'vpc-123',
|
|
300
|
+
tags: {},
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
physicalId: 'sg-789',
|
|
305
|
+
resourceType: 'AWS::EC2::SecurityGroup',
|
|
306
|
+
properties: {
|
|
307
|
+
GroupId: 'sg-789',
|
|
308
|
+
VpcId: 'vpc-123',
|
|
309
|
+
tags: {},
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
physicalId: 'igw-abc',
|
|
314
|
+
resourceType: 'AWS::EC2::InternetGateway',
|
|
315
|
+
properties: {
|
|
316
|
+
InternetGatewayId: 'igw-abc',
|
|
317
|
+
tags: {},
|
|
318
|
+
},
|
|
319
|
+
},
|
|
277
320
|
];
|
|
278
321
|
|
|
279
322
|
const buildTemplate = { resources: {} };
|
|
@@ -357,9 +400,33 @@ describe('RepairViaImportUseCase - importWithLogicalIdMapping', () => {
|
|
|
357
400
|
};
|
|
358
401
|
|
|
359
402
|
const orphanedResources = [
|
|
360
|
-
{
|
|
361
|
-
|
|
362
|
-
|
|
403
|
+
{
|
|
404
|
+
physicalId: 'vpc-123',
|
|
405
|
+
resourceType: 'AWS::EC2::VPC',
|
|
406
|
+
properties: {
|
|
407
|
+
VpcId: 'vpc-123',
|
|
408
|
+
CidrBlock: '10.0.0.0/16',
|
|
409
|
+
tags: {},
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
physicalId: 'vpc-456',
|
|
414
|
+
resourceType: 'AWS::EC2::VPC',
|
|
415
|
+
properties: {
|
|
416
|
+
VpcId: 'vpc-456',
|
|
417
|
+
CidrBlock: '10.0.0.0/16',
|
|
418
|
+
tags: {},
|
|
419
|
+
},
|
|
420
|
+
}, // No match
|
|
421
|
+
{
|
|
422
|
+
physicalId: 'subnet-789',
|
|
423
|
+
resourceType: 'AWS::EC2::Subnet',
|
|
424
|
+
properties: {
|
|
425
|
+
SubnetId: 'subnet-789',
|
|
426
|
+
VpcId: 'vpc-123',
|
|
427
|
+
tags: {},
|
|
428
|
+
},
|
|
429
|
+
},
|
|
363
430
|
];
|
|
364
431
|
|
|
365
432
|
const buildTemplate = { resources: {} };
|
|
@@ -420,8 +487,24 @@ describe('RepairViaImportUseCase - importWithLogicalIdMapping', () => {
|
|
|
420
487
|
};
|
|
421
488
|
|
|
422
489
|
const orphanedResources = [
|
|
423
|
-
{
|
|
424
|
-
|
|
490
|
+
{
|
|
491
|
+
physicalId: 'vpc-123',
|
|
492
|
+
resourceType: 'AWS::EC2::VPC',
|
|
493
|
+
properties: {
|
|
494
|
+
VpcId: 'vpc-123',
|
|
495
|
+
CidrBlock: '10.0.0.0/16',
|
|
496
|
+
tags: {},
|
|
497
|
+
},
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
physicalId: 'vpc-456',
|
|
501
|
+
resourceType: 'AWS::EC2::VPC',
|
|
502
|
+
properties: {
|
|
503
|
+
VpcId: 'vpc-456',
|
|
504
|
+
CidrBlock: '10.0.0.0/16',
|
|
505
|
+
tags: {},
|
|
506
|
+
},
|
|
507
|
+
},
|
|
425
508
|
];
|
|
426
509
|
|
|
427
510
|
const buildTemplate = { resources: {} };
|
|
@@ -473,9 +556,33 @@ describe('RepairViaImportUseCase - importWithLogicalIdMapping', () => {
|
|
|
473
556
|
};
|
|
474
557
|
|
|
475
558
|
const orphanedResources = [
|
|
476
|
-
{
|
|
477
|
-
|
|
478
|
-
|
|
559
|
+
{
|
|
560
|
+
physicalId: 'vpc-123',
|
|
561
|
+
resourceType: 'AWS::EC2::VPC',
|
|
562
|
+
properties: {
|
|
563
|
+
VpcId: 'vpc-123',
|
|
564
|
+
CidrBlock: '10.0.0.0/16',
|
|
565
|
+
tags: {},
|
|
566
|
+
},
|
|
567
|
+
},
|
|
568
|
+
{
|
|
569
|
+
physicalId: 'vpc-456',
|
|
570
|
+
resourceType: 'AWS::EC2::VPC',
|
|
571
|
+
properties: {
|
|
572
|
+
VpcId: 'vpc-456',
|
|
573
|
+
CidrBlock: '10.0.0.0/16',
|
|
574
|
+
tags: {},
|
|
575
|
+
},
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
physicalId: 'vpc-789',
|
|
579
|
+
resourceType: 'AWS::EC2::VPC',
|
|
580
|
+
properties: {
|
|
581
|
+
VpcId: 'vpc-789',
|
|
582
|
+
CidrBlock: '10.0.0.0/16',
|
|
583
|
+
tags: {},
|
|
584
|
+
},
|
|
585
|
+
},
|
|
479
586
|
];
|
|
480
587
|
|
|
481
588
|
const buildTemplate = { resources: {} };
|
|
@@ -538,7 +645,15 @@ describe('RepairViaImportUseCase - importWithLogicalIdMapping', () => {
|
|
|
538
645
|
};
|
|
539
646
|
|
|
540
647
|
const orphanedResources = [
|
|
541
|
-
{
|
|
648
|
+
{
|
|
649
|
+
physicalId: 'vpc-123',
|
|
650
|
+
resourceType: 'AWS::EC2::VPC',
|
|
651
|
+
properties: {
|
|
652
|
+
VpcId: 'vpc-123',
|
|
653
|
+
CidrBlock: '10.0.0.0/16',
|
|
654
|
+
tags: {},
|
|
655
|
+
},
|
|
656
|
+
},
|
|
542
657
|
];
|
|
543
658
|
|
|
544
659
|
const buildTemplate = { resources: { FriggVPC: { Type: 'AWS::EC2::VPC' } } };
|
|
@@ -759,4 +874,257 @@ describe('RepairViaImportUseCase - importWithLogicalIdMapping', () => {
|
|
|
759
874
|
expect(warnings[1].count).toBe(2);
|
|
760
875
|
});
|
|
761
876
|
});
|
|
877
|
+
|
|
878
|
+
describe('_deduplicateResourcesByLogicalId', () => {
|
|
879
|
+
it('should select ONE resource per logical ID when multiple map to same ID', () => {
|
|
880
|
+
// Arrange: 3 VPCs all tagged with "FriggVPC", but only vpc-123 is in deployed template
|
|
881
|
+
const mappedResources = [
|
|
882
|
+
{
|
|
883
|
+
logicalId: 'FriggVPC',
|
|
884
|
+
physicalId: 'vpc-123',
|
|
885
|
+
resourceType: 'AWS::EC2::VPC',
|
|
886
|
+
matchMethod: 'tag',
|
|
887
|
+
confidence: 'high',
|
|
888
|
+
},
|
|
889
|
+
{
|
|
890
|
+
logicalId: 'FriggVPC',
|
|
891
|
+
physicalId: 'vpc-456',
|
|
892
|
+
resourceType: 'AWS::EC2::VPC',
|
|
893
|
+
matchMethod: 'tag',
|
|
894
|
+
confidence: 'high',
|
|
895
|
+
},
|
|
896
|
+
{
|
|
897
|
+
logicalId: 'FriggVPC',
|
|
898
|
+
physicalId: 'vpc-789',
|
|
899
|
+
resourceType: 'AWS::EC2::VPC',
|
|
900
|
+
matchMethod: 'tag',
|
|
901
|
+
confidence: 'high',
|
|
902
|
+
},
|
|
903
|
+
];
|
|
904
|
+
|
|
905
|
+
const deployedTemplate = {
|
|
906
|
+
resources: {
|
|
907
|
+
MyLambda: {
|
|
908
|
+
Type: 'AWS::Lambda::Function',
|
|
909
|
+
Properties: {
|
|
910
|
+
VpcConfig: {
|
|
911
|
+
SubnetIds: ['subnet-in-vpc-123'], // This subnet belongs to vpc-123
|
|
912
|
+
SecurityGroupIds: [],
|
|
913
|
+
},
|
|
914
|
+
},
|
|
915
|
+
},
|
|
916
|
+
},
|
|
917
|
+
};
|
|
918
|
+
|
|
919
|
+
// Act
|
|
920
|
+
const result = useCase._deduplicateResourcesByLogicalId(
|
|
921
|
+
mappedResources,
|
|
922
|
+
deployedTemplate
|
|
923
|
+
);
|
|
924
|
+
|
|
925
|
+
// Assert: Should select ONLY the VPC that's actually referenced
|
|
926
|
+
expect(result.selectedResources).toHaveLength(1);
|
|
927
|
+
expect(result.selectedResources[0].physicalId).toBe('vpc-123');
|
|
928
|
+
expect(result.selectedResources[0].logicalId).toBe('FriggVPC');
|
|
929
|
+
|
|
930
|
+
// The other 2 VPCs should be marked as duplicates
|
|
931
|
+
expect(result.duplicates).toHaveLength(2);
|
|
932
|
+
expect(result.duplicates.map((d) => d.physicalId)).toEqual(
|
|
933
|
+
expect.arrayContaining(['vpc-456', 'vpc-789'])
|
|
934
|
+
);
|
|
935
|
+
});
|
|
936
|
+
|
|
937
|
+
it('should keep all resources when they have unique logical IDs', () => {
|
|
938
|
+
// Arrange: Different logical IDs, no duplication
|
|
939
|
+
const mappedResources = [
|
|
940
|
+
{
|
|
941
|
+
logicalId: 'FriggVPC',
|
|
942
|
+
physicalId: 'vpc-123',
|
|
943
|
+
resourceType: 'AWS::EC2::VPC',
|
|
944
|
+
},
|
|
945
|
+
{
|
|
946
|
+
logicalId: 'FriggPrivateSubnet1',
|
|
947
|
+
physicalId: 'subnet-456',
|
|
948
|
+
resourceType: 'AWS::EC2::Subnet',
|
|
949
|
+
},
|
|
950
|
+
{
|
|
951
|
+
logicalId: 'FriggLambdaSecurityGroup',
|
|
952
|
+
physicalId: 'sg-789',
|
|
953
|
+
resourceType: 'AWS::EC2::SecurityGroup',
|
|
954
|
+
},
|
|
955
|
+
];
|
|
956
|
+
|
|
957
|
+
const deployedTemplate = { resources: {} };
|
|
958
|
+
|
|
959
|
+
// Act
|
|
960
|
+
const result = useCase._deduplicateResourcesByLogicalId(
|
|
961
|
+
mappedResources,
|
|
962
|
+
deployedTemplate
|
|
963
|
+
);
|
|
964
|
+
|
|
965
|
+
// Assert: All 3 resources should be selected
|
|
966
|
+
expect(result.selectedResources).toHaveLength(3);
|
|
967
|
+
expect(result.duplicates).toHaveLength(0);
|
|
968
|
+
});
|
|
969
|
+
|
|
970
|
+
it('should use deployed template references to select correct resource', () => {
|
|
971
|
+
// Arrange: 5 subnets with same logical ID, need to pick the ones in deployed template
|
|
972
|
+
const mappedResources = [
|
|
973
|
+
{
|
|
974
|
+
logicalId: 'FriggPrivateSubnet1',
|
|
975
|
+
physicalId: 'subnet-111',
|
|
976
|
+
resourceType: 'AWS::EC2::Subnet',
|
|
977
|
+
},
|
|
978
|
+
{
|
|
979
|
+
logicalId: 'FriggPrivateSubnet1',
|
|
980
|
+
physicalId: 'subnet-222', // THIS ONE is in deployed template
|
|
981
|
+
resourceType: 'AWS::EC2::Subnet',
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
logicalId: 'FriggPrivateSubnet1',
|
|
985
|
+
physicalId: 'subnet-333',
|
|
986
|
+
resourceType: 'AWS::EC2::Subnet',
|
|
987
|
+
},
|
|
988
|
+
{
|
|
989
|
+
logicalId: 'FriggPrivateSubnet1',
|
|
990
|
+
physicalId: 'subnet-444',
|
|
991
|
+
resourceType: 'AWS::EC2::Subnet',
|
|
992
|
+
},
|
|
993
|
+
{
|
|
994
|
+
logicalId: 'FriggPrivateSubnet1',
|
|
995
|
+
physicalId: 'subnet-555',
|
|
996
|
+
resourceType: 'AWS::EC2::Subnet',
|
|
997
|
+
},
|
|
998
|
+
];
|
|
999
|
+
|
|
1000
|
+
const deployedTemplate = {
|
|
1001
|
+
resources: {
|
|
1002
|
+
MyLambda: {
|
|
1003
|
+
Type: 'AWS::Lambda::Function',
|
|
1004
|
+
Properties: {
|
|
1005
|
+
VpcConfig: {
|
|
1006
|
+
SubnetIds: ['subnet-222', 'subnet-other'], // subnet-222 is THE correct one
|
|
1007
|
+
SecurityGroupIds: [],
|
|
1008
|
+
},
|
|
1009
|
+
},
|
|
1010
|
+
},
|
|
1011
|
+
},
|
|
1012
|
+
};
|
|
1013
|
+
|
|
1014
|
+
// Act
|
|
1015
|
+
const result = useCase._deduplicateResourcesByLogicalId(
|
|
1016
|
+
mappedResources,
|
|
1017
|
+
deployedTemplate
|
|
1018
|
+
);
|
|
1019
|
+
|
|
1020
|
+
// Assert: Should select subnet-222 because it's in deployed template
|
|
1021
|
+
expect(result.selectedResources).toHaveLength(1);
|
|
1022
|
+
expect(result.selectedResources[0].physicalId).toBe('subnet-222');
|
|
1023
|
+
|
|
1024
|
+
// Other 4 subnets should be duplicates
|
|
1025
|
+
expect(result.duplicates).toHaveLength(4);
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
it('should handle multiple logical IDs with duplicates', () => {
|
|
1029
|
+
// Arrange: 3 VPCs + 2 SecurityGroups, all duplicates
|
|
1030
|
+
// Note: VPC selection falls back to first when no direct reference exists
|
|
1031
|
+
const mappedResources = [
|
|
1032
|
+
{
|
|
1033
|
+
logicalId: 'FriggVPC',
|
|
1034
|
+
physicalId: 'vpc-111', // Will be selected (fallback to first)
|
|
1035
|
+
resourceType: 'AWS::EC2::VPC',
|
|
1036
|
+
},
|
|
1037
|
+
{
|
|
1038
|
+
logicalId: 'FriggVPC',
|
|
1039
|
+
physicalId: 'vpc-222',
|
|
1040
|
+
resourceType: 'AWS::EC2::VPC',
|
|
1041
|
+
},
|
|
1042
|
+
{
|
|
1043
|
+
logicalId: 'FriggVPC',
|
|
1044
|
+
physicalId: 'vpc-333',
|
|
1045
|
+
resourceType: 'AWS::EC2::VPC',
|
|
1046
|
+
},
|
|
1047
|
+
{
|
|
1048
|
+
logicalId: 'FriggLambdaSecurityGroup',
|
|
1049
|
+
physicalId: 'sg-aaa', // Will be selected (in deployed template)
|
|
1050
|
+
resourceType: 'AWS::EC2::SecurityGroup',
|
|
1051
|
+
},
|
|
1052
|
+
{
|
|
1053
|
+
logicalId: 'FriggLambdaSecurityGroup',
|
|
1054
|
+
physicalId: 'sg-bbb',
|
|
1055
|
+
resourceType: 'AWS::EC2::SecurityGroup',
|
|
1056
|
+
},
|
|
1057
|
+
];
|
|
1058
|
+
|
|
1059
|
+
const deployedTemplate = {
|
|
1060
|
+
resources: {
|
|
1061
|
+
MyLambda: {
|
|
1062
|
+
Type: 'AWS::Lambda::Function',
|
|
1063
|
+
Properties: {
|
|
1064
|
+
VpcConfig: {
|
|
1065
|
+
SubnetIds: ['subnet-xxx'], // Not matching any VPC
|
|
1066
|
+
SecurityGroupIds: ['sg-aaa'], // sg-aaa is the correct one
|
|
1067
|
+
},
|
|
1068
|
+
},
|
|
1069
|
+
},
|
|
1070
|
+
},
|
|
1071
|
+
};
|
|
1072
|
+
|
|
1073
|
+
// Act
|
|
1074
|
+
const result = useCase._deduplicateResourcesByLogicalId(
|
|
1075
|
+
mappedResources,
|
|
1076
|
+
deployedTemplate
|
|
1077
|
+
);
|
|
1078
|
+
|
|
1079
|
+
// Assert: Should select ONE of each logical ID
|
|
1080
|
+
expect(result.selectedResources).toHaveLength(2);
|
|
1081
|
+
expect(result.selectedResources.map((r) => r.physicalId)).toEqual(
|
|
1082
|
+
expect.arrayContaining(['vpc-111', 'sg-aaa']) // VPC fallback + SG match
|
|
1083
|
+
);
|
|
1084
|
+
|
|
1085
|
+
// 3 resources should be duplicates (2 VPCs + 1 SG)
|
|
1086
|
+
expect(result.duplicates).toHaveLength(3);
|
|
1087
|
+
});
|
|
1088
|
+
|
|
1089
|
+
it('should fall back to first resource if none match deployed template', () => {
|
|
1090
|
+
// Arrange: Multiple resources but none are in deployed template
|
|
1091
|
+
const mappedResources = [
|
|
1092
|
+
{
|
|
1093
|
+
logicalId: 'FriggVPC',
|
|
1094
|
+
physicalId: 'vpc-111',
|
|
1095
|
+
resourceType: 'AWS::EC2::VPC',
|
|
1096
|
+
},
|
|
1097
|
+
{
|
|
1098
|
+
logicalId: 'FriggVPC',
|
|
1099
|
+
physicalId: 'vpc-222',
|
|
1100
|
+
resourceType: 'AWS::EC2::VPC',
|
|
1101
|
+
},
|
|
1102
|
+
];
|
|
1103
|
+
|
|
1104
|
+
const deployedTemplate = {
|
|
1105
|
+
resources: {
|
|
1106
|
+
MyLambda: {
|
|
1107
|
+
Type: 'AWS::Lambda::Function',
|
|
1108
|
+
Properties: {
|
|
1109
|
+
VpcConfig: {
|
|
1110
|
+
SubnetIds: ['subnet-other'], // Different VPC
|
|
1111
|
+
SecurityGroupIds: [],
|
|
1112
|
+
},
|
|
1113
|
+
},
|
|
1114
|
+
},
|
|
1115
|
+
},
|
|
1116
|
+
};
|
|
1117
|
+
|
|
1118
|
+
// Act
|
|
1119
|
+
const result = useCase._deduplicateResourcesByLogicalId(
|
|
1120
|
+
mappedResources,
|
|
1121
|
+
deployedTemplate
|
|
1122
|
+
);
|
|
1123
|
+
|
|
1124
|
+
// Assert: Should pick first one as fallback
|
|
1125
|
+
expect(result.selectedResources).toHaveLength(1);
|
|
1126
|
+
expect(result.selectedResources[0].physicalId).toBe('vpc-111');
|
|
1127
|
+
expect(result.duplicates).toHaveLength(1);
|
|
1128
|
+
});
|
|
1129
|
+
});
|
|
762
1130
|
});
|