Files
git.stella-ops.org/src/StellaOps.Concelier.Storage.Mongo.Tests/MongoJobStoreTests.cs
2025-10-18 20:46:16 +03:00

114 lines
4.6 KiB
C#

using Microsoft.Extensions.Logging.Abstractions;
using MongoDB.Driver;
using StellaOps.Concelier.Core.Jobs;
using StellaOps.Concelier.Storage.Mongo;
namespace StellaOps.Concelier.Storage.Mongo.Tests;
[Collection("mongo-fixture")]
public sealed class MongoJobStoreTests : IClassFixture<MongoIntegrationFixture>
{
private readonly MongoIntegrationFixture _fixture;
public MongoJobStoreTests(MongoIntegrationFixture fixture)
{
_fixture = fixture;
}
[Fact]
public async Task CreateStartCompleteLifecycle()
{
await ResetCollectionAsync();
var collection = _fixture.Database.GetCollection<JobRunDocument>(MongoStorageDefaults.Collections.Jobs);
var store = new MongoJobStore(collection, NullLogger<MongoJobStore>.Instance);
var request = new JobRunCreateRequest(
Kind: "mongo:test",
Trigger: "unit",
Parameters: new Dictionary<string, object?> { ["scope"] = "lifecycle" },
ParametersHash: "abc",
Timeout: TimeSpan.FromSeconds(5),
LeaseDuration: TimeSpan.FromSeconds(2),
CreatedAt: DateTimeOffset.UtcNow);
var created = await store.CreateAsync(request, CancellationToken.None);
Assert.Equal(JobRunStatus.Pending, created.Status);
var started = await store.TryStartAsync(created.RunId, DateTimeOffset.UtcNow, CancellationToken.None);
Assert.NotNull(started);
Assert.Equal(JobRunStatus.Running, started!.Status);
var completed = await store.TryCompleteAsync(created.RunId, new JobRunCompletion(JobRunStatus.Succeeded, DateTimeOffset.UtcNow, null), CancellationToken.None);
Assert.NotNull(completed);
Assert.Equal(JobRunStatus.Succeeded, completed!.Status);
var recent = await store.GetRecentRunsAsync("mongo:test", 10, CancellationToken.None);
var snapshot = Assert.Single(recent);
Assert.Equal(JobRunStatus.Succeeded, snapshot.Status);
var active = await store.GetActiveRunsAsync(CancellationToken.None);
Assert.Empty(active);
var last = await store.GetLastRunAsync("mongo:test", CancellationToken.None);
Assert.NotNull(last);
Assert.Equal(completed.RunId, last!.RunId);
}
[Fact]
public async Task StartAndFailRunHonorsStateTransitions()
{
await ResetCollectionAsync();
var collection = _fixture.Database.GetCollection<JobRunDocument>(MongoStorageDefaults.Collections.Jobs);
var store = new MongoJobStore(collection, NullLogger<MongoJobStore>.Instance);
var request = new JobRunCreateRequest(
Kind: "mongo:failure",
Trigger: "unit",
Parameters: new Dictionary<string, object?>(),
ParametersHash: null,
Timeout: null,
LeaseDuration: null,
CreatedAt: DateTimeOffset.UtcNow);
var created = await store.CreateAsync(request, CancellationToken.None);
var firstStart = await store.TryStartAsync(created.RunId, DateTimeOffset.UtcNow, CancellationToken.None);
Assert.NotNull(firstStart);
// Second start attempt should be rejected once running.
var secondStart = await store.TryStartAsync(created.RunId, DateTimeOffset.UtcNow.AddSeconds(1), CancellationToken.None);
Assert.Null(secondStart);
var failure = await store.TryCompleteAsync(
created.RunId,
new JobRunCompletion(JobRunStatus.Failed, DateTimeOffset.UtcNow.AddSeconds(2), "boom"),
CancellationToken.None);
Assert.NotNull(failure);
Assert.Equal("boom", failure!.Error);
Assert.Equal(JobRunStatus.Failed, failure.Status);
}
[Fact]
public async Task CompletingUnknownRunReturnsNull()
{
await ResetCollectionAsync();
var collection = _fixture.Database.GetCollection<JobRunDocument>(MongoStorageDefaults.Collections.Jobs);
var store = new MongoJobStore(collection, NullLogger<MongoJobStore>.Instance);
var result = await store.TryCompleteAsync(Guid.NewGuid(), new JobRunCompletion(JobRunStatus.Succeeded, DateTimeOffset.UtcNow, null), CancellationToken.None);
Assert.Null(result);
}
private async Task ResetCollectionAsync()
{
try
{
await _fixture.Database.DropCollectionAsync(MongoStorageDefaults.Collections.Jobs);
}
catch (MongoCommandException ex) when (ex.CodeName == "NamespaceNotFound" || ex.Message.Contains("ns not found", StringComparison.OrdinalIgnoreCase))
{
}
}
}