mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-25 05:00:07 +00:00
213 lines
8.0 KiB
C#
213 lines
8.0 KiB
C#
using AutopilotMonitor.Functions.Functions.Reports;
|
|
using AutopilotMonitor.Shared.DataAccess;
|
|
|
|
namespace AutopilotMonitor.Functions.Tests;
|
|
|
|
/// <summary>
|
|
/// Tests for the hardware rejection aggregation logic extracted from GetHardwareRejectedFunction.
|
|
/// All tests target the pure static BuildAggregatedResult method — no HTTP or DI needed.
|
|
/// </summary>
|
|
public class GetHardwareRejectedFunctionTests
|
|
{
|
|
private static readonly DateTime T0 = new(2026, 3, 1, 12, 0, 0, DateTimeKind.Utc);
|
|
|
|
// =========================================================================
|
|
// Empty / no matching reports
|
|
// =========================================================================
|
|
|
|
[Fact]
|
|
public void BuildAggregatedResult_EmptyList_ReturnsEmpty()
|
|
{
|
|
var (aggregated, totalRawReports) = GetHardwareRejectedFunction.BuildAggregatedResult([]);
|
|
|
|
Assert.Empty(aggregated);
|
|
Assert.Equal(0, totalRawReports);
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildAggregatedResult_FiltersHardwareNotAllowedOnly()
|
|
{
|
|
var reports = new List<DistressReportEntry>
|
|
{
|
|
MakeEntry("HardwareNotAllowed", "Dell", "Latitude", "SN1", T0),
|
|
MakeEntry("CertificateExpired", "Dell", "Latitude", "SN2", T0.AddMinutes(1)),
|
|
MakeEntry("Timeout", "HP", "EliteBook", "SN3", T0.AddMinutes(2)),
|
|
};
|
|
|
|
var (aggregated, totalRawReports) = GetHardwareRejectedFunction.BuildAggregatedResult(reports);
|
|
|
|
Assert.Single(aggregated);
|
|
Assert.Equal(1, totalRawReports);
|
|
}
|
|
|
|
// =========================================================================
|
|
// Aggregation logic
|
|
// =========================================================================
|
|
|
|
[Fact]
|
|
public void BuildAggregatedResult_AggregatesCaseInsensitive()
|
|
{
|
|
var reports = new List<DistressReportEntry>
|
|
{
|
|
MakeEntry("HardwareNotAllowed", "Dell", "Latitude 5520", "SN1", T0),
|
|
MakeEntry("HardwareNotAllowed", "DELL", "LATITUDE 5520", "SN2", T0.AddMinutes(1)),
|
|
MakeEntry("HardwareNotAllowed", "dell", "latitude 5520", "SN3", T0.AddMinutes(2)),
|
|
};
|
|
|
|
var (aggregated, _) = GetHardwareRejectedFunction.BuildAggregatedResult(reports);
|
|
|
|
Assert.Single(aggregated);
|
|
var item = ToDynamic(aggregated[0]);
|
|
Assert.Equal(3, (int)item.attemptCount);
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildAggregatedResult_CountsAttemptsCorrectly()
|
|
{
|
|
var reports = new List<DistressReportEntry>
|
|
{
|
|
MakeEntry("HardwareNotAllowed", "Dell", "Latitude", "SN1", T0),
|
|
MakeEntry("HardwareNotAllowed", "Dell", "Latitude", "SN2", T0.AddMinutes(1)),
|
|
MakeEntry("HardwareNotAllowed", "Dell", "Latitude", "SN3", T0.AddMinutes(2)),
|
|
MakeEntry("HardwareNotAllowed", "HP", "EliteBook", "SN4", T0.AddMinutes(3)),
|
|
};
|
|
|
|
var (aggregated, totalRawReports) = GetHardwareRejectedFunction.BuildAggregatedResult(reports);
|
|
|
|
Assert.Equal(4, totalRawReports);
|
|
Assert.Equal(2, aggregated.Count);
|
|
|
|
var dell = ToDynamic(aggregated.First(a => ((string)ToDynamic(a).manufacturer).Equals("Dell", StringComparison.OrdinalIgnoreCase)));
|
|
Assert.Equal(3, (int)dell.attemptCount);
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildAggregatedResult_CountsUniqueSerials()
|
|
{
|
|
var reports = new List<DistressReportEntry>
|
|
{
|
|
MakeEntry("HardwareNotAllowed", "Dell", "Latitude", "SN1", T0),
|
|
MakeEntry("HardwareNotAllowed", "Dell", "Latitude", "SN1", T0.AddMinutes(1)), // duplicate
|
|
MakeEntry("HardwareNotAllowed", "Dell", "Latitude", "sn1", T0.AddMinutes(2)), // duplicate (case)
|
|
MakeEntry("HardwareNotAllowed", "Dell", "Latitude", "SN2", T0.AddMinutes(3)),
|
|
};
|
|
|
|
var (aggregated, _) = GetHardwareRejectedFunction.BuildAggregatedResult(reports);
|
|
|
|
var item = ToDynamic(aggregated[0]);
|
|
Assert.Equal(2, (int)item.uniqueSerials);
|
|
Assert.Equal(4, (int)item.attemptCount);
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildAggregatedResult_LimitsSampleSerialsToFive()
|
|
{
|
|
var reports = Enumerable.Range(1, 8)
|
|
.Select(i => MakeEntry("HardwareNotAllowed", "Dell", "Latitude", $"SN{i}", T0.AddMinutes(i)))
|
|
.ToList();
|
|
|
|
var (aggregated, _) = GetHardwareRejectedFunction.BuildAggregatedResult(reports);
|
|
|
|
var item = ToDynamic(aggregated[0]);
|
|
var samples = (IEnumerable<object>)item.sampleSerialNumbers;
|
|
Assert.Equal(5, samples.Count());
|
|
Assert.Equal(8, (int)item.uniqueSerials);
|
|
}
|
|
|
|
// =========================================================================
|
|
// Timestamps
|
|
// =========================================================================
|
|
|
|
[Fact]
|
|
public void BuildAggregatedResult_FirstSeenLastSeen_Correct()
|
|
{
|
|
var t1 = T0;
|
|
var t2 = T0.AddHours(1);
|
|
var t3 = T0.AddHours(2);
|
|
|
|
var reports = new List<DistressReportEntry>
|
|
{
|
|
MakeEntry("HardwareNotAllowed", "Dell", "Latitude", "SN1", t1),
|
|
MakeEntry("HardwareNotAllowed", "Dell", "Latitude", "SN2", t2),
|
|
MakeEntry("HardwareNotAllowed", "Dell", "Latitude", "SN3", t3),
|
|
};
|
|
|
|
var (aggregated, _) = GetHardwareRejectedFunction.BuildAggregatedResult(reports);
|
|
|
|
var item = ToDynamic(aggregated[0]);
|
|
Assert.Equal(t1, (DateTime)item.firstSeen);
|
|
Assert.Equal(t3, (DateTime)item.lastSeen);
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildAggregatedResult_OrderedByLastSeenDescending()
|
|
{
|
|
var reports = new List<DistressReportEntry>
|
|
{
|
|
MakeEntry("HardwareNotAllowed", "Dell", "Latitude", "SN1", T0),
|
|
MakeEntry("HardwareNotAllowed", "HP", "EliteBook", "SN2", T0.AddHours(2)),
|
|
MakeEntry("HardwareNotAllowed", "Lenovo", "ThinkPad", "SN3", T0.AddHours(1)),
|
|
};
|
|
|
|
var (aggregated, _) = GetHardwareRejectedFunction.BuildAggregatedResult(reports);
|
|
|
|
Assert.Equal(3, aggregated.Count);
|
|
var first = ToDynamic(aggregated[0]);
|
|
var second = ToDynamic(aggregated[1]);
|
|
var third = ToDynamic(aggregated[2]);
|
|
|
|
Assert.True((DateTime)first.lastSeen > (DateTime)second.lastSeen);
|
|
Assert.True((DateTime)second.lastSeen > (DateTime)third.lastSeen);
|
|
}
|
|
|
|
// =========================================================================
|
|
// Null manufacturer/model
|
|
// =========================================================================
|
|
|
|
[Fact]
|
|
public void BuildAggregatedResult_NullManufacturerModel_GroupedAsEmpty()
|
|
{
|
|
var reports = new List<DistressReportEntry>
|
|
{
|
|
MakeEntry("HardwareNotAllowed", null, null, "SN1", T0),
|
|
MakeEntry("HardwareNotAllowed", null, null, "SN2", T0.AddMinutes(1)),
|
|
};
|
|
|
|
var (aggregated, _) = GetHardwareRejectedFunction.BuildAggregatedResult(reports);
|
|
|
|
Assert.Single(aggregated);
|
|
var item = ToDynamic(aggregated[0]);
|
|
Assert.Equal("", (string)item.manufacturer);
|
|
Assert.Equal("", (string)item.model);
|
|
Assert.Equal(2, (int)item.attemptCount);
|
|
}
|
|
|
|
// =========================================================================
|
|
// Helpers
|
|
// =========================================================================
|
|
|
|
private static DistressReportEntry MakeEntry(
|
|
string errorType, string? manufacturer, string? model, string? serial, DateTime ingestedAt) =>
|
|
new()
|
|
{
|
|
TenantId = "test-tenant",
|
|
ErrorType = errorType,
|
|
Manufacturer = manufacturer,
|
|
Model = model,
|
|
SerialNumber = serial,
|
|
IngestedAt = ingestedAt,
|
|
AgentTimestamp = ingestedAt,
|
|
};
|
|
|
|
private static dynamic ToDynamic(object obj)
|
|
{
|
|
var type = obj.GetType();
|
|
var dict = new System.Dynamic.ExpandoObject() as IDictionary<string, object?>;
|
|
foreach (var prop in type.GetProperties())
|
|
{
|
|
dict[prop.Name] = prop.GetValue(obj);
|
|
}
|
|
return dict;
|
|
}
|
|
}
|