feat: add SQS + EventBridge
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
import {describe, expect, test} from 'bun:test'
|
||||
import {
|
||||
GetBucketNotificationConfigurationCommand,
|
||||
GetBucketTaggingCommand,
|
||||
ListBucketsCommand,
|
||||
PutBucketNotificationConfigurationCommand,
|
||||
type S3Client,
|
||||
} from '@aws-sdk/client-s3'
|
||||
import {AddPermissionCommand, GetFunctionCommand, RemovePermissionCommand, type LambdaClient} from '@aws-sdk/client-lambda'
|
||||
import {AwsStorageAdapter} from './AwsStorageAdapter'
|
||||
|
||||
function fakeS3(overrides: Partial<{
|
||||
@@ -100,4 +103,90 @@ describe('AwsStorageAdapter', () => {
|
||||
expect(result.map((r) => r.name).sort()).toEqual(['prod-assets', 'prod-logs'])
|
||||
expect(requestedBuckets.sort()).toEqual(['prod-assets', 'prod-logs'])
|
||||
})
|
||||
|
||||
test('adds an S3 Lambda trigger without replacing other bucket notifications', async () => {
|
||||
const sent: unknown[] = []
|
||||
const s3 = {
|
||||
send: async (command: unknown) => {
|
||||
sent.push(command)
|
||||
if (command instanceof GetBucketNotificationConfigurationCommand) {
|
||||
return {
|
||||
QueueConfigurations: [{Id: 'queue-trigger', QueueArn: 'arn:aws:sqs:us-east-1:000000000000:jobs', Events: ['s3:ObjectCreated:*']}],
|
||||
EventBridgeConfiguration: {},
|
||||
}
|
||||
}
|
||||
if (command instanceof PutBucketNotificationConfigurationCommand) return {}
|
||||
throw new Error(`Unexpected command: ${command?.constructor?.name}`)
|
||||
},
|
||||
} as unknown as S3Client
|
||||
const lambda = fakeLambda()
|
||||
const adapter = new AwsStorageAdapter(s3, lambda.client, '000000000000')
|
||||
|
||||
await adapter.createS3LambdaTrigger('uploads', {
|
||||
functionName: 'thumbnailer',
|
||||
events: ['s3:ObjectCreated:*'],
|
||||
prefix: 'images/',
|
||||
suffix: '.jpg',
|
||||
})
|
||||
|
||||
const put = sent.find((command) => command instanceof PutBucketNotificationConfigurationCommand) as PutBucketNotificationConfigurationCommand
|
||||
expect(put.input.NotificationConfiguration?.QueueConfigurations).toHaveLength(1)
|
||||
expect(put.input.NotificationConfiguration?.EventBridgeConfiguration).toEqual({})
|
||||
expect(put.input.NotificationConfiguration?.LambdaFunctionConfigurations).toEqual([{
|
||||
Id: 'floci-ui-s3-thumbnailer-s3-ObjectCreated---images---jpg',
|
||||
LambdaFunctionArn: 'arn:aws:lambda:us-east-1:000000000000:function:thumbnailer',
|
||||
Events: ['s3:ObjectCreated:*'],
|
||||
Filter: {Key: {FilterRules: [{Name: 'prefix', Value: 'images/'}, {Name: 'suffix', Value: '.jpg'}]}},
|
||||
}])
|
||||
const permission = lambda.sent.find((command) => command instanceof AddPermissionCommand) as AddPermissionCommand
|
||||
expect(permission.input).toMatchObject({
|
||||
FunctionName: 'thumbnailer',
|
||||
Principal: 's3.amazonaws.com',
|
||||
SourceArn: 'arn:aws:s3:::uploads',
|
||||
SourceAccount: '000000000000',
|
||||
})
|
||||
})
|
||||
|
||||
test('removes the S3 permission only after the final bucket trigger for a Lambda is deleted', async () => {
|
||||
const sent: unknown[] = []
|
||||
const s3 = {
|
||||
send: async (command: unknown) => {
|
||||
sent.push(command)
|
||||
if (command instanceof GetBucketNotificationConfigurationCommand) {
|
||||
return {LambdaFunctionConfigurations: [{
|
||||
Id: 'trigger-a',
|
||||
LambdaFunctionArn: 'arn:aws:lambda:us-east-1:000000000000:function:thumbnailer',
|
||||
Events: ['s3:ObjectCreated:*'],
|
||||
}]}
|
||||
}
|
||||
if (command instanceof PutBucketNotificationConfigurationCommand) return {}
|
||||
throw new Error(`Unexpected command: ${command?.constructor?.name}`)
|
||||
},
|
||||
} as unknown as S3Client
|
||||
const lambda = fakeLambda()
|
||||
const adapter = new AwsStorageAdapter(s3, lambda.client)
|
||||
|
||||
await adapter.deleteS3LambdaTrigger('uploads', 'trigger-a')
|
||||
|
||||
const put = sent.find((command) => command instanceof PutBucketNotificationConfigurationCommand) as PutBucketNotificationConfigurationCommand
|
||||
expect(put.input.NotificationConfiguration?.LambdaFunctionConfigurations).toEqual([])
|
||||
expect(lambda.sent.some((command) => command instanceof RemovePermissionCommand)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
function fakeLambda(): {client: LambdaClient; sent: unknown[]} {
|
||||
const sent: unknown[] = []
|
||||
return {
|
||||
sent,
|
||||
client: {
|
||||
send: async (command: unknown) => {
|
||||
sent.push(command)
|
||||
if (command instanceof GetFunctionCommand) {
|
||||
return {Configuration: {FunctionArn: 'arn:aws:lambda:us-east-1:000000000000:function:thumbnailer'}}
|
||||
}
|
||||
if (command instanceof AddPermissionCommand || command instanceof RemovePermissionCommand) return {}
|
||||
throw new Error(`Unexpected command: ${command?.constructor?.name}`)
|
||||
},
|
||||
} as unknown as LambdaClient,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user