mirror of https://github.com/certd/certd
chore: test优化
parent
cac949de56
commit
31f82e58b5
|
@ -14,7 +14,7 @@ import { usePreferences } from "/@/vben/preferences";
|
||||||
import { LocalStorage } from "/@/utils/util.storage";
|
import { LocalStorage } from "/@/utils/util.storage";
|
||||||
|
|
||||||
import { FsEditorCode } from "@fast-crud/editor-code";
|
import { FsEditorCode } from "@fast-crud/editor-code";
|
||||||
import "@fast-crud/editor-code/dist/style.css"
|
import "@fast-crud/editor-code/dist/style.css";
|
||||||
|
|
||||||
class ColumnSizeSaver {
|
class ColumnSizeSaver {
|
||||||
save: (key: string, size: number) => void;
|
save: (key: string, size: number) => void;
|
||||||
|
|
|
@ -19,6 +19,10 @@ div#app {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pre.pre{
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
|
}
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
h2,
|
h2,
|
||||||
h3,
|
h3,
|
||||||
|
|
|
@ -54,8 +54,8 @@ export function useVbenModal<TParentModalProps extends ModalProps = ModalProps>(
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
inheritAttrs: false,
|
|
||||||
name: "VbenParentModal",
|
name: "VbenParentModal",
|
||||||
|
inheritAttrs: false,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return [Modal, extendedApi as ExtendedModalApi] as const;
|
return [Modal, extendedApi as ExtendedModalApi] as const;
|
||||||
|
@ -104,8 +104,8 @@ export function useVbenModal<TParentModalProps extends ModalProps = ModalProps>(
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
inheritAttrs: false,
|
|
||||||
name: "VbenModal",
|
name: "VbenModal",
|
||||||
|
inheritAttrs: false,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
injectData.extendApi?.(extendedApi);
|
injectData.extendApi?.(extendedApi);
|
||||||
|
|
|
@ -57,4 +57,3 @@ export async function DeleteBatch(ids: any[]) {
|
||||||
data: { ids },
|
data: { ids },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -385,10 +385,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
column: {
|
column: {
|
||||||
conditionalRender: false,
|
conditionalRender: false,
|
||||||
cellRender({ row }) {
|
cellRender({ row }) {
|
||||||
const {
|
const { certEffectiveTime: effectiveTime, certExpiresTime: expiresTime } = row || {};
|
||||||
certEffectiveTime: effectiveTime,
|
|
||||||
certExpiresTime: expiresTime,
|
|
||||||
} = row || {};
|
|
||||||
if (!expiresTime) {
|
if (!expiresTime) {
|
||||||
return "-";
|
return "-";
|
||||||
}
|
}
|
||||||
|
|
|
@ -366,10 +366,7 @@ export default function ({ crudExpose, context: { groupDictRef, selectedRowKeys
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
cellRender({ row }) {
|
cellRender({ row }) {
|
||||||
const {
|
const { certEffectiveTime: effectiveTime, certExpiresTime: expiresTime } = row?.lastVars || {};
|
||||||
certEffectiveTime: effectiveTime,
|
|
||||||
certExpiresTime: expiresTime,
|
|
||||||
} = row?.lastVars || {};
|
|
||||||
if (!expiresTime) {
|
if (!expiresTime) {
|
||||||
return "-";
|
return "-";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="domain-test-card">
|
<div class="domain-test-card">
|
||||||
<div class="card-header">
|
<div class="card-header flex flex-wrap justify-start">
|
||||||
|
<div v-if="title">{{ title }}</div>
|
||||||
<a-form v-if="editing" layout="inline" :model="formData">
|
<a-form v-if="editing" layout="inline" :model="formData">
|
||||||
<a-form-item label="域名">
|
<a-form-item label="域名">
|
||||||
<a-input v-model:value="formData.domain" placeholder="请输入要测试的域名或IP" style="width: 240px" />
|
<a-input v-model:value="formData.domain" placeholder="请输入要测试的域名或IP" style="width: 240px" />
|
||||||
|
@ -29,18 +30,27 @@
|
||||||
<!-- Telnet测试结果 -->
|
<!-- Telnet测试结果 -->
|
||||||
<test-case ref="telnetTestRef" title="Telnet测试" :port="getCurrentPort()" :test-method="() => createTelnetTestMethod()" :disabled="!getCurrentDomain() || !getCurrentPort()" />
|
<test-case ref="telnetTestRef" title="Telnet测试" :port="getCurrentPort()" :test-method="() => createTelnetTestMethod()" :disabled="!getCurrentDomain() || !getCurrentPort()" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="summary">
|
||||||
|
<a-alert :message="testSummary.title" :type="testSummary.status === 'success' ? 'success' : testSummary.status === 'failed' ? 'error' : 'warning'" show-icon :closable="false">
|
||||||
|
<template v-if="testSummary.text" #description>
|
||||||
|
<pre class="summary-text pre">{{ testSummary.text }}</pre>
|
||||||
|
</template>
|
||||||
|
</a-alert>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, reactive, computed, onMounted } from "vue";
|
import { ref, reactive, computed, onMounted, watch } from "vue";
|
||||||
import { message } from "ant-design-vue";
|
import { message } from "ant-design-vue";
|
||||||
import { DomainResolve, PingTest, TelnetTest } from "./api";
|
import { DomainResolve, PingTest, TelnetTest } from "./api";
|
||||||
import TestCase from "./TestCase.vue";
|
import TestCase from "./TestCase.vue";
|
||||||
|
|
||||||
// 组件属性
|
// 组件属性
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
title?: string;
|
||||||
domain?: string;
|
domain?: string;
|
||||||
port?: number;
|
port?: number;
|
||||||
autoStart?: boolean;
|
autoStart?: boolean;
|
||||||
|
@ -92,6 +102,91 @@ const getCurrentPort = () => {
|
||||||
return formData.port;
|
return formData.port;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取各测试用例的状态
|
||||||
|
const getTestStatus = (testRef: any) => {
|
||||||
|
const result = testRef?.getResult();
|
||||||
|
if (!result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isNetTestResult = typeof result === "object" && result !== null && "success" in result && "message" in result;
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: isNetTestResult ? result.success : false,
|
||||||
|
message: isNetTestResult ? result.message : "测试失败",
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 生成测试总结
|
||||||
|
const testSummary = computed(() => {
|
||||||
|
if (loading.value) {
|
||||||
|
return { status: "waiting", title: "测试中,请稍后..." };
|
||||||
|
}
|
||||||
|
// 通过computed获取各测试结果
|
||||||
|
const domainResolveResult = getTestStatus(domainResolveRef.value);
|
||||||
|
const pingTestResult = getTestStatus(pingTestRef.value);
|
||||||
|
const telnetTestResult = getTestStatus(telnetTestRef.value);
|
||||||
|
|
||||||
|
// 检查是否有测试结果
|
||||||
|
const testDone = domainResolveResult != null && pingTestResult != null && telnetTestResult != null;
|
||||||
|
if (!testDone) {
|
||||||
|
return { status: "waiting", title: '请点击"开始测试"按钮进行网络测试' };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 详细分析不同的测试结果组合
|
||||||
|
// 1. 三个测试都失败
|
||||||
|
if (domainResolveResult?.success === false && pingTestResult?.success === false && telnetTestResult?.success === false) {
|
||||||
|
return {
|
||||||
|
status: "failed",
|
||||||
|
title: "所有测试均未通过",
|
||||||
|
text: `这表明应用容器内的网络可能完全不通。建议:\n1. 检查宿主机的网络连接状态\n2. 确认容器网络配置是否正确\n3. 检查防火墙设置是否阻止了网络访问`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 域名解析成功,但Ping不通
|
||||||
|
if (domainResolveResult?.success === true && pingTestResult?.success === false) {
|
||||||
|
return {
|
||||||
|
status: "partial",
|
||||||
|
title: "域名解析成功,但Ping不通",
|
||||||
|
text: `可能原因:\n1. DNS被劫持,解析到了错误的IP地址\n2. 目标服务器禁止了Ping请求\n3. 目标服务器IP被墙\n4. 目标服务器网络不通或已下线`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 域名解析和Ping都成功,但Telnet连接失败
|
||||||
|
if (domainResolveResult?.success === true && pingTestResult?.success === true && telnetTestResult?.success === false) {
|
||||||
|
return {
|
||||||
|
status: "partial",
|
||||||
|
title: "域名解析和Ping测试均通过,但Telnet连接失败",
|
||||||
|
text: `可能原因:\n1. 端口号输入错误,请确认目标服务使用的正确端口\n2. 目标服务器上该端口未开放或服务未启动\n3. 防火墙或安全组限制了该端口的访问\n4. 目标网站被墙`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 域名解析失败,但其他测试可能成功或未执行
|
||||||
|
if (domainResolveResult?.success === false) {
|
||||||
|
return {
|
||||||
|
status: "partial",
|
||||||
|
title: "域名解析失败",
|
||||||
|
text: `可能原因:\n1. 域名输入错误或不存在\n2. DNS服务器配置问题\n3. 本地网络DNS解析故障\n4. 域名已过期或被注销`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 所有测试都成功
|
||||||
|
if (domainResolveResult?.success === true && pingTestResult?.success === true && telnetTestResult?.success === true) {
|
||||||
|
return {
|
||||||
|
status: "success",
|
||||||
|
title: "所有测试均通过",
|
||||||
|
text: `域名${formData.domain}解析正常,能够正常Ping通,且端口${formData.port}可访问。`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 其他部分成功的情况
|
||||||
|
return {
|
||||||
|
status: "partial",
|
||||||
|
title: "部分测试未通过",
|
||||||
|
text: `请结合具体测试结果进行分析:\n- 域名解析:${domainResolveResult ? (domainResolveResult.success ? "成功" : "失败") : "未执行"}\n- Ping测试:${pingTestResult ? (pingTestResult.success ? "成功" : "失败") : "未执行"}\n- Telnet测试:${telnetTestResult ? (telnetTestResult.success ? "成功" : "失败") : "未执行"}`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
// 运行全部测试
|
// 运行全部测试
|
||||||
async function runAllTests() {
|
async function runAllTests() {
|
||||||
const domain = getCurrentDomain();
|
const domain = getCurrentDomain();
|
||||||
|
@ -121,64 +216,73 @@ onMounted(() => {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less">
|
||||||
.domain-test-card {
|
.domain-test-card {
|
||||||
border: 1px solid #e8e8e8;
|
border: 1px solid #e8e8e8;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
}
|
|
||||||
|
|
||||||
.card-header {
|
.card-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
background-color: #fafafa;
|
background-color: #fafafa;
|
||||||
border-bottom: 1px solid #e8e8e8;
|
border-bottom: 1px solid #e8e8e8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-header h3 {
|
.card-header h3 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-content {
|
.card-content {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-form {
|
.input-form {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
background-color: #fafafa;
|
background-color: #fafafa;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.domain-info {
|
.domain-info {
|
||||||
padding: 5.5px 12px;
|
padding: 5.5px 12px;
|
||||||
background-color: #f0f0f0;
|
background-color: #f0f0f0;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
.test-buttons {
|
.test-buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.test-results {
|
.test-results {
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 调整按钮大小 */
|
.summary {
|
||||||
.ant-btn {
|
margin-top: 16px;
|
||||||
font-size: 12px;
|
padding: 12px;
|
||||||
padding: 2px 8px;
|
background-color: #f8f9fa;
|
||||||
height: 24px;
|
border-radius: 4px;
|
||||||
|
.summary-text {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 调整按钮大小 */
|
||||||
|
.ant-btn {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -77,6 +77,7 @@ const runTest = async () => {
|
||||||
// 暴露方法给父组件
|
// 暴露方法给父组件
|
||||||
defineExpose({
|
defineExpose({
|
||||||
test: runTest,
|
test: runTest,
|
||||||
|
getResult: () => result.value,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 辅助计算属性,用于模板中显示结果
|
// 辅助计算属性,用于模板中显示结果
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<fs-page class="page-sys-nettest">
|
<fs-page class="page-sys-nettest">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="title">网络测试</div>
|
<div class="title">
|
||||||
|
网络测试
|
||||||
|
<span class="sub">测试您的服务器容器网络连接是否正常</span>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="nettest-container">
|
<div class="nettest-container">
|
||||||
<!-- 服务端信息 -->
|
<!-- 服务端信息 -->
|
||||||
<server-info-card />
|
<server-info-card />
|
||||||
|
|
||||||
<!-- 测试区域 -->
|
<!-- 测试区域 -->
|
||||||
<div class="test-areas">
|
<div class="test-areas flex-wrap md:flex-nowrap">
|
||||||
<!-- 用户输入域名测试 -->
|
|
||||||
<domain-test-card class="w-50%" />
|
|
||||||
|
|
||||||
<!-- 百度域名测试 (用于对比) -->
|
<!-- 百度域名测试 (用于对比) -->
|
||||||
<domain-test-card class="w-50%" :domain="'baidu.com'" :port="443" :auto-start="true" />
|
<domain-test-card class="test-card" :domain="'baidu.com'" :port="443" :auto-start="true" />
|
||||||
|
<!-- 用户输入域名测试 -->
|
||||||
|
<domain-test-card class="test-card" :title="'自定义域名测试'" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fs-page>
|
</fs-page>
|
||||||
|
@ -36,5 +38,9 @@ import ServerInfoCard from "./ServerInfoCard.vue";
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.test-card {
|
||||||
|
min-width: 50%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -55,15 +55,15 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
groups: {
|
groups: {
|
||||||
base: {
|
base: {
|
||||||
header: t("certd.basicInfo"),
|
header: t("certd.basicInfo"),
|
||||||
columns: ["title", "type", "disabled", "order", "supportBuy", "intro"]
|
columns: ["title", "type", "disabled", "order", "supportBuy", "intro"],
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
header: t("certd.packageContent"),
|
header: t("certd.packageContent"),
|
||||||
columns: ["content.maxDomainCount", "content.maxPipelineCount", "content.maxDeployCount", "content.maxMonitorCount"]
|
columns: ["content.maxDomainCount", "content.maxPipelineCount", "content.maxDeployCount", "content.maxMonitorCount"],
|
||||||
},
|
},
|
||||||
price: {
|
price: {
|
||||||
header: t("certd.price"),
|
header: t("certd.price"),
|
||||||
columns: ["durationPrices"]
|
columns: ["durationPrices"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -87,7 +87,7 @@ export class NetTestService {
|
||||||
// 判断测试是否成功
|
// 判断测试是否成功
|
||||||
const success = this.isWindows()
|
const success = this.isWindows()
|
||||||
? output.includes('TTL=')
|
? output.includes('TTL=')
|
||||||
: output.includes('0% packet loss');
|
: output.includes('time=');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success,
|
success,
|
||||||
|
@ -100,7 +100,7 @@ export class NetTestService {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: 'Ping测试执行失败',
|
message: 'Ping测试执行失败',
|
||||||
testLog: errorMessage,
|
testLog: error.stderr|| error.stdout || errorMessage,
|
||||||
error: errorMessage
|
error: errorMessage
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ export class NetTestService {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: '域名解析测试执行失败',
|
message: '域名解析测试执行失败',
|
||||||
testLog: errorMessage,
|
testLog: error.stdoout || error.stderr || errorMessage,
|
||||||
error: errorMessage
|
error: errorMessage
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -201,12 +201,13 @@ export class NetTestService {
|
||||||
});
|
});
|
||||||
const line = extDnsServers.trim()
|
const line = extDnsServers.trim()
|
||||||
if (line.includes('ExtServers') && line.includes('[')) {
|
if (line.includes('ExtServers') && line.includes('[')) {
|
||||||
const extDns = extDnsServers.trim().split(' ')[1].replace('[', '').replace(']', '').split(' ');
|
const extDns = line.substring(line.indexOf('[') + 1, line.indexOf(']')).split(' ');
|
||||||
dnsServers = dnsServers.concat(extDns);
|
const dnsList = extDns.map(item=>`Ext:${item}`)
|
||||||
|
dnsServers = dnsServers.concat(dnsList);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('获取DNS服务器失败', error);
|
logger.error('获取DNS ExtServers 服务器失败', error);
|
||||||
dnsServers.push(error instanceof Error ? error.message : String(error));
|
// dnsServers.push(error instanceof Error ? error.message : String(error));
|
||||||
}
|
}
|
||||||
return dnsServers;
|
return dnsServers;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue