Skip to content

Commit 9f0333f

Browse files
authored
CCM-12438: api level routing feature flag (#730)
1 parent 44d972f commit 9f0333f

File tree

11 files changed

+581
-202
lines changed

11 files changed

+581
-202
lines changed

infrastructure/terraform/modules/backend-api/module_delete_routing_config_lambda.tf

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,15 @@ data "aws_iam_policy_document" "delete_routing_config_lambda_policy" {
6565
var.kms_key_arn
6666
]
6767
}
68+
69+
statement {
70+
sid = "AllowSSMParameterRead"
71+
effect = "Allow"
72+
73+
actions = [
74+
"ssm:GetParameter",
75+
]
76+
77+
resources = [local.client_ssm_path_pattern]
78+
}
6879
}

infrastructure/terraform/modules/backend-api/module_submit_routing_config_lambda.tf

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,15 @@ data "aws_iam_policy_document" "submit_routing_config_lambda_policy" {
6565
var.kms_key_arn
6666
]
6767
}
68+
69+
statement {
70+
sid = "AllowSSMParameterRead"
71+
effect = "Allow"
72+
73+
actions = [
74+
"ssm:GetParameter",
75+
]
76+
77+
resources = [local.client_ssm_path_pattern]
78+
}
6879
}

lambdas/backend-api/src/__tests__/templates/app/routing-config-client.test.ts

Lines changed: 204 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ describe('RoutingConfigClient', () => {
275275
};
276276

277277
mocks.clientConfigRepository.get.mockResolvedValueOnce({
278-
data: { features: {}, campaignIds: [campaignId] },
278+
data: { features: { routing: true }, campaignIds: [campaignId] },
279279
});
280280

281281
mocks.routingConfigRepository.create.mockResolvedValueOnce({
@@ -298,9 +298,16 @@ describe('RoutingConfigClient', () => {
298298
});
299299
});
300300

301-
test('returns 400 error when input is invalid', async () => {
301+
test('returns validation error when input is invalid', async () => {
302302
const { client, mocks } = setup();
303303

304+
mocks.clientConfigRepository.get.mockResolvedValueOnce({
305+
data: {
306+
features: { routing: true },
307+
campaignIds: [routingConfig.campaignId],
308+
},
309+
});
310+
304311
const result = await client.createRoutingConfig(
305312
{ a: 1 } as unknown as CreateUpdateRoutingConfig,
306313
user
@@ -356,7 +363,7 @@ describe('RoutingConfigClient', () => {
356363
};
357364

358365
mocks.clientConfigRepository.get.mockResolvedValueOnce({
359-
data: { features: {}, campaignIds: ['campaign'] },
366+
data: { features: { routing: true }, campaignIds: ['campaign'] },
360367
});
361368

362369
mocks.routingConfigRepository.create.mockResolvedValueOnce({
@@ -420,6 +427,41 @@ describe('RoutingConfigClient', () => {
420427
});
421428
});
422429

430+
test('returns failure if routing feature is disabled for the client', async () => {
431+
const { client, mocks } = setup();
432+
433+
const input: CreateUpdateRoutingConfig = {
434+
name: 'rc',
435+
campaignId: 'campaign',
436+
cascade: [
437+
{
438+
cascadeGroups: ['standard'],
439+
channel: 'SMS',
440+
channelType: 'primary',
441+
defaultTemplateId: 'sms',
442+
},
443+
],
444+
cascadeGroupOverrides: [{ name: 'standard' }],
445+
};
446+
447+
mocks.clientConfigRepository.get.mockResolvedValueOnce({
448+
data: { features: { routing: false }, campaignIds: ['campaign'] },
449+
});
450+
451+
const result = await client.createRoutingConfig(input, user);
452+
453+
expect(mocks.routingConfigRepository.create).not.toHaveBeenCalled();
454+
455+
expect(result).toEqual({
456+
error: {
457+
errorMeta: {
458+
code: 400,
459+
description: 'Routing feature is disabled',
460+
},
461+
},
462+
});
463+
});
464+
423465
test('returns failure if campaignId is not allowed for the client', async () => {
424466
const { client, mocks } = setup();
425467

@@ -438,7 +480,10 @@ describe('RoutingConfigClient', () => {
438480
};
439481

440482
mocks.clientConfigRepository.get.mockResolvedValueOnce({
441-
data: { features: {}, campaignIds: ['another campaign'] },
483+
data: {
484+
features: { routing: true },
485+
campaignIds: ['another campaign'],
486+
},
442487
});
443488

444489
const result = await client.createRoutingConfig(input, user);
@@ -460,6 +505,10 @@ describe('RoutingConfigClient', () => {
460505
test('returns completed routing config', async () => {
461506
const { client, mocks } = setup();
462507

508+
mocks.clientConfigRepository.get.mockResolvedValueOnce({
509+
data: { features: { routing: true } },
510+
});
511+
463512
const id = '2cb1c52d-befa-42f4-8628-06cfe63aa64d';
464513

465514
const completed: RoutingConfig = {
@@ -482,12 +531,63 @@ describe('RoutingConfigClient', () => {
482531
data: completed,
483532
});
484533
});
534+
535+
test('returns failures from client config repository', async () => {
536+
const { client, mocks } = setup();
537+
538+
mocks.clientConfigRepository.get.mockResolvedValueOnce({
539+
error: {
540+
errorMeta: {
541+
code: 500,
542+
description: 'could not fetch client config',
543+
},
544+
},
545+
});
546+
547+
const result = await client.submitRoutingConfig('some-id', user);
548+
549+
expect(mocks.routingConfigRepository.submit).not.toHaveBeenCalled();
550+
551+
expect(result).toEqual({
552+
error: {
553+
errorMeta: {
554+
code: 500,
555+
description: 'could not fetch client config',
556+
},
557+
},
558+
});
559+
});
560+
561+
test('returns failure if routing feature is disabled for the client', async () => {
562+
const { client, mocks } = setup();
563+
564+
mocks.clientConfigRepository.get.mockResolvedValueOnce({
565+
data: { features: { routing: false } },
566+
});
567+
568+
const result = await client.submitRoutingConfig('some-id', user);
569+
570+
expect(mocks.routingConfigRepository.submit).not.toHaveBeenCalled();
571+
572+
expect(result).toEqual({
573+
error: {
574+
errorMeta: {
575+
code: 400,
576+
description: 'Routing feature is disabled',
577+
},
578+
},
579+
});
580+
});
485581
});
486582

487583
describe('deleteRoutingConfig', () => {
488584
test('returns undefined after deleting routing config', async () => {
489585
const { client, mocks } = setup();
490586

587+
mocks.clientConfigRepository.get.mockResolvedValueOnce({
588+
data: { features: { routing: true } },
589+
});
590+
491591
const id = '2cb1c52d-befa-42f4-8628-06cfe63aa64d';
492592

493593
const deleted: RoutingConfig = {
@@ -514,6 +614,10 @@ describe('RoutingConfigClient', () => {
514614
test('returns error response from repository', async () => {
515615
const { client, mocks } = setup();
516616

617+
mocks.clientConfigRepository.get.mockResolvedValueOnce({
618+
data: { features: { routing: true } },
619+
});
620+
517621
const id = '2cb1c52d-befa-42f4-8628-06cfe63aa64d';
518622

519623
const errorResponse = {
@@ -531,6 +635,53 @@ describe('RoutingConfigClient', () => {
531635

532636
expect(result).toEqual(errorResponse);
533637
});
638+
639+
test('returns failures from client config repository', async () => {
640+
const { client, mocks } = setup();
641+
642+
mocks.clientConfigRepository.get.mockResolvedValueOnce({
643+
error: {
644+
errorMeta: {
645+
code: 500,
646+
description: 'could not fetch client config',
647+
},
648+
},
649+
});
650+
651+
const result = await client.deleteRoutingConfig('some-id', user);
652+
653+
expect(mocks.routingConfigRepository.delete).not.toHaveBeenCalled();
654+
655+
expect(result).toEqual({
656+
error: {
657+
errorMeta: {
658+
code: 500,
659+
description: 'could not fetch client config',
660+
},
661+
},
662+
});
663+
});
664+
665+
test('returns failure if routing feature is disabled for the client', async () => {
666+
const { client, mocks } = setup();
667+
668+
mocks.clientConfigRepository.get.mockResolvedValueOnce({
669+
data: { features: { routing: false }, campaignIds: ['campaign'] },
670+
});
671+
672+
const result = await client.deleteRoutingConfig('some-id', user);
673+
674+
expect(mocks.routingConfigRepository.delete).not.toHaveBeenCalled();
675+
676+
expect(result).toEqual({
677+
error: {
678+
errorMeta: {
679+
code: 400,
680+
description: 'Routing feature is disabled',
681+
},
682+
},
683+
});
684+
});
534685
});
535686

536687
describe('updateRoutingConfig', () => {
@@ -550,7 +701,10 @@ describe('RoutingConfigClient', () => {
550701
};
551702

552703
mocks.clientConfigRepository.get.mockResolvedValueOnce({
553-
data: { features: {}, campaignIds: [routingConfig.campaignId] },
704+
data: {
705+
features: { routing: true },
706+
campaignIds: [routingConfig.campaignId],
707+
},
554708
});
555709

556710
mocks.routingConfigRepository.update.mockResolvedValueOnce({
@@ -576,6 +730,12 @@ describe('RoutingConfigClient', () => {
576730

577731
test('returns validation error when update is invalid', async () => {
578732
const { client, mocks } = setup();
733+
mocks.clientConfigRepository.get.mockResolvedValueOnce({
734+
data: {
735+
features: { routing: true },
736+
campaignIds: [routingConfig.campaignId],
737+
},
738+
});
579739

580740
const update: CreateUpdateRoutingConfig = {
581741
campaignId: routingConfig.campaignId,
@@ -648,6 +808,41 @@ describe('RoutingConfigClient', () => {
648808
});
649809
});
650810

811+
test('returns failure if routing feature is disabled for the client', async () => {
812+
const { client, mocks } = setup();
813+
814+
const update: CreateUpdateRoutingConfig = {
815+
cascade: routingConfig.cascade,
816+
cascadeGroupOverrides: routingConfig.cascadeGroupOverrides,
817+
name: routingConfig.name,
818+
campaignId: 'this campaign',
819+
};
820+
821+
mocks.clientConfigRepository.get.mockResolvedValueOnce({
822+
data: {
823+
features: { routing: false },
824+
campaignIds: ['this campaign'],
825+
},
826+
});
827+
828+
const result = await client.updateRoutingConfig(
829+
routingConfig.id,
830+
update,
831+
user
832+
);
833+
834+
expect(mocks.routingConfigRepository.update).not.toHaveBeenCalled();
835+
836+
expect(result).toEqual({
837+
error: {
838+
errorMeta: {
839+
code: 400,
840+
description: 'Routing feature is disabled',
841+
},
842+
},
843+
});
844+
});
845+
651846
test('returns failure if campaignId is not allowed for the client', async () => {
652847
const { client, mocks } = setup();
653848

@@ -659,7 +854,10 @@ describe('RoutingConfigClient', () => {
659854
};
660855

661856
mocks.clientConfigRepository.get.mockResolvedValueOnce({
662-
data: { features: {}, campaignIds: ['another campaign'] },
857+
data: {
858+
features: { routing: true },
859+
campaignIds: ['another campaign'],
860+
},
663861
});
664862

665863
const result = await client.updateRoutingConfig(

0 commit comments

Comments
 (0)