90 lines
3.5 KiB
C#
90 lines
3.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Paca.Mobile.Core;
|
|
using Xunit;
|
|
|
|
namespace Paca.Tests.Core;
|
|
|
|
public class MediaStorageGarbageCollectorGateTests
|
|
{
|
|
[Fact]
|
|
public void Gate321_MediaStorageGarbageCollector_ProtectsActiveFiles_AndSelectsStaleOnly()
|
|
{
|
|
var now = new DateTime(2026, 9, 4, 20, 30, 0);
|
|
|
|
var candidateFiles = new List<CandidateFileInfo>
|
|
{
|
|
// Stale part file from 3 days ago (150 MB)
|
|
new("C:\\downloads\\movie.mp4.part", 150 * 1024 * 1024, now.AddDays(-3)),
|
|
// Active part file created 10 minutes ago (50 MB) -> MUST BE PROTECTED!
|
|
new("C:\\downloads\\active.mp4.part", 50 * 1024 * 1024, now.AddMinutes(-10)),
|
|
// Normal finished mp4 from 2 days ago -> MUST NOT BE TOUCHED!
|
|
new("C:\\downloads\\finished.mp4", 500 * 1024 * 1024, now.AddDays(-2)),
|
|
// Stale tmp fragment from 40 hours ago (80 MB)
|
|
new("C:\\downloads\\stream_frag.tmp", 80 * 1024 * 1024, now.AddHours(-40))
|
|
};
|
|
|
|
var minAge = TimeSpan.FromHours(24);
|
|
var orphans = MediaStorageGarbageCollector.FilterOrphanFiles(candidateFiles, minAge, now);
|
|
|
|
Assert.Equal(2, orphans.Count);
|
|
Assert.Contains(orphans, x => x.Path.EndsWith("movie.mp4.part"));
|
|
Assert.Contains(orphans, x => x.Path.EndsWith("stream_frag.tmp"));
|
|
Assert.DoesNotContain(orphans, x => x.Path.EndsWith("active.mp4.part"));
|
|
Assert.DoesNotContain(orphans, x => x.Path.EndsWith("finished.mp4"));
|
|
}
|
|
|
|
[Fact]
|
|
public void Gate322_MediaStorageGarbageCollector_CalculatesReclaimableSpace_Correctly()
|
|
{
|
|
var now = new DateTime(2026, 9, 4, 20, 30, 0);
|
|
var candidateFiles = new List<CandidateFileInfo>
|
|
{
|
|
new("C:\\temp\\a.part", 200 * 1024 * 1024, now.AddDays(-2)),
|
|
new("C:\\temp\\b.frag", 300 * 1024 * 1024, now.AddDays(-5))
|
|
};
|
|
|
|
var result = MediaStorageGarbageCollector.AnalyzeReclaimableSpace(candidateFiles, TimeSpan.FromHours(24), now);
|
|
|
|
Assert.Equal(2, result.OrphanCount);
|
|
Assert.Equal(500 * 1024 * 1024, result.TotalReclaimableBytes);
|
|
Assert.Equal(500.0, result.TotalReclaimableMb);
|
|
}
|
|
|
|
[Fact]
|
|
public void Gate323_MediaStorageGarbageCollector_RecognizesAllTemporaryExtensions()
|
|
{
|
|
var tempExts = new[] { ".part", ".tmp", ".frag", ".ytdl", ".download" };
|
|
|
|
foreach (var ext in tempExts)
|
|
{
|
|
Assert.True(MediaStorageGarbageCollector.IsTemporaryExtension($"file{ext}"));
|
|
}
|
|
|
|
Assert.False(MediaStorageGarbageCollector.IsTemporaryExtension("video.mp4"));
|
|
Assert.False(MediaStorageGarbageCollector.IsTemporaryExtension("audio.mp3"));
|
|
Assert.False(MediaStorageGarbageCollector.IsTemporaryExtension("subtitles.vtt"));
|
|
}
|
|
|
|
[Fact]
|
|
public void Gate324_MediaStorageGarbageCollector_PerformsBatchDeletion_Gracefully()
|
|
{
|
|
var filesToDelete = new List<string> { "file1.part", "file2.part", "file3.part" };
|
|
var deletedList = new List<string>();
|
|
|
|
var result = MediaStorageGarbageCollector.ExecuteCleanUpWithDeleter(
|
|
filesToDelete,
|
|
deleter: path =>
|
|
{
|
|
if (path == "file2.part") throw new System.IO.IOException("File in use");
|
|
deletedList.Add(path);
|
|
}
|
|
);
|
|
|
|
Assert.Equal(2, result.SuccessCount);
|
|
Assert.Equal(1, result.FailedCount);
|
|
Assert.Equal(2, deletedList.Count);
|
|
Assert.Contains("file2.part", result.FailedFiles[0].Path);
|
|
}
|
|
}
|