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
127
tests/Paca.Tests/Mobile/MobilePacaDropBatchBundleGateTests.cs
Normal file
127
tests/Paca.Tests/Mobile/MobilePacaDropBatchBundleGateTests.cs
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Paca.Mobile.Core;
|
||||
using Xunit;
|
||||
|
||||
namespace Paca.Tests.Mobile;
|
||||
|
||||
/// <summary>
|
||||
/// Gate 167 ~ 170: PacaDrop 다중 미디어 배치 번들링 & 자동 스트리밍 언패커 기계적 검증
|
||||
/// </summary>
|
||||
public class MobilePacaDropBatchBundleGateTests
|
||||
{
|
||||
[Fact]
|
||||
public void Gate167_BatchBundleManifest_Integrity()
|
||||
{
|
||||
var file1Data = Encoding.UTF8.GetBytes("Media Content 1 - 4K Video Stream");
|
||||
var file2Data = Encoding.UTF8.GetBytes("Media Content 2 - 128k Audio Track");
|
||||
|
||||
var entries = new List<BundleEntryMetadata>
|
||||
{
|
||||
new("video1.mp4", file1Data.Length, Convert.ToHexString(SHA256.HashData(file1Data))),
|
||||
new("audio1.mp3", file2Data.Length, Convert.ToHexString(SHA256.HashData(file2Data)))
|
||||
};
|
||||
|
||||
var manifest = new BatchBundleManifest("bundle-001", entries, DateTimeOffset.UtcNow);
|
||||
|
||||
Assert.Equal("bundle-001", manifest.BundleId);
|
||||
Assert.Equal(2, manifest.Entries.Count);
|
||||
Assert.Equal(file1Data.Length + file2Data.Length, manifest.TotalBytes);
|
||||
Assert.True(manifest.VerifyEntry("video1.mp4", file1Data));
|
||||
Assert.False(manifest.VerifyEntry("video1.mp4", Encoding.UTF8.GetBytes("Corrupted")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Gate168_BatchBundle_Pack_And_Unpack_Streaming()
|
||||
{
|
||||
var file1Data = Encoding.UTF8.GetBytes("Payload for Track 1");
|
||||
var file2Data = Encoding.UTF8.GetBytes("Payload for Track 2");
|
||||
|
||||
using var bundleStream = new MemoryStream();
|
||||
|
||||
// 1. 번들 생성 (PC 측 동작 시뮬레이션)
|
||||
await PacaBatchBundlePacker.PackAsync(bundleStream, new Dictionary<string, byte[]>
|
||||
{
|
||||
["intro.mp4"] = file1Data,
|
||||
["outro.mp3"] = file2Data
|
||||
});
|
||||
|
||||
bundleStream.Position = 0;
|
||||
|
||||
// 2. 모바일 언패커로 추출 (모바일 수신 시뮬레이션)
|
||||
var tempExtractDir = Path.Combine(Path.GetTempPath(), "Paca_Test_Bundle_" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(tempExtractDir);
|
||||
|
||||
try
|
||||
{
|
||||
var extractedFiles = await PacaBatchBundleExtractor.ExtractAsync(bundleStream, tempExtractDir);
|
||||
|
||||
Assert.Equal(2, extractedFiles.Count);
|
||||
Assert.True(File.Exists(Path.Combine(tempExtractDir, "intro.mp4")));
|
||||
Assert.True(File.Exists(Path.Combine(tempExtractDir, "outro.mp3")));
|
||||
|
||||
var read1 = await File.ReadAllBytesAsync(Path.Combine(tempExtractDir, "intro.mp4"));
|
||||
var read2 = await File.ReadAllBytesAsync(Path.Combine(tempExtractDir, "outro.mp3"));
|
||||
|
||||
Assert.Equal(file1Data, read1);
|
||||
Assert.Equal(file2Data, read2);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Directory.Exists(tempExtractDir))
|
||||
{
|
||||
Directory.Delete(tempExtractDir, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Gate169_BatchBundle_CorruptedEntry_FailsSafely()
|
||||
{
|
||||
using var garbageStream = new MemoryStream(Encoding.UTF8.GetBytes("Not A Valid Paca Bundle Data"));
|
||||
var tempExtractDir = Path.Combine(Path.GetTempPath(), "Paca_Corrupt_" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(tempExtractDir);
|
||||
|
||||
try
|
||||
{
|
||||
await Assert.ThrowsAnyAsync<Exception>(async () =>
|
||||
{
|
||||
await PacaBatchBundleExtractor.ExtractAsync(garbageStream, tempExtractDir);
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Directory.Exists(tempExtractDir)) Directory.Delete(tempExtractDir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Gate170_AutoIngestToLibraryManager()
|
||||
{
|
||||
var manager = new OfflineLibraryManager();
|
||||
var extractedEntries = new List<BundleExtractedFile>
|
||||
{
|
||||
new("item-1", "video.mp4", 50_000_000, "/temp/video.mp4", true),
|
||||
new("item-2", "song.mp3", 5_000_000, "/temp/song.mp3", true)
|
||||
};
|
||||
|
||||
foreach (var entry in extractedEntries)
|
||||
{
|
||||
manager.RegisterMedia(new OfflineMediaItem(
|
||||
entry.Id,
|
||||
entry.FileName,
|
||||
entry.SizeBytes,
|
||||
entry.FilePath,
|
||||
DateTimeOffset.UtcNow,
|
||||
entry.IsChecksumVerified
|
||||
));
|
||||
}
|
||||
|
||||
Assert.Equal(55_000_000L, manager.TotalPacaBytes);
|
||||
Assert.Equal(2, manager.GetItems(MediaFilter.All, MediaSortOrder.NewestFirst).Count);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue