@mapbox/cloudfriend 9.2.1 → 9.3.1

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.
Files changed (71) hide show
  1. package/.claude/settings.local.json +8 -0
  2. package/.idea/cloudfriend.iml +9 -0
  3. package/.idea/codeStyles/Project.xml +7 -0
  4. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  5. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  6. package/.idea/misc.xml +6 -0
  7. package/.idea/modules.xml +8 -0
  8. package/.idea/vcs.xml +6 -0
  9. package/.nyc_output/6686e513-03b6-415d-9b8b-0fcde7a4e430.json +1 -0
  10. package/.nyc_output/f58a557c-a1c0-4dcc-83c5-bbca4d01baf9.json +1 -0
  11. package/.nyc_output/processinfo/6686e513-03b6-415d-9b8b-0fcde7a4e430.json +1 -0
  12. package/.nyc_output/processinfo/f58a557c-a1c0-4dcc-83c5-bbca4d01baf9.json +1 -0
  13. package/.nyc_output/processinfo/index.json +1 -0
  14. package/cfniceberg_createtable.yaml +71 -0
  15. package/changelog.md +4 -0
  16. package/coverage/clover.xml +83 -51
  17. package/coverage/coverage-final.json +32 -31
  18. package/coverage/lcov-report/cloudfriend/bin/build-template.js.html +1 -1
  19. package/coverage/lcov-report/cloudfriend/bin/index.html +1 -1
  20. package/coverage/lcov-report/cloudfriend/bin/validate-template.js.html +1 -1
  21. package/coverage/lcov-report/cloudfriend/index.html +1 -1
  22. package/coverage/lcov-report/cloudfriend/index.js.html +1 -1
  23. package/coverage/lcov-report/cloudfriend/lib/build.js.html +1 -1
  24. package/coverage/lcov-report/cloudfriend/lib/conditions.js.html +1 -1
  25. package/coverage/lcov-report/cloudfriend/lib/index.html +1 -1
  26. package/coverage/lcov-report/cloudfriend/lib/intrinsic.js.html +2 -2
  27. package/coverage/lcov-report/cloudfriend/lib/merge.js.html +16 -16
  28. package/coverage/lcov-report/cloudfriend/lib/pseudo.js.html +1 -1
  29. package/coverage/lcov-report/cloudfriend/lib/rules.js.html +1 -1
  30. package/coverage/lcov-report/cloudfriend/lib/shortcuts/cross-account-role.js.html +1 -1
  31. package/coverage/lcov-report/cloudfriend/lib/shortcuts/event-lambda.js.html +1 -1
  32. package/coverage/lcov-report/cloudfriend/lib/shortcuts/glue-database.js.html +1 -1
  33. package/coverage/lcov-report/cloudfriend/lib/shortcuts/glue-iceberg-table.js.html +646 -0
  34. package/coverage/lcov-report/cloudfriend/lib/shortcuts/glue-json-table.js.html +1 -1
  35. package/coverage/lcov-report/cloudfriend/lib/shortcuts/glue-orc-table.js.html +1 -1
  36. package/coverage/lcov-report/cloudfriend/lib/shortcuts/glue-parquet-table.js.html +1 -1
  37. package/coverage/lcov-report/cloudfriend/lib/shortcuts/glue-presto-view.js.html +1 -1
  38. package/coverage/lcov-report/cloudfriend/lib/shortcuts/glue-spark-view.js.html +1 -1
  39. package/coverage/lcov-report/cloudfriend/lib/shortcuts/glue-table.js.html +1 -1
  40. package/coverage/lcov-report/cloudfriend/lib/shortcuts/hookshot.js.html +1 -1
  41. package/coverage/lcov-report/cloudfriend/lib/shortcuts/index.html +24 -9
  42. package/coverage/lcov-report/cloudfriend/lib/shortcuts/index.js.html +5 -2
  43. package/coverage/lcov-report/cloudfriend/lib/shortcuts/kinesis-firehose-base.js.html +1 -1
  44. package/coverage/lcov-report/cloudfriend/lib/shortcuts/lambda.js.html +1 -1
  45. package/coverage/lcov-report/cloudfriend/lib/shortcuts/log-subscription-lambda.js.html +1 -1
  46. package/coverage/lcov-report/cloudfriend/lib/shortcuts/queue-lambda.js.html +1 -1
  47. package/coverage/lcov-report/cloudfriend/lib/shortcuts/queue.js.html +1 -1
  48. package/coverage/lcov-report/cloudfriend/lib/shortcuts/role.js.html +1 -1
  49. package/coverage/lcov-report/cloudfriend/lib/shortcuts/s3-kinesis-firehose.js.html +1 -1
  50. package/coverage/lcov-report/cloudfriend/lib/shortcuts/scheduled-lambda.js.html +1 -1
  51. package/coverage/lcov-report/cloudfriend/lib/shortcuts/service-role.js.html +1 -1
  52. package/coverage/lcov-report/cloudfriend/lib/shortcuts/stream-lambda.js.html +1 -1
  53. package/coverage/lcov-report/cloudfriend/lib/validate.js.html +1 -1
  54. package/coverage/lcov-report/index.html +19 -19
  55. package/coverage/lcov.info +107 -28
  56. package/lib/shortcuts/api.md +37 -0
  57. package/lib/shortcuts/glue-iceberg-table.js +187 -0
  58. package/lib/shortcuts/index.js +1 -0
  59. package/package.json +2 -2
  60. package/requirements.dev.txt +2 -2
  61. package/test/fixtures/shortcuts/glue-iceberg-table-defaults.json +41 -0
  62. package/test/fixtures/shortcuts/glue-iceberg-table-no-defaults.json +39 -0
  63. package/test/fixtures/shortcuts/glue-iceberg-table-with-all-optimizers.json +101 -0
  64. package/test/fixtures/shortcuts/glue-iceberg-table-with-both-optimizers.json +80 -0
  65. package/test/fixtures/shortcuts/glue-iceberg-table-with-compaction-custom.json +68 -0
  66. package/test/fixtures/shortcuts/glue-iceberg-table-with-compaction-defaults.json +57 -0
  67. package/test/fixtures/shortcuts/glue-iceberg-table-with-optimizer-custom.json +75 -0
  68. package/test/fixtures/shortcuts/glue-iceberg-table-with-optimizer-defaults.json +64 -0
  69. package/test/fixtures/shortcuts/glue-iceberg-table-with-orphan-deletion-custom.json +74 -0
  70. package/test/fixtures/shortcuts/glue-iceberg-table-with-orphan-deletion-defaults.json +62 -0
  71. package/test/shortcuts.test.js +294 -3
@@ -0,0 +1,75 @@
1
+ {
2
+ "AWSTemplateFormatVersion": "2010-09-09",
3
+ "Metadata": {},
4
+ "Parameters": {},
5
+ "Rules": {},
6
+ "Mappings": {},
7
+ "Conditions": {},
8
+ "Resources": {
9
+ "OptimizerRole": {
10
+ "Type": "AWS::IAM::Role",
11
+ "Properties": {
12
+ "AssumeRolePolicyDocument": {}
13
+ }
14
+ },
15
+ "MyTable": {
16
+ "Type": "AWS::Glue::Table",
17
+ "Properties": {
18
+ "CatalogId": {
19
+ "Ref": "AWS::AccountId"
20
+ },
21
+ "DatabaseName": "my_database",
22
+ "Name": "my_table",
23
+ "OpenTableFormatInput": {
24
+ "IcebergInput": {
25
+ "MetadataOperation": "CREATE",
26
+ "Version": "2",
27
+ "IcebergTableInput": {
28
+ "Location": "s3://fake/location",
29
+ "Schema": {
30
+ "Type": "struct",
31
+ "Fields": [
32
+ {
33
+ "Name": "column",
34
+ "Type": "string",
35
+ "Id": 1,
36
+ "Required": true
37
+ }
38
+ ]
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ },
45
+ "MyTableRetentionOptimizer": {
46
+ "Type": "AWS::Glue::TableOptimizer",
47
+ "DependsOn": "MyTable",
48
+ "Properties": {
49
+ "CatalogId": {
50
+ "Ref": "AWS::AccountId"
51
+ },
52
+ "DatabaseName": "my_database",
53
+ "TableName": "my_table",
54
+ "Type": "retention",
55
+ "TableOptimizerConfiguration": {
56
+ "RoleArn": {
57
+ "Fn::GetAtt": [
58
+ "OptimizerRole",
59
+ "Arn"
60
+ ]
61
+ },
62
+ "Enabled": true,
63
+ "RetentionConfiguration": {
64
+ "IcebergConfiguration": {
65
+ "SnapshotRetentionPeriodInDays": 7,
66
+ "NumberOfSnapshotsToRetain": 3,
67
+ "CleanExpiredFiles": false
68
+ }
69
+ }
70
+ }
71
+ }
72
+ }
73
+ },
74
+ "Outputs": {}
75
+ }
@@ -0,0 +1,64 @@
1
+ {
2
+ "AWSTemplateFormatVersion": "2010-09-09",
3
+ "Metadata": {},
4
+ "Parameters": {},
5
+ "Rules": {},
6
+ "Mappings": {},
7
+ "Conditions": {},
8
+ "Resources": {
9
+ "MyTable": {
10
+ "Type": "AWS::Glue::Table",
11
+ "Properties": {
12
+ "CatalogId": {
13
+ "Ref": "AWS::AccountId"
14
+ },
15
+ "DatabaseName": "my_database",
16
+ "Name": "my_table",
17
+ "OpenTableFormatInput": {
18
+ "IcebergInput": {
19
+ "MetadataOperation": "CREATE",
20
+ "Version": "2",
21
+ "IcebergTableInput": {
22
+ "Location": "s3://fake/location",
23
+ "Schema": {
24
+ "Type": "struct",
25
+ "Fields": [
26
+ {
27
+ "Name": "column",
28
+ "Type": "string",
29
+ "Id": 1,
30
+ "Required": true
31
+ }
32
+ ]
33
+ }
34
+ }
35
+ }
36
+ }
37
+ }
38
+ },
39
+ "MyTableRetentionOptimizer": {
40
+ "Type": "AWS::Glue::TableOptimizer",
41
+ "DependsOn": "MyTable",
42
+ "Properties": {
43
+ "CatalogId": {
44
+ "Ref": "AWS::AccountId"
45
+ },
46
+ "DatabaseName": "my_database",
47
+ "TableName": "my_table",
48
+ "Type": "retention",
49
+ "TableOptimizerConfiguration": {
50
+ "RoleArn": "arn:aws:iam::123456789012:role/OptimizerRole",
51
+ "Enabled": true,
52
+ "RetentionConfiguration": {
53
+ "IcebergConfiguration": {
54
+ "SnapshotRetentionPeriodInDays": 5,
55
+ "NumberOfSnapshotsToRetain": 1,
56
+ "CleanExpiredFiles": true
57
+ }
58
+ }
59
+ }
60
+ }
61
+ }
62
+ },
63
+ "Outputs": {}
64
+ }
@@ -0,0 +1,74 @@
1
+ {
2
+ "AWSTemplateFormatVersion": "2010-09-09",
3
+ "Metadata": {},
4
+ "Parameters": {},
5
+ "Rules": {},
6
+ "Mappings": {},
7
+ "Conditions": {},
8
+ "Resources": {
9
+ "OrphanFileDeletionRole": {
10
+ "Type": "AWS::IAM::Role",
11
+ "Properties": {
12
+ "AssumeRolePolicyDocument": {}
13
+ }
14
+ },
15
+ "MyTable": {
16
+ "Type": "AWS::Glue::Table",
17
+ "Properties": {
18
+ "CatalogId": {
19
+ "Ref": "AWS::AccountId"
20
+ },
21
+ "DatabaseName": "my_database",
22
+ "Name": "my_table",
23
+ "OpenTableFormatInput": {
24
+ "IcebergInput": {
25
+ "MetadataOperation": "CREATE",
26
+ "Version": "2",
27
+ "IcebergTableInput": {
28
+ "Location": "s3://fake/location",
29
+ "Schema": {
30
+ "Type": "struct",
31
+ "Fields": [
32
+ {
33
+ "Name": "column",
34
+ "Type": "string",
35
+ "Id": 1,
36
+ "Required": true
37
+ }
38
+ ]
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ },
45
+ "MyTableOrphanFileDeletionOptimizer": {
46
+ "Type": "AWS::Glue::TableOptimizer",
47
+ "DependsOn": "MyTable",
48
+ "Properties": {
49
+ "CatalogId": {
50
+ "Ref": "AWS::AccountId"
51
+ },
52
+ "DatabaseName": "my_database",
53
+ "TableName": "my_table",
54
+ "Type": "orphan_file_deletion",
55
+ "TableOptimizerConfiguration": {
56
+ "RoleArn": {
57
+ "Fn::GetAtt": [
58
+ "OrphanFileDeletionRole",
59
+ "Arn"
60
+ ]
61
+ },
62
+ "Enabled": true,
63
+ "OrphanFileDeletionConfiguration": {
64
+ "IcebergConfiguration": {
65
+ "OrphanFileRetentionPeriodInDays": 7,
66
+ "Location": "s3://fake/location/subdir"
67
+ }
68
+ }
69
+ }
70
+ }
71
+ }
72
+ },
73
+ "Outputs": {}
74
+ }
@@ -0,0 +1,62 @@
1
+ {
2
+ "AWSTemplateFormatVersion": "2010-09-09",
3
+ "Metadata": {},
4
+ "Parameters": {},
5
+ "Rules": {},
6
+ "Mappings": {},
7
+ "Conditions": {},
8
+ "Resources": {
9
+ "MyTable": {
10
+ "Type": "AWS::Glue::Table",
11
+ "Properties": {
12
+ "CatalogId": {
13
+ "Ref": "AWS::AccountId"
14
+ },
15
+ "DatabaseName": "my_database",
16
+ "Name": "my_table",
17
+ "OpenTableFormatInput": {
18
+ "IcebergInput": {
19
+ "MetadataOperation": "CREATE",
20
+ "Version": "2",
21
+ "IcebergTableInput": {
22
+ "Location": "s3://fake/location",
23
+ "Schema": {
24
+ "Type": "struct",
25
+ "Fields": [
26
+ {
27
+ "Name": "column",
28
+ "Type": "string",
29
+ "Id": 1,
30
+ "Required": true
31
+ }
32
+ ]
33
+ }
34
+ }
35
+ }
36
+ }
37
+ }
38
+ },
39
+ "MyTableOrphanFileDeletionOptimizer": {
40
+ "Type": "AWS::Glue::TableOptimizer",
41
+ "DependsOn": "MyTable",
42
+ "Properties": {
43
+ "CatalogId": {
44
+ "Ref": "AWS::AccountId"
45
+ },
46
+ "DatabaseName": "my_database",
47
+ "TableName": "my_table",
48
+ "Type": "orphan_file_deletion",
49
+ "TableOptimizerConfiguration": {
50
+ "RoleArn": "arn:aws:iam::123456789012:role/OrphanFileDeletionRole",
51
+ "Enabled": true,
52
+ "OrphanFileDeletionConfiguration": {
53
+ "IcebergConfiguration": {
54
+ "OrphanFileRetentionPeriodInDays": 3
55
+ }
56
+ }
57
+ }
58
+ }
59
+ }
60
+ },
61
+ "Outputs": {}
62
+ }
@@ -15,8 +15,13 @@ const noUndefined = (template) => JSON.parse(JSON.stringify(template));
15
15
  describe('[shortcuts] fixture validation', () => {
16
16
  // Runs cfn-lint, ignoring "warnings". Install via pip or Homebrew to run these
17
17
  // tests locally.
18
- const cfnLint = (filepath) => new Promise((resolve, reject) => {
19
- cp.exec(`cfn-lint ${filepath} --ignore-checks W`, (err, stdout) => {
18
+ const cfnLint = (filepath, filename) => new Promise((resolve, reject) => {
19
+ // Ignore E3003 (missing TableInput) and E3002 (unexpected properties) for Iceberg tables only
20
+ // cfn-lint doesn't yet support OpenTableFormatInput (Iceberg table format)
21
+ const isIcebergTable = filename.includes('glue-iceberg-table');
22
+ const ignoreChecks = isIcebergTable ? 'W,E3003,E3002' : 'W';
23
+
24
+ cp.execFile('cfn-lint', [filepath, '--ignore-checks', ignoreChecks], (err, stdout) => {
20
25
  if (err) return reject(new Error(stdout));
21
26
  return resolve();
22
27
  });
@@ -28,7 +33,7 @@ describe('[shortcuts] fixture validation', () => {
28
33
 
29
34
  test.each(toValidate)('%s fixture passes validation', async (filename) => {
30
35
  await Promise.all([
31
- cfnLint(path.join(__dirname, 'fixtures', 'shortcuts', filename)),
36
+ cfnLint(path.join(__dirname, 'fixtures', 'shortcuts', filename), filename),
32
37
  sleep(1000)
33
38
  ]);
34
39
  });
@@ -1246,6 +1251,292 @@ describe('[shortcuts] glue parquet table', () => {
1246
1251
  });
1247
1252
  });
1248
1253
 
1254
+ describe('[shortcuts] glue iceberg table', () => {
1255
+ test('throws without options', () => {
1256
+ expect(() => new cf.shortcuts.GlueIcebergTable()).toThrow('Options required');
1257
+ });
1258
+
1259
+ test('throws without required parameters', () => {
1260
+ expect(() => new cf.shortcuts.GlueIcebergTable({})).toThrow(/You must provide a LogicalName, Name, DatabaseName, Location, and Schema/);
1261
+ });
1262
+
1263
+ test('expected resources generated with defaults', () => {
1264
+ const db = new cf.shortcuts.GlueIcebergTable({
1265
+ LogicalName: 'MyTable',
1266
+ DatabaseName: 'my_database',
1267
+ Name: 'my_table',
1268
+ Schema: {
1269
+ Type: 'struct',
1270
+ Fields: [
1271
+ { Name: 'column', Type: 'string', Id: 1, Required: true }
1272
+ ]
1273
+ },
1274
+ Location: 's3://fake/location'
1275
+ });
1276
+
1277
+ const template = cf.merge(db);
1278
+ if (update) fixtures.update('glue-iceberg-table-defaults', template);
1279
+ expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-defaults'));
1280
+ });
1281
+
1282
+ test('expected resources generated without defaults', () => {
1283
+ const db = new cf.shortcuts.GlueIcebergTable({
1284
+ LogicalName: 'MyTable',
1285
+ DatabaseName: 'my_database',
1286
+ Name: 'my_table',
1287
+ Schema: {
1288
+ Type: 'struct',
1289
+ Fields: [
1290
+ { Name: 'column', Type: 'string', Id: 1, Required: true }
1291
+ ]
1292
+ },
1293
+ CatalogId: '1234',
1294
+ Location: 's3://fake/location',
1295
+ IcebergVersion: '2'
1296
+ });
1297
+
1298
+ const template = cf.merge(db);
1299
+ if (update) fixtures.update('glue-iceberg-table-no-defaults', template);
1300
+ expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-no-defaults'));
1301
+ });
1302
+
1303
+ test('throws when EnableOptimizer is true but OptimizerRoleArn is missing', () => {
1304
+ expect(() => new cf.shortcuts.GlueIcebergTable({
1305
+ LogicalName: 'MyTable',
1306
+ DatabaseName: 'my_database',
1307
+ Name: 'my_table',
1308
+ Schema: {
1309
+ Type: 'struct',
1310
+ Fields: [
1311
+ { Name: 'column', Type: 'string', Id: 1, Required: true }
1312
+ ]
1313
+ },
1314
+ Location: 's3://fake/location',
1315
+ EnableOptimizer: true
1316
+ })).toThrow(/You must provide an OptimizerRoleArn when EnableOptimizer is true/);
1317
+ });
1318
+
1319
+ test('expected resources generated with optimizer using default retention settings', () => {
1320
+ const db = new cf.shortcuts.GlueIcebergTable({
1321
+ LogicalName: 'MyTable',
1322
+ DatabaseName: 'my_database',
1323
+ Name: 'my_table',
1324
+ Schema: {
1325
+ Type: 'struct',
1326
+ Fields: [
1327
+ { Name: 'column', Type: 'string', Id: 1, Required: true }
1328
+ ]
1329
+ },
1330
+ Location: 's3://fake/location',
1331
+ EnableOptimizer: true,
1332
+ OptimizerRoleArn: 'arn:aws:iam::123456789012:role/OptimizerRole'
1333
+ });
1334
+
1335
+ const template = cf.merge(db);
1336
+ if (update) fixtures.update('glue-iceberg-table-with-optimizer-defaults', template);
1337
+ expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-with-optimizer-defaults'));
1338
+ });
1339
+
1340
+ test('expected resources generated with optimizer using custom retention settings', () => {
1341
+ const db = new cf.shortcuts.GlueIcebergTable({
1342
+ LogicalName: 'MyTable',
1343
+ DatabaseName: 'my_database',
1344
+ Name: 'my_table',
1345
+ Schema: {
1346
+ Type: 'struct',
1347
+ Fields: [
1348
+ { Name: 'column', Type: 'string', Id: 1, Required: true }
1349
+ ]
1350
+ },
1351
+ Location: 's3://fake/location',
1352
+ EnableOptimizer: true,
1353
+ OptimizerRoleArn: cf.getAtt('OptimizerRole', 'Arn'),
1354
+ SnapshotRetentionPeriodInDays: 7,
1355
+ NumberOfSnapshotsToRetain: 3,
1356
+ CleanExpiredFiles: false
1357
+ });
1358
+
1359
+ const template = cf.merge(
1360
+ { Resources: { OptimizerRole: { Type: 'AWS::IAM::Role', Properties: { AssumeRolePolicyDocument: {} } } } },
1361
+ db
1362
+ );
1363
+ if (update) fixtures.update('glue-iceberg-table-with-optimizer-custom', template);
1364
+ expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-with-optimizer-custom'));
1365
+ });
1366
+
1367
+ test('throws when EnableCompaction is true but CompactionRoleArn is missing', () => {
1368
+ expect(() => new cf.shortcuts.GlueIcebergTable({
1369
+ LogicalName: 'MyTable',
1370
+ DatabaseName: 'my_database',
1371
+ Name: 'my_table',
1372
+ Schema: {
1373
+ Type: 'struct',
1374
+ Fields: [
1375
+ { Name: 'column', Type: 'string', Id: 1, Required: true }
1376
+ ]
1377
+ },
1378
+ Location: 's3://fake/location',
1379
+ EnableCompaction: true
1380
+ })).toThrow(/You must provide a CompactionRoleArn when EnableCompaction is true/);
1381
+ });
1382
+
1383
+ test('expected resources generated with compaction using default settings', () => {
1384
+ const db = new cf.shortcuts.GlueIcebergTable({
1385
+ LogicalName: 'MyTable',
1386
+ DatabaseName: 'my_database',
1387
+ Name: 'my_table',
1388
+ Schema: {
1389
+ Type: 'struct',
1390
+ Fields: [
1391
+ { Name: 'column', Type: 'string', Id: 1, Required: true }
1392
+ ]
1393
+ },
1394
+ Location: 's3://fake/location',
1395
+ EnableCompaction: true,
1396
+ CompactionRoleArn: 'arn:aws:iam::123456789012:role/CompactionRole'
1397
+ });
1398
+
1399
+ const template = cf.merge(db);
1400
+ if (update) fixtures.update('glue-iceberg-table-with-compaction-defaults', template);
1401
+ expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-with-compaction-defaults'));
1402
+ });
1403
+
1404
+ test('expected resources generated with compaction using custom settings', () => {
1405
+ const db = new cf.shortcuts.GlueIcebergTable({
1406
+ LogicalName: 'MyTable',
1407
+ DatabaseName: 'my_database',
1408
+ Name: 'my_table',
1409
+ Schema: {
1410
+ Type: 'struct',
1411
+ Fields: [
1412
+ { Name: 'column', Type: 'string', Id: 1, Required: true }
1413
+ ]
1414
+ },
1415
+ Location: 's3://fake/location',
1416
+ EnableCompaction: true,
1417
+ CompactionRoleArn: cf.getAtt('CompactionRole', 'Arn')
1418
+ });
1419
+
1420
+ const template = cf.merge(
1421
+ { Resources: { CompactionRole: { Type: 'AWS::IAM::Role', Properties: { AssumeRolePolicyDocument: {} } } } },
1422
+ db
1423
+ );
1424
+ if (update) fixtures.update('glue-iceberg-table-with-compaction-custom', template);
1425
+ expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-with-compaction-custom'));
1426
+ });
1427
+
1428
+ test('expected resources generated with both retention and compaction optimizers', () => {
1429
+ const db = new cf.shortcuts.GlueIcebergTable({
1430
+ LogicalName: 'MyTable',
1431
+ DatabaseName: 'my_database',
1432
+ Name: 'my_table',
1433
+ Schema: {
1434
+ Type: 'struct',
1435
+ Fields: [
1436
+ { Name: 'column', Type: 'string', Id: 1, Required: true }
1437
+ ]
1438
+ },
1439
+ Location: 's3://fake/location',
1440
+ EnableOptimizer: true,
1441
+ OptimizerRoleArn: 'arn:aws:iam::123456789012:role/RetentionRole',
1442
+ EnableCompaction: true,
1443
+ CompactionRoleArn: 'arn:aws:iam::123456789012:role/CompactionRole'
1444
+ });
1445
+
1446
+ const template = cf.merge(db);
1447
+ if (update) fixtures.update('glue-iceberg-table-with-both-optimizers', template);
1448
+ expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-with-both-optimizers'));
1449
+ });
1450
+
1451
+ test('throws when EnableOrphanFileDeletion is true but OrphanFileDeletionRoleArn is missing', () => {
1452
+ expect(() => new cf.shortcuts.GlueIcebergTable({
1453
+ LogicalName: 'MyTable',
1454
+ DatabaseName: 'my_database',
1455
+ Name: 'my_table',
1456
+ Schema: {
1457
+ Type: 'struct',
1458
+ Fields: [
1459
+ { Name: 'column', Type: 'string', Id: 1, Required: true }
1460
+ ]
1461
+ },
1462
+ Location: 's3://fake/location',
1463
+ EnableOrphanFileDeletion: true
1464
+ })).toThrow(/You must provide an OrphanFileDeletionRoleArn when EnableOrphanFileDeletion is true/);
1465
+ });
1466
+
1467
+ test('expected resources generated with orphan file deletion using default settings', () => {
1468
+ const db = new cf.shortcuts.GlueIcebergTable({
1469
+ LogicalName: 'MyTable',
1470
+ DatabaseName: 'my_database',
1471
+ Name: 'my_table',
1472
+ Schema: {
1473
+ Type: 'struct',
1474
+ Fields: [
1475
+ { Name: 'column', Type: 'string', Id: 1, Required: true }
1476
+ ]
1477
+ },
1478
+ Location: 's3://fake/location',
1479
+ EnableOrphanFileDeletion: true,
1480
+ OrphanFileDeletionRoleArn: 'arn:aws:iam::123456789012:role/OrphanFileDeletionRole'
1481
+ });
1482
+
1483
+ const template = cf.merge(db);
1484
+ if (update) fixtures.update('glue-iceberg-table-with-orphan-deletion-defaults', template);
1485
+ expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-with-orphan-deletion-defaults'));
1486
+ });
1487
+
1488
+ test('expected resources generated with orphan file deletion using custom settings', () => {
1489
+ const db = new cf.shortcuts.GlueIcebergTable({
1490
+ LogicalName: 'MyTable',
1491
+ DatabaseName: 'my_database',
1492
+ Name: 'my_table',
1493
+ Schema: {
1494
+ Type: 'struct',
1495
+ Fields: [
1496
+ { Name: 'column', Type: 'string', Id: 1, Required: true }
1497
+ ]
1498
+ },
1499
+ Location: 's3://fake/location',
1500
+ EnableOrphanFileDeletion: true,
1501
+ OrphanFileDeletionRoleArn: cf.getAtt('OrphanFileDeletionRole', 'Arn'),
1502
+ OrphanFileRetentionPeriodInDays: 7,
1503
+ OrphanFileDeletionLocation: 's3://fake/location/subdir'
1504
+ });
1505
+
1506
+ const template = cf.merge(
1507
+ { Resources: { OrphanFileDeletionRole: { Type: 'AWS::IAM::Role', Properties: { AssumeRolePolicyDocument: {} } } } },
1508
+ db
1509
+ );
1510
+ if (update) fixtures.update('glue-iceberg-table-with-orphan-deletion-custom', template);
1511
+ expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-with-orphan-deletion-custom'));
1512
+ });
1513
+
1514
+ test('expected resources generated with all three optimizers using same role', () => {
1515
+ const db = new cf.shortcuts.GlueIcebergTable({
1516
+ LogicalName: 'MyTable',
1517
+ DatabaseName: 'my_database',
1518
+ Name: 'my_table',
1519
+ Schema: {
1520
+ Type: 'struct',
1521
+ Fields: [
1522
+ { Name: 'column', Type: 'string', Id: 1, Required: true }
1523
+ ]
1524
+ },
1525
+ Location: 's3://fake/location',
1526
+ EnableOptimizer: true,
1527
+ OptimizerRoleArn: 'arn:aws:iam::123456789012:role/SharedRole',
1528
+ EnableCompaction: true,
1529
+ CompactionRoleArn: 'arn:aws:iam::123456789012:role/SharedRole',
1530
+ EnableOrphanFileDeletion: true,
1531
+ OrphanFileDeletionRoleArn: 'arn:aws:iam::123456789012:role/SharedRole'
1532
+ });
1533
+
1534
+ const template = cf.merge(db);
1535
+ if (update) fixtures.update('glue-iceberg-table-with-all-optimizers', template);
1536
+ expect(noUndefined(template)).toEqual(fixtures.get('glue-iceberg-table-with-all-optimizers'));
1537
+ });
1538
+ });
1539
+
1249
1540
  describe('[shortcuts] glue view', () => {
1250
1541
  test('throws without options', () => {
1251
1542
  expect(() => new cf.shortcuts.GluePrestoView()).toThrow('Options required');