Skip to content

Commit 5b1cc0a

Browse files
committed
feat: remove entries when parameter is deleted
1 parent 51ba728 commit 5b1cc0a

File tree

8 files changed

+93
-26
lines changed

8 files changed

+93
-26
lines changed

cdk/RegistryStack.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ export class RegistryStack extends Stack {
122122
source: ['aws.ssm'],
123123
detailType: ['Parameter Store Change'],
124124
detail: {
125-
operation: ['Create', 'Update'],
125+
operation: ['Create', 'Update', 'Delete'],
126126
},
127127
},
128128
targets: [new EventsTargets.LambdaFunction(publishToS3)],

feature-runner/run-features.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { CloudFormationClient } from '@aws-sdk/client-cloudformation'
22
import { SSMClient } from '@aws-sdk/client-ssm'
33
import { runFolder } from '@nordicsemiconductor/bdd-markdown'
44
import { stackOutput } from '@nordicsemiconductor/cloudformation-helpers'
5-
import { randomUUID } from 'node:crypto'
65
import path from 'node:path'
76
import type { StackOutputs } from '../cdk/RegistryStack.js'
87
import { STACK_NAME } from '../cdk/stackConfig.js'
@@ -15,13 +14,17 @@ const config = await stackOutput(new CloudFormationClient({}))<StackOutputs>(
1514
export type World = {
1615
registryEndpoint: string
1716
stackName: string
18-
randomString: string
19-
randomNumber: number
20-
}
17+
} & Record<string, any>
2118

2219
const runner = await runFolder<World>({
2320
folder: path.join(process.cwd(), 'features'),
2421
name: 'Public Parameter Registry',
22+
logObserver: {
23+
onDebug: console.debug,
24+
onError: console.error,
25+
onInfo: console.log,
26+
onProgress: console.debug,
27+
},
2528
})
2629

2730
const stepDefs = steps({ ssm: new SSMClient({}) })
@@ -30,8 +33,6 @@ runner.addStepRunners(...stepDefs.steps)
3033
const res = await runner.run({
3134
registryEndpoint: config.registryEndpoint,
3235
stackName: STACK_NAME,
33-
randomNumber: Math.floor(Math.random() * 1000000),
34-
randomString: randomUUID(),
3536
})
3637

3738
await stepDefs.cleanup()

feature-runner/steps.ts

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
DeleteParameterCommand,
23
DeleteParametersCommand,
34
ParameterType,
45
PutParameterCommand,
@@ -11,15 +12,15 @@ import {
1112
type StepRunner,
1213
type StepRunnerArgs,
1314
} from '@nordicsemiconductor/bdd-markdown'
14-
import { check, objectMatching } from 'tsmatchers'
15+
import { randomUUID } from 'node:crypto'
16+
import { check, not, objectMatching, objectWithKeys } from 'tsmatchers'
1517
import { type World } from './run-features.js'
16-
1718
export const steps = ({
1819
ssm,
1920
}: {
2021
ssm: SSMClient
2122
}): { steps: StepRunner<World>[]; cleanup: () => Promise<void> } => {
22-
const Names: string[] = []
23+
let Names: string[] = []
2324
return {
2425
steps: [
2526
async ({
@@ -29,21 +30,45 @@ export const steps = ({
2930
step: { debug },
3031
},
3132
}: StepRunnerArgs<World>): Promise<StepRunResult> => {
32-
const match = /^`(?<value>[^`]+)` is stored in `(?<name>[^`]+)`$/.exec(
33-
step.title,
34-
)
33+
const match =
34+
/^a random (?<type>string|number) in `(?<storageName>[^`]+)` is stored in `(?<name>[^`]+)`$/.exec(
35+
step.title,
36+
)
3537
if (match === null) return noMatch
3638
const Name = `/${context.stackName}/public/${match.groups?.name}`
39+
const value =
40+
match.groups?.type === 'string'
41+
? randomUUID()
42+
: Math.floor(Math.random() * 1000000)
3743
debug(Name)
3844
await ssm.send(
3945
new PutParameterCommand({
4046
Name,
41-
Value: match.groups?.value ?? '',
47+
Value: `${value}`,
4248
Type: ParameterType.STRING,
4349
Overwrite: true,
4450
}),
4551
)
4652
Names.push(Name)
53+
context[match.groups?.storageName ?? ''] = value
54+
},
55+
async ({
56+
step,
57+
context,
58+
log: {
59+
step: { debug },
60+
},
61+
}: StepRunnerArgs<World>): Promise<StepRunResult> => {
62+
const match = /^`(?<name>[^`]+)` is deleted$/.exec(step.title)
63+
if (match === null) return noMatch
64+
const Name = `/${context.stackName}/public/${match.groups?.name}`
65+
debug(Name)
66+
await ssm.send(
67+
new DeleteParameterCommand({
68+
Name,
69+
}),
70+
)
71+
Names = Names.filter((n) => n !== Name)
4772
},
4873
async ({
4974
step,
@@ -71,6 +96,29 @@ export const steps = ({
7196
)
7297
return registry
7398
},
99+
async ({
100+
step,
101+
log: {
102+
step: { debug },
103+
},
104+
}: StepRunnerArgs<World>): Promise<StepRunResult> => {
105+
const match =
106+
/^the result of GET `(?<url>[^`]+)` should not have property `(?<property>[^`]+)`$/.exec(
107+
step.title,
108+
)
109+
if (match === null) return noMatch
110+
const res = await fetch(match?.groups?.url ?? '')
111+
const body = await res.text()
112+
debug(body)
113+
let registry: Record<string, any> = {}
114+
try {
115+
registry = JSON.parse(body)
116+
} catch {
117+
throw new Error(`Failed to parse body as JSON: ${body}`)
118+
}
119+
check(registry).is(not(objectWithKeys(match.groups?.property ?? '')))
120+
return registry
121+
},
74122
],
75123
cleanup: async () => {
76124
if (Names.length === 0) return
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
retry:
3+
initialDelay: 5000
4+
needs:
5+
- Get Parameters
6+
---
7+
8+
# Remove a deleted parameters
9+
10+
> After removing a parameter, it should be removed from the registry
11+
12+
## Background
13+
14+
Given `example/aNumberParameter` is deleted
15+
16+
## Get the parameters
17+
18+
Soon the result of GET `${registryEndpoint}` should not have property `example`

features/GetParameters.feature.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ retry:
99
1010
## Background
1111

12-
Given `${randomString}` is stored in `aStringParameter`
12+
Given a random string in `randomString` is stored in `aStringParameter`
1313

14-
And `${randomNumber}` is stored in `example/aNumberParameter`
14+
And a random number in `randomNumber` is stored in `example/aNumberParameter`
1515

1616
## Get the parameters
1717

lambda/publishToS3.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const handler = async (event: {
2828
detail: {
2929
name: string // '/public-parameter-registry/public/some-parameter'
3030
type: string // 'String'
31-
operation: string // 'Create', 'Update
31+
operation: string // 'Create', 'Update', 'Delete'
3232
}
3333
}): Promise<void> => {
3434
console.log(JSON.stringify({ event }))

package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"@aws-sdk/client-s3": "3.315.0",
3131
"@aws-sdk/client-ssm": "3.315.0",
3232
"@nordicsemiconductor/asset-tracker-cloud-code-style": "12.0.23",
33-
"@nordicsemiconductor/bdd-markdown": "3.5.47",
33+
"@nordicsemiconductor/bdd-markdown": "3.6.0",
3434
"@nordicsemiconductor/cloudformation-helpers": "8.0.0",
3535
"@nordicsemiconductor/eslint-config-asset-tracker-cloud-typescript": "15.0.0",
3636
"@swc/cli": "0.1.62",

0 commit comments

Comments
 (0)