mirror of
https://github.com/certd/certd.git
synced 2026-05-15 20:47:31 +08:00
chore: 补充单元测试
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
"dev-build": "npm run build",
|
||||
"preview": "vite preview",
|
||||
"test": "mocha --loader=ts-node/esm",
|
||||
"test:unit": "mocha --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
|
||||
"pub": "npm publish",
|
||||
"compile": "tsc --skipLibCheck --watch"
|
||||
},
|
||||
@@ -42,8 +43,10 @@
|
||||
"eslint": "^8.41.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"mocha": "^10.2.0",
|
||||
"prettier": "^2.8.8",
|
||||
"rimraf": "^5.0.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/// <reference types="mocha" />
|
||||
|
||||
import { expect } from "chai";
|
||||
|
||||
import { amountUtils } from "./util.amount.js";
|
||||
|
||||
describe("amountUtils", () => {
|
||||
describe("toCent", () => {
|
||||
it("converts yuan values to cents", () => {
|
||||
expect(amountUtils.toCent(1)).to.equal(100);
|
||||
expect(amountUtils.toCent(12.34)).to.equal(1234);
|
||||
});
|
||||
|
||||
it("rounds to the nearest cent", () => {
|
||||
expect(amountUtils.toCent(1.235)).to.equal(124);
|
||||
expect(amountUtils.toCent(1.234)).to.equal(123);
|
||||
});
|
||||
});
|
||||
|
||||
describe("toYuan", () => {
|
||||
it("converts cent values to yuan", () => {
|
||||
expect(amountUtils.toYuan(100)).to.equal(1);
|
||||
expect(amountUtils.toYuan(1234)).to.equal(12.34);
|
||||
});
|
||||
|
||||
it("rounds yuan values to two decimal places", () => {
|
||||
expect(amountUtils.toYuan(1235)).to.equal(12.35);
|
||||
expect(amountUtils.toYuan(1)).to.equal(0.01);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
/// <reference types="mocha" />
|
||||
|
||||
import { expect } from "chai";
|
||||
|
||||
import { domainUtils } from "./util.domain.js";
|
||||
|
||||
describe("domainUtils", () => {
|
||||
describe("match", () => {
|
||||
it("matches exact domains", () => {
|
||||
expect(domainUtils.match("example.com", ["example.com"])).to.equal(true);
|
||||
expect(domainUtils.match("api.example.com", ["example.com"])).to.equal(false);
|
||||
});
|
||||
|
||||
it("matches wildcard domains by suffix", () => {
|
||||
expect(domainUtils.match("api.example.com", ["*.example.com"])).to.equal(true);
|
||||
expect(domainUtils.match("deep.api.example.com", ["*.example.com"])).to.equal(false);
|
||||
expect(domainUtils.match("example.com", ["*.example.com"])).to.equal(false);
|
||||
});
|
||||
|
||||
it("requires every target domain to match", () => {
|
||||
expect(domainUtils.match(["api.example.com", "admin.example.com"], ["*.example.com"])).to.equal(true);
|
||||
expect(domainUtils.match(["api.example.com", "other.com"], ["*.example.com"])).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isIp", () => {
|
||||
it("detects valid IPv4 addresses", () => {
|
||||
expect(domainUtils.isIpv4("127.0.0.1")).to.equal(true);
|
||||
expect(domainUtils.isIpv4("255.255.255.255")).to.equal(true);
|
||||
});
|
||||
|
||||
it("rejects invalid IPv4 addresses", () => {
|
||||
expect(domainUtils.isIpv4("999.1.1.1")).to.equal(false);
|
||||
expect(domainUtils.isIpv4("1.2.3")).to.equal(false);
|
||||
expect(domainUtils.isIpv4("example.com")).to.equal(false);
|
||||
});
|
||||
|
||||
it("detects IPv6 addresses", () => {
|
||||
expect(domainUtils.isIpv6("2001:db8::1")).to.equal(true);
|
||||
expect(domainUtils.isIp("2001:db8::1")).to.equal(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -51,7 +51,10 @@ function isIpv4(d: string) {
|
||||
return false;
|
||||
}
|
||||
const isIPv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
||||
return isIPv4Regex.test(d);
|
||||
if (!isIPv4Regex.test(d)) {
|
||||
return false;
|
||||
}
|
||||
return d.split(".").every(item => Number(item) <= 255);
|
||||
}
|
||||
|
||||
function isIpv6(d: string) {
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/// <reference types="mocha" />
|
||||
|
||||
import { expect } from "chai";
|
||||
|
||||
import { optionsUtils } from "./util.options.js";
|
||||
|
||||
describe("optionsUtils", () => {
|
||||
describe("groupByDomain", () => {
|
||||
it("splits options by domain match", () => {
|
||||
const matchedOption = { value: "matched", domain: "api.example.com" };
|
||||
const wildcardMatchedOption = { value: "wildcard", domain: "admin.example.com" };
|
||||
const unmatchedOption = { value: "unmatched", domain: "other.com" };
|
||||
|
||||
const result = optionsUtils.groupByDomain([matchedOption, wildcardMatchedOption, unmatchedOption], ["api.example.com", "*.example.com"]);
|
||||
|
||||
expect(result.matched).to.deep.equal([matchedOption, wildcardMatchedOption]);
|
||||
expect(result.notMatched).to.deep.equal([unmatchedOption]);
|
||||
});
|
||||
|
||||
it("treats options without matching domains as not matched", () => {
|
||||
const optionWithoutDomain = { value: "empty" };
|
||||
|
||||
const result = optionsUtils.groupByDomain([optionWithoutDomain], ["example.com"]);
|
||||
|
||||
expect(result.matched).to.deep.equal([]);
|
||||
expect(result.notMatched).to.deep.equal([optionWithoutDomain]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildGroupOptions", () => {
|
||||
it("builds disabled group labels around matched and unmatched options", () => {
|
||||
const matchedOption = { value: "matched", domain: "api.example.com" };
|
||||
const unmatchedOption = { value: "unmatched", domain: "other.com" };
|
||||
|
||||
const result = optionsUtils.buildGroupOptions([matchedOption, unmatchedOption], ["api.example.com"]);
|
||||
|
||||
expect(result).to.deep.equal([{ value: "matched", disabled: true, label: "----已匹配----" }, matchedOption, { value: "unmatched", disabled: true, label: "----未匹配----" }, unmatchedOption]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
/// <reference types="mocha" />
|
||||
|
||||
import { expect } from "chai";
|
||||
|
||||
import { stringUtils } from "./util.string.js";
|
||||
|
||||
describe("stringUtils", () => {
|
||||
describe("maxLength", () => {
|
||||
it("returns an empty string for empty input", () => {
|
||||
expect(stringUtils.maxLength()).to.equal("");
|
||||
expect(stringUtils.maxLength("")).to.equal("");
|
||||
});
|
||||
|
||||
it("returns the original string when it is within the limit", () => {
|
||||
expect(stringUtils.maxLength("certd", 5)).to.equal("certd");
|
||||
expect(stringUtils.maxLength("certd", 6)).to.equal("certd");
|
||||
});
|
||||
|
||||
it("truncates strings longer than the limit and appends ellipsis", () => {
|
||||
expect(stringUtils.maxLength("certificate", 4)).to.equal("cert...");
|
||||
});
|
||||
});
|
||||
|
||||
describe("appendTimeSuffix", () => {
|
||||
it("returns an empty string for empty input", () => {
|
||||
expect(stringUtils.appendTimeSuffix()).to.equal("");
|
||||
expect(stringUtils.appendTimeSuffix("")).to.equal("");
|
||||
});
|
||||
|
||||
it("appends a millisecond timestamp suffix", () => {
|
||||
const result = stringUtils.appendTimeSuffix("certd");
|
||||
|
||||
expect(result).to.match(/^certd-\d{17}$/);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -7,7 +7,7 @@
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"inlineSourceMap":false,
|
||||
"inlineSourceMap": false,
|
||||
"sourceMap": false,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedLocals": true,
|
||||
@@ -22,21 +22,11 @@
|
||||
"composite": false,
|
||||
"useDefineForClassFields": true,
|
||||
"strict": true,
|
||||
"typeRoots": [ "./typings", "./node_modules/@types"],
|
||||
"typeRoots": ["./typings", "./node_modules/@types"],
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": false,
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"lib": ["ESNext", "DOM"]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.json"
|
||||
],
|
||||
"exclude": [
|
||||
"*.js",
|
||||
"*.ts",
|
||||
"*.spec.ts",
|
||||
"dist",
|
||||
"node_modules",
|
||||
"test"
|
||||
],
|
||||
"include": ["src/**/*.ts", "src/**/*.json"],
|
||||
"exclude": ["*.js", "*.ts", "*.spec.ts", "dist", "node_modules", "src/**/*.test.ts", "test"]
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
"build3": "rollup -c",
|
||||
"preview": "vite preview",
|
||||
"test": "mocha --loader=ts-node/esm",
|
||||
"test:unit": "mocha --no-config --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
|
||||
"pub": "npm publish",
|
||||
"compile": "tsc --skipLibCheck --watch"
|
||||
},
|
||||
@@ -42,6 +43,7 @@
|
||||
"mocha": "^10.2.0",
|
||||
"prettier": "^2.8.8",
|
||||
"rimraf": "^5.0.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/// <reference types="mocha" />
|
||||
|
||||
import { expect } from "chai";
|
||||
|
||||
import { PluginGroup, pluginGroups } from "./group.js";
|
||||
|
||||
describe("PluginGroup", () => {
|
||||
it("initializes a group with defaults", () => {
|
||||
const group = new PluginGroup("custom", "Custom");
|
||||
|
||||
expect(group.key).to.equal("custom");
|
||||
expect(group.title).to.equal("Custom");
|
||||
expect(group.order).to.equal(0);
|
||||
expect(group.icon).to.equal("");
|
||||
expect(group.plugins).to.deep.equal([]);
|
||||
});
|
||||
|
||||
it("exposes built-in groups with stable keys", () => {
|
||||
expect(pluginGroups.cert.key).to.equal("cert");
|
||||
expect(pluginGroups.host.key).to.equal("host");
|
||||
expect(pluginGroups.other.order).to.equal(10);
|
||||
});
|
||||
});
|
||||
@@ -7,7 +7,7 @@
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"inlineSourceMap":false,
|
||||
"inlineSourceMap": false,
|
||||
"sourceMap": false,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedLocals": true,
|
||||
@@ -22,22 +22,11 @@
|
||||
"composite": false,
|
||||
"useDefineForClassFields": true,
|
||||
"strict": true,
|
||||
// "sourceMap": true,
|
||||
// "sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": false,
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"lib": ["ESNext", "DOM"]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.json"
|
||||
],
|
||||
"exclude": [
|
||||
"*.js",
|
||||
"*.ts",
|
||||
"*.spec.ts",
|
||||
"dist",
|
||||
"node_modules",
|
||||
"test"
|
||||
],
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.json"],
|
||||
"exclude": ["*.js", "*.ts", "*.spec.ts", "dist", "node_modules", "src/**/*.test.ts", "test"]
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"build": "npm run before-build && tsc --skipLibCheck",
|
||||
"dev-build": "npm run build",
|
||||
"test": "midway-bin test --ts -V",
|
||||
"test:unit": "mocha --no-config --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
|
||||
"test1": "midway-bin test --ts -V -f test/blank.test.ts -t 'hash-check'",
|
||||
"cov": "midway-bin cov --ts",
|
||||
"lint": "mwts check",
|
||||
@@ -52,14 +53,17 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.3.3",
|
||||
"@types/mocha": "^10.0.1",
|
||||
"@types/node": "^18",
|
||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||
"@typescript-eslint/parser": "^8.26.1",
|
||||
"eslint": "^8.24.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"mocha": "^10.2.0",
|
||||
"prettier": "^2.8.8",
|
||||
"rimraf": "^5.0.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"tslib": "^2.8.1",
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/// <reference types="mocha" />
|
||||
/// <reference types="node" />
|
||||
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { Constants } from "./constants.js";
|
||||
import { ParamException } from "./exception/param-exception.js";
|
||||
import { Result } from "./result.js";
|
||||
|
||||
describe("lib-server basic helpers", () => {
|
||||
it("builds success and error results", () => {
|
||||
const success = Result.success("ok", { id: 1 });
|
||||
assert.ok(success instanceof Result);
|
||||
assert.equal(success.code, 0);
|
||||
assert.equal(success.message, "ok");
|
||||
assert.deepEqual(success.data, { id: 1 });
|
||||
|
||||
const error = Result.error(400, "bad request");
|
||||
assert.ok(error instanceof Result);
|
||||
assert.equal(error.code, 400);
|
||||
assert.equal(error.message, "bad request");
|
||||
assert.equal(error.data, undefined);
|
||||
});
|
||||
|
||||
it("uses default param exception metadata", () => {
|
||||
const error = new ParamException(undefined);
|
||||
|
||||
assert.equal(error.name, "ParamException");
|
||||
assert.equal(error.code, Constants.res.param.code);
|
||||
assert.equal(error.message, Constants.res.param.message);
|
||||
});
|
||||
});
|
||||
@@ -8,7 +8,7 @@
|
||||
"isolatedModules": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"inlineSourceMap":false,
|
||||
"inlineSourceMap": false,
|
||||
"sourceMap": false,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedLocals": true,
|
||||
@@ -17,25 +17,15 @@
|
||||
"pretty": true,
|
||||
"declaration": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"typeRoots": [ "./typings", "./node_modules/@types"],
|
||||
"typeRoots": ["./typings", "./node_modules/@types"],
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"composite": false,
|
||||
"useDefineForClassFields": true,
|
||||
"strict": false,
|
||||
"resolveJsonModule": true,
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"lib": ["ESNext", "DOM"]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.json"
|
||||
],
|
||||
"exclude": [
|
||||
"*.js",
|
||||
"*.ts",
|
||||
"dist",
|
||||
"node_modules",
|
||||
"test"
|
||||
],
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.json"],
|
||||
"exclude": ["*.js", "*.ts", "dist", "node_modules", "src/**/*.test.ts", "test"]
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"build3": "rollup -c",
|
||||
"build2": "vue-tsc --noEmit && vite build",
|
||||
"preview": "vite preview",
|
||||
"test:unit": "mocha --no-config --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
|
||||
"pub": "npm publish",
|
||||
"compile": "tsc --skipLibCheck --watch"
|
||||
},
|
||||
@@ -54,6 +55,7 @@
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"mocha": "^10.1.0",
|
||||
"prettier": "^2.8.8",
|
||||
"ts-node": "^10.9.2",
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/// <reference types="mocha" />
|
||||
|
||||
import { expect } from "chai";
|
||||
|
||||
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "./util.js";
|
||||
|
||||
describe("plugin-lib common util", () => {
|
||||
it("builds cert domain getter input define with defaults", () => {
|
||||
const define = createCertDomainGetterInputDefine();
|
||||
|
||||
expect(define.title).to.equal("当前证书域名");
|
||||
expect(define.component.name).to.equal("cert-domains-getter");
|
||||
expect(define.required).to.equal(true);
|
||||
expect(define.template).to.equal(false);
|
||||
expect(define.mergeScript).to.contain("form.cert");
|
||||
});
|
||||
|
||||
it("allows overriding cert input key and props", () => {
|
||||
const define = createCertDomainGetterInputDefine({
|
||||
certInputKey: "customCert",
|
||||
props: {
|
||||
title: "自定义域名",
|
||||
required: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(define.title).to.equal("自定义域名");
|
||||
expect(define.required).to.equal(false);
|
||||
expect(define.mergeScript).to.contain("form.customCert");
|
||||
});
|
||||
|
||||
it("builds remote select input define with expected component options", () => {
|
||||
const define = createRemoteSelectInputDefine({
|
||||
title: "选择资源",
|
||||
action: "ListResource",
|
||||
typeName: "resource",
|
||||
multi: false,
|
||||
search: true,
|
||||
watches: ["region"],
|
||||
});
|
||||
|
||||
expect(define.title).to.equal("选择资源");
|
||||
expect(define.required).to.equal(true);
|
||||
expect(define.component).to.include({
|
||||
name: "remote-select",
|
||||
vModel: "value",
|
||||
action: "ListResource",
|
||||
typeName: "resource",
|
||||
mode: "default",
|
||||
multi: false,
|
||||
search: true,
|
||||
});
|
||||
expect(define.component.watches).to.deep.equal(["certDomains", "accessId", "region"]);
|
||||
});
|
||||
});
|
||||
@@ -7,7 +7,7 @@
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"inlineSourceMap":false,
|
||||
"inlineSourceMap": false,
|
||||
"sourceMap": false,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedLocals": true,
|
||||
@@ -16,27 +16,17 @@
|
||||
"pretty": true,
|
||||
"declaration": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"typeRoots": [ "./typings", "./node_modules/@types"],
|
||||
"typeRoots": ["./typings", "./node_modules/@types"],
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"composite": false,
|
||||
"useDefineForClassFields": true,
|
||||
"strict": false,
|
||||
// "sourceMap": true,
|
||||
// "sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": false,
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"lib": ["ESNext", "DOM"]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.json"
|
||||
],
|
||||
"exclude": [
|
||||
"*.js",
|
||||
"*.ts",
|
||||
"dist",
|
||||
"node_modules",
|
||||
"test"
|
||||
],
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.json"],
|
||||
"exclude": ["*.js", "*.ts", "dist", "node_modules", "src/**/*.test.ts", "test"]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
showRunStrategy: false
|
||||
default:
|
||||
strategy:
|
||||
runStrategy: 1
|
||||
name: VolcengineDeployToVKE
|
||||
title: 火山引擎-替换VKE证书
|
||||
icon: svg:icon-volcengine
|
||||
group: volcengine
|
||||
desc: 替换火山引擎VKE集群中的TLS Secret证书
|
||||
input:
|
||||
cert:
|
||||
title: 域名证书
|
||||
helper: 请选择前置任务输出的域名证书
|
||||
component:
|
||||
name: output-selector
|
||||
from:
|
||||
- ':cert:'
|
||||
required: true
|
||||
order: 0
|
||||
certDomains:
|
||||
title: 当前证书域名
|
||||
component:
|
||||
name: cert-domains-getter
|
||||
mergeScript: |2-
|
||||
|
||||
return {
|
||||
component:{
|
||||
inputKey: ctx.compute(({form})=>{
|
||||
return form.cert
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
template: false
|
||||
required: false
|
||||
order: 0
|
||||
accessId:
|
||||
title: Access授权
|
||||
helper: 火山引擎AccessKeyId、AccessKeySecret
|
||||
component:
|
||||
name: access-selector
|
||||
type: volcengine
|
||||
required: true
|
||||
order: 0
|
||||
regionId:
|
||||
title: Region
|
||||
helper: VKE集群所在地域
|
||||
component:
|
||||
name: a-select
|
||||
options:
|
||||
- label: 北京
|
||||
value: cn-beijing
|
||||
- label: 上海
|
||||
value: cn-shanghai
|
||||
- label: 广州
|
||||
value: cn-guangzhou
|
||||
- label: 香港
|
||||
value: cn-hongkong
|
||||
- label: 柔佛
|
||||
value: ap-southeast-1
|
||||
- label: 雅加达
|
||||
value: ap-southeast-3
|
||||
value: cn-beijing
|
||||
required: true
|
||||
order: 0
|
||||
clusterId:
|
||||
title: VKE集群
|
||||
component:
|
||||
name: remote-select
|
||||
vModel: value
|
||||
mode: tags
|
||||
type: plugin
|
||||
action: onGetClusterList
|
||||
search: false
|
||||
pager: false
|
||||
multi: true
|
||||
watches:
|
||||
- certDomains
|
||||
- accessId
|
||||
- accessId
|
||||
- regionId
|
||||
required: true
|
||||
mergeScript: |2-
|
||||
|
||||
return {
|
||||
component:{
|
||||
form: ctx.compute(({form})=>{
|
||||
return form
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
helper: 选择要替换证书的VKE集群,也可以手动输入集群ID
|
||||
order: 0
|
||||
kubeconfigType:
|
||||
title: Kubeconfig类型
|
||||
helper: Public需要集群API Server已开启公网访问;Private需要Certd能访问集群私网地址
|
||||
component:
|
||||
name: a-select
|
||||
options:
|
||||
- label: 公网
|
||||
value: Public
|
||||
- label: 私网
|
||||
value: Private
|
||||
- label: 集群内
|
||||
value: TargetCluster
|
||||
value: Public
|
||||
required: true
|
||||
order: 0
|
||||
namespace:
|
||||
title: 命名空间
|
||||
value: default
|
||||
component:
|
||||
placeholder: 命名空间
|
||||
required: true
|
||||
order: 0
|
||||
targetType:
|
||||
title: 替换方式
|
||||
helper: 按Ingress会自动读取spec.tls[].secretName;按Secret需要手动填写Secret名称
|
||||
component:
|
||||
name: a-select
|
||||
options:
|
||||
- label: 按Ingress替换
|
||||
value: ingress
|
||||
- label: 按Secret替换
|
||||
value: secret
|
||||
value: ingress
|
||||
required: true
|
||||
order: 0
|
||||
ingressName:
|
||||
title: IngressName
|
||||
required: true
|
||||
helper: 根据Ingress名称查找TLS Secret并替换
|
||||
mergeScript: |2-
|
||||
|
||||
return {
|
||||
show: ctx.compute(({form}) => form.targetType === 'ingress'),
|
||||
required: ctx.compute(({form}) => form.targetType === 'ingress')
|
||||
}
|
||||
|
||||
order: 0
|
||||
secretName:
|
||||
title: Secret名称
|
||||
required: true
|
||||
helper: 存储TLS证书的Secret名称,可填写多个
|
||||
component:
|
||||
name: a-select
|
||||
vModel: value
|
||||
mode: tags
|
||||
open: false
|
||||
mergeScript: |2-
|
||||
|
||||
return {
|
||||
show: ctx.compute(({form}) => form.targetType === 'secret'),
|
||||
required: ctx.compute(({form}) => form.targetType === 'secret')
|
||||
}
|
||||
|
||||
order: 0
|
||||
createOnNotFound:
|
||||
title: Secret自动创建
|
||||
helper: 如果Secret不存在,则创建kubernetes.io/tls类型Secret
|
||||
value: false
|
||||
component:
|
||||
name: a-switch
|
||||
vModel: checked
|
||||
order: 0
|
||||
skipTLSVerify:
|
||||
title: 忽略证书校验
|
||||
helper: 连接Kubernetes API Server时跳过TLS校验
|
||||
value: false
|
||||
component:
|
||||
name: a-switch
|
||||
vModel: checked
|
||||
order: 0
|
||||
output: {}
|
||||
pluginType: deploy
|
||||
type: builtIn
|
||||
scriptFilePath: /plugins/plugin-volcengine/plugins/plugin-deploy-to-vke.js
|
||||
@@ -19,6 +19,7 @@
|
||||
"dev-new": "cross-env NODE_ENV=dev-new mwtsc --watch --run @midwayjs/mock/app",
|
||||
"rm-newdb": "rimraf ./data/db-new.sqlite",
|
||||
"test": "cross-env NODE_ENV=unittest mocha",
|
||||
"test:unit": "cross-env NODE_ENV=unittest mocha --no-config --node-option no-warnings --node-option loader=ts-node/esm \"src/**/*.test.ts\"",
|
||||
"cov": "cross-env c8 --all --reporter=text --reporter=lcovonly pnpm run test",
|
||||
"lint": "mwts check",
|
||||
"lint:fix": "mwts fix",
|
||||
@@ -161,6 +162,7 @@
|
||||
"mocha": "^10.2.0",
|
||||
"prettier": "^2.8.8",
|
||||
"rimraf": "^5.0.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2",
|
||||
"why-is-node-running": "^3.2.2"
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/// <reference types="mocha" />
|
||||
/// <reference types="node" />
|
||||
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { RandomUtil } from "./random.js";
|
||||
|
||||
describe("RandomUtil.randomStr", () => {
|
||||
it("generates an 8-character alphanumeric string by default", () => {
|
||||
const result = RandomUtil.randomStr();
|
||||
|
||||
assert.equal(result.length, 8);
|
||||
assert.match(result, /^[A-Za-z0-9]+$/);
|
||||
});
|
||||
|
||||
it("uses the requested length", () => {
|
||||
assert.equal(RandomUtil.randomStr(0), "");
|
||||
assert.equal(RandomUtil.randomStr(1).length, 1);
|
||||
assert.equal(RandomUtil.randomStr(16).length, 16);
|
||||
});
|
||||
|
||||
it("supports a custom character set", () => {
|
||||
assert.equal(RandomUtil.randomStr(6, "A"), "AAAAAA");
|
||||
});
|
||||
|
||||
it("supports the legacy true option as alphanumeric mode", () => {
|
||||
const result = RandomUtil.randomStr(32, true);
|
||||
|
||||
assert.match(result, /^[A-Za-z0-9]+$/);
|
||||
});
|
||||
|
||||
it("can generate from numbers only", () => {
|
||||
const result = RandomUtil.randomStr(12, { letters: false });
|
||||
|
||||
assert.match(result, /^[0-9]+$/);
|
||||
});
|
||||
|
||||
it("can generate from caller-provided option character sets", () => {
|
||||
assert.equal(RandomUtil.randomStr(4, { numbers: "7", letters: false }), "7777");
|
||||
assert.equal(RandomUtil.randomStr(4, { numbers: false, letters: "x" }), "xxxx");
|
||||
assert.equal(RandomUtil.randomStr(4, { numbers: false, letters: false, specials: "!" }), "!!!!");
|
||||
});
|
||||
|
||||
it("can generate from built-in specials only", () => {
|
||||
const result = RandomUtil.randomStr(20, { numbers: false, letters: false, specials: true });
|
||||
|
||||
assert.match(result, /^[~!@#$%^*()_+\-=[\]{}|;:,./<>?]+$/);
|
||||
});
|
||||
|
||||
it("rejects an empty character set", () => {
|
||||
assert.throws(() => RandomUtil.randomStr(4, ""), /at least one available character/);
|
||||
assert.throws(() => RandomUtil.randomStr(4, { numbers: false, letters: false }), /at least one available character/);
|
||||
});
|
||||
});
|
||||
@@ -2,14 +2,16 @@ const numbers = "0123456789";
|
||||
const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
const specials = "~!@#$%^*()_+-=[]{}|;:,./<>?";
|
||||
|
||||
type RandomStrOptions = true | string | { numbers?: false | string; letters?: false | string; specials?: boolean | string };
|
||||
|
||||
/**
|
||||
* Generate random string
|
||||
* @param {Number} length
|
||||
* @param {Object} options
|
||||
*/
|
||||
function randomStr(length, options?) {
|
||||
length || (length = 8);
|
||||
options || (options = {});
|
||||
function randomStr(length?: number, options?: RandomStrOptions) {
|
||||
length ?? (length = 8);
|
||||
options ?? (options = {});
|
||||
|
||||
let chars = "";
|
||||
let result = "";
|
||||
@@ -32,6 +34,10 @@ function randomStr(length, options?) {
|
||||
}
|
||||
}
|
||||
|
||||
if (chars.length === 0) {
|
||||
throw new Error("randomStr requires at least one available character");
|
||||
}
|
||||
|
||||
while (length > 0) {
|
||||
length--;
|
||||
result += chars[Math.floor(Math.random() * chars.length)];
|
||||
@@ -40,4 +46,3 @@ function randomStr(length, options?) {
|
||||
}
|
||||
|
||||
export const RandomUtil = { randomStr };
|
||||
|
||||
|
||||
@@ -16,16 +16,10 @@
|
||||
"pretty": true,
|
||||
"declaration": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"typeRoots": [ "./typings", "./node_modules/@types"],
|
||||
"typeRoots": ["./typings", "./node_modules/@types"],
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"preserveWatchOutput": true
|
||||
},
|
||||
"exclude": [
|
||||
"*.js",
|
||||
"*.ts",
|
||||
"dist",
|
||||
"node_modules",
|
||||
"test"
|
||||
]
|
||||
"exclude": ["*.js", "*.ts", "dist", "node_modules", "src/**/*.test.ts", "test"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user