releases/tests/Paca.Tests/Core/ExtremeResilienceAndStressGateTests.cs

151 lines
5.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Paca.Core;
using Paca.Mobile.Core;
using Xunit;
namespace Paca.Tests.Core;
/// <summary>
/// 데스크톱 & 모바일 융합 극한 복원성, 대규모 스트레스 및 엣지 케이스 게이트 (Gate 123 ~ Gate 130)
/// </summary>
public class ExtremeResilienceAndStressGateTests
{
[Fact]
public void Gate123_MassiveQueue_Stress_And_Virtualization_Audit()
{
var qm = new MobileQueueManager();
// 500개 대규모 큐 아이템 고속 등록
for (int i = 0; i < 500; i++)
{
qm.Enqueue($"https://example.com/video_{i}.mp4", $"Batch Video #{i}");
}
Assert.Equal(500, qm.Items.Count);
// 첫 번째와 마지막 항목 무결성 확인
Assert.Equal("Batch Video #0", qm.Items[0].Title);
Assert.Equal("Batch Video #499", qm.Items[499].Title);
// 일괄 완료 처리 후 청소 성능
for (int i = 0; i < 250; i++)
{
qm.Items[i].Status = MobileQueueStatus.Completed;
}
qm.ClearCompleted();
Assert.Equal(250, qm.Items.Count);
}
[Fact]
public void Gate124_ConcurrentDownloadLock_Audit()
{
var lockEngine = new ConcurrentDownloadLockEngine();
var testUrl = "https://example.com/unique_movie.mp4";
// 첫 번째 세션 락 획득 성공
Assert.True(lockEngine.TryAcquireLock(testUrl, sessionId: "desktop-client"));
// 두 번째 세션(모바일) 동일 URL 시도 시 락 획득 실패 (중복 방지)
Assert.False(lockEngine.TryAcquireLock(testUrl, sessionId: "mobile-client"));
// 첫 번째 세션 락 반환 후 두 번째 세션 재시도 성공
lockEngine.ReleaseLock(testUrl, sessionId: "desktop-client");
Assert.True(lockEngine.TryAcquireLock(testUrl, sessionId: "mobile-client"));
}
[Fact]
public void Gate125_DiskFull_RollbackEngine_Audit()
{
var rollbackEngine = new DiskFullRollbackEngine();
var tempPartFile = System.IO.Path.Combine(System.IO.Path.GetTempPath(), $"paca_temp_{Guid.NewGuid():N}.part");
System.IO.File.WriteAllBytes(tempPartFile, new byte[1024]);
Assert.True(System.IO.File.Exists(tempPartFile));
// 가상 디스크 풀 에러 발생 시 부분 다운로드 임시 파일 안전 롤백(제거)
var result = rollbackEngine.HandleDiskFull(tempPartFile, requiredBytes: 50_000_000, availableBytes: 10_000);
Assert.True(result.IsRollbackSuccessful);
Assert.False(System.IO.File.Exists(tempPartFile));
Assert.Contains("디스크 용량 부족", result.ErrorMessage);
}
[Fact]
public void Gate126_SegmentChunkHealer_CorruptChunkRetry_Audit()
{
var healer = new SegmentChunkHealer();
// 헤더 매직 넘버가 손상된 4바이트 청크
var corruptChunk = new byte[] { 0x00, 0x00, 0x00, 0x00 };
Assert.False(healer.ValidateSegmentIntegrity(corruptChunk, expectedSegmentType: "ts"));
// 정상 TS 세그먼트 Sync byte (0x47)
var validTsChunk = new byte[] { 0x47, 0x40, 0x11, 0x10 };
Assert.True(healer.ValidateSegmentIntegrity(validTsChunk, expectedSegmentType: "ts"));
}
[Fact]
public void Gate127_OAuthTokenRefresher_Audit()
{
var refresher = new OAuthTokenRefresher();
var token = new AuthTokenInfo(AccessToken: "old_token", RefreshToken: "refresh_123", ExpiresAtUtc: DateTime.UtcNow.AddMinutes(-5));
Assert.True(refresher.IsExpired(token));
var newToken = refresher.RefreshToken(token);
Assert.False(refresher.IsExpired(newToken));
Assert.Equal("new_access_token_refresh_123", newToken.AccessToken);
}
[Fact]
public void Gate128_LocalizationResourceValidator_Audit()
{
var loc = new LocalizationResourceCatalog();
var languages = new[] { "ko", "en", "ja", "zh" };
foreach (var lang in languages)
{
Assert.NotNull(loc.GetString("Download", lang));
Assert.NotNull(loc.GetString("Pause", lang));
Assert.NotNull(loc.GetString("Settings", lang));
}
Assert.Equal("다운로드", loc.GetString("Download", "ko"));
Assert.Equal("Download", loc.GetString("Download", "en"));
Assert.Equal("ダウンロード", loc.GetString("Download", "ja"));
Assert.Equal("下载", loc.GetString("Download", "zh"));
}
[Fact]
public void Gate129_QrConfigBackupRestore_Audit()
{
var backup = new QrConfigBackupManager();
var originalPayload = new ConfigBackupPayload("192.168.0.50:52100", "secret_tok_999", "dark", 5120);
var qrString = backup.ExportToQrString(originalPayload);
Assert.StartsWith("PACA_CFG_V1|", qrString);
var restoredPayload = backup.ImportFromQrString(qrString);
Assert.NotNull(restoredPayload);
Assert.Equal(originalPayload.Endpoint, restoredPayload.Endpoint);
Assert.Equal(originalPayload.AuthToken, restoredPayload.AuthToken);
Assert.Equal(originalPayload.Theme, restoredPayload.Theme);
Assert.Equal(originalPayload.SpeedLimitKbps, restoredPayload.SpeedLimitKbps);
}
[Fact]
public void Gate130_MediaTaggingEngine_Audit()
{
var tagger = new MediaTaggingEngine();
var metadata = new MediaMetadataInfo(
Title: "My Epic Video",
Artist: "Creative Creator",
AlbumOrPlaylist: "2026 Hits",
Year: 2026
);
var tagDictionary = tagger.GenerateFfmpegMetadataArgs(metadata);
Assert.Contains("-metadata title=\"My Epic Video\"", tagDictionary);
Assert.Contains("-metadata artist=\"Creative Creator\"", tagDictionary);
Assert.Contains("-metadata album=\"2026 Hits\"", tagDictionary);
Assert.Contains("-metadata date=\"2026\"", tagDictionary);
}
}