feat(datasync): add custom interval support to DataUpdateRepository

Add optional customIntervals parameter to GetSyncStatusAsync to allow
per-pipeline interval overrides instead of hardcoded defaults. This
enables tables like MisData to use longer sync intervals (e.g., 70 days)
while other tables use standard intervals.

Key changes:
- IDataUpdateRepository.GetSyncStatusAsync now accepts an optional
  Dictionary<string, int> for custom intervals keyed by "TableName_UpdateType"
- GetExpectedInterval and IsOverdue made public static for testing and reuse
- Added GetDefaultInterval method for accessing default values
- Updated DataSyncHealthCheck to use new signature
- Added comprehensive unit tests for custom interval behavior
This commit is contained in:
Joseph Doherty
2026-01-07 01:33:15 -05:00
parent e234c9f29a
commit da02784feb
5 changed files with 299 additions and 22 deletions
@@ -36,7 +36,7 @@ public class DataSyncHealthCheckTests
CreateSyncStatus("LotUsage", UpdateTypes.Mass, isOverdue: false, recentFailures: 0)
};
_repository.GetSyncStatusAsync(Arg.Any<CancellationToken>())
_repository.GetSyncStatusAsync(Arg.Any<Dictionary<string, int>?>(), Arg.Any<CancellationToken>())
.Returns(statuses);
// Act
@@ -59,7 +59,7 @@ public class DataSyncHealthCheckTests
CreateSyncStatus("LotUsage", UpdateTypes.Daily, isOverdue: false, recentFailures: 0)
};
_repository.GetSyncStatusAsync(Arg.Any<CancellationToken>())
_repository.GetSyncStatusAsync(Arg.Any<Dictionary<string, int>?>(), Arg.Any<CancellationToken>())
.Returns(statuses);
// Act
@@ -86,7 +86,7 @@ public class DataSyncHealthCheckTests
CreateSyncStatus("LotUsage", UpdateTypes.Daily, isOverdue: false, recentFailures: 0)
};
_repository.GetSyncStatusAsync(Arg.Any<CancellationToken>())
_repository.GetSyncStatusAsync(Arg.Any<Dictionary<string, int>?>(), Arg.Any<CancellationToken>())
.Returns(statuses);
// Act
@@ -108,7 +108,7 @@ public class DataSyncHealthCheckTests
CreateSyncStatus("LotUsage", UpdateTypes.Mass, isOverdue: false, recentFailures: 0)
};
_repository.GetSyncStatusAsync(Arg.Any<CancellationToken>())
_repository.GetSyncStatusAsync(Arg.Any<Dictionary<string, int>?>(), Arg.Any<CancellationToken>())
.Returns(statuses);
// Act
@@ -130,7 +130,7 @@ public class DataSyncHealthCheckTests
CreateSyncStatus("Item", UpdateTypes.Mass, isOverdue: false, recentFailures: 0)
};
_repository.GetSyncStatusAsync(Arg.Any<CancellationToken>())
_repository.GetSyncStatusAsync(Arg.Any<Dictionary<string, int>?>(), Arg.Any<CancellationToken>())
.Returns(statuses);
// Act
@@ -156,7 +156,7 @@ public class DataSyncHealthCheckTests
CreateSyncStatus("Lot", UpdateTypes.Mass, isOverdue: false, recentFailures: 0)
};
_repository.GetSyncStatusAsync(Arg.Any<CancellationToken>())
_repository.GetSyncStatusAsync(Arg.Any<Dictionary<string, int>?>(), Arg.Any<CancellationToken>())
.Returns(statuses);
// Act
@@ -171,7 +171,7 @@ public class DataSyncHealthCheckTests
public async Task CheckHealthAsync_RepositoryThrows_ReturnsUnhealthy()
{
// Arrange
_repository.GetSyncStatusAsync(Arg.Any<CancellationToken>())
_repository.GetSyncStatusAsync(Arg.Any<Dictionary<string, int>?>(), Arg.Any<CancellationToken>())
.ThrowsAsync(new Exception("Database connection failed"));
// Act
@@ -199,7 +199,7 @@ public class DataSyncHealthCheckTests
new("WorkOrder", UpdateTypes.Daily, now.AddHours(-12), true, 1440, false, 0)
};
_repository.GetSyncStatusAsync(Arg.Any<CancellationToken>())
_repository.GetSyncStatusAsync(Arg.Any<Dictionary<string, int>?>(), Arg.Any<CancellationToken>())
.Returns(statuses);
// Act
@@ -225,7 +225,7 @@ public class DataSyncHealthCheckTests
new("WorkOrder", UpdateTypes.Mass, null, false, 10080, true, 0)
};
_repository.GetSyncStatusAsync(Arg.Any<CancellationToken>())
_repository.GetSyncStatusAsync(Arg.Any<Dictionary<string, int>?>(), Arg.Any<CancellationToken>())
.Returns(statuses);
// Act
@@ -244,7 +244,7 @@ public class DataSyncHealthCheckTests
CreateSyncStatus("WorkOrder", UpdateTypes.Daily, isOverdue: true, recentFailures: 0)
};
_repository.GetSyncStatusAsync(Arg.Any<CancellationToken>())
_repository.GetSyncStatusAsync(Arg.Any<Dictionary<string, int>?>(), Arg.Any<CancellationToken>())
.Returns(statuses);
// Act
@@ -262,7 +262,7 @@ public class DataSyncHealthCheckTests
public async Task CheckHealthAsync_EmptyStatusList_ReturnsHealthy()
{
// Arrange: No tables configured
_repository.GetSyncStatusAsync(Arg.Any<CancellationToken>())
_repository.GetSyncStatusAsync(Arg.Any<Dictionary<string, int>?>(), Arg.Any<CancellationToken>())
.Returns(new List<TableSyncStatus>());
// Act