Skip to content

Commit 9246255

Browse files
Add more tests for retention policies
1 parent 660f1fd commit 9246255

2 files changed

Lines changed: 175 additions & 0 deletions

File tree

tests/Eftdb.Tests/Generators/RetentionPolicyOperationGeneratorTests.cs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,118 @@ FROM timescaledb_information.jobs
400400

401401
#endregion
402402

403+
#region Generate_Alter_DropCreatedBefore_job_settings_change_skips_alter_job
404+
405+
[Fact]
406+
public void Generate_Alter_DropCreatedBefore_job_settings_change_skips_alter_job()
407+
{
408+
// Arrange
409+
AlterRetentionPolicyOperation operation = new()
410+
{
411+
Schema = "public",
412+
TableName = "TestTable",
413+
DropAfter = null,
414+
OldDropAfter = null,
415+
DropCreatedBefore = "30 days",
416+
OldDropCreatedBefore = "30 days",
417+
InitialStart = null,
418+
OldInitialStart = null,
419+
ScheduleInterval = "2 days", // <-- Changed from "1 day"
420+
OldScheduleInterval = "1 day"
421+
};
422+
423+
// No recreation needed, but alter_job is skipped for DropCreatedBefore due to TimescaleDB bug #9446.
424+
RetentionPolicyOperationGenerator generator = new(true);
425+
List<string> result = generator.Generate(operation);
426+
427+
// Assert
428+
Assert.Empty(result);
429+
}
430+
431+
#endregion
432+
433+
#region Generate_Alter_MaxRuntime_change_emits_alter_job
434+
435+
[Fact]
436+
public void Generate_Alter_MaxRuntime_change_emits_alter_job()
437+
{
438+
// Arrange
439+
AlterRetentionPolicyOperation operation = new()
440+
{
441+
Schema = "public",
442+
TableName = "TestTable",
443+
DropAfter = "7 days",
444+
OldDropAfter = "7 days",
445+
DropCreatedBefore = null,
446+
OldDropCreatedBefore = null,
447+
InitialStart = null,
448+
OldInitialStart = null,
449+
MaxRuntime = "2 hours", // <-- Changed from "1 hour"
450+
OldMaxRuntime = "1 hour",
451+
ScheduleInterval = "1 day",
452+
OldScheduleInterval = "1 day",
453+
MaxRetries = -1,
454+
OldMaxRetries = -1,
455+
RetryPeriod = "1 day",
456+
OldRetryPeriod = "1 day"
457+
};
458+
459+
string expected = @".Sql(@""
460+
SELECT alter_job(job_id, max_runtime => INTERVAL '2 hours')
461+
FROM timescaledb_information.jobs
462+
WHERE proc_name = 'policy_retention' AND hypertable_schema = 'public' AND hypertable_name = 'TestTable';
463+
"")";
464+
465+
// Act
466+
string result = GetGeneratedCode(operation);
467+
468+
// Assert
469+
Assert.Equal(SqlHelper.NormalizeSql(expected), SqlHelper.NormalizeSql(result));
470+
}
471+
472+
#endregion
473+
474+
#region Generate_Alter_RetryPeriod_change_emits_alter_job
475+
476+
[Fact]
477+
public void Generate_Alter_RetryPeriod_change_emits_alter_job()
478+
{
479+
// Arrange
480+
AlterRetentionPolicyOperation operation = new()
481+
{
482+
Schema = "public",
483+
TableName = "TestTable",
484+
DropAfter = "7 days",
485+
OldDropAfter = "7 days",
486+
DropCreatedBefore = null,
487+
OldDropCreatedBefore = null,
488+
InitialStart = null,
489+
OldInitialStart = null,
490+
ScheduleInterval = "1 day",
491+
OldScheduleInterval = "1 day",
492+
MaxRuntime = "00:00:00",
493+
OldMaxRuntime = "00:00:00",
494+
MaxRetries = -1,
495+
OldMaxRetries = -1,
496+
RetryPeriod = "30 minutes", // <-- Changed from "1 day"
497+
OldRetryPeriod = "1 day"
498+
};
499+
500+
string expected = @".Sql(@""
501+
SELECT alter_job(job_id, retry_period => INTERVAL '30 minutes')
502+
FROM timescaledb_information.jobs
503+
WHERE proc_name = 'policy_retention' AND hypertable_schema = 'public' AND hypertable_name = 'TestTable';
504+
"")";
505+
506+
// Act
507+
string result = GetGeneratedCode(operation);
508+
509+
// Assert
510+
Assert.Equal(SqlHelper.NormalizeSql(expected), SqlHelper.NormalizeSql(result));
511+
}
512+
513+
#endregion
514+
403515
// --- Tests for runtime quoting (isDesignTime=false) ---
404516

405517
private static List<string> GetRuntimeStatements(dynamic operation)

tests/Eftdb.Tests/Integration/MigrationOperationOrderingTests.cs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using CmdScale.EntityFrameworkCore.TimescaleDB.Configuration.Hypertable;
22
using CmdScale.EntityFrameworkCore.TimescaleDB.Configuration.ReorderPolicy;
3+
using CmdScale.EntityFrameworkCore.TimescaleDB.Configuration.RetentionPolicy;
34
using CmdScale.EntityFrameworkCore.TimescaleDB.Operations;
45
using Microsoft.EntityFrameworkCore;
56
using Microsoft.EntityFrameworkCore.Migrations.Operations;
@@ -726,6 +727,68 @@ public void Should_Order_Hypertable_And_Indexes_Correctly()
726727

727728
#endregion
728729

730+
#region Should_Order_CreateHypertable_Before_AddRetentionPolicy
731+
732+
private class OrderingMetric9
733+
{
734+
public DateTime Timestamp { get; set; }
735+
public double Value { get; set; }
736+
}
737+
738+
private class OrderingContext9 : DbContext
739+
{
740+
public DbSet<OrderingMetric9> Metrics => Set<OrderingMetric9>();
741+
742+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
743+
=> optionsBuilder.UseNpgsql("Host=localhost;Database=test;Username=test;Password=test")
744+
.UseTimescaleDb();
745+
746+
protected override void OnModelCreating(ModelBuilder modelBuilder)
747+
{
748+
modelBuilder.Entity<OrderingMetric9>(entity =>
749+
{
750+
entity.ToTable("OrderingMetrics9");
751+
entity.HasNoKey();
752+
entity.IsHypertable(x => x.Timestamp)
753+
.WithChunkTimeInterval("1 day");
754+
entity.WithRetentionPolicy(dropAfter: "30 days");
755+
});
756+
}
757+
}
758+
759+
/// <summary>
760+
/// Verifies that CreateHypertableOperation appears before AddRetentionPolicyOperation.
761+
/// Retention policies require the hypertable to exist first.
762+
/// </summary>
763+
[Fact]
764+
public void Should_Order_CreateHypertable_Before_AddRetentionPolicy()
765+
{
766+
// Arrange
767+
using OrderingContext9 context = new();
768+
769+
// Act
770+
IReadOnlyList<MigrationOperation> operations = GenerateMigrationOperations(null, context);
771+
772+
// Assert
773+
int createTableIndex = operations.ToList().FindIndex(op =>
774+
op is CreateTableOperation createTable && createTable.Name == "OrderingMetrics9");
775+
int hypertableIndex = operations.ToList().FindIndex(op =>
776+
op is CreateHypertableOperation hypertable && hypertable.TableName == "OrderingMetrics9");
777+
int retentionPolicyIndex = operations.ToList().FindIndex(op =>
778+
op is AddRetentionPolicyOperation policy && policy.TableName == "OrderingMetrics9");
779+
780+
Assert.NotEqual(-1, createTableIndex);
781+
Assert.NotEqual(-1, hypertableIndex);
782+
Assert.NotEqual(-1, retentionPolicyIndex);
783+
784+
Assert.True(createTableIndex < hypertableIndex,
785+
$"CreateTable (index {createTableIndex}) should appear before CreateHypertable (index {hypertableIndex})");
786+
Assert.True(hypertableIndex < retentionPolicyIndex,
787+
$"CreateHypertable (index {hypertableIndex}) should appear before AddRetentionPolicy (index {retentionPolicyIndex})");
788+
}
789+
790+
#endregion
791+
729792
#region Should_Fail_With_Unstable_Sort_Many_Tables
730793

731794
// Many entity classes to generate enough operations to trigger unstable sort behavior

0 commit comments

Comments
 (0)