feat(datasync): add ScheduleConfig and ScheduleDefaults models
Add configuration models for the new schedule-based pipeline configuration: - ScheduleConfig: Per-schedule configuration (Enabled, IntervalMinutes, PrePurge, ReIndex, UpdateWhen) - ScheduleDefaults: Default configurations for Mass (weekly), Daily, and Hourly schedules - PipelineSchedules: Per-pipeline schedule overrides - MergeWith method for merging pipeline overrides with defaults Part of Task 1 from pipeline-schedule-alignment implementation plan.
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
namespace JdeScoping.DataSync.Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Configuration for a single schedule type (Mass/Daily/Hourly).
|
||||
/// </summary>
|
||||
public record ScheduleConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether this schedule is enabled.
|
||||
/// </summary>
|
||||
public bool Enabled { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Interval in minutes between syncs.
|
||||
/// </summary>
|
||||
public int IntervalMinutes { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to truncate the table before import (full reload).
|
||||
/// </summary>
|
||||
public bool PrePurge { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to rebuild indexes after import.
|
||||
/// </summary>
|
||||
public bool ReIndex { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Condition for updating existing rows (e.g., "src.LastUpdateDt > tgt.LastUpdateDt").
|
||||
/// </summary>
|
||||
public string? UpdateWhen { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Merges this config with defaults. Non-null/non-default values in this config override defaults.
|
||||
/// </summary>
|
||||
public ScheduleConfig MergeWith(ScheduleConfig defaults)
|
||||
{
|
||||
return new ScheduleConfig
|
||||
{
|
||||
Enabled = Enabled,
|
||||
IntervalMinutes = IntervalMinutes > 0 ? IntervalMinutes : defaults.IntervalMinutes,
|
||||
PrePurge = PrePurge || defaults.PrePurge,
|
||||
ReIndex = ReIndex || defaults.ReIndex,
|
||||
UpdateWhen = UpdateWhen ?? defaults.UpdateWhen
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default schedule configurations for all pipelines.
|
||||
/// </summary>
|
||||
public record ScheduleDefaults
|
||||
{
|
||||
/// <summary>
|
||||
/// Default Mass schedule config (weekly, full reload).
|
||||
/// </summary>
|
||||
public ScheduleConfig Mass { get; init; } = new()
|
||||
{
|
||||
Enabled = true,
|
||||
IntervalMinutes = 10080, // Weekly
|
||||
PrePurge = true,
|
||||
ReIndex = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Default Daily schedule config (incremental merge).
|
||||
/// </summary>
|
||||
public ScheduleConfig Daily { get; init; } = new()
|
||||
{
|
||||
Enabled = true,
|
||||
IntervalMinutes = 1440, // Daily
|
||||
PrePurge = false,
|
||||
ReIndex = false,
|
||||
UpdateWhen = "src.LastUpdateDt > tgt.LastUpdateDt"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Default Hourly schedule config (incremental merge).
|
||||
/// </summary>
|
||||
public ScheduleConfig Hourly { get; init; } = new()
|
||||
{
|
||||
Enabled = true,
|
||||
IntervalMinutes = 60, // Hourly
|
||||
PrePurge = false,
|
||||
ReIndex = false,
|
||||
UpdateWhen = "src.LastUpdateDt > tgt.LastUpdateDt"
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Per-pipeline schedule overrides.
|
||||
/// </summary>
|
||||
public record PipelineSchedules
|
||||
{
|
||||
public ScheduleConfig? Mass { get; init; }
|
||||
public ScheduleConfig? Daily { get; init; }
|
||||
public ScheduleConfig? Hourly { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
using JdeScoping.DataSync.Configuration;
|
||||
using Shouldly;
|
||||
|
||||
namespace JdeScoping.DataSync.Tests.Configuration;
|
||||
|
||||
public class ScheduleConfigTests
|
||||
{
|
||||
[Fact]
|
||||
public void ScheduleConfig_DefaultValues_AreCorrect()
|
||||
{
|
||||
var config = new ScheduleConfig();
|
||||
|
||||
config.Enabled.ShouldBeTrue();
|
||||
config.IntervalMinutes.ShouldBe(0);
|
||||
config.PrePurge.ShouldBeFalse();
|
||||
config.ReIndex.ShouldBeFalse();
|
||||
config.UpdateWhen.ShouldBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScheduleConfig_WithValues_StoresCorrectly()
|
||||
{
|
||||
var config = new ScheduleConfig
|
||||
{
|
||||
Enabled = false,
|
||||
IntervalMinutes = 60,
|
||||
PrePurge = true,
|
||||
ReIndex = true,
|
||||
UpdateWhen = "src.LastUpdateDt > tgt.LastUpdateDt"
|
||||
};
|
||||
|
||||
config.Enabled.ShouldBeFalse();
|
||||
config.IntervalMinutes.ShouldBe(60);
|
||||
config.PrePurge.ShouldBeTrue();
|
||||
config.ReIndex.ShouldBeTrue();
|
||||
config.UpdateWhen.ShouldBe("src.LastUpdateDt > tgt.LastUpdateDt");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScheduleDefaults_HasCorrectDefaultValues()
|
||||
{
|
||||
var defaults = new ScheduleDefaults();
|
||||
|
||||
defaults.Mass.ShouldNotBeNull();
|
||||
defaults.Daily.ShouldNotBeNull();
|
||||
defaults.Hourly.ShouldNotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScheduleDefaults_Mass_HasCorrectValues()
|
||||
{
|
||||
var defaults = new ScheduleDefaults();
|
||||
|
||||
defaults.Mass.Enabled.ShouldBeTrue();
|
||||
defaults.Mass.IntervalMinutes.ShouldBe(10080); // Weekly
|
||||
defaults.Mass.PrePurge.ShouldBeTrue();
|
||||
defaults.Mass.ReIndex.ShouldBeTrue();
|
||||
defaults.Mass.UpdateWhen.ShouldBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScheduleDefaults_Daily_HasCorrectValues()
|
||||
{
|
||||
var defaults = new ScheduleDefaults();
|
||||
|
||||
defaults.Daily.Enabled.ShouldBeTrue();
|
||||
defaults.Daily.IntervalMinutes.ShouldBe(1440); // Daily
|
||||
defaults.Daily.PrePurge.ShouldBeFalse();
|
||||
defaults.Daily.ReIndex.ShouldBeFalse();
|
||||
defaults.Daily.UpdateWhen.ShouldBe("src.LastUpdateDt > tgt.LastUpdateDt");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScheduleDefaults_Hourly_HasCorrectValues()
|
||||
{
|
||||
var defaults = new ScheduleDefaults();
|
||||
|
||||
defaults.Hourly.Enabled.ShouldBeTrue();
|
||||
defaults.Hourly.IntervalMinutes.ShouldBe(60); // Hourly
|
||||
defaults.Hourly.PrePurge.ShouldBeFalse();
|
||||
defaults.Hourly.ReIndex.ShouldBeFalse();
|
||||
defaults.Hourly.UpdateWhen.ShouldBe("src.LastUpdateDt > tgt.LastUpdateDt");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PipelineSchedules_AllPropertiesNullable()
|
||||
{
|
||||
var schedules = new PipelineSchedules();
|
||||
|
||||
schedules.Mass.ShouldBeNull();
|
||||
schedules.Daily.ShouldBeNull();
|
||||
schedules.Hourly.ShouldBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PipelineSchedules_WithValues_StoresCorrectly()
|
||||
{
|
||||
var schedules = new PipelineSchedules
|
||||
{
|
||||
Mass = new ScheduleConfig { PrePurge = true },
|
||||
Daily = new ScheduleConfig { Enabled = true },
|
||||
Hourly = new ScheduleConfig { Enabled = false }
|
||||
};
|
||||
|
||||
schedules.Mass.ShouldNotBeNull();
|
||||
schedules.Mass!.PrePurge.ShouldBeTrue();
|
||||
schedules.Daily.ShouldNotBeNull();
|
||||
schedules.Daily!.Enabled.ShouldBeTrue();
|
||||
schedules.Hourly.ShouldNotBeNull();
|
||||
schedules.Hourly!.Enabled.ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MergeWith_WhenConfigHasNoOverrides_ReturnsDefaultValues()
|
||||
{
|
||||
var config = new ScheduleConfig();
|
||||
var defaults = new ScheduleConfig
|
||||
{
|
||||
Enabled = true,
|
||||
IntervalMinutes = 60,
|
||||
PrePurge = false,
|
||||
ReIndex = false,
|
||||
UpdateWhen = "src.LastUpdateDt > tgt.LastUpdateDt"
|
||||
};
|
||||
|
||||
var merged = config.MergeWith(defaults);
|
||||
|
||||
merged.IntervalMinutes.ShouldBe(60);
|
||||
merged.UpdateWhen.ShouldBe("src.LastUpdateDt > tgt.LastUpdateDt");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MergeWith_WhenConfigHasOverrides_UsesOverrideValues()
|
||||
{
|
||||
var config = new ScheduleConfig
|
||||
{
|
||||
IntervalMinutes = 120,
|
||||
PrePurge = true,
|
||||
UpdateWhen = "custom condition"
|
||||
};
|
||||
var defaults = new ScheduleConfig
|
||||
{
|
||||
IntervalMinutes = 60,
|
||||
PrePurge = false,
|
||||
UpdateWhen = "default condition"
|
||||
};
|
||||
|
||||
var merged = config.MergeWith(defaults);
|
||||
|
||||
merged.IntervalMinutes.ShouldBe(120);
|
||||
merged.PrePurge.ShouldBeTrue();
|
||||
merged.UpdateWhen.ShouldBe("custom condition");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MergeWith_PreservesEnabledFromConfig()
|
||||
{
|
||||
var config = new ScheduleConfig { Enabled = false };
|
||||
var defaults = new ScheduleConfig { Enabled = true };
|
||||
|
||||
var merged = config.MergeWith(defaults);
|
||||
|
||||
merged.Enabled.ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MergeWith_WhenIntervalZero_UsesDefaultInterval()
|
||||
{
|
||||
var config = new ScheduleConfig { IntervalMinutes = 0 };
|
||||
var defaults = new ScheduleConfig { IntervalMinutes = 1440 };
|
||||
|
||||
var merged = config.MergeWith(defaults);
|
||||
|
||||
merged.IntervalMinutes.ShouldBe(1440);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user