259 lines
8.7 KiB
C#
259 lines
8.7 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using RobotNet10.NavigationTune.Shared.Interfaces;
|
|
using RobotNet10.NavigationTune.Shared.Models;
|
|
|
|
namespace RobotNet10.NavigationTune.Data;
|
|
|
|
/// <summary>
|
|
/// Repository for test runs
|
|
/// </summary>
|
|
public class TestRepository(TuningDbContext context) : ITestRepository
|
|
{
|
|
public async Task<TestRun?> GetByIdAsync(Guid id)
|
|
{
|
|
var testRun = await context.TestRuns
|
|
.Include(r => r.Metrics)
|
|
.Include(r => r.SafetyViolations)
|
|
.FirstOrDefaultAsync(r => r.Id == id);
|
|
|
|
if (testRun != null)
|
|
{
|
|
// Load scenario and parameter set separately
|
|
var scenarioEntity = await context.TestScenarios.FindAsync(testRun.ScenarioId);
|
|
if (scenarioEntity != null)
|
|
testRun.Scenario = scenarioEntity.ToTestScenario();
|
|
|
|
testRun.ParameterSet = await context.ParameterSets.FindAsync(testRun.ParameterSetId);
|
|
}
|
|
|
|
return testRun;
|
|
}
|
|
|
|
public async Task<List<TestRun>> GetAllAsync()
|
|
{
|
|
var testRuns = await context.TestRuns
|
|
.Include(r => r.Metrics)
|
|
.OrderByDescending(r => r.StartTime)
|
|
.ToListAsync();
|
|
|
|
// Load scenarios and parameter sets
|
|
foreach (var testRun in testRuns)
|
|
{
|
|
var scenarioEntity = await context.TestScenarios.FindAsync(testRun.ScenarioId);
|
|
if (scenarioEntity != null)
|
|
testRun.Scenario = scenarioEntity.ToTestScenario();
|
|
|
|
testRun.ParameterSet = await context.ParameterSets.FindAsync(testRun.ParameterSetId);
|
|
}
|
|
|
|
return testRuns;
|
|
}
|
|
|
|
public async Task<int> GetCountAsync()
|
|
{
|
|
return await context.TestRuns.CountAsync();
|
|
}
|
|
|
|
public async Task<List<TestRun>> GetPagedAsync(int skip, int take)
|
|
{
|
|
var testRuns = await context.TestRuns
|
|
.Include(r => r.Metrics)
|
|
.OrderByDescending(r => r.StartTime)
|
|
.Skip(skip)
|
|
.Take(take)
|
|
.ToListAsync();
|
|
|
|
var scenarioIds = testRuns.Select(r => r.ScenarioId).Distinct().ToList();
|
|
var parameterSetIds = testRuns.Select(r => r.ParameterSetId).Distinct().ToList();
|
|
|
|
var scenarios = await context.TestScenarios
|
|
.Where(s => scenarioIds.Contains(s.Id))
|
|
.ToListAsync();
|
|
var parameterSets = await context.ParameterSets
|
|
.Where(p => parameterSetIds.Contains(p.Id))
|
|
.ToListAsync();
|
|
|
|
foreach (var testRun in testRuns)
|
|
{
|
|
var scenarioEntity = scenarios.FirstOrDefault(s => s.Id == testRun.ScenarioId);
|
|
if (scenarioEntity != null)
|
|
testRun.Scenario = scenarioEntity.ToTestScenario();
|
|
|
|
testRun.ParameterSet = parameterSets.FirstOrDefault(p => p.Id == testRun.ParameterSetId);
|
|
}
|
|
|
|
return testRuns;
|
|
}
|
|
|
|
public async Task<List<TestRun>> GetByScenarioAsync(Guid scenarioId)
|
|
{
|
|
var testRuns = await context.TestRuns
|
|
.Include(r => r.Metrics)
|
|
.Where(r => r.ScenarioId == scenarioId)
|
|
.OrderByDescending(r => r.StartTime)
|
|
.ToListAsync();
|
|
|
|
// Load scenarios and parameter sets
|
|
var scenarioEntity = await context.TestScenarios.FindAsync(scenarioId);
|
|
foreach (var testRun in testRuns)
|
|
{
|
|
if (scenarioEntity != null)
|
|
testRun.Scenario = scenarioEntity.ToTestScenario();
|
|
|
|
testRun.ParameterSet = await context.ParameterSets.FindAsync(testRun.ParameterSetId);
|
|
}
|
|
|
|
return testRuns;
|
|
}
|
|
|
|
public async Task<List<TestRun>> GetByParameterSetAsync(Guid parameterSetId)
|
|
{
|
|
var testRuns = await context.TestRuns
|
|
.Include(r => r.Metrics)
|
|
.Where(r => r.ParameterSetId == parameterSetId)
|
|
.OrderByDescending(r => r.StartTime)
|
|
.ToListAsync();
|
|
|
|
// Load scenarios and parameter sets
|
|
var parameterSet = await context.ParameterSets.FindAsync(parameterSetId);
|
|
foreach (var testRun in testRuns)
|
|
{
|
|
var scenarioEntity = await context.TestScenarios.FindAsync(testRun.ScenarioId);
|
|
if (scenarioEntity != null)
|
|
testRun.Scenario = scenarioEntity.ToTestScenario();
|
|
|
|
testRun.ParameterSet = parameterSet;
|
|
}
|
|
|
|
return testRuns;
|
|
}
|
|
|
|
public async Task<List<TestRun>> GetByDateRangeAsync(DateTime from, DateTime to)
|
|
{
|
|
var testRuns = await context.TestRuns
|
|
.Include(r => r.Metrics)
|
|
.Where(r => r.StartTime >= from && r.StartTime <= to)
|
|
.OrderByDescending(r => r.StartTime)
|
|
.ToListAsync();
|
|
|
|
// Load scenarios and parameter sets
|
|
var scenarioIds = testRuns.Select(r => r.ScenarioId).Distinct().ToList();
|
|
var parameterSetIds = testRuns.Select(r => r.ParameterSetId).Distinct().ToList();
|
|
|
|
var scenarios = await context.TestScenarios
|
|
.Where(s => scenarioIds.Contains(s.Id))
|
|
.ToListAsync();
|
|
var parameterSets = await context.ParameterSets
|
|
.Where(p => parameterSetIds.Contains(p.Id))
|
|
.ToListAsync();
|
|
|
|
foreach (var testRun in testRuns)
|
|
{
|
|
var scenarioEntity = scenarios.FirstOrDefault(s => s.Id == testRun.ScenarioId);
|
|
if (scenarioEntity != null)
|
|
testRun.Scenario = scenarioEntity.ToTestScenario();
|
|
|
|
testRun.ParameterSet = parameterSets.FirstOrDefault(p => p.Id == testRun.ParameterSetId);
|
|
}
|
|
|
|
return testRuns;
|
|
}
|
|
|
|
public async Task<Guid> SaveAsync(TestRun testRun)
|
|
{
|
|
context.TestRuns.Add(testRun);
|
|
await context.SaveChangesAsync();
|
|
return testRun.Id;
|
|
}
|
|
|
|
public async Task UpdateAsync(TestRun testRun)
|
|
{
|
|
var entry = context.Entry(testRun);
|
|
if (entry.State == EntityState.Detached)
|
|
context.TestRuns.Update(testRun);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update test run from execution result without loading/replacing navigation properties,
|
|
/// to avoid DbUpdateConcurrencyException when entity was created in another scope.
|
|
/// </summary>
|
|
public async Task UpdateFromResultAsync(
|
|
Guid testRunId,
|
|
TestStatus status,
|
|
DateTime? endTime,
|
|
double duration,
|
|
string? errorMessage,
|
|
TestMetrics? metrics,
|
|
List<SafetyViolation>? safetyViolations)
|
|
{
|
|
var testRun = await context.TestRuns
|
|
.AsNoTracking()
|
|
.FirstOrDefaultAsync(r => r.Id == testRunId);
|
|
if (testRun == null)
|
|
return;
|
|
|
|
testRun.Status = status;
|
|
testRun.EndTime = endTime;
|
|
testRun.Duration = duration;
|
|
testRun.ErrorMessage = errorMessage;
|
|
context.TestRuns.Update(testRun);
|
|
await context.SaveChangesAsync();
|
|
|
|
var existingMetrics = await context.TestMetrics.Where(m => m.TestRunId == testRunId).ToListAsync();
|
|
if (existingMetrics.Count > 0)
|
|
context.TestMetrics.RemoveRange(existingMetrics);
|
|
|
|
var existingViolations = await context.SafetyViolations.Where(v => v.TestRunId == testRunId).ToListAsync();
|
|
if (existingViolations.Count > 0)
|
|
context.SafetyViolations.RemoveRange(existingViolations);
|
|
|
|
if (metrics != null)
|
|
{
|
|
metrics.TestRunId = testRunId;
|
|
if (metrics.Id == default)
|
|
metrics.Id = Guid.NewGuid();
|
|
context.TestMetrics.Add(metrics);
|
|
}
|
|
|
|
if (safetyViolations != null && safetyViolations.Count > 0)
|
|
{
|
|
foreach (var v in safetyViolations)
|
|
{
|
|
v.TestRunId = testRunId;
|
|
if (v.Id == default)
|
|
v.Id = Guid.NewGuid();
|
|
}
|
|
context.SafetyViolations.AddRange(safetyViolations);
|
|
}
|
|
|
|
await context.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task DeleteAsync(Guid id)
|
|
{
|
|
var testRun = await GetByIdAsync(id);
|
|
if (testRun != null)
|
|
{
|
|
context.TestRuns.Remove(testRun);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
}
|
|
|
|
public async Task DeleteManyAsync(IEnumerable<Guid> ids)
|
|
{
|
|
var idList = ids.Distinct().ToList();
|
|
if (idList.Count == 0)
|
|
return;
|
|
|
|
var toRemove = await context.TestRuns
|
|
.Where(r => idList.Contains(r.Id))
|
|
.ToListAsync();
|
|
if (toRemove.Count > 0)
|
|
{
|
|
context.TestRuns.RemoveRange(toRemove);
|
|
await context.SaveChangesAsync();
|
|
}
|
|
}
|
|
}
|