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('='); } } }