Files
FictionArchive/FictionArchive.Service.NovelService.Tests/Sagas/NovelImportSagaTests.cs
gamer147 3c8c8c8707
All checks were successful
CI / build-backend (pull_request) Successful in 1m46s
CI / build-frontend (pull_request) Successful in 44s
[FA-misc] Fix issues with novel imports
2026-01-30 12:48:40 -05:00

138 lines
6.2 KiB
C#

using FictionArchive.Common.Enums;
using FictionArchive.Service.NovelService.Sagas;
using FictionArchive.Service.Shared.Contracts.Events;
using FluentAssertions;
using MassTransit;
using MassTransit.Testing;
using Microsoft.Extensions.DependencyInjection;
using NodaTime;
using NodaTime.Testing;
using Xunit;
namespace FictionArchive.Service.NovelService.Tests.Sagas;
public class NovelImportSagaTests
{
private readonly FakeClock _clock = new(Instant.FromUtc(2026, 1, 27, 12, 0, 0));
[Fact]
public async Task Should_transition_to_importing_on_import_requested()
{
await using var provider = CreateTestProvider();
var harness = provider.GetRequiredService<ITestHarness>();
await harness.Start();
var importId = Guid.NewGuid();
await harness.Bus.Publish<INovelImportRequested>(new NovelImportRequested(importId, "https://example.com/novel"));
var sagaHarness = harness.GetSagaStateMachineHarness<NovelImportSaga, NovelImportSagaState>();
(await sagaHarness.Exists(importId, x => x.Importing)).HasValue.Should().BeTrue();
}
[Fact]
public async Task Should_transition_to_completed_when_no_chapters()
{
await using var provider = CreateTestProvider();
var harness = provider.GetRequiredService<ITestHarness>();
await harness.Start();
var importId = Guid.NewGuid();
await harness.Bus.Publish<INovelImportRequested>(new NovelImportRequested(importId, "https://example.com/novel"));
await harness.Bus.Publish<INovelMetadataImported>(new NovelMetadataImported(importId, 1, 0, false));
var sagaHarness = harness.GetSagaStateMachineHarness<NovelImportSaga, NovelImportSagaState>();
(await sagaHarness.Exists(importId, x => x.Completed)).HasValue.Should().BeTrue();
(await harness.Published.Any<INovelImportCompleted>(x =>
x.Context.Message.ImportId == importId && x.Context.Message.Success)).Should().BeTrue();
}
[Fact]
public async Task Should_transition_to_processing_when_chapters_pending()
{
await using var provider = CreateTestProvider();
var harness = provider.GetRequiredService<ITestHarness>();
await harness.Start();
var importId = Guid.NewGuid();
await harness.Bus.Publish<INovelImportRequested>(new NovelImportRequested(importId, "https://example.com/novel"));
await harness.Bus.Publish<INovelMetadataImported>(new NovelMetadataImported(importId, 1, 2, false));
var sagaHarness = harness.GetSagaStateMachineHarness<NovelImportSaga, NovelImportSagaState>();
(await sagaHarness.Exists(importId, x => x.Processing)).HasValue.Should().BeTrue();
}
[Fact]
public async Task Should_complete_when_all_chapters_pulled_and_images_uploaded()
{
await using var provider = CreateTestProvider();
var harness = provider.GetRequiredService<ITestHarness>();
await harness.Start();
var importId = Guid.NewGuid();
await harness.Bus.Publish<INovelImportRequested>(new NovelImportRequested(importId, "https://example.com/novel"));
await harness.Bus.Publish<INovelMetadataImported>(new NovelMetadataImported(importId, 1, 2, false));
await harness.Bus.Publish<IChapterPullCompleted>(new ChapterPullCompleted(importId, 1, 1));
await harness.Bus.Publish<IChapterPullCompleted>(new ChapterPullCompleted(importId, 2, 0));
await harness.Bus.Publish<IFileUploadRequestStatusUpdate>(new FileUploadRequestStatusUpdate(
importId, Guid.NewGuid(), RequestStatus.Success, "https://cdn.example.com/image.jpg", null));
var sagaHarness = harness.GetSagaStateMachineHarness<NovelImportSaga, NovelImportSagaState>();
(await sagaHarness.Exists(importId, x => x.Completed)).HasValue.Should().BeTrue();
}
[Fact]
public async Task Should_transition_to_processing_when_cover_image_queued_with_no_chapters()
{
await using var provider = CreateTestProvider();
var harness = provider.GetRequiredService<ITestHarness>();
await harness.Start();
var importId = Guid.NewGuid();
await harness.Bus.Publish<INovelImportRequested>(new NovelImportRequested(importId, "https://example.com/novel"));
await harness.Bus.Publish<INovelMetadataImported>(new NovelMetadataImported(importId, 1, 0, true));
var sagaHarness = harness.GetSagaStateMachineHarness<NovelImportSaga, NovelImportSagaState>();
(await sagaHarness.Exists(importId, x => x.Processing)).HasValue.Should().BeTrue();
}
[Fact]
public async Task Should_complete_when_chapters_pulled_images_uploaded_and_cover_uploaded()
{
await using var provider = CreateTestProvider();
var harness = provider.GetRequiredService<ITestHarness>();
await harness.Start();
var importId = Guid.NewGuid();
await harness.Bus.Publish<INovelImportRequested>(new NovelImportRequested(importId, "https://example.com/novel"));
await harness.Bus.Publish<INovelMetadataImported>(new NovelMetadataImported(importId, 1, 1, true));
await harness.Bus.Publish<IChapterPullCompleted>(new ChapterPullCompleted(importId, 1, 0));
var sagaHarness = harness.GetSagaStateMachineHarness<NovelImportSaga, NovelImportSagaState>();
// Should still be processing - cover image not yet uploaded
(await sagaHarness.Exists(importId, x => x.Processing)).HasValue.Should().BeTrue();
// Upload cover image
await harness.Bus.Publish<IFileUploadRequestStatusUpdate>(new FileUploadRequestStatusUpdate(
importId, Guid.NewGuid(), RequestStatus.Success, "https://cdn.example.com/cover.jpg", null));
(await sagaHarness.Exists(importId, x => x.Completed)).HasValue.Should().BeTrue();
(await harness.Published.Any<INovelImportCompleted>(x =>
x.Context.Message.ImportId == importId && x.Context.Message.Success)).Should().BeTrue();
}
private ServiceProvider CreateTestProvider()
{
return new ServiceCollection()
.AddSingleton<IClock>(_clock)
.AddMassTransitTestHarness(cfg =>
{
cfg.AddSagaStateMachine<NovelImportSaga, NovelImportSagaState>()
.InMemoryRepository();
})
.BuildServiceProvider(true);
}
}