using System; using System.Collections.Generic; using System.Linq; using Paca.Core; using Paca.Mobile.Core; using Xunit; namespace Paca.Tests.Core; /// /// 데스크톱 & 모바일 융합 극한 복원성, 대규모 스트레스 및 엣지 케이스 게이트 (Gate 123 ~ Gate 130) /// 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); } }