Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ module "backend_api" {

send_to_firehose = false

enable_routing_config_event_stream = true

email_domain = local.email_domain
template_submitted_sender_email_address = local.sandbox_letter_supplier_mock_template_submitted_sender
proof_requested_sender_email_address = local.sandbox_letter_supplier_mock_proof_requested_sender
Expand Down
1 change: 0 additions & 1 deletion infrastructure/terraform/modules/backend-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ No requirements.
| <a name="input_csi"></a> [csi](#input\_csi) | CSI from the parent component | `string` | n/a | yes |
| <a name="input_email_domain"></a> [email\_domain](#input\_email\_domain) | Email domain | `string` | n/a | yes |
| <a name="input_enable_backup"></a> [enable\_backup](#input\_enable\_backup) | Enable Backups for the DynamoDB table? | `bool` | `true` | no |
| <a name="input_enable_routing_config_event_stream"></a> [enable\_routing\_config\_event\_stream](#input\_enable\_routing\_config\_event\_stream) | Enable DynamoDB streaming from routing config table to EventBridge | `bool` | `false` | no |
| <a name="input_environment"></a> [environment](#input\_environment) | The name of the tfscaffold environment | `string` | n/a | yes |
| <a name="input_function_s3_bucket"></a> [function\_s3\_bucket](#input\_function\_s3\_bucket) | Name of S3 bucket to upload lambda artefacts to | `string` | n/a | yes |
| <a name="input_group"></a> [group](#input\_group) | The group variables are being inherited from (often synonmous with account short-name) | `string` | n/a | yes |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ resource "aws_pipes_pipe" "routing_config_table_events" {
role_arn = aws_iam_role.pipe_routing_config_table_events.arn
source = aws_dynamodb_table.routing_configuration.stream_arn
target = module.sqs_template_mgmt_events.sqs_queue_arn
desired_state = var.enable_routing_config_event_stream ? "RUNNING" : "STOPPED"
desired_state = "RUNNING"
kms_key_identifier = var.kms_key_arn

source_parameters {
Expand Down
6 changes: 0 additions & 6 deletions infrastructure/terraform/modules/backend-api/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,6 @@ variable "enable_backup" {
default = true
}

variable "enable_routing_config_event_stream" {
type = bool
description = "Enable DynamoDB streaming from routing config table to EventBridge"
default = false
}

variable "kms_key_arn" {
type = string
description = "KMS Key ARN"
Expand Down
234 changes: 219 additions & 15 deletions lambdas/event-publisher/src/__tests__/domain/event-builder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,11 @@ const publishableTemplateEventRecord = (
tableName: tables.templates,
});

const expectedEvent = (status: string, type: string, dataschema: string) => ({
const expectedTemplateEvent = (
status: string,
type: string,
dataschema: string
) => ({
id: '7f2ae4b0-82c2-4911-9b84-8997d7f3f40d',
datacontenttype: 'application/json',
time: '2022-01-01T09:00:00.000Z',
Expand Down Expand Up @@ -241,6 +245,130 @@ const expectedEvent = (status: string, type: string, dataschema: string) => ({
},
});

const publishableRoutingConfigEventRecord = (status: string) => ({
dynamodb: {
SequenceNumber: '4',
NewImage: {
owner: {
S: 'owner',
},
id: {
S: '92b676e9-470f-4d04-ab14-965ef145e15d',
},
clientId: {
S: 'client-id',
},
campaignId: {
S: 'campaign-id',
},
createdAt: {
S: '2022-01-01T09:00:00.000Z',
},
name: {
S: 'routing-config-name',
},
defaultCascadeGroup: {
S: 'standard',
},
cascade: {
L: [
{
M: {
channel: { S: 'EMAIL' },
channelType: { S: 'primary' },
defaultTemplateId: { S: 'bed3398c-bbe3-435d-80c1-58154d4bf7dd' },
cascadeGroups: { L: [{ S: 'standard' }] },
},
},
{
M: {
channel: { S: 'LETTER' },
channelType: { S: 'primary' },
defaultTemplateId: { S: 'd290f1ee-6c54-4b01-90e6-d701748f0851' },
cascadeGroups: { L: [{ S: 'standard' }] },
},
},
{
M: {
channel: { S: 'LETTER' },
channelType: { S: 'primary' },
defaultTemplateId: { S: '3fa85f64-5717-4562-b3fc-2c963f66afa6' },
cascadeGroups: { L: [{ S: 'translations' }] },
},
},
],
},
cascadeGroupOverrides: {
L: [
{
M: {
name: { S: 'translations' },
language: { L: [{ S: 'fr' }] },
},
},
],
},
status: {
S: status,
},
},
},
eventID: '7f2ae4b0-82c2-4911-9b84-8997d7f3f40d',
tableName: tables.routing,
});

const expectedRoutingConfigEvent = (
status: string,
type: string,
dataschema: string
) => ({
id: '7f2ae4b0-82c2-4911-9b84-8997d7f3f40d',
datacontenttype: 'application/json',
time: '2022-01-01T09:00:00.000Z',
source: 'event-source',
type,
specversion: '1.0',
dataschema,
dataschemaversion: VERSION,
plane: 'control',
subject: '92b676e9-470f-4d04-ab14-965ef145e15d',
data: {
id: '92b676e9-470f-4d04-ab14-965ef145e15d',
clientId: 'client-id',
campaignId: 'campaign-id',
createdAt: '2022-01-01T09:00:00.000Z',
name: 'routing-config-name',
defaultCascadeGroup: 'standard',
cascade: [
{
channel: 'EMAIL',
channelType: 'primary',
cascadeGroups: ['standard'],
defaultTemplateId: 'bed3398c-bbe3-435d-80c1-58154d4bf7dd',
},
{
channel: 'LETTER',
channelType: 'primary',
cascadeGroups: ['standard'],
defaultTemplateId: 'd290f1ee-6c54-4b01-90e6-d701748f0851',
},
{
channel: 'LETTER',
channelType: 'primary',
cascadeGroups: ['translations'],
defaultTemplateId: '3fa85f64-5717-4562-b3fc-2c963f66afa6',
},
],
cascadeGroupOverrides: [
{
name: 'translations',
language: ['fr'],
},
],
status,
},
});

test('errors on unrecognised event table source', () => {
const invalidpublishableTemplateEventRecord = {
...publishableTemplateEventRecord('SUBMITTED'),
Expand Down Expand Up @@ -290,7 +418,7 @@ describe('template events', () => {
);

expect(event).toEqual(
expectedEvent(
expectedTemplateEvent(
'SUBMITTED',
'uk.nhs.notify.template-management.TemplateCompleted.v1',
'https://notify.nhs.uk/events/schemas/TemplateCompleted/v1.json'
Expand All @@ -304,7 +432,7 @@ describe('template events', () => {
);

expect(event).toEqual(
expectedEvent(
expectedTemplateEvent(
'PROOF_AVAILABLE',
'uk.nhs.notify.template-management.TemplateDrafted.v1',
'https://notify.nhs.uk/events/schemas/TemplateDrafted/v1.json'
Expand All @@ -327,7 +455,7 @@ describe('template events', () => {
const event = eventBuilder.buildEvent(noOldImage);

expect(event).toEqual(
expectedEvent(
expectedTemplateEvent(
'SUBMITTED',
'uk.nhs.notify.template-management.TemplateCompleted.v1',
'https://notify.nhs.uk/events/schemas/TemplateCompleted/v1.json'
Expand All @@ -341,7 +469,7 @@ describe('template events', () => {
);

expect(event).toEqual(
expectedEvent(
expectedTemplateEvent(
'DELETED',
'uk.nhs.notify.template-management.TemplateDeleted.v1',
'https://notify.nhs.uk/events/schemas/TemplateDeleted/v1.json'
Expand All @@ -361,7 +489,7 @@ describe('template events', () => {
});

test('does not build template event on hard delete', () => {
const hardDeletepublishableTemplateEventRecord = {
const hardDeletePublishableTemplateEventRecord = {
...publishableTemplateEventRecord('SUBMITTED'),
dynamodb: {
SequenceNumber: '4',
Expand All @@ -370,24 +498,100 @@ describe('template events', () => {
};

const event = eventBuilder.buildEvent(
hardDeletepublishableTemplateEventRecord
hardDeletePublishableTemplateEventRecord
);

expect(event).toEqual(undefined);
});
});

describe('routing config events', () => {
test('should return undefined when table source is routing config table', () => {
const event = eventBuilder.buildEvent({
test('errors on output schema validation failure', () => {
const valid = publishableRoutingConfigEventRecord('DRAFT');

const invalidDomainEventRecord = {
...valid,
dynamodb: {
...valid.dynamodb,
NewImage: {
...valid.dynamodb.NewImage,
cascade: {
L: [
{
M: {
channel: { S: 'EMAIL' },
channelType: { S: 'primary' },
defaultTemplateId: { S: null },
cascadeGroups: { L: [{ S: 'standard' }] },
},
},
],
},
},
},
};

const event = eventBuilder.buildEvent(
invalidDomainEventRecord as unknown as PublishableEventRecord
);

expect(event).toEqual(undefined);
});

test('builds routing config completed event', () => {
const event = eventBuilder.buildEvent(
publishableRoutingConfigEventRecord('COMPLETED')
);

expect(event).toEqual(
expectedRoutingConfigEvent(
'COMPLETED',
'uk.nhs.notify.template-management.RoutingConfigCompleted.v1',
'https://notify.nhs.uk/events/schemas/RoutingConfigCompleted/v1.json'
)
);
});

test('builds routing config drafted event', () => {
const event = eventBuilder.buildEvent(
publishableRoutingConfigEventRecord('DRAFT')
);

expect(event).toEqual(
expectedRoutingConfigEvent(
'DRAFT',
'uk.nhs.notify.template-management.RoutingConfigDrafted.v1',
'https://notify.nhs.uk/events/schemas/RoutingConfigDrafted/v1.json'
)
);
});

test('builds routing config deleted event', () => {
const event = eventBuilder.buildEvent(
publishableRoutingConfigEventRecord('DELETED')
);

expect(event).toEqual(
expectedRoutingConfigEvent(
'DELETED',
'uk.nhs.notify.template-management.RoutingConfigDeleted.v1',
'https://notify.nhs.uk/events/schemas/RoutingConfigDeleted/v1.json'
)
);
});

test('does not build routing config event on hard delete', () => {
const hardDeletePublishableRoutingConfigEventRecord = {
...publishableRoutingConfigEventRecord('DRAFT'),
dynamodb: {
SequenceNumber: '1',
NewImage: {},
OldImage: {},
SequenceNumber: '4',
NewImage: undefined,
},
eventID: 'cf1344e0-fd57-426a-860a-3efc9d2b1977',
tableName: tables.routing,
});
};

const event = eventBuilder.buildEvent(
hardDeletePublishableRoutingConfigEventRecord
);

expect(event).toEqual(undefined);
});
Expand Down
Loading