using System.Xml.Linq;
using SQLInsight.Collectors.Concurrency;
namespace SQLInsight.Collectors.Tests;
public class DeadlockParserTests
{
private const string Graph = """
UPDATE dbo.Orders SET Status = 2 WHERE Id = @id
UPDATE dbo.Orders SET Status = 3 WHERE Id = @id
""";
[Fact]
public void Parses_event_file_format()
{
var evt = XElement.Parse($"""
{Graph}
""");
var deadlock = DeadlockParser.ParseEvent(evt)!;
Assert.Equal(new DateTimeOffset(2026, 9, 29, 10, 15, 30, 123, TimeSpan.Zero), deadlock.Time);
Assert.Equal(2, deadlock.Processes.Count);
var victim = Assert.Single(deadlock.Processes, p => p.IsVictim);
Assert.Equal(60, victim.SessionId);
Assert.Equal("Sales", victim.DatabaseName);
Assert.Equal("Sales.Api", victim.ClientApp);
Assert.Equal("UPDATE dbo.Orders SET Status = 2 WHERE Id = @id", victim.InputBuffer);
Assert.Equal("5", deadlock.Processes[1].DatabaseName); // no currentdbname on older builds
Assert.StartsWith("", deadlock.GraphXml, StringComparison.Ordinal);
}
[Fact]
public void Parses_sql2008_escaped_graph()
{
// SQL Server 2008 RTM–SP1 put the graph in the ring buffer as escaped text.
var escaped = System.Security.SecurityElement.Escape(Graph);
var evt = XElement.Parse($"""
{escaped}
""");
var deadlock = DeadlockParser.ParseEvent(evt)!;
Assert.Equal(2, deadlock.Processes.Count);
}
[Fact]
public void Garbage_is_ignored()
{
var evt = XElement.Parse("""not xml""");
Assert.Null(DeadlockParser.ParseEvent(evt));
}
[Theory]
[InlineData("SQLInsight Pro (repository)", "SQLInsight Pro (repository)", true)]
[InlineData("SQLInsight Pro", "SQLInsight Pro (repository)", true)]
[InlineData("SQLInsight Pro (repository)", "Sales.Api", false)]
[InlineData("SQLInsight Pro (repository)", null, false)]
public void Deadlocks_between_sqlinsights_own_sessions_are_recognised(string first, string? second, bool own)
{
var deadlock = new SQLInsight.Core.Data.DeadlockEvent
{
Time = DateTimeOffset.UnixEpoch,
GraphXml = "",
Processes = [new() { Id = "p1", ClientApp = first }, new() { Id = "p2", ClientApp = second }],
};
Assert.Equal(own, deadlock.IsOwn);
}
}