using System.Net; using Xunit; namespace HikvisionAttendanceService.Tests; public class UserSyncRetryHelperTests { [Theory] [InlineData(0, 1000)] [InlineData(1, 2000)] [InlineData(2, 4000)] public void GetBackoffDelayMilliseconds_exponential(int attempt, int expectedMs) { Assert.Equal(expectedMs, UserSyncRetryHelper.GetBackoffDelayMilliseconds(attempt)); } [Fact] public void GetBackoffDelayMilliseconds_caps_at_30s() { Assert.Equal(30_000, UserSyncRetryHelper.GetBackoffDelayMilliseconds(20)); } [Theory] [InlineData(503, true)] [InlineData(502, true)] [InlineData(429, true)] [InlineData(408, true)] [InlineData(401, false)] [InlineData(404, false)] [InlineData(200, false)] public void IsTransientHttpStatus(int code, bool transient) { Assert.Equal(transient, UserSyncRetryHelper.IsTransientHttpStatus((HttpStatusCode)code)); } } public class HistoricalAcsDynamicBatchTests { [Theory] [InlineData(0, 30)] [InlineData(999, 30)] [InlineData(1000, 50)] [InlineData(4999, 50)] [InlineData(5000, 100)] public void DetermineDynamicAcsBatchSize_thresholds(int parsedOk, int expected) { // internal method accessed via reflection because it lives inside HikvisionAttendanceManager.cs var t = typeof(HikvisionAttendanceService.HikvisionAttendanceManager); var m = t.GetMethod("DetermineDynamicAcsBatchSize", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); Assert.NotNull(m); var v = (int)m!.Invoke(null, new object[] { parsedOk, 30 })!; Assert.Equal(expected, v); } }