180 lines
7.1 KiB
C#
180 lines
7.1 KiB
C#
using System.IO;
|
|
using System.Net;
|
|
using Paca.App.Services;
|
|
using Paca.App.ViewModels;
|
|
using Paca.Browser.Tabs;
|
|
using Paca.Core.Detection;
|
|
using Paca.Core.Util;
|
|
using Paca.Core.Utils;
|
|
using Paca.Tests.Infrastructure;
|
|
using Xunit;
|
|
|
|
namespace Paca.Tests.Browser;
|
|
|
|
/// <summary>
|
|
/// 21차: 극한 실사용자 프로세스 시뮬레이션 4대 심층 E2E 파이프라인.
|
|
/// </summary>
|
|
public class DeepUserScenarioTests
|
|
{
|
|
[Fact]
|
|
public void 극한시나리오1_멀티탭_복합미디어_탐색_동시슬롯_배치제어_풀라이프사이클()
|
|
{
|
|
using var pipeline = AppScenarioPipeline.Create();
|
|
|
|
// 1. 사용자가 4개의 탭을 열어 서로 다른 사이트 탐색
|
|
pipeline.OpenTab("https://stream1.test/live.m3u8")
|
|
.OpenTab("https://dash.test/manifest.mpd")
|
|
.OpenTab("https://direct.test/movie.mp4")
|
|
.OpenTab("https://youtube.com/watch?v=abcdef12345");
|
|
|
|
Xunit.Assert.Equal(4, pipeline.TabManager.Tabs.Count);
|
|
|
|
// 2. 4개의 미디어가 감지되어 대기열에 순차 진입
|
|
pipeline.SimulateMediaDetection("https://stream1.test/live.m3u8", MediaKind.Hls)
|
|
.SimulateMediaDetection("https://dash.test/manifest.mpd", MediaKind.Dash)
|
|
.SimulateMediaDetection("https://direct.test/movie.mp4", MediaKind.Direct)
|
|
.SimulateMediaDetection("https://youtube.com/watch?v=abcdef12345", MediaKind.Social);
|
|
|
|
pipeline.AssertQueueCount(4);
|
|
pipeline.AssertDetectedCount(4);
|
|
|
|
// 3. 사용자가 다중 선택(Ctrl+A) 후 일괄 일시정지 실행
|
|
pipeline.SelectItems(_ => true)
|
|
.BatchPause();
|
|
|
|
foreach (var item in pipeline.DownloadManager.Items)
|
|
{
|
|
Xunit.Assert.True(item.PausedForResume || item.Status == "일시정지" || item.Status == "대기");
|
|
}
|
|
|
|
// 4. 사용자가 특정 2개만 선택하여 일괄 재개
|
|
pipeline.SelectItems(i => i.Kind == MediaKind.Hls || i.Kind == MediaKind.Direct)
|
|
.BatchResume();
|
|
|
|
var resumedItems = pipeline.DownloadManager.Items.Where(i => i.IsSelected).ToList();
|
|
Xunit.Assert.Equal(2, resumedItems.Count);
|
|
|
|
// 5. 사용자가 나머지 항목 일괄 삭제 실행
|
|
pipeline.SelectItems(i => !i.IsSelected)
|
|
.BatchDelete();
|
|
|
|
pipeline.AssertQueueCount(2);
|
|
}
|
|
|
|
[Fact]
|
|
public void 극한시나리오2_네트워크단절_및_안티봇_지수백오프_복구_파이프라인()
|
|
{
|
|
using var pipeline = AppScenarioPipeline.Create();
|
|
|
|
// 다운로드 항목 생성 및 실패 시뮬레이션
|
|
var item = new DownloadItemViewModel("Resilient Stream")
|
|
{
|
|
MediaUrl = new Uri("https://stream.test/index.m3u8"),
|
|
Kind = MediaKind.Hls,
|
|
Status = "다운로드 중"
|
|
};
|
|
pipeline.DownloadManager.Items.Add(item);
|
|
|
|
// 1. 네트워크 타임아웃 오류 발생
|
|
item.Status = "실패";
|
|
item.Error = "HTTP 503 Service Unavailable";
|
|
item.RetryCount = 1;
|
|
|
|
Xunit.Assert.Equal("실패", item.Status);
|
|
Xunit.Assert.Equal(1, item.RetryCount);
|
|
|
|
// 2. 백오프 후 자동 재시도 복구 시뮬레이션
|
|
item.Status = "대기";
|
|
item.Error = null;
|
|
item.RetryCount++;
|
|
|
|
Xunit.Assert.Equal("대기", item.Status);
|
|
Xunit.Assert.Null(item.Error);
|
|
Xunit.Assert.Equal(2, item.RetryCount);
|
|
|
|
// 3. YouTube 안티봇 n-challenge 토큰 갱신 플래그 검증
|
|
pipeline.Config.AutoUpdateYtDlp = true;
|
|
pipeline.Config.AutoInstallDeno = true;
|
|
Xunit.Assert.True(pipeline.Config.AutoUpdateYtDlp);
|
|
Xunit.Assert.True(pipeline.Config.AutoInstallDeno);
|
|
}
|
|
|
|
[Fact]
|
|
public void 극한시나리오3_멀티작업공간_다중탭_크래시복원_및_재생목록_지속성_파이프라인()
|
|
{
|
|
using var pipeline = AppScenarioPipeline.Create();
|
|
|
|
// 1. 사용자가 여러 탭을 설정 (핀 고정, 음소거, 잠금)
|
|
var tab1 = pipeline.TabManager.NewTab("https://work.test/docs");
|
|
tab1.IsPinned = true;
|
|
tab1.Title = "업무 문서";
|
|
|
|
var tab2 = pipeline.TabManager.NewTab("https://music.test/audio");
|
|
tab2.IsAudioPlaying = true;
|
|
tab2.IsMuted = true;
|
|
tab2.Title = "배경 음악";
|
|
|
|
var tab3 = pipeline.TabManager.NewTab("https://study.test/video");
|
|
tab3.IsLocked = true;
|
|
tab3.Title = "학습 강의";
|
|
|
|
// 2. 재생목록에 트랙 추가
|
|
pipeline.AddPlaylistTrack("https://music.test/stream.m3u8", "배경 음악 트랙", "HLS")
|
|
.AddPlaylistTrack("https://study.test/lecture.mp4", "학습 강의 영상", "MP4");
|
|
|
|
pipeline.AssertPlaylistCount(2);
|
|
|
|
// 3. 세션 스냅샷 캡처 (비정상 종료 또는 앱 재부팅 시뮬레이션)
|
|
var snapshot = pipeline.SaveSession();
|
|
Xunit.Assert.NotNull(snapshot);
|
|
Xunit.Assert.True(snapshot.Urls.Count >= 3);
|
|
|
|
// 4. 새로운 세션에서 콜드 복원
|
|
var newTabManager = new TabManager(() => new TabItem(), _ => { });
|
|
newTabManager.RestoreSession(snapshot);
|
|
|
|
Xunit.Assert.Equal(snapshot.Urls.Count, newTabManager.Tabs.Count);
|
|
|
|
var restoredPinned = newTabManager.Tabs.FirstOrDefault(t => t.Url == "https://work.test/docs");
|
|
Xunit.Assert.NotNull(restoredPinned);
|
|
Xunit.Assert.True(restoredPinned.IsPinned);
|
|
Xunit.Assert.Equal("https://work.test/docs", restoredPinned.Url);
|
|
}
|
|
|
|
[Fact]
|
|
public void 극한시나리오4_스케줄러_게이트_템플릿명명_모바일서버_스트리밍브리지_파이프라인()
|
|
{
|
|
using var pipeline = AppScenarioPipeline.Create();
|
|
|
|
// 1. 야간 스케줄러 및 파일명 템플릿 구성
|
|
var scheduler = new DownloadScheduler("01:00-06:00");
|
|
bool gateOpen = false;
|
|
pipeline.SetScheduleGate(() => gateOpen);
|
|
|
|
// 낮 14:00 시점: 게이트 닫힘
|
|
var daytime = new DateTime(2026, 8, 29, 14, 0, 0);
|
|
Xunit.Assert.False(scheduler.IsOpen(daytime));
|
|
|
|
// 2. 야간 02:30 시점: 게이트 열림
|
|
var nighttime = new DateTime(2026, 8, 29, 2, 30, 0);
|
|
Xunit.Assert.True(scheduler.IsOpen(nighttime));
|
|
|
|
gateOpen = scheduler.IsOpen(nighttime);
|
|
Xunit.Assert.True(gateOpen);
|
|
|
|
// 3. 파일명 템플릿 변환 검증
|
|
var template = "VideoDownloader_{Title}_{Resolution}_{Date}";
|
|
var formattedName = FileNameUtil.ApplyTemplate(template, "Nightly Movie", "1080p", "20260829");
|
|
Xunit.Assert.Equal("VideoDownloader_Nightly Movie_1080p_20260829", formattedName);
|
|
|
|
// 4. 디스크 파일 생성 및 대역폭 리미터 스트림 검증
|
|
var filePath = Path.Combine(pipeline.Config.OutputFolder, formattedName + ".mp4");
|
|
File.WriteAllBytes(filePath, new byte[1024 * 50]); // 50 KB
|
|
|
|
Xunit.Assert.True(File.Exists(filePath));
|
|
using var fileStream = File.OpenRead(filePath);
|
|
using var throttledStream = new ThrottledStream(fileStream, 100 * 1024); // 100 KB/s
|
|
Xunit.Assert.True(throttledStream.CanRead);
|
|
Xunit.Assert.Equal(50 * 1024, throttledStream.Length);
|
|
}
|
|
}
|