using System;
using Dapper;
using MySqlConnector;
namespace CncWebApi.Tests
{
///
/// WebApi层测试数据库辅助类
/// 与Service.Tests共享同一个cnc_test库
///
public static class TestDb
{
/// 测试库连接串
public static readonly string ConnectionString =
"Server=localhost;Database=cnc_test;Uid=root;Pwd=root;Charset=utf8mb4;SslMode=None;";
/// 清空所有测试表并重置种子数据
public static void TruncateAll()
{
using (var conn = new MySqlConnection(ConnectionString))
{
var tables = new[]
{
"log_collect_raw",
"log_collector_heartbeat",
"cnc_worker_machine",
"cnc_production_segment",
"cnc_machine_daily_status",
"cnc_worker_daily_summary",
"cnc_daily_production",
"cnc_production_adjustment",
"cnc_alert",
"log_system",
"cnc_machine",
"cnc_collect_address",
"cnc_brand_field_mapping",
"cnc_screen_filter",
"cnc_screen_config",
"cnc_worker",
"cnc_sys_config",
"cnc_workshop",
"cnc_brand"
};
conn.Execute("SET FOREIGN_KEY_CHECKS = 0");
foreach (var table in tables)
{
conn.Execute($"DELETE FROM {table}");
conn.Execute($"ALTER TABLE {table} AUTO_INCREMENT = 1");
}
conn.Execute("SET FOREIGN_KEY_CHECKS = 1");
}
SeedData();
}
/// 插入基础种子数据
public static void SeedData()
{
using (var conn = new MySqlConnection(ConnectionString))
{
conn.Execute(@"INSERT IGNORE INTO cnc_brand (id, brand_name, device_field, tags_path, is_enabled, created_at, updated_at)
VALUES (1, 'FANUC', 'device', 'tags', 1, NOW(), NOW())");
conn.Execute(@"INSERT IGNORE INTO cnc_workshop (id, name, sort_order, is_enabled, created_at, updated_at)
VALUES (1, 'A栋', 1, 1, NOW(), NOW()), (2, 'B栋', 2, 1, NOW(), NOW())");
conn.Execute(@"INSERT IGNORE INTO cnc_sys_config (config_key, config_value, value_type, description, updated_at)
VALUES ('admin_username', 'admin', 'string', '管理员用户名', NOW()),
('admin_password_hash', '$2a$11$dummyhashfortesting', 'string', '管理员密码哈希', NOW())");
}
}
/// 设置真实BCrypt密码哈希
public static void SetRealPasswordHash(string plainPassword)
{
var hash = BCrypt.Net.BCrypt.HashPassword(plainPassword);
using (var conn = new MySqlConnection(ConnectionString))
{
conn.Execute("UPDATE cnc_sys_config SET config_value = @hash WHERE config_key = 'admin_password_hash'", new { hash });
}
}
/// 执行SQL
public static int Execute(string sql, object param = null)
{
using (var conn = new MySqlConnection(ConnectionString))
{
return conn.Execute(sql, param);
}
}
/// 查询单个值
public static T QuerySingle(string sql, object param = null)
{
using (var conn = new MySqlConnection(ConnectionString))
{
return conn.QuerySingle(sql, param);
}
}
/// 查询可空单个值
public static T QueryFirstOrDefault(string sql, object param = null)
{
using (var conn = new MySqlConnection(ConnectionString))
{
return conn.QueryFirstOrDefault(sql, param);
}
}
/// 生成有效JWT Token(用于需要认证的Controller测试)
public static string GenerateTestToken(string jwtSecret = "test-jwt-secret-key-for-unit-testing-2024")
{
const string headerJson = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}";
long exp = DateTimeOffset.UtcNow.AddHours(8).ToUnixTimeSeconds();
string payloadJson = $"{{\"sub\":\"admin\",\"name\":\"admin\",\"exp\":{exp}}}";
string header = Base64UrlEncode(System.Text.Encoding.UTF8.GetBytes(headerJson));
string payload = Base64UrlEncode(System.Text.Encoding.UTF8.GetBytes(payloadJson));
string unsigned = header + "." + payload;
using (var hmac = new System.Security.Cryptography.HMACSHA256(System.Text.Encoding.UTF8.GetBytes(jwtSecret)))
{
var sig = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(unsigned));
string signature = Base64UrlEncode(sig);
return unsigned + "." + signature;
}
}
private static string Base64UrlEncode(byte[] input)
{
return Convert.ToBase64String(input).Replace("+", "-").Replace("/", "_").TrimEnd('=');
}
}
}