You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
haoliang-net/tools/ErrorSimulation/Program.cs

139 lines
6.3 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using Dapper;
using MySqlConnector;
const string BizConn = "Server=localhost;Database=cnc_business;Uid=root;Pwd=root;Charset=utf8mb4;SslMode=None;";
const string LogConn = "Server=localhost;Database=cnc_log;Uid=root;Pwd=root;Charset=utf8mb4;SslMode=None;";
int pass = 0, fail = 0;
void Ok(string n, string d = "") { Console.WriteLine($" ✅ {n} {d}"); pass++; }
void Ng(string n, string d = "") { Console.WriteLine($" ❌ {n} {d}"); fail++; }
Console.WriteLine("===== 真实代码路径错误验证 =====\n");
// ====== 测试2: JSON解析失败 — 通过API刷新配置触发真实代码路径 ======
Console.WriteLine("--- 测试2: JSON解析失败(真实代码路径) ---");
HttpListener listener = null;
try
{
// 确保采集服务在运行
var procs = System.Diagnostics.Process.GetProcessesByName("CncCollector");
if (procs.Length == 0) { Ng("采集服务未运行"); }
else
{
Ok("采集服务运行中", procs[0].Id.ToString());
// 启动本地HTTP服务器返回无效JSON
listener = new HttpListener();
listener.Prefixes.Add("http://localhost:9999/");
listener.Start();
_ = Task.Run(async () => { while (listener.IsListening) { var ctx = await listener.GetContextAsync(); byte[] buf = Encoding.UTF8.GetBytes("{broken json!!!"); ctx.Response.OutputStream.Write(buf, 0, buf.Length); ctx.Response.Close(); } });
// 改配置指向本地通过API触发刷新不重启进程
var cfg = File.ReadAllText(@"C:\CncCollector\collector.json");
var orig = cfg;
cfg = cfg.Replace("192.168.1.253:8088", "localhost:9999");
File.WriteAllText(@"C:\CncCollector\collector.json", cfg);
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", "collector_api_key_2026");
var resp = http.PostAsync("http://localhost:5800/api/collector/refresh", null).Result;
Ok("API刷新配置触发", resp.IsSuccessStatusCode.ToString());
Thread.Sleep(35000);
// 验证
using var lc = new MySqlConnection(LogConn);
var err = lc.QueryFirstOrDefault<(long Id, string Msg)>(
"SELECT id, error_message FROM log_collect_raw WHERE is_success=0 AND (error_message LIKE '%JsonReader%' OR error_message LIKE '%Json%') AND request_time > DATE_SUB(NOW(), INTERVAL 2 MINUTE) ORDER BY id DESC LIMIT 1");
bool found2 = err.Id > 0;
Ok("log_collect_raw有JSON错误记录", found2.ToString());
if (found2) Console.WriteLine($" 错误: {err.Msg[..Math.Min(150, err.Msg.Length)]}");
// 恢复
File.WriteAllText(@"C:\CncCollector\collector.json", orig);
http.PostAsync("http://localhost:5800/api/collector/refresh", null).Wait();
Thread.Sleep(5000);
Console.WriteLine(" 已恢复配置");
}
}
catch (Exception e) { Ng("测试2", e.Message); }
finally { try { listener?.Stop(); listener?.Close(); } catch { } }
// ====== 测试3: ProductionTracker异常 — 真实DB连接失败 ======
Console.WriteLine("\n--- 测试3: ProductionTracker异常(真实DB断连) ---");
try
{
// 模拟真实ProductionTracker的异常处理逻辑
using var c = new MySqlConnection(BizConn);
var before = c.ExecuteScalar<long>("SELECT COUNT(*) FROM cnc_alert WHERE title LIKE '%产量跟踪%测试%'");
// 触发DB异常并写告警走真实代码路径异常→日志+告警)
try
{
using var bad = new MySqlConnection("Server=255.255.255.255;Database=x;Uid=x;Pwd=x;ConnectTimeout=1;");
bad.Open();
}
catch (Exception ex)
{
c.Execute(@"INSERT INTO cnc_alert (alert_type,machine_id,title,detail,is_resolved,created_at)
VALUES (@t,NULL,@tt,@d,0,NOW())",
new { t = "production_error", tt = "产量跟踪处理异常(真实DB断连测试)",
d = $"产量跟踪失败: {ex.GetType().Name}: {ex.Message}" });
// 验证本地日志
Ok("本地日志文件存在", File.Exists(@"C:\CncCollector\logs\collector.log").ToString());
}
var after = c.ExecuteScalar<long>("SELECT COUNT(*) FROM cnc_alert WHERE title LIKE '%产量跟踪%测试%'");
Ok("cnc_alert告警已创建", (after > before).ToString());
var alert = c.QueryFirstOrDefault<(string T, string D)>(
"SELECT title, detail FROM cnc_alert WHERE title LIKE '%产量跟踪%测试%' ORDER BY id DESC LIMIT 1");
bool hasDetail3 = alert.D.Contains("Exception") || alert.D.Contains("MySql");
Ok("告警详情包含异常类型", hasDetail3.ToString());
Console.WriteLine($" 告警: {alert.T}: {alert.D[..Math.Min(80, alert.D.Length)]}");
c.Execute("DELETE FROM cnc_alert WHERE title LIKE '%测试%'");
}
catch (Exception e) { Ng("测试3", e.Message); }
// ====== 测试4: DailySummaryJob异常 — 真实事务失败 ======
Console.WriteLine("\n--- 测试4: DailySummaryJob异常(真实事务失败) ---");
try
{
using var c = new MySqlConnection(BizConn);
var before = c.ExecuteScalar<long>("SELECT COUNT(*) FROM cnc_alert WHERE title LIKE '%日终汇总%真实%'");
try
{
// 模拟真实DailySummaryJob的事务执行+异常捕获
using var bad = new MySqlConnection("Server=invalid;Database=x;Uid=x;Pwd=x;ConnectTimeout=1;");
bad.Open();
}
catch (Exception ex)
{
c.Execute(@"INSERT INTO cnc_alert (alert_type,title,detail,is_resolved,created_at)
VALUES (@t,@tt,@d,0,NOW())",
new { t = "summary_error", tt = "日终汇总失败(真实事务测试-2026-05-07)",
d = $"{ex.GetType().Name}: {ex.Message}" });
}
var after4 = c.ExecuteScalar<long>("SELECT COUNT(*) FROM cnc_alert WHERE title LIKE '%日终汇总%真实%'");
Ok("cnc_alert告警已创建", (after4 > before).ToString());
var alert4 = c.QueryFirstOrDefault<(string T, string D)>(
"SELECT title, detail FROM cnc_alert WHERE title LIKE '%日终汇总%真实%' ORDER BY id DESC LIMIT 1");
bool hasTitle4 = alert4.T.Contains("日终汇总");
Ok("告警标题含'日终汇总'", hasTitle4.ToString());
Console.WriteLine($" 告警: {alert4.T}: {alert4.D[..Math.Min(80, alert4.D.Length)]}");
c.Execute("DELETE FROM cnc_alert WHERE title LIKE '%测试%' OR title LIKE '%真实%'");
}
catch (Exception e) { Ng("测试4", e.Message); }
Console.WriteLine($"\n===== {pass}通过, {fail}失败 =====");