Skip to content

Commit 280589d

Browse files
authored
feat: feat/apigw custom domain (#195)
* feat: dont re-deploy when custom domain unchange * fix: remove custom domain test(for need oldState data) * feat: add log when custom domain unchange * chore: remove lodash in deps * fix: preserve output when custom domain unchange * feat(apigw): check customDomain changes base on actual result * feat(apigw): only modify exact changed custom domain * fix: fix custom domain unbind, add tests to validate bind and unbind * fix: remove debug log
1 parent 38ef6e0 commit 280589d

File tree

7 files changed

+369
-109
lines changed

7 files changed

+369
-109
lines changed

__tests__/apigw.test.ts

Lines changed: 149 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
import { ApigwDeployInputs, ApigwDeployOutputs } from './../src/modules/apigw/interface';
22
import { Apigw } from '../src';
3-
4-
function deepClone<T>(obj: T): T {
5-
return JSON.parse(JSON.stringify(obj));
6-
}
3+
import { deepClone } from '../src/utils';
74

85
describe('apigw', () => {
6+
const domains = [`test-1.${Date.now()}.com`, `test-2.${Date.now()}.com`];
97
const credentials = {
108
SecretId: process.env.TENCENT_SECRET_ID,
119
SecretKey: process.env.TENCENT_SECRET_KEY,
@@ -15,22 +13,6 @@ describe('apigw', () => {
1513
serviceName: 'serverless_test',
1614
environment: 'release',
1715
netTypes: ['OUTER'],
18-
// customDomains: [
19-
// {
20-
// domain: 'test.yuga.chat',
21-
// // TODO: change to your certId
22-
// certificateId: 'cWOJJjax',
23-
// isDefaultMapping: false,
24-
// pathMappingSet: [
25-
// {
26-
// path: '/',
27-
// environment: 'release',
28-
// },
29-
// ],
30-
// protocols: ['http', 'https'],
31-
// isForcedHttps: true
32-
// },
33-
// ],
3416
usagePlan: {
3517
usagePlanId: 'usagePlan-8bbr8pup',
3618
usagePlanName: 'slscmp',
@@ -375,46 +357,156 @@ describe('apigw', () => {
375357
Action: 'DescribeService',
376358
ServiceId: outputs.serviceId,
377359
});
378-
379360
expect(detail).toBeNull();
380361
});
381362

382-
// FIXME: remove custom domain test (not complete)
383-
// test.only('[Apigw] Bind CustomDomain success', async () => {
384-
// const apigwInputs = deepClone(inputs);
385-
// apigwInputs.customDomains = [
386-
// {
387-
// domain: 'test-1.sls.plus',
388-
// // certificateId: 'cWOJJjax',
389-
// isDefaultMapping: false,
390-
// pathMappingSet: [
391-
// {
392-
// path: '/',
393-
// environment: 'release',
394-
// },
395-
// ],
396-
// protocols: ['http'],
397-
// isForcedHttps: true,
398-
// },
399-
// {
400-
// domain: 'test-2.sls.plus',
401-
// // certificateId: 'cWOJJjax',
402-
// isDefaultMapping: false,
403-
// pathMappingSet: [
404-
// {
405-
// path: '/',
406-
// environment: 'release',
407-
// },
408-
// ],
409-
// protocols: ['http'],
410-
// isForcedHttps: true,
411-
// },
412-
// ];
413-
// const deployOutputs = await apigw.deploy(inputs);
363+
test('[Apigw CustomDomain] Bind CustomDomain success', async () => {
364+
const apigwInputs = deepClone(inputs);
365+
366+
apigwInputs.usagePlan = undefined;
367+
apigwInputs.customDomains = [
368+
{
369+
domain: domains[0],
370+
// certificateId: 'cWOJJjax',
371+
isDefaultMapping: false,
372+
pathMappingSet: [
373+
{
374+
path: '/',
375+
environment: 'release',
376+
},
377+
],
378+
protocols: ['http'],
379+
},
380+
{
381+
domain: domains[1],
382+
// certificateId: 'cWOJJjax',
383+
isDefaultMapping: false,
384+
pathMappingSet: [
385+
{
386+
path: '/',
387+
environment: 'release',
388+
},
389+
],
390+
protocols: ['http'],
391+
},
392+
];
393+
outputs = await apigw.deploy(apigwInputs);
394+
expect(outputs.customDomains).toEqual([
395+
{
396+
isBinded: true,
397+
created: true,
398+
subDomain: domains[0],
399+
cname: expect.any(String),
400+
url: `http://${domains[0]}`,
401+
},
402+
{
403+
isBinded: true,
404+
created: true,
405+
subDomain: domains[1],
406+
cname: expect.any(String),
407+
url: `http://${domains[1]}`,
408+
},
409+
]);
410+
411+
const d = await apigw.getCurrentCustomDomainsDict(outputs.serviceId);
412+
expect(d[domains[0]]).toBeDefined();
413+
expect(d[domains[1]]).toBeDefined();
414+
});
415+
416+
let oldState: ApigwDeployOutputs;
417+
418+
test('[Apigw CustomDomain] rebind customDomain success (skipped)', async () => {
419+
const apigwInputs = deepClone(inputs);
420+
apigwInputs.usagePlan = undefined;
421+
apigwInputs.serviceId = outputs.serviceId;
422+
apigwInputs.customDomains = [
423+
{
424+
domain: domains[0],
425+
// certificateId: 'cWOJJjax',
426+
isDefaultMapping: false,
427+
pathMappingSet: [
428+
{
429+
path: '/',
430+
environment: 'release',
431+
},
432+
],
433+
protocols: ['http'],
434+
},
435+
{
436+
domain: domains[1],
437+
// certificateId: 'cWOJJjax',
438+
isDefaultMapping: false,
439+
pathMappingSet: [
440+
{
441+
path: '/',
442+
environment: 'release',
443+
},
444+
],
445+
protocols: ['http'],
446+
},
447+
];
448+
449+
outputs = await apigw.deploy(apigwInputs);
450+
oldState = outputs;
451+
expect(outputs.customDomains).toEqual([
452+
{
453+
isBinded: true,
454+
created: true,
455+
subDomain: domains[0],
456+
cname: expect.any(String),
457+
url: `http://${domains[0]}`,
458+
},
459+
{
460+
isBinded: true,
461+
created: true,
462+
subDomain: domains[1],
463+
cname: expect.any(String),
464+
url: `http://${domains[1]}`,
465+
},
466+
]);
467+
468+
const d = await apigw.getCurrentCustomDomainsDict(outputs.serviceId);
469+
expect(d[domains[0]]).toBeDefined();
470+
expect(d[domains[1]]).toBeDefined();
471+
});
472+
473+
test('[Apigw CustomDomain] unbind customDomain success', async () => {
474+
const apigwInputs = deepClone(inputs);
475+
476+
apigwInputs.usagePlan = undefined;
477+
apigwInputs.serviceId = outputs.serviceId;
478+
apigwInputs.customDomains = undefined;
479+
apigwInputs.oldState = oldState;
480+
481+
outputs = await apigw.deploy(apigwInputs);
482+
expect(outputs.customDomains).toBeUndefined();
414483

415-
// const deployOutputsAgain = await apigw.deploy(inputs);
484+
const d = await apigw.getCurrentCustomDomainsDict(outputs.serviceId);
485+
expect(d[domains[0]]).toBeUndefined();
486+
expect(d[domains[1]]).toBeUndefined();
487+
});
488+
489+
test('[Apigw CustomDomain] should remove apigw success', async () => {
490+
// FIXME: 手动修改为 created
491+
outputs.customDomains?.forEach((v) => {
492+
v.created = true;
493+
});
494+
outputs.apiList?.forEach((v) => {
495+
v.created = true;
496+
if (v.usagePlan) {
497+
v.usagePlan.created = true;
498+
}
499+
});
500+
outputs.created = true;
501+
if (outputs.usagePlan) {
502+
outputs.usagePlan.created = true;
503+
}
416504

417-
// console.log({ deployOutputs, deployOutputsAgain });
418-
// await apigw.remove(deployOutputs);
419-
// });
505+
await apigw.remove(outputs);
506+
const detail = await apigw.request({
507+
Action: 'DescribeService',
508+
ServiceId: outputs.serviceId,
509+
});
510+
expect(detail).toBeNull();
511+
});
420512
});

package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,9 @@
8686
"@tencent-sdk/capi": "^1.1.8",
8787
"@tencent-sdk/cls": "^0.1.7",
8888
"@types/jest": "^26.0.20",
89-
"@types/lodash": "^4.14.167",
90-
"@types/node": "^14.14.20",
89+
"@types/node": "^14.14.31",
9190
"@ygkit/request": "^0.1.8",
9291
"cos-nodejs-sdk-v5": "2.8.6",
93-
"lodash": "^4.17.20",
9492
"moment": "^2.29.1",
9593
"tencent-cloud-sdk": "^1.0.5",
9694
"type-fest": "^0.20.2"

src/modules/apigw/apis.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const ACTIONS = [
3131
'BindEnvironment',
3232
'UnBindEnvironment',
3333
'DescribeServiceSubDomains',
34+
'DescribeServiceSubDomainMappings',
3435
'BindSubDomain',
3536
'UnBindSubDomain',
3637
] as const;

0 commit comments

Comments
 (0)