feat(ai): queue strategy snapshots
This commit is contained in:
@@ -13,9 +13,9 @@ using Xunit;
|
||||
|
||||
namespace JobTrackerApi.Tests;
|
||||
|
||||
// Candidate fit and focus plan share AiWorkspaceNote persistence with the same rules as
|
||||
// InterviewPrepNote: reuse across calls, regenerate on refresh, regenerate when the attachment
|
||||
// selection changes (career-workspace-implementation-roadmap.md Phase F5).
|
||||
// Candidate fit and Strategy Snapshot share AiWorkspaceNote persistence. Strategy generation is
|
||||
// durable now, so this file verifies its service-level result cache rather than invoking a model
|
||||
// from the GET endpoint.
|
||||
public sealed class AiWorkspaceNotePersistenceTests
|
||||
{
|
||||
[Fact]
|
||||
@@ -66,24 +66,25 @@ public sealed class AiWorkspaceNotePersistenceTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetFocusPlan_persists_and_reuses_the_generated_note()
|
||||
public async Task StrategySnapshot_generation_persists_a_stable_cached_result()
|
||||
{
|
||||
await using var db = TestHostFactory.CreateInMemoryDb();
|
||||
var job = await SeedJobWithCvAsync(db);
|
||||
|
||||
var summarizer = new Mock<ISummarizerService>();
|
||||
var callCount = 0;
|
||||
summarizer.Setup(x => x.SummarizeSectionAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
|
||||
.ReturnsAsync(() => { callCount++; return $"Text {callCount}"; });
|
||||
summarizer.Setup(x => x.GenerateSectionWithMetadataAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new AiGenerationResult("""{"strategicSummary":"Lead with backend delivery.","cvBulletIdeas":["Built APIs"],"proofPointsToLeadWith":["Led delivery"],"coverLetterAngles":["Relevant platform work"]}""", "ollama", "test-model"));
|
||||
|
||||
var controller = CreateController(db, summarizer.Object, "user-1");
|
||||
var service = new StrategySnapshotService(db, summarizer.Object);
|
||||
var generated = await service.GenerateAsync(job.Id, [], CancellationToken.None);
|
||||
var cached = await service.GetCachedAsync(job.Id, string.Empty, CancellationToken.None);
|
||||
|
||||
await controller.GetFocusPlan(job.Id, null, false, CancellationToken.None);
|
||||
var callsAfterFirst = callCount;
|
||||
|
||||
await controller.GetFocusPlan(job.Id, null, false, CancellationToken.None);
|
||||
|
||||
Assert.Equal(callsAfterFirst, callCount);
|
||||
Assert.NotNull(cached);
|
||||
Assert.Equal(generated.Result.StrategicSummary, cached.StrategicSummary);
|
||||
Assert.Equal(generated.Result.CvBulletIdeas, cached.CvBulletIdeas);
|
||||
Assert.Equal(generated.Result.ProofPointsToLeadWith, cached.ProofPointsToLeadWith);
|
||||
Assert.Equal(generated.Result.CoverLetterAngles, cached.CoverLetterAngles);
|
||||
Assert.Equal("ollama", generated.Provider);
|
||||
|
||||
var stored = Assert.Single(db.AiWorkspaceNotes.IgnoreQueryFilters().Where(x => x.JobApplicationId == job.Id && x.NoteType == "focus-plan"));
|
||||
Assert.NotEmpty(stored.ResultJson);
|
||||
|
||||
Reference in New Issue
Block a user