feat(ads/seo/release): v1.2.0 with live Google Ads, isolated ad profile, ads.txt, and SEO/AEO/GEO optimization
This commit is contained in:
parent
a88aafa1e5
commit
0e568f1f0a
975 changed files with 130593 additions and 16783 deletions
|
|
@ -0,0 +1,90 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue