Adds the portal pair (shadowverse-portal.com deck-builder endpoints) as anonymous routes on the app server. The translation middleware learns a new [NoWireEncryption] attribute that skips both AES calls but keeps the rest of the msgpack + base64 + envelope pipeline intact, matching prod's portal wire profile observed in data_dumps/traffic_prod_deckcode.ndjson. Storage is a 3-minute IMemoryCache — codes are anonymous-global, 4-char lowercase alphanumeric (matches the shortest prod sample). Foil bit is stripped on mint to match prod's normalize-on-encode behaviour. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
57 lines
1.7 KiB
C#
57 lines
1.7 KiB
C#
using Microsoft.Extensions.Caching.Memory;
|
|
using SVSim.EmulatedEntrypoint.Models.Dtos.Responses.DeckBuilder;
|
|
using SVSim.EmulatedEntrypoint.Services;
|
|
|
|
namespace SVSim.UnitTests.Services;
|
|
|
|
public class DeckCodeServiceTests
|
|
{
|
|
private static DeckCodeService NewService(out IMemoryCache cache, IRandom? random = null)
|
|
{
|
|
cache = new MemoryCache(new MemoryCacheOptions());
|
|
return new DeckCodeService(cache, random ?? new SystemRandom());
|
|
}
|
|
|
|
[Test]
|
|
public void Mint_returns_4char_lowercase_alphanumeric_code()
|
|
{
|
|
var svc = NewService(out _);
|
|
|
|
var code = svc.Mint(new DeckPayload { Clan = "1", CardID = new() { 100211010 } });
|
|
|
|
Assert.That(code, Has.Length.EqualTo(4));
|
|
Assert.That(code, Does.Match("^[a-z0-9]+$"));
|
|
}
|
|
|
|
[Test]
|
|
public void Resolve_returns_payload_when_code_unexpired()
|
|
{
|
|
var svc = NewService(out _);
|
|
var original = new DeckPayload { Clan = "4", CardID = new() { 100414020, 100414020 } };
|
|
|
|
var code = svc.Mint(original);
|
|
var resolved = svc.TryResolve(code);
|
|
|
|
Assert.That(resolved, Is.SameAs(original));
|
|
}
|
|
|
|
[Test]
|
|
public void Resolve_returns_null_for_unknown_code()
|
|
{
|
|
var svc = NewService(out _);
|
|
|
|
Assert.That(svc.TryResolve("nope"), Is.Null);
|
|
}
|
|
|
|
[Test]
|
|
public void Resolve_returns_null_after_cache_eviction()
|
|
{
|
|
// Don't sleep for the 3-minute TTL — drop the entry directly to simulate expiry.
|
|
var svc = NewService(out var cache);
|
|
var code = svc.Mint(new DeckPayload { Clan = "1", CardID = new() { 100211010 } });
|
|
cache.Remove(DeckCodeService.CacheKey(code));
|
|
|
|
Assert.That(svc.TryResolve(code), Is.Null);
|
|
}
|
|
}
|