贯通车队运行链并支持轨迹自动推导β
This commit is contained in:
@@ -0,0 +1,297 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MultiWheelC.Fleet;
|
||||
using MyParking.Shared;
|
||||
|
||||
namespace MultiWheelC.Tests
|
||||
{
|
||||
internal static class FleetSafetySupervisorTests
|
||||
{
|
||||
private const long PlanId = 7;
|
||||
private const double CurrentTimeSeconds = 10.0;
|
||||
private const double CommunicationTimeoutSeconds = 0.5;
|
||||
|
||||
public static void Run()
|
||||
{
|
||||
VerifyHealthyFleetContinues();
|
||||
VerifyMissingMemberStopsFleet();
|
||||
VerifyCommunicationTimeoutStopsFleet();
|
||||
VerifyUnavailableStateStopsFleet();
|
||||
VerifyMemberFaultStopsFleet();
|
||||
VerifyFailureCodeStopsFleet();
|
||||
VerifyPlanMismatchStopsFleet();
|
||||
VerifyStopIsLatchedUntilNewPlanStarts();
|
||||
|
||||
Console.WriteLine(
|
||||
"FleetSafetySupervisor测试通过,共8个场景。");
|
||||
}
|
||||
|
||||
private static void VerifyHealthyFleetContinues()
|
||||
{
|
||||
var supervisor = CreateStartedSupervisor();
|
||||
|
||||
var decision = supervisor.Evaluate(
|
||||
CreateLayout(),
|
||||
CreateHealthyStatuses(),
|
||||
CurrentTimeSeconds);
|
||||
|
||||
AssertFalse(
|
||||
decision.ShouldStop,
|
||||
"成员状态健康时不应停车");
|
||||
}
|
||||
|
||||
private static void VerifyMissingMemberStopsFleet()
|
||||
{
|
||||
var supervisor = CreateStartedSupervisor();
|
||||
|
||||
var decision = supervisor.Evaluate(
|
||||
CreateLayout(),
|
||||
new[] { CreateHealthyStatus(1) },
|
||||
CurrentTimeSeconds);
|
||||
|
||||
AssertStopFromVehicle(
|
||||
decision,
|
||||
2,
|
||||
"缺少成员报告");
|
||||
}
|
||||
|
||||
private static void VerifyCommunicationTimeoutStopsFleet()
|
||||
{
|
||||
var supervisor = CreateStartedSupervisor();
|
||||
var statuses = new[]
|
||||
{
|
||||
CreateHealthyStatus(1),
|
||||
new FleetMemberSafetyStatus(
|
||||
vehicleId: 2,
|
||||
planId: PlanId,
|
||||
isStateAvailable: true,
|
||||
isFaulted: false,
|
||||
failureCode: 0,
|
||||
lastAcceptedReportTimeSeconds: 9.4)
|
||||
};
|
||||
|
||||
var decision = supervisor.Evaluate(
|
||||
CreateLayout(),
|
||||
statuses,
|
||||
CurrentTimeSeconds);
|
||||
|
||||
AssertStopFromVehicle(
|
||||
decision,
|
||||
2,
|
||||
"通信超时");
|
||||
}
|
||||
|
||||
private static void VerifyUnavailableStateStopsFleet()
|
||||
{
|
||||
var supervisor = CreateStartedSupervisor();
|
||||
var statuses = new[]
|
||||
{
|
||||
CreateHealthyStatus(1),
|
||||
new FleetMemberSafetyStatus(
|
||||
vehicleId: 2,
|
||||
planId: PlanId,
|
||||
isStateAvailable: false,
|
||||
isFaulted: false,
|
||||
failureCode: 0,
|
||||
lastAcceptedReportTimeSeconds: 9.9)
|
||||
};
|
||||
|
||||
var decision = supervisor.Evaluate(
|
||||
CreateLayout(),
|
||||
statuses,
|
||||
CurrentTimeSeconds);
|
||||
|
||||
AssertStopFromVehicle(
|
||||
decision,
|
||||
2,
|
||||
"状态不可用");
|
||||
}
|
||||
|
||||
private static void VerifyMemberFaultStopsFleet()
|
||||
{
|
||||
var supervisor = CreateStartedSupervisor();
|
||||
var statuses = new[]
|
||||
{
|
||||
CreateHealthyStatus(1),
|
||||
new FleetMemberSafetyStatus(
|
||||
vehicleId: 2,
|
||||
planId: PlanId,
|
||||
isStateAvailable: true,
|
||||
isFaulted: true,
|
||||
failureCode: 0,
|
||||
lastAcceptedReportTimeSeconds: 9.9)
|
||||
};
|
||||
|
||||
var decision = supervisor.Evaluate(
|
||||
CreateLayout(),
|
||||
statuses,
|
||||
CurrentTimeSeconds);
|
||||
|
||||
AssertStopFromVehicle(
|
||||
decision,
|
||||
2,
|
||||
"成员故障状态");
|
||||
}
|
||||
|
||||
private static void VerifyFailureCodeStopsFleet()
|
||||
{
|
||||
var supervisor = CreateStartedSupervisor();
|
||||
var statuses = new[]
|
||||
{
|
||||
CreateHealthyStatus(1),
|
||||
new FleetMemberSafetyStatus(
|
||||
vehicleId: 2,
|
||||
planId: PlanId,
|
||||
isStateAvailable: true,
|
||||
isFaulted: false,
|
||||
failureCode: 42,
|
||||
lastAcceptedReportTimeSeconds: 9.9)
|
||||
};
|
||||
|
||||
var decision = supervisor.Evaluate(
|
||||
CreateLayout(),
|
||||
statuses,
|
||||
CurrentTimeSeconds);
|
||||
|
||||
AssertStopFromVehicle(
|
||||
decision,
|
||||
2,
|
||||
"成员故障码");
|
||||
}
|
||||
|
||||
private static void VerifyPlanMismatchStopsFleet()
|
||||
{
|
||||
var supervisor = CreateStartedSupervisor();
|
||||
var statuses = new[]
|
||||
{
|
||||
CreateHealthyStatus(1),
|
||||
new FleetMemberSafetyStatus(
|
||||
vehicleId: 2,
|
||||
planId: PlanId - 1,
|
||||
isStateAvailable: true,
|
||||
isFaulted: false,
|
||||
failureCode: 0,
|
||||
lastAcceptedReportTimeSeconds: 9.9)
|
||||
};
|
||||
|
||||
var decision = supervisor.Evaluate(
|
||||
CreateLayout(),
|
||||
statuses,
|
||||
CurrentTimeSeconds);
|
||||
|
||||
AssertStopFromVehicle(
|
||||
decision,
|
||||
2,
|
||||
"任务编号不一致");
|
||||
}
|
||||
|
||||
private static void VerifyStopIsLatchedUntilNewPlanStarts()
|
||||
{
|
||||
var supervisor = CreateStartedSupervisor();
|
||||
supervisor.Evaluate(
|
||||
CreateLayout(),
|
||||
new[] { CreateHealthyStatus(1) },
|
||||
CurrentTimeSeconds);
|
||||
|
||||
var latchedDecision = supervisor.Evaluate(
|
||||
CreateLayout(),
|
||||
CreateHealthyStatuses(),
|
||||
CurrentTimeSeconds);
|
||||
AssertTrue(
|
||||
latchedDecision.ShouldStop,
|
||||
"故障恢复后停车决定仍应锁存");
|
||||
|
||||
supervisor.Start(PlanId + 1);
|
||||
var recoveredDecision = supervisor.Evaluate(
|
||||
CreateLayout(),
|
||||
new[]
|
||||
{
|
||||
CreateHealthyStatus(1, PlanId + 1),
|
||||
CreateHealthyStatus(2, PlanId + 1)
|
||||
},
|
||||
CurrentTimeSeconds);
|
||||
AssertFalse(
|
||||
recoveredDecision.ShouldStop,
|
||||
"开始新任务后应清除旧任务停车锁存");
|
||||
}
|
||||
|
||||
private static FleetSafetySupervisor
|
||||
CreateStartedSupervisor()
|
||||
{
|
||||
var supervisor = new FleetSafetySupervisor(
|
||||
CommunicationTimeoutSeconds);
|
||||
supervisor.Start(PlanId);
|
||||
return supervisor;
|
||||
}
|
||||
|
||||
private static FleetLayout CreateLayout()
|
||||
{
|
||||
return new FleetLayout(
|
||||
new[]
|
||||
{
|
||||
new VehicleLayout(
|
||||
1,
|
||||
new Pose2D(-1.0, 0.0, 0.0)),
|
||||
new VehicleLayout(
|
||||
2,
|
||||
new Pose2D(1.0, 0.0, Math.PI))
|
||||
});
|
||||
}
|
||||
|
||||
private static IReadOnlyList<FleetMemberSafetyStatus>
|
||||
CreateHealthyStatuses()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
CreateHealthyStatus(1),
|
||||
CreateHealthyStatus(2)
|
||||
};
|
||||
}
|
||||
|
||||
private static FleetMemberSafetyStatus CreateHealthyStatus(
|
||||
int vehicleId,
|
||||
long planId = PlanId)
|
||||
{
|
||||
return new FleetMemberSafetyStatus(
|
||||
vehicleId,
|
||||
planId,
|
||||
isStateAvailable: true,
|
||||
isFaulted: false,
|
||||
failureCode: 0,
|
||||
lastAcceptedReportTimeSeconds: 9.9);
|
||||
}
|
||||
|
||||
private static void AssertStopFromVehicle(
|
||||
FleetSafetyDecision decision,
|
||||
int expectedVehicleId,
|
||||
string scenario)
|
||||
{
|
||||
AssertTrue(
|
||||
decision.ShouldStop,
|
||||
$"{scenario}时应停车");
|
||||
AssertTrue(
|
||||
decision.SourceVehicleId == expectedVehicleId,
|
||||
$"{scenario}的来源车辆不正确");
|
||||
AssertTrue(
|
||||
!string.IsNullOrWhiteSpace(decision.Reason),
|
||||
$"{scenario}应提供停车原因");
|
||||
}
|
||||
|
||||
private static void AssertTrue(
|
||||
bool condition,
|
||||
string message)
|
||||
{
|
||||
if (!condition)
|
||||
{
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AssertFalse(
|
||||
bool condition,
|
||||
string message)
|
||||
{
|
||||
AssertTrue(!condition, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user