109 lines
4.6 KiB
C#
109 lines
4.6 KiB
C#
using System.Windows;
|
|
using System.Windows.Threading;
|
|
using Microsoft.Web.WebView2.Core;
|
|
using VideoDownloader.Browser;
|
|
using VideoDownloader.Tests.Infrastructure;
|
|
|
|
namespace VideoDownloader.Tests.E2E;
|
|
|
|
/// <summary>
|
|
/// E2E (T3-11/T3-14): 실제 WebView2 에서 권한 정책 응답과 추적 요청 차단·집계를 검증.
|
|
/// TabViewService 와 동일한 배선(PermissionGate/TrackerBlocklist/TrackerCounter)을 사용한다.
|
|
/// </summary>
|
|
[Collection("E2E")]
|
|
public class PermissionTrackerE2ETests
|
|
{
|
|
[Fact]
|
|
public async Task 권한_요청이_정책을_거쳐_허용된다_T3_11()
|
|
{
|
|
using var sta = StaDispatcher.Start();
|
|
var udf = Path.Combine(Path.GetTempPath(), $"vd_e2e_{Guid.NewGuid():N}");
|
|
var result = await sta.InvokeAsync(async () =>
|
|
{
|
|
var window = new Window();
|
|
var browser = new Microsoft.Web.WebView2.Wpf.WebView2();
|
|
window.Content = browser;
|
|
window.Show();
|
|
|
|
var env = await CoreWebView2Environment.CreateAsync(userDataFolder: udf);
|
|
await browser.EnsureCoreWebView2Async(env);
|
|
var cv = browser.CoreWebView2;
|
|
|
|
// TabViewService 배선과 동일: 기억된 판정은 즉시 응답(출처는 이벤트에서 관측된 것으로 기억)
|
|
var gate = new PermissionGate();
|
|
cv.PermissionRequested += (_, e) =>
|
|
{
|
|
var o = VideoDownloader.App.Services.TabViewService.OriginOf(e.Uri);
|
|
gate.Remember("Notifications", o, PermissionVerdict.Allow); // E2E: 알림은 허용 정책
|
|
var verdict = gate.Decide(e.PermissionKind.ToString(), o);
|
|
e.State = verdict == PermissionVerdict.Allow ? CoreWebView2PermissionState.Allow : CoreWebView2PermissionState.Deny;
|
|
e.Handled = true;
|
|
};
|
|
|
|
var html = "<html><body><script>Notification.requestPermission().then(p => { document.title = 'PERM=' + p; });</script></body></html>";
|
|
cv.NavigateToString(html);
|
|
await WaitUntilNavCompleted(cv);
|
|
var title = await Wait.Until(() => Task.FromResult(cv.DocumentTitle ?? ""),
|
|
t => t.StartsWith("PERM=", StringComparison.Ordinal), 10000);
|
|
|
|
window.Close();
|
|
return title;
|
|
});
|
|
|
|
try { Directory.Delete(udf, true); } catch { }
|
|
Assert.Equal("PERM=granted", result);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task 블랙리스트_스크립트가_차단되고_카운터에_집계된다_T3_14()
|
|
{
|
|
using var sta = StaDispatcher.Start();
|
|
var udf = Path.Combine(Path.GetTempPath(), $"vd_e2e_{Guid.NewGuid():N}");
|
|
var result = await sta.InvokeAsync(async () =>
|
|
{
|
|
var window = new Window();
|
|
var browser = new Microsoft.Web.WebView2.Wpf.WebView2();
|
|
window.Content = browser;
|
|
window.Show();
|
|
|
|
var env = await CoreWebView2Environment.CreateAsync(userDataFolder: udf);
|
|
await browser.EnsureCoreWebView2Async(env);
|
|
var cv = browser.CoreWebView2;
|
|
|
|
var bl = new TrackerBlocklist(new[] { "blocked.test" });
|
|
var counter = new TrackerCounter();
|
|
cv.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.All);
|
|
cv.WebResourceRequested += (_, e) =>
|
|
{
|
|
if (!bl.Matches(new Uri(e.Request.Uri))) return;
|
|
e.Response = env.CreateWebResourceResponse(null, 204, "Blocked", "");
|
|
counter.Record(e.Request.Uri);
|
|
};
|
|
|
|
var html = "<html><body><p>tracker-e2e</p>" +
|
|
"<script src=\"https://www.blocked.test/a.js\"></script>" +
|
|
"<script src=\"https://www.blocked.test/b.js\"></script>" +
|
|
"<script src=\"https://ok.example.com/c.js\"></script>" +
|
|
"</body></html>";
|
|
cv.NavigateToString(html);
|
|
await WaitUntilNavCompleted(cv);
|
|
await Wait.Until(() => Task.FromResult(counter.Total), t => t >= 2, 10000);
|
|
|
|
window.Close();
|
|
return counter.Total;
|
|
});
|
|
|
|
try { Directory.Delete(udf, true); } catch { }
|
|
Assert.Equal(2, result); // 정상 도메인(ok.example.com)은 집계되지 않음
|
|
}
|
|
|
|
private static async Task WaitUntilNavCompleted(CoreWebView2 cv)
|
|
{
|
|
var tcs = new TaskCompletionSource();
|
|
EventHandler<CoreWebView2NavigationCompletedEventArgs> h = (_, _) => tcs.TrySetResult();
|
|
cv.NavigationCompleted += h;
|
|
if (tcs.Task.IsCompleted) return;
|
|
await Task.WhenAny(tcs.Task, Task.Delay(15000));
|
|
cv.NavigationCompleted -= h;
|
|
}
|
|
}
|