using Microsoft.Extensions.Logging.Abstractions; using ZB.MOM.WW.CBDDC.Core; using ZB.MOM.WW.CBDDC.Core.Network; using ZB.MOM.WW.CBDDC.Core.Storage; namespace ZB.MOM.WW.CBDDC.Network.Tests; public class MultiDatasetSyncOrchestratorTests { /// /// Verifies multi-dataset sync is disabled, only the primary context is created. /// [Fact] public void Constructor_WhenMultiDatasetDisabled_ShouldOnlyCreatePrimaryContext() { var sut = CreateSut( [ new DatasetSyncOptions { DatasetId = DatasetId.Primary, Enabled = true }, new DatasetSyncOptions { DatasetId = DatasetId.Logs, Enabled = true } ], new MultiDatasetRuntimeOptions { EnableMultiDatasetSync = false, EnableDatasetPrimary = true, EnableDatasetLogs = true }); var datasetIds = sut.Contexts.Select(c => c.DatasetId).ToList(); datasetIds.Count.ShouldBe(1); datasetIds[0].ShouldBe(DatasetId.Primary); } /// /// Verifies that failures in one orchestrator do not prevent remaining contexts from starting and stopping. /// [Fact] public async Task StartStop_WhenOneDatasetThrows_ShouldContinueOtherDatasets() { var orchestrators = new Dictionary(StringComparer.Ordinal) { [DatasetId.Primary] = new TrackingSyncOrchestrator(), [DatasetId.Logs] = new TrackingSyncOrchestrator(startException: new InvalidOperationException("boom")), [DatasetId.Timeseries] = new TrackingSyncOrchestrator() }; var sut = CreateSut( [], new MultiDatasetRuntimeOptions { EnableMultiDatasetSync = true, EnableDatasetPrimary = true, EnableDatasetLogs = true, EnableDatasetTimeseries = true }, options => orchestrators[DatasetId.Normalize(options.DatasetId)]); await sut.Start(); await sut.Stop(); orchestrators[DatasetId.Primary].StartCalls.ShouldBe(1); orchestrators[DatasetId.Primary].StopCalls.ShouldBe(1); orchestrators[DatasetId.Logs].StartCalls.ShouldBe(1); orchestrators[DatasetId.Logs].StopCalls.ShouldBe(1); orchestrators[DatasetId.Timeseries].StartCalls.ShouldBe(1); orchestrators[DatasetId.Timeseries].StopCalls.ShouldBe(1); } private static MultiDatasetSyncOrchestrator CreateSut( IEnumerable datasetOptions, MultiDatasetRuntimeOptions runtimeOptions, Func? orchestratorFactory = null) { return new MultiDatasetSyncOrchestrator( Substitute.For(), Substitute.For(), Substitute.For(), Substitute.For(), Substitute.For(), Substitute.For(), NullLoggerFactory.Instance, datasetOptions, runtimeOptions, orchestratorFactory: orchestratorFactory); } private sealed class TrackingSyncOrchestrator(Exception? startException = null, Exception? stopException = null) : ISyncOrchestrator { /// /// Number of times has been called. /// public int StartCalls { get; private set; } /// /// Number of times has been called. /// public int StopCalls { get; private set; } /// /// Starts the orchestrator. /// public Task Start() { StartCalls++; if (startException != null) throw startException; return Task.CompletedTask; } /// /// Stops the orchestrator. /// public Task Stop() { StopCalls++; if (stopException != null) throw stopException; return Task.CompletedTask; } } }