Skip to content

Commit

Permalink
Implementing tags update + simple tests
Browse files Browse the repository at this point in the history
  • Loading branch information
CarlosGamero committed Oct 18, 2024
1 parent 9213aae commit 9473b60
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 40 deletions.
56 changes: 46 additions & 10 deletions packages/sns/lib/utils/snsUtils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import {
type CreateTopicCommandInput,
ListTagsForResourceCommand,
ListTopicsCommand,
type SNSClient,
TagResourceCommand,
paginateListTopics,
Expand All @@ -15,11 +13,12 @@ import {
SetTopicAttributesCommand,
UnsubscribeCommand,
} from '@aws-sdk/client-sns'
import type { Either } from '@lokalise/node-core'
import { type Either, isError } from '@lokalise/node-core'
import { calculateOutgoingMessageSize as sqsCalculateOutgoingMessageSize } from '@message-queue-toolkit/sqs'

import type { ExtraSNSCreationParams } from '../sns/AbstractSnsService'

import { GetCallerIdentityCommand, STSClient } from '@aws-sdk/client-sts'
import { generateTopicSubscriptionPolicy } from './snsAttributeUtils'

type AttributesResult = {
Expand Down Expand Up @@ -85,14 +84,19 @@ export async function assertTopic(
topicOptions: CreateTopicCommandInput,
extraParams?: ExtraSNSCreationParams,
) {
'aws:sns:region:account_id:topic_name'
const command = new CreateTopicCommand(topicOptions)
const response = await snsClient.send(command)

if (!response.TopicArn) {
throw new Error('No topic arn in response')
let topicArn: string
try {
const command = new CreateTopicCommand(topicOptions)
const response = await snsClient.send(command)
if (!response.TopicArn) throw new Error('No topic arn in response')
topicArn = response.TopicArn
} catch (err) {
// We only manually build ARN in case of tag update
if (!extraParams?.forceTagUpdate) throw err
// To build ARN we need topic name and error should be "topic already exist with different tags"
if (!topicOptions.Name || !isTopicAlreadyExistWithDifferentTagsError(err)) throw err
topicArn = await buildTopicArn(snsClient, topicOptions.Name)
}
const topicArn = response.TopicArn

if (extraParams?.queueUrlsWithSubscribePermissionsPrefix || extraParams?.allowedSourceOwner) {
const setTopicAttributesCommand = new SetTopicAttributesCommand({
Expand Down Expand Up @@ -189,3 +193,35 @@ export async function getTopicArnByName(snsClient: SNSClient, topicName?: string
*/
export const calculateOutgoingMessageSize = (message: unknown) =>
sqsCalculateOutgoingMessageSize(message)

const isTopicAlreadyExistWithDifferentTagsError = (error: unknown) =>
!!error &&
isError(error) &&
'Error' in error &&
!!error.Error &&
typeof error.Error === 'object' &&
'Code' in error.Error &&
'Message' in error.Error &&
typeof error.Error.Message === 'string' &&
error.Error.Code === 'InvalidParameter' &&
error.Error.Message.includes('already exists with different tags')

/**
* Manually builds the ARN of a topic based on the current AWS account and the topic name.
* It follows the following pattern: arn:aws:sns:<region>:<account-id>:<topic-name>
* Doc -> https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html
*/
const buildTopicArn = async (client: SNSClient, topicName: string) => {
const region =
typeof client.config.region === 'string' ? client.config.region : await client.config.region()

const stsClient = new STSClient({
endpoint: client.config.endpoint,
region,
credentials: client.config.credentials,
endpointProvider: client.config.endpointProvider,
})
const identityResponse = await stsClient.send(new GetCallerIdentityCommand({}))

return `arn:aws:sns:${region}:${identityResponse.Account}:${topicName}`
}
35 changes: 5 additions & 30 deletions packages/sns/test/publishers/SnsPermissionPublisher.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,38 +140,13 @@ describe('SnsPermissionPublisher', () => {
expect(updateCall).toBeDefined()

const postTags = await getTags(arn)
expect(postTags.Tags).toEqual([...newTags, { Key: 'leftover', Value: 'some-leftover' }])
const tags = postTags.Tags
expect(tags).toHaveLength(4)
expect(postTags.Tags).toEqual(
expect.arrayContaining([...newTags, { Key: 'leftover', Value: 'some-leftover' }]),
)
})
})

// TESTING HOW SNS TAGS UPDATE WORKS
it.skip('to be removed', async () => {
await deleteTopic(snsClient, topicNome)
const arn = await assertTopic(snsClient, {
Name: topicNome,
Tags: [
{ Key: 'hello', Value: 'world' },
{ Key: 'goodbye', Value: 'world' },
],
})

const command = new ListTagsForResourceCommand({ ResourceArn: arn })
const res = await snsClient.send(command)
console.log(res.Tags)

const updateCommand = new TagResourceCommand({
ResourceArn: arn,
Tags: [
{ Key: 'hello', Value: 'friend' },
{ Key: 'goodbye', Value: 'world' },
],
})
await snsClient.send(updateCommand)

const command2 = new ListTagsForResourceCommand({ ResourceArn: arn })
const res2 = await snsClient.send(command2)
console.log(res2.Tags)
})
})

describe('publish', () => {
Expand Down

0 comments on commit 9473b60

Please sign in to comment.