fix: recover merged uploads and rotate logs

This commit is contained in:
2026-08-14 13:09:49 +08:00
parent 7a33b2c6e3
commit 51e4c41ee2
6 changed files with 169 additions and 6 deletions
@@ -553,6 +553,40 @@ public sealed class OpenListUploadTests
Assert.Equal(1, await fixture.Context.RecordUploadJobs.CountAsync());
}
[Fact]
public async Task AutomaticRecovery_RequeuesSucceededJobWhenMergedArtifactDrifts()
{
await using var fixture = await QueueFixture.CreateAsync();
await fixture.Queue.EnqueueAsync(fixture.RecordTaskId);
var originalJob = await fixture.Context.RecordUploadJobs.AsNoTracking().SingleAsync();
fixture.OpenList.Objects[originalJob.TargetVideoPath] = new OpenListObjectInfo(
"segment.mp4",
originalJob.VideoSizeBytes,
false,
new Dictionary<string, string>
{
["sha256"] = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes("video-content"))).ToLowerInvariant()
});
Assert.True(await fixture.Queue.ProcessNextAsync());
var result = await fixture.Context.RecordResults.SingleAsync();
var mergedPath = Path.Combine(Path.GetDirectoryName(result.FilePath)!, "segment-merged-recovery.mp4");
await File.WriteAllBytesAsync(mergedPath, Encoding.UTF8.GetBytes("merged-video-content"));
result.Update(mergedPath, new FileInfo(mergedPath).Length, 61, null, 0, RecordTaskStatus.Completed, null);
await fixture.Context.SaveChangesAsync();
var recovered = await fixture.Queue.RecoverPendingAutomaticUploadsAsync();
Assert.Equal(1, recovered);
fixture.Context.ChangeTracker.Clear();
var refreshedJob = await fixture.Context.RecordUploadJobs.SingleAsync();
var refreshedResult = await fixture.Context.RecordResults.SingleAsync();
Assert.Equal(RecordArtifactUploadStatus.Queued, refreshedJob.Status);
Assert.Equal(RecordArtifactUploadStatus.Queued, refreshedResult.UploadStatus);
Assert.EndsWith("segment-merged-recovery.mp4", refreshedJob.TargetVideoPath, StringComparison.Ordinal);
Assert.Equal(originalJob.TargetVideoPath, refreshedJob.PendingCleanupVideoPath);
}
[Fact]
public async Task CompletionOutbox_IsCreatedWhenRecordResultWasWrittenOutsideEfTracking()
{
@@ -94,6 +94,18 @@ public sealed class RecordingContinuityTests
Assert.Equal((0, 2), window);
}
[Theory]
[InlineData(RecordArtifactUploadStatus.NotUploaded, false, true)]
[InlineData(RecordArtifactUploadStatus.NotUploaded, true, false)]
[InlineData(RecordArtifactUploadStatus.Queued, true, false)]
[InlineData(RecordArtifactUploadStatus.Uploading, true, false)]
[InlineData(RecordArtifactUploadStatus.Succeeded, true, false)]
public void ShortFragmentMerge_RejectsArtifactsThatEnteredUpload(
RecordArtifactUploadStatus uploadStatus,
bool hasUploadJob,
bool expected) =>
Assert.Equal(expected, ShortFragmentConsolidationService.IsMergeEligible(uploadStatus, hasUploadJob));
[Fact]
public void DanmakuMerge_ShiftsRelativeOffset_ButPreservesAbsoluteTimestamp()
{