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
100
tests/Paca.Tests/App/ThumbnailCacheServiceGateTests.cs
Normal file
100
tests/Paca.Tests/App/ThumbnailCacheServiceGateTests.cs
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Paca.App.Services;
|
||||
using Paca.Core.Config;
|
||||
using Xunit;
|
||||
|
||||
namespace Paca.Tests.App;
|
||||
|
||||
public class ThumbnailCacheServiceGateTests : IDisposable
|
||||
{
|
||||
private readonly string _tempDir;
|
||||
private readonly ThumbnailCacheService _service;
|
||||
|
||||
public ThumbnailCacheServiceGateTests()
|
||||
{
|
||||
_tempDir = Path.Combine(Path.GetTempPath(), "paca_thumb_test_" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(_tempDir);
|
||||
_service = new ThumbnailCacheService(new AppConfig(), _tempDir);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(_tempDir))
|
||||
Directory.Delete(_tempDir, true);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Gate_SaveBase64Thumbnail_DecodesAndWritesFile()
|
||||
{
|
||||
// 1x1 투명/단색 픽셀 mock base64 (JFIF header)
|
||||
var fakeJpgBytes = new byte[] { 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0xFF, 0xD9 };
|
||||
var b64 = "data:image/jpeg;base64," + Convert.ToBase64String(fakeJpgBytes);
|
||||
|
||||
var filePath = await _service.SaveBase64ThumbnailAsync(b64, "video_123");
|
||||
|
||||
Assert.NotNull(filePath);
|
||||
Assert.True(File.Exists(filePath));
|
||||
var readBytes = await File.ReadAllBytesAsync(filePath);
|
||||
Assert.Equal(fakeJpgBytes, readBytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Gate_DownloadAndCacheThumbnail_SendsRefererAndCaches()
|
||||
{
|
||||
var fakeJpgBytes = new byte[] { 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0xFF, 0xD9 };
|
||||
string? capturedReferer = null;
|
||||
|
||||
var handler = new FakeHttpHandler(req =>
|
||||
{
|
||||
capturedReferer = req.Headers.Referrer?.ToString();
|
||||
return new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new ByteArrayContent(fakeJpgBytes)
|
||||
};
|
||||
});
|
||||
|
||||
var customService = new ThumbnailCacheService(new AppConfig(), _tempDir, new HttpClient(handler));
|
||||
var filePath = await customService.DownloadAndCacheThumbnailAsync(
|
||||
"https://img.ruliweb.com/thumb/1a099d.jpg",
|
||||
"https://bbs.ruliweb.com/best/123",
|
||||
"ruliweb_123"
|
||||
);
|
||||
|
||||
Assert.NotNull(filePath);
|
||||
Assert.True(File.Exists(filePath));
|
||||
Assert.Equal("https://bbs.ruliweb.com/best/123", capturedReferer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Gate_EnsureThumbnail_RoutesDataUriOrHttpProperly()
|
||||
{
|
||||
var fakeJpgBytes = new byte[] { 0xFF, 0xD8, 0xFF, 0xD9 };
|
||||
var b64 = "data:image/jpeg;base64," + Convert.ToBase64String(fakeJpgBytes);
|
||||
|
||||
var result = await _service.EnsureThumbnailAsync(
|
||||
rawThumbOrPoster: b64,
|
||||
mediaUrl: "https://example.com/video.mp4",
|
||||
referer: "https://example.com"
|
||||
);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.True(File.Exists(result));
|
||||
}
|
||||
|
||||
private sealed class FakeHttpHandler : HttpMessageHandler
|
||||
{
|
||||
private readonly Func<HttpRequestMessage, HttpResponseMessage> _handler;
|
||||
public FakeHttpHandler(Func<HttpRequestMessage, HttpResponseMessage> handler) => _handler = handler;
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
|
||||
=> Task.FromResult(_handler(request));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue