import_viewer: round-trip ViewerStoryProgress with per-family offsets

This commit is contained in:
gamer147
2026-06-23 20:05:13 -04:00
parent 2cb254553f
commit 79e936dcf2
3 changed files with 206 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using SVSim.Database;
using SVSim.Database.Entities.Story;
using SVSim.Database.Enums;
using SVSim.Database.Models;
using SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Admin;
@@ -796,4 +797,142 @@ public class AdminControllerTests
.SingleAsync(m => m.ViewerId == viewerId && m.MissionCatalogId == 9005);
Assert.That(mission.Slot, Is.EqualTo(3));
}
[Test]
public async Task ImportViewer_StoryProgress_OffsetsByFamily()
{
using var factory = new SVSimTestFactory();
using (var seedScope = factory.Services.CreateScope())
{
var db = seedScope.ServiceProvider.GetRequiredService<SVSimDbContext>();
db.StoryWorlds.Add(new StoryWorld { Id = 5 }); // Main
db.StoryWorlds.Add(new StoryWorld { Id = 10_000_005 }); // Limited
db.StoryWorlds.Add(new StoryWorld { Id = 20_000_005 }); // Event
await db.SaveChangesAsync();
}
var client = factory.CreateClient();
ulong steamId = 70000000000000007UL;
var resp = await client.PostAsJsonAsync("/admin/import_viewer", new ImportViewerRequest
{
SteamId = steamId,
StoryProgress = new List<ImportStoryProgress>
{
new() { StoryApiType = 1, StoryId = 5, IsFinish = true, IsSkipped = false },
new() { StoryApiType = 2, StoryId = 5, IsFinish = false, IsSkipped = true },
new() { StoryApiType = 3, StoryId = 5, IsFinish = true, IsSkipped = true }
}
});
resp.EnsureSuccessStatusCode();
var body = await resp.Content.ReadFromJsonAsync<ImportViewerResponse>(JsonOptions);
Assert.That(body!.SkippedStoryCount, Is.EqualTo(0));
using var scope = factory.Services.CreateScope();
var verifyDb = scope.ServiceProvider.GetRequiredService<SVSimDbContext>();
var viewerId = await verifyDb.Viewers
.Where(v => v.SocialAccountConnections
.Any(s => s.AccountType == SocialAccountType.Steam && s.AccountId == steamId))
.Select(v => v.Id).SingleAsync();
var ids = verifyDb.ViewerStoryProgress.Where(p => p.ViewerId == viewerId).Select(p => p.StoryId).ToList();
Assert.That(ids, Is.EquivalentTo(new[] { 5, 10_000_005, 20_000_005 }));
}
[Test]
public async Task ImportViewer_StoryProgress_SubChapterUsesSubId()
{
using var factory = new SVSimTestFactory();
using (var seedScope = factory.Services.CreateScope())
{
var db = seedScope.ServiceProvider.GetRequiredService<SVSimDbContext>();
db.StoryWorlds.Add(new StoryWorld { Id = 10 }); // parent chapter
db.StoryWorlds.Add(new StoryWorld { Id = 11 }); // sub_chapter (own row)
await db.SaveChangesAsync();
}
var client = factory.CreateClient();
ulong steamId = 70000000000000008UL;
var resp = await client.PostAsJsonAsync("/admin/import_viewer", new ImportViewerRequest
{
SteamId = steamId,
StoryProgress = new List<ImportStoryProgress>
{
new() { StoryApiType = 1, StoryId = 10, IsFinish = true, IsSkipped = false },
new() { StoryApiType = 1, StoryId = 10, SubChapterId = 11, IsFinish = true, IsSkipped = true }
}
});
resp.EnsureSuccessStatusCode();
using var scope = factory.Services.CreateScope();
var verifyDb = scope.ServiceProvider.GetRequiredService<SVSimDbContext>();
var viewerId = await verifyDb.Viewers
.Where(v => v.SocialAccountConnections
.Any(s => s.AccountType == SocialAccountType.Steam && s.AccountId == steamId))
.Select(v => v.Id).SingleAsync();
var ids = verifyDb.ViewerStoryProgress.Where(p => p.ViewerId == viewerId).Select(p => p.StoryId).ToList();
Assert.That(ids, Is.EquivalentTo(new[] { 10, 11 }));
}
[Test]
public async Task ImportViewer_StoryProgress_UnknownStoryIdSkipped()
{
using var factory = new SVSimTestFactory();
var client = factory.CreateClient();
ulong steamId = 70000000000000009UL;
var resp = await client.PostAsJsonAsync("/admin/import_viewer", new ImportViewerRequest
{
SteamId = steamId,
StoryProgress = new List<ImportStoryProgress>
{
new() { StoryApiType = 1, StoryId = 9999, IsFinish = true, IsSkipped = false }
}
});
resp.EnsureSuccessStatusCode();
var body = await resp.Content.ReadFromJsonAsync<ImportViewerResponse>(JsonOptions);
Assert.That(body!.SkippedStoryCount, Is.EqualTo(1));
using var scope = factory.Services.CreateScope();
var verifyDb = scope.ServiceProvider.GetRequiredService<SVSimDbContext>();
Assert.That(verifyDb.ViewerStoryProgress.Any(), Is.False);
}
[Test]
public async Task ImportViewer_AllNewSections_AreIdempotentOnReImport()
{
using var factory = new SVSimTestFactory();
using (var seedScope = factory.Services.CreateScope())
{
var db = seedScope.ServiceProvider.GetRequiredService<SVSimDbContext>();
db.MissionCatalog.Add(new MissionCatalogEntry { Id = 8001, LotType = 6, EventType = "x", EventArg = null });
db.AchievementCatalog.Add(new AchievementCatalogEntry { AchievementType = 800, Level = 1, EventType = "y", EventArg = null });
db.StoryWorlds.Add(new StoryWorld { Id = 50 });
await db.SaveChangesAsync();
}
var client = factory.CreateClient();
ulong steamId = 70000000000000010UL;
var req = new ImportViewerRequest
{
SteamId = steamId,
MissionMeta = new ImportMissionMeta { HasReceivedPickTwoMission = true, MissionReceiveType = 1, MissionChangeTime = 1L },
Missions = new List<ImportMission> { new() { MissionId = 8001, MissionStatus = 1, TotalCount = 5 } },
Achievements = new List<ImportAchievement> { new() { AchievementType = 800, Level = 1, NowAchievedLevel = 1, ResultAnnounceSawLevel = 0, TotalCount = 9 } },
StoryProgress = new List<ImportStoryProgress> { new() { StoryApiType = 1, StoryId = 50, IsFinish = true } }
};
(await client.PostAsJsonAsync("/admin/import_viewer", req)).EnsureSuccessStatusCode();
(await client.PostAsJsonAsync("/admin/import_viewer", req)).EnsureSuccessStatusCode();
using var scope = factory.Services.CreateScope();
var verifyDb = scope.ServiceProvider.GetRequiredService<SVSimDbContext>();
var viewerId = await verifyDb.Viewers
.Where(v => v.SocialAccountConnections
.Any(s => s.AccountType == SocialAccountType.Steam && s.AccountId == steamId))
.Select(v => v.Id).SingleAsync();
Assert.That(verifyDb.ViewerMissions.Count(m => m.ViewerId == viewerId), Is.EqualTo(1));
Assert.That(verifyDb.ViewerAchievements.Count(a => a.ViewerId == viewerId), Is.EqualTo(1));
Assert.That(verifyDb.ViewerStoryProgress.Count(p => p.ViewerId == viewerId), Is.EqualTo(1));
Assert.That(verifyDb.ViewerEventCounters.Count(c => c.ViewerId == viewerId), Is.EqualTo(2));
}
}