文件夹整理

This commit is contained in:
wkc
2026-02-09 14:28:25 +08:00
parent 056d239041
commit 02249c402e
2429 changed files with 3159 additions and 239710 deletions

View File

@@ -1,446 +0,0 @@
/**
* 中介导入功能测试脚本 - 验证ON DUPLICATE KEY UPDATE重构
*
* 测试场景:
* 1. 更新模式 - 测试importPersonBatch/importEntityBatch的INSERT ON DUPLICATE KEY UPDATE
* 2. 仅新增模式 - 测试冲突检测和失败记录
* 3. 边界情况 - 空列表、全部冲突、部分冲突等
*/
const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');
const path = require('path');
// 配置
const BASE_URL = 'http://localhost:8080';
const LOGIN_URL = `${BASE_URL}/login/test`;
const PERSON_IMPORT_URL = `${BASE_URL}/ccdi/intermediary/importPersonData`;
const ENTITY_IMPORT_URL = `${BASE_URL}/ccdi/intermediary/importEntityData`;
const PERSON_STATUS_URL = `${BASE_URL}/ccdi/intermediary/person/import/status`;
const ENTITY_STATUS_URL = `${BASE_URL}/ccdi/intermediary/entity/import/status`;
const PERSON_FAILURES_URL = `${BASE_URL}/ccdi/intermediary/person/import/failures`;
const ENTITY_FAILURES_URL = `${BASE_URL}/ccdi/intermediary/entity/import/failures`;
// 测试数据文件路径
const TEST_DATA_DIR = path.join(__dirname, '../test-data/intermediary');
const PERSON_TEST_FILE = path.join(TEST_DATA_DIR, '个人中介黑名单测试数据_1000条_第1批.xlsx');
const ENTITY_TEST_FILE = path.join(TEST_DATA_DIR, '机构中介黑名单测试数据_1000条_第1批.xlsx');
let authToken = '';
// 颜色输出
const colors = {
reset: '\x1b[0m',
green: '\x1b[32m',
red: '\x1b[31m',
yellow: '\x1b[33m',
blue: '\x1b[36m'
};
function log(message, color = 'reset') {
console.log(`${colors[color]}${message}${colors.reset}`);
}
function logSuccess(message) {
log(`${message}`, 'green');
}
function logError(message) {
log(`${message}`, 'red');
}
function logInfo(message) {
log(` ${message}`, 'blue');
}
function logSection(title) {
console.log('\n' + '='.repeat(60));
log(title, 'yellow');
console.log('='.repeat(60));
}
/**
* 登录获取Token
*/
async function login() {
logSection('登录系统');
try {
const response = await axios.post(LOGIN_URL, {
username: 'admin',
password: 'admin123'
});
if (response.data.code === 200) {
authToken = response.data.data;
logSuccess('登录成功');
logInfo(`Token: ${authToken.substring(0, 20)}...`);
return true;
} else {
logError(`登录失败: ${response.data.msg}`);
return false;
}
} catch (error) {
logError(`登录请求失败: ${error.message}`);
return false;
}
}
/**
* 上传文件并开始导入
*/
async function importData(file, url, updateSupport, description) {
logSection(description);
if (!fs.existsSync(file)) {
logError(`测试文件不存在: ${file}`);
return null;
}
logInfo(`上传文件: ${path.basename(file)}`);
logInfo(`更新模式: ${updateSupport ? '是' : '否'}`);
try {
const form = new FormData();
form.append('file', fs.createReadStream(file));
form.append('updateSupport', updateSupport.toString());
const response = await axios.post(url, form, {
headers: {
...form.getHeaders(),
'Authorization': `Bearer ${authToken}`
}
});
if (response.data.code === 200) {
logSuccess('导入任务已提交');
logInfo(`响应信息: ${response.data.msg}`);
// 从响应中提取taskId
const match = response.data.msg.match(/任务ID: ([a-zA-Z0-9-]+)/);
if (match) {
const taskId = match[1];
logInfo(`任务ID: ${taskId}`);
return taskId;
}
} else {
logError(`导入失败: ${response.data.msg}`);
}
} catch (error) {
logError(`导入请求失败: ${error.message}`);
if (error.response) {
logError(`状态码: ${error.response.status}`);
logError(`响应数据: ${JSON.stringify(error.response.data)}`);
}
}
return null;
}
/**
* 轮询查询导入状态
*/
async function pollImportStatus(taskId, url, description, maxAttempts = 30, interval = 2000) {
logInfo(`等待导入完成...`);
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
const response = await axios.get(`${url}?taskId=${taskId}`, {
headers: {
'Authorization': `Bearer ${authToken}`
}
});
if (response.data.code === 200) {
const status = response.data.data;
logInfo(`[尝试 ${attempt}/${maxAttempts}] 状态: ${status.status}, 进度: ${status.progress}%`);
if (status.status === 'SUCCESS' || status.status === 'PARTIAL_SUCCESS') {
logSuccess(`${description}完成!`);
logInfo(`总数: ${status.totalCount}, 成功: ${status.successCount}, 失败: ${status.failureCount}`);
return status;
} else if (status.status === 'FAILURE') {
logError(`${description}失败`);
return status;
}
}
} catch (error) {
logError(`查询状态失败: ${error.message}`);
}
await sleep(interval);
}
logError('导入超时');
return null;
}
/**
* 获取导入失败记录
*/
async function getImportFailures(taskId, url, description) {
logSection(`获取${description}失败记录`);
try {
const response = await axios.get(`${url}?taskId=${taskId}`, {
headers: {
'Authorization': `Bearer ${authToken}`
}
});
if (response.data.code === 200) {
const failures = response.data.data;
logInfo(`失败记录数: ${failures.length}`);
if (failures.length > 0) {
logInfo('前3条失败记录:');
failures.slice(0, 3).forEach((failure, index) => {
console.log(` ${index + 1}. ${failure.errorMessage || '未知错误'}`);
});
// 保存失败记录到文件
const failureFile = path.join(__dirname, `failures_${taskId}.json`);
fs.writeFileSync(failureFile, JSON.stringify(failures, null, 2));
logInfo(`失败记录已保存到: ${failureFile}`);
}
return failures;
}
} catch (error) {
logError(`获取失败记录失败: ${error.message}`);
}
return [];
}
/**
* 辅助函数: 延迟
*/
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* 测试场景1: 个人中介 - 更新模式(第一次导入)
*/
async function testPersonImportUpdateMode() {
logSection('测试场景1: 个人中介 - 更新模式(第一次导入)');
const taskId = await importData(
PERSON_TEST_FILE,
PERSON_IMPORT_URL,
true, // 更新模式
'个人中介导入(更新模式)'
);
if (!taskId) {
logError('导入任务未创建');
return false;
}
const status = await pollImportStatus(taskId, PERSON_STATUS_URL, '个人中介导入');
if (status && (status.status === 'SUCCESS' || status.status === 'PARTIAL_SUCCESS')) {
const failures = await getImportFailures(taskId, PERSON_FAILURES_URL, '个人中介');
logSuccess(`测试场景1完成 - 成功: ${status.successCount}, 失败: ${status.failureCount}`);
return true;
}
return false;
}
/**
* 测试场景2: 个人中介 - 仅新增模式(重复导入应失败)
*/
async function testPersonImportInsertOnly() {
logSection('测试场景2: 个人中介 - 仅新增模式(重复导入)');
const taskId = await importData(
PERSON_TEST_FILE,
PERSON_IMPORT_URL,
false, // 仅新增模式
'个人中介导入(仅新增)'
);
if (!taskId) {
logError('导入任务未创建');
return false;
}
const status = await pollImportStatus(taskId, PERSON_STATUS_URL, '个人中介导入');
if (status && (status.status === 'SUCCESS' || status.status === 'PARTIAL_SUCCESS')) {
const failures = await getImportFailures(taskId, PERSON_FAILURES_URL, '个人中介');
// 在仅新增模式下,重复导入应该全部失败
if (failures.length > 0) {
logSuccess(`测试场景2完成 - 预期有失败记录, 实际失败: ${failures.length}`);
return true;
} else {
logError('测试场景2失败 - 预期有失败记录, 但实际没有');
return false;
}
}
return false;
}
/**
* 测试场景3: 实体中介 - 更新模式(第一次导入)
*/
async function testEntityImportUpdateMode() {
logSection('测试场景3: 实体中介 - 更新模式(第一次导入)');
const taskId = await importData(
ENTITY_TEST_FILE,
ENTITY_IMPORT_URL,
true, // 更新模式
'实体中介导入(更新模式)'
);
if (!taskId) {
logError('导入任务未创建');
return false;
}
const status = await pollImportStatus(taskId, ENTITY_STATUS_URL, '实体中介导入');
if (status && (status.status === 'SUCCESS' || status.status === 'PARTIAL_SUCCESS')) {
const failures = await getImportFailures(taskId, ENTITY_FAILURES_URL, '实体中介');
logSuccess(`测试场景3完成 - 成功: ${status.successCount}, 失败: ${status.failureCount}`);
return true;
}
return false;
}
/**
* 测试场景4: 实体中介 - 仅新增模式(重复导入应失败)
*/
async function testEntityImportInsertOnly() {
logSection('测试场景4: 实体中介 - 仅新增模式(重复导入)');
const taskId = await importData(
ENTITY_TEST_FILE,
ENTITY_IMPORT_URL,
false, // 仅新增模式
'实体中介导入(仅新增)'
);
if (!taskId) {
logError('导入任务未创建');
return false;
}
const status = await pollImportStatus(taskId, ENTITY_STATUS_URL, '实体中介导入');
if (status && (status.status === 'SUCCESS' || status.status === 'PARTIAL_SUCCESS')) {
const failures = await getImportFailures(taskId, ENTITY_FAILURES_URL, '实体中介');
// 在仅新增模式下,重复导入应该全部失败
if (failures.length > 0) {
logSuccess(`测试场景4完成 - 预期有失败记录, 实际失败: ${failures.length}`);
return true;
} else {
logError('测试场景4失败 - 预期有失败记录, 但实际没有');
return false;
}
}
return false;
}
/**
* 测试场景5: 个人中介 - 再次更新模式(应该更新已有数据)
*/
async function testPersonImportUpdateAgain() {
logSection('测试场景5: 个人中介 - 再次更新模式');
const taskId = await importData(
PERSON_TEST_FILE,
PERSON_IMPORT_URL,
true, // 更新模式
'个人中介导入(再次更新)'
);
if (!taskId) {
logError('导入任务未创建');
return false;
}
const status = await pollImportStatus(taskId, PERSON_STATUS_URL, '个人中介导入');
if (status && (status.status === 'SUCCESS' || status.status === 'PARTIAL_SUCCESS')) {
const failures = await getImportFailures(taskId, PERSON_FAILURES_URL, '个人中介');
logSuccess(`测试场景5完成 - 成功: ${status.successCount}, 失败: ${status.failureCount}`);
return true;
}
return false;
}
/**
* 主测试流程
*/
async function runTests() {
console.log('\n╔════════════════════════════════════════════════════════════╗');
console.log('║ 中介导入功能测试 - ON DUPLICATE KEY UPDATE验证 ║');
console.log('╚════════════════════════════════════════════════════════════╝');
const startTime = Date.now();
const results = {
passed: 0,
failed: 0
};
// 登录
const loginSuccess = await login();
if (!loginSuccess) {
logError('无法登录,终止测试');
return;
}
// 执行测试
const tests = [
{ name: '场景1: 个人中介-更新模式(首次)', fn: testPersonImportUpdateMode },
{ name: '场景2: 个人中介-仅新增(重复)', fn: testPersonImportInsertOnly },
{ name: '场景3: 实体中介-更新模式(首次)', fn: testEntityImportUpdateMode },
{ name: '场景4: 实体中介-仅新增(重复)', fn: testEntityImportInsertOnly },
{ name: '场景5: 个人中介-再次更新', fn: testPersonImportUpdateAgain }
];
for (const test of tests) {
try {
const passed = await test.fn();
if (passed) {
results.passed++;
} else {
results.failed++;
}
await sleep(2000); // 测试之间间隔
} catch (error) {
logError(`${test.name} 执行异常: ${error.message}`);
results.failed++;
}
}
// 输出测试结果摘要
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
console.log('\n' + '='.repeat(60));
log('测试结果摘要', 'yellow');
console.log('='.repeat(60));
logSuccess(`通过: ${results.passed}/${tests.length}`);
if (results.failed > 0) {
logError(`失败: ${results.failed}/${tests.length}`);
}
logInfo(`总耗时: ${duration}`);
console.log('='.repeat(60) + '\n');
}
// 运行测试
runTests().catch(error => {
logError(`测试运行失败: ${error.message}`);
console.error(error);
process.exit(1);
});