82485d1939
- Implemented `docker-compose.kvrocks.auth.yml` for Kvrocks with password authentication. - Created `docker-compose.redis.yml` for Redis deployment. - Added Kvrocks configuration file `kvrocks.auth.conf` with necessary settings. - Updated documentation with deployment guidelines for Kvrocks. - Introduced ESLint configuration for code quality. - Developed deployment configuration check script `check-deployment-configs.js`. - Added D1 database initialization script `d1-init.sql` for KatelyaTV. - Created test script `test-kvrocks-deployment.js` to validate Kvrocks deployment. - Implemented fix verification script `verify-kvrocks-fix.js` for password handling. - Updated `wrangler.toml` for Cloudflare deployment configuration.
261 lines
7.6 KiB
JavaScript
261 lines
7.6 KiB
JavaScript
#!/usr/bin/env node
|
||
|
||
/**
|
||
* Kvrocks 部署测试脚本
|
||
* 用于验证 Docker + Kvrocks 部署是否正常工作
|
||
*/
|
||
|
||
const { createClient } = require('redis');
|
||
const { spawn } = require('child_process');
|
||
const fs = require('fs');
|
||
|
||
// 配置
|
||
const TEST_CONFIG = {
|
||
KVROCKS_URL: process.env.KVROCKS_URL || 'redis://localhost:6666',
|
||
KVROCKS_PASSWORD: process.env.KVROCKS_PASSWORD,
|
||
KVROCKS_DATABASE: parseInt(process.env.KVROCKS_DATABASE || '0'),
|
||
TEST_TIMEOUT: 30000, // 30秒超时
|
||
};
|
||
|
||
console.log('🧪 Kvrocks 部署测试开始...\n');
|
||
|
||
// 测试结果统计
|
||
let testResults = {
|
||
total: 0,
|
||
passed: 0,
|
||
failed: 0,
|
||
errors: []
|
||
};
|
||
|
||
// 辅助函数
|
||
function logTest(name, status, message = '') {
|
||
testResults.total++;
|
||
if (status === 'PASS') {
|
||
testResults.passed++;
|
||
console.log(`✅ ${name}: PASS ${message}`);
|
||
} else {
|
||
testResults.failed++;
|
||
console.log(`❌ ${name}: FAIL ${message}`);
|
||
testResults.errors.push(`${name}: ${message}`);
|
||
}
|
||
}
|
||
|
||
// 测试1:检查 Docker Compose 文件
|
||
async function testDockerComposeFiles() {
|
||
console.log('📁 测试 Docker Compose 配置文件...');
|
||
|
||
const files = [
|
||
'docker-compose.kvrocks.yml',
|
||
'docker-compose.kvrocks.auth.yml'
|
||
];
|
||
|
||
for (const file of files) {
|
||
try {
|
||
if (fs.existsSync(file)) {
|
||
const content = fs.readFileSync(file, 'utf8');
|
||
if (content.includes('kvrocks:') && content.includes('katelyatv:')) {
|
||
logTest(`Docker Compose 文件 ${file}`, 'PASS', '配置正确');
|
||
} else {
|
||
logTest(`Docker Compose 文件 ${file}`, 'FAIL', '配置缺失');
|
||
}
|
||
} else {
|
||
logTest(`Docker Compose 文件 ${file}`, 'FAIL', '文件不存在');
|
||
}
|
||
} catch (error) {
|
||
logTest(`Docker Compose 文件 ${file}`, 'FAIL', error.message);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 测试2:检查环境变量配置
|
||
async function testEnvironmentConfig() {
|
||
console.log('\n🔧 测试环境变量配置...');
|
||
|
||
// 检查必需的环境变量
|
||
const requiredVars = ['NEXT_PUBLIC_STORAGE_TYPE'];
|
||
const optionalVars = ['KVROCKS_PASSWORD', 'NEXTAUTH_SECRET'];
|
||
|
||
for (const varName of requiredVars) {
|
||
if (process.env[varName]) {
|
||
logTest(`环境变量 ${varName}`, 'PASS', `值: ${process.env[varName]}`);
|
||
} else {
|
||
logTest(`环境变量 ${varName}`, 'FAIL', '未设置');
|
||
}
|
||
}
|
||
|
||
for (const varName of optionalVars) {
|
||
if (process.env[varName]) {
|
||
logTest(`环境变量 ${varName}`, 'PASS', '已设置');
|
||
} else {
|
||
logTest(`环境变量 ${varName}`, 'PASS', '未设置(可选)');
|
||
}
|
||
}
|
||
|
||
// 检查存储类型
|
||
if (process.env.NEXT_PUBLIC_STORAGE_TYPE === 'kvrocks') {
|
||
logTest('存储类型配置', 'PASS', 'kvrocks');
|
||
} else {
|
||
logTest('存储类型配置', 'FAIL', `期望 kvrocks,实际 ${process.env.NEXT_PUBLIC_STORAGE_TYPE}`);
|
||
}
|
||
}
|
||
|
||
// 测试3:Kvrocks 连接测试
|
||
async function testKvrocksConnection() {
|
||
console.log('\n🔌 测试 Kvrocks 连接...');
|
||
|
||
let client;
|
||
try {
|
||
// 构建客户端配置
|
||
const clientConfig = {
|
||
url: TEST_CONFIG.KVROCKS_URL,
|
||
database: TEST_CONFIG.KVROCKS_DATABASE,
|
||
socket: {
|
||
connectTimeout: 5000,
|
||
},
|
||
};
|
||
|
||
// 只有当密码存在且不为空时才添加密码配置
|
||
if (TEST_CONFIG.KVROCKS_PASSWORD && TEST_CONFIG.KVROCKS_PASSWORD.trim() !== '') {
|
||
clientConfig.password = TEST_CONFIG.KVROCKS_PASSWORD;
|
||
console.log('🔐 使用密码认证连接');
|
||
} else {
|
||
console.log('🔓 无密码认证连接');
|
||
}
|
||
|
||
client = createClient(clientConfig);
|
||
|
||
// 连接
|
||
await client.connect();
|
||
logTest('Kvrocks 连接', 'PASS', '连接成功');
|
||
|
||
// 测试 PING
|
||
const pong = await client.ping();
|
||
if (pong === 'PONG') {
|
||
logTest('Kvrocks PING', 'PASS', 'PONG');
|
||
} else {
|
||
logTest('Kvrocks PING', 'FAIL', `响应: ${pong}`);
|
||
}
|
||
|
||
// 测试基本操作
|
||
const testKey = 'test:' + Date.now();
|
||
const testValue = 'test-value-' + Math.random();
|
||
|
||
await client.set(testKey, testValue);
|
||
const getValue = await client.get(testKey);
|
||
|
||
if (getValue === testValue) {
|
||
logTest('Kvrocks 读写操作', 'PASS', '数据一致');
|
||
} else {
|
||
logTest('Kvrocks 读写操作', 'FAIL', `期望 ${testValue},实际 ${getValue}`);
|
||
}
|
||
|
||
// 清理测试数据
|
||
await client.del(testKey);
|
||
|
||
// 测试数据库信息
|
||
const info = await client.info();
|
||
if (info.includes('kvrocks_version')) {
|
||
const version = info.match(/kvrocks_version:([^\r\n]+)/)?.[1];
|
||
logTest('Kvrocks 版本信息', 'PASS', `版本: ${version}`);
|
||
} else {
|
||
logTest('Kvrocks 版本信息', 'FAIL', '无法获取版本信息');
|
||
}
|
||
|
||
} catch (error) {
|
||
logTest('Kvrocks 连接', 'FAIL', error.message);
|
||
} finally {
|
||
if (client && client.isOpen) {
|
||
await client.quit();
|
||
}
|
||
}
|
||
}
|
||
|
||
// 测试4:Docker 服务状态检查
|
||
async function testDockerServices() {
|
||
console.log('\n🐳 测试 Docker 服务状态...');
|
||
|
||
return new Promise((resolve) => {
|
||
const docker = spawn('docker-compose', ['ps'], { stdio: 'pipe' });
|
||
let output = '';
|
||
|
||
docker.stdout.on('data', (data) => {
|
||
output += data.toString();
|
||
});
|
||
|
||
docker.on('close', (code) => {
|
||
if (code === 0) {
|
||
if (output.includes('kvrocks') && output.includes('Up')) {
|
||
logTest('Docker Kvrocks 服务', 'PASS', '服务运行中');
|
||
} else {
|
||
logTest('Docker Kvrocks 服务', 'FAIL', '服务未运行');
|
||
}
|
||
|
||
if (output.includes('katelyatv') && output.includes('Up')) {
|
||
logTest('Docker KatelyaTV 服务', 'PASS', '服务运行中');
|
||
} else {
|
||
logTest('Docker KatelyaTV 服务', 'FAIL', '服务未运行或未启动');
|
||
}
|
||
} else {
|
||
logTest('Docker 服务检查', 'FAIL', 'docker-compose 命令执行失败');
|
||
}
|
||
resolve();
|
||
});
|
||
|
||
docker.on('error', (error) => {
|
||
logTest('Docker 服务检查', 'FAIL', `Docker 未安装或不可用: ${error.message}`);
|
||
resolve();
|
||
});
|
||
});
|
||
}
|
||
|
||
// 主测试函数
|
||
async function runTests() {
|
||
console.log(`🏗️ 测试配置:`);
|
||
console.log(` Kvrocks URL: ${TEST_CONFIG.KVROCKS_URL}`);
|
||
console.log(` 密码认证: ${TEST_CONFIG.KVROCKS_PASSWORD ? '是' : '否'}`);
|
||
console.log(` 数据库: ${TEST_CONFIG.KVROCKS_DATABASE}`);
|
||
console.log('');
|
||
|
||
try {
|
||
await testDockerComposeFiles();
|
||
await testEnvironmentConfig();
|
||
await testDockerServices();
|
||
await testKvrocksConnection();
|
||
|
||
} catch (error) {
|
||
console.error('测试执行出错:', error);
|
||
testResults.failed++;
|
||
testResults.errors.push(`测试执行出错: ${error.message}`);
|
||
}
|
||
|
||
// 输出测试结果
|
||
console.log('\n' + '='.repeat(50));
|
||
console.log('📊 测试结果汇总:');
|
||
console.log(` 总计: ${testResults.total} 项测试`);
|
||
console.log(` 通过: ${testResults.passed} 项 ✅`);
|
||
console.log(` 失败: ${testResults.failed} 项 ❌`);
|
||
|
||
if (testResults.failed > 0) {
|
||
console.log('\n🚨 失败的测试项:');
|
||
testResults.errors.forEach((error, index) => {
|
||
console.log(` ${index + 1}. ${error}`);
|
||
});
|
||
|
||
console.log('\n💡 解决建议:');
|
||
console.log(' 1. 检查 Docker 服务是否正常启动');
|
||
console.log(' 2. 验证环境变量配置是否正确');
|
||
console.log(' 3. 确认网络连接是否正常');
|
||
console.log(' 4. 查看详细部署指南: docs/KVROCKS_DEPLOYMENT.md');
|
||
} else {
|
||
console.log('\n🎉 所有测试通过!Kvrocks 部署正常工作。');
|
||
}
|
||
|
||
console.log('='.repeat(50));
|
||
|
||
// 退出代码
|
||
process.exit(testResults.failed > 0 ? 1 : 0);
|
||
}
|
||
|
||
// 运行测试
|
||
runTests().catch(console.error);
|