first commit
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
using Fragalytics.Web;
|
||||
using Fragalytics.Web.Infrastructure;
|
||||
using Fragalytics.Web.Models;
|
||||
using Fragalytics.Web.Services;
|
||||
using Fragalytics.Web.Services.Parser;
|
||||
using Fragalytics.Web.Services.Render;
|
||||
using Fragalytics.Web.Services.Scoring;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
var failures = new List<string>();
|
||||
|
||||
try
|
||||
{
|
||||
RunScoringTest();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
failures.Add($"Scoring test failed: {exception.Message}");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await RunFlowTestAsync();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
failures.Add($"Flow test failed: {exception.Message}");
|
||||
}
|
||||
|
||||
if (failures.Count > 0)
|
||||
{
|
||||
foreach (var failure in failures)
|
||||
{
|
||||
Console.Error.WriteLine(failure);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
Console.WriteLine("All tests passed.");
|
||||
return 0;
|
||||
|
||||
static void RunScoringTest()
|
||||
{
|
||||
var rules = new HighlightScoringRules
|
||||
{
|
||||
Weights = new Dictionary<string, double>
|
||||
{
|
||||
["base_kill"] = 10,
|
||||
["headshot"] = 8,
|
||||
["opening_kill"] = 12,
|
||||
["wallbang"] = 10,
|
||||
["smoke_kill"] = 10,
|
||||
["round_win"] = 6,
|
||||
["multikill_2"] = 8,
|
||||
["multikill_3"] = 18,
|
||||
["multikill_4"] = 30,
|
||||
["multikill_5"] = 45,
|
||||
["clutch_1v2"] = 18,
|
||||
["clutch_1v3"] = 28,
|
||||
["clutch_1v4"] = 40,
|
||||
["clutch_1v5"] = 55,
|
||||
["impact_last_enemy"] = 12,
|
||||
["impact_low_time"] = 4
|
||||
},
|
||||
Clip = new ClipWindowRules { PreTicks = 160, PostTicks = 96 },
|
||||
Thresholds = new ScoreThresholdRules { HighlightScoreMin = 18 }
|
||||
};
|
||||
|
||||
var scorer = new HighlightScorer(rules);
|
||||
var round = new RoundRecord { Id = 1, Number = 3, WinnerSide = "CT" };
|
||||
var players = new Dictionary<int, PlayerRecord>
|
||||
{
|
||||
[7] = new() { Id = 7, Name = "Alpha", Side = "CT" }
|
||||
};
|
||||
|
||||
var first = new EventRecord { Id = 1, RoundId = 1, Tick = 100, ActorPlayerId = 7, EventType = "kill" };
|
||||
var target = new EventRecord
|
||||
{
|
||||
Id = 2,
|
||||
RoundId = 1,
|
||||
Tick = 450,
|
||||
Second = 38,
|
||||
ActorPlayerId = 7,
|
||||
EventType = "kill",
|
||||
IsHeadshot = true,
|
||||
KillerAliveCount = 1,
|
||||
EnemyAliveCount = 3
|
||||
};
|
||||
|
||||
var result = scorer.ScoreKill(target, round, [first, target], players, 1);
|
||||
|
||||
Assert(result.Score >= 18, "Expected score above threshold.");
|
||||
Assert(result.Tags.Contains("headshot"), "Expected headshot tag.");
|
||||
Assert(result.Tags.Contains("multikill"), "Expected multikill tag.");
|
||||
Assert(result.Tags.Contains("clutch"), "Expected clutch tag.");
|
||||
Assert(result.Tags.Contains("1vX"), "Expected 1vX tag.");
|
||||
}
|
||||
|
||||
static async Task RunFlowTestAsync()
|
||||
{
|
||||
var root = Path.Combine(Path.GetTempPath(), "fragalytics-tests", Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(root);
|
||||
Directory.CreateDirectory(Path.Combine(root, "data"));
|
||||
Directory.CreateDirectory(Path.Combine(root, "uploads"));
|
||||
|
||||
var environment = new FakeEnvironment(root);
|
||||
var options = Options.Create(new FragalyticsOptions
|
||||
{
|
||||
DataDirectory = Path.Combine(root, "data"),
|
||||
UploadDirectory = Path.Combine(root, "uploads"),
|
||||
AutoStartWorker = false
|
||||
});
|
||||
|
||||
var scoringRulesSource = Path.GetFullPath(
|
||||
Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "..", "src", "Fragalytics.Web", "scoring-rules.json"));
|
||||
File.Copy(
|
||||
scoringRulesSource,
|
||||
Path.Combine(root, "scoring-rules.json"),
|
||||
overwrite: true);
|
||||
|
||||
var store = new JsonAppStore(options);
|
||||
var scoringProvider = new ScoringRulesProvider(environment);
|
||||
var renderWorker = new NoOpRenderWorkerAdapter();
|
||||
var scoring = new MatchScoringService(scoringProvider, renderWorker);
|
||||
var ingest = new DemoIngestService(store, options, new SampleDemoParserAdapter(), scoring);
|
||||
var clipMedia = new ClipMediaService(store, options);
|
||||
|
||||
await using var payload = new MemoryStream("fake demo bytes"u8.ToArray());
|
||||
var demoId = await ingest.SaveUploadAsync("sample.dem", payload, CancellationToken.None);
|
||||
Assert(demoId == 1, "Expected first demo id to be 1.");
|
||||
|
||||
await ingest.ProcessNextAsync(CancellationToken.None);
|
||||
|
||||
var state = await store.GetSnapshotAsync();
|
||||
Assert(state.Demos.Count == 1, "Expected one demo.");
|
||||
Assert(state.Demos[0].Status == "parsed", "Expected parsed demo status.");
|
||||
Assert(state.Matches.Count == 1, "Expected one match.");
|
||||
Assert(state.Highlights.Count > 0, "Expected highlights.");
|
||||
Assert(state.ClipJobs.Count == state.Highlights.Count, "Expected one clip job per highlight.");
|
||||
|
||||
await using var clipPayload = new MemoryStream("fake rendered mp4 bytes"u8.ToArray());
|
||||
await clipMedia.AttachClipAssetAsync(state.ClipJobs[0].Id, "sample.mp4", "video/mp4", clipPayload, CancellationToken.None);
|
||||
state = await store.GetSnapshotAsync();
|
||||
Assert(state.ClipAssets.Count == 1, "Expected one clip asset.");
|
||||
Assert(state.ClipJobs[0].Status == "rendered", "Expected rendered clip status after attach.");
|
||||
Assert(state.ClipJobs[0].Payload.ContainsKey("cameraMode"), "Expected render payload defaults on clip job.");
|
||||
|
||||
await ingest.RescoreAllAsync(CancellationToken.None);
|
||||
state = await store.GetSnapshotAsync();
|
||||
Assert(state.Highlights.Count > 0, "Expected highlights after rescoring.");
|
||||
}
|
||||
|
||||
static void Assert(bool condition, string message)
|
||||
{
|
||||
if (!condition)
|
||||
{
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class FakeEnvironment : IWebHostEnvironment
|
||||
{
|
||||
public FakeEnvironment(string rootPath)
|
||||
{
|
||||
ContentRootPath = rootPath;
|
||||
ContentRootFileProvider = new PhysicalFileProvider(rootPath);
|
||||
WebRootPath = rootPath;
|
||||
WebRootFileProvider = new PhysicalFileProvider(rootPath);
|
||||
ApplicationName = "Fragalytics.Web.Tests";
|
||||
EnvironmentName = "Development";
|
||||
}
|
||||
|
||||
public string ApplicationName { get; set; }
|
||||
public IFileProvider WebRootFileProvider { get; set; }
|
||||
public string WebRootPath { get; set; }
|
||||
public string EnvironmentName { get; set; }
|
||||
public string ContentRootPath { get; set; }
|
||||
public IFileProvider ContentRootFileProvider { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user