298 lines
9.7 KiB
C#
298 lines
9.7 KiB
C#
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using JetBrains.Annotations;
|
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
using TBF.Rig.RegisterReaders.PoseidonCmdStartStop;
|
|
|
|
namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
|
|
{
|
|
[TestClass]
|
|
[TestSubject(typeof(CliRunner))]
|
|
public class CliRunnerTimeoutTest
|
|
{
|
|
private static SerialPortData CreateDefaultSerialPortData()
|
|
{
|
|
return new SerialPortData(
|
|
"COM3",
|
|
"cmdSleepTest.exe",
|
|
SerialPortData.MeterProduct.Poseidon,
|
|
SerialPortData.HatType.Mth,
|
|
30,
|
|
TBF.Rig.RegisterReaders.PoseidonCmdStartStop.GetDescription.ToDescription(SerialPortData.MacroTypes.readall));
|
|
}
|
|
|
|
private static string GetCmdSleepTestPath()
|
|
{
|
|
return CreateDefaultSerialPortData().SerialPortCmdClientPath;
|
|
}
|
|
|
|
private static void EnsureExeExists(string exePath)
|
|
{
|
|
if (!File.Exists(exePath))
|
|
{
|
|
Assert.Inconclusive(
|
|
$"Test executable '{exePath}' not found. " +
|
|
"Please ensure cmdSleepTest.exe exists in the test directory.");
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void SerialPortData_ForTimeoutTests_ShouldUseVersion2Defaults()
|
|
{
|
|
SerialPortData serialPort = CreateDefaultSerialPortData();
|
|
|
|
string args = serialPort.DefaultArgSettings(SerialPortData.EMeterArg.AllParams);
|
|
|
|
Assert.AreEqual(
|
|
"-p COM3 -m Poseidon --hat mth --timeout 30 --operation readall",
|
|
args);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void SerialPortData_ForTimeoutTests_ShouldStillSupportOldMeterType()
|
|
{
|
|
SerialPortData serialPort = new SerialPortData(
|
|
"COM3",
|
|
"cmdSleepTest.exe",
|
|
74);
|
|
|
|
string args = serialPort.DefaultArgSettings(SerialPortData.EMeterArg.AllParams);
|
|
|
|
Assert.AreEqual(
|
|
"-p COM3 -m 74 --hat mth --timeout 10 --operation readall",
|
|
args);
|
|
}
|
|
|
|
[TestMethod]
|
|
public async Task Timeout_ShouldBeDetected_ForLongRunningTask()
|
|
{
|
|
string exePath = GetCmdSleepTestPath();
|
|
EnsureExeExists(exePath);
|
|
|
|
var cliRunner = new CliRunner(false);
|
|
|
|
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=5000");
|
|
|
|
await Task.Delay(200);
|
|
|
|
bool timedOut = cliRunner.TimeOutReceived(100);
|
|
|
|
Assert.IsTrue(timedOut, "Timeout should have been detected.");
|
|
}
|
|
|
|
[TestMethod]
|
|
public async Task CancelUndoneTasksAsTimedOut_ShouldMarkRunningTaskAsTimedOut()
|
|
{
|
|
string exePath = GetCmdSleepTestPath();
|
|
EnsureExeExists(exePath);
|
|
|
|
var cliRunner = new CliRunner(false);
|
|
|
|
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=5000");
|
|
|
|
await Task.Delay(150);
|
|
|
|
cliRunner.CancelUndoneTasksAsTimedOut();
|
|
cliRunner.RefreshTaskStates();
|
|
|
|
Assert.AreEqual(1, cliRunner.TaskPool.Count);
|
|
|
|
var taskInfo = cliRunner.TaskPool.Single();
|
|
|
|
Assert.IsNotNull(taskInfo);
|
|
Assert.AreEqual(CliTaskState.TimedOut, taskInfo.State);
|
|
Assert.IsFalse(taskInfo.UseResult, "Timed out task must not be used.");
|
|
}
|
|
|
|
[TestMethod]
|
|
public void CancelUndoneTasksAsTimedOut_ShouldKeepCompletedTaskCompleted()
|
|
{
|
|
string exePath = GetCmdSleepTestPath();
|
|
EnsureExeExists(exePath);
|
|
|
|
var cliRunner = new CliRunner(false);
|
|
|
|
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=50");
|
|
|
|
try
|
|
{
|
|
cliRunner.WaitAll();
|
|
}
|
|
catch
|
|
{
|
|
// Let assertions inspect states.
|
|
}
|
|
|
|
cliRunner.RefreshTaskStates();
|
|
cliRunner.CancelUndoneTasksAsTimedOut();
|
|
cliRunner.RefreshTaskStates();
|
|
|
|
Assert.AreEqual(1, cliRunner.TaskPool.Count);
|
|
|
|
var taskInfo = cliRunner.TaskPool.Single();
|
|
|
|
Assert.IsNotNull(taskInfo);
|
|
Assert.AreEqual(CliTaskState.Completed, taskInfo.State);
|
|
Assert.IsTrue(taskInfo.UseResult, "Completed task should remain usable.");
|
|
|
|
var task = taskInfo.Task as Task<JsonDataFromPoseidon>;
|
|
|
|
Assert.IsNotNull(task);
|
|
Assert.AreEqual(TaskStatus.RanToCompletion, task.Status);
|
|
Assert.IsNotNull(task.Result);
|
|
Assert.IsFalse(string.IsNullOrEmpty(task.Result.DeviceId));
|
|
}
|
|
|
|
[TestMethod]
|
|
public async Task CancelUndoneTasksAsTimedOut_ShouldKeepDoneTask_AndMarkUndoneTask()
|
|
{
|
|
string exePath = GetCmdSleepTestPath();
|
|
EnsureExeExists(exePath);
|
|
|
|
var cliRunner = new CliRunner(false);
|
|
|
|
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=50");
|
|
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=5000");
|
|
|
|
await Task.Delay(250);
|
|
|
|
cliRunner.RefreshTaskStates();
|
|
|
|
Assert.AreEqual(2, cliRunner.TaskPool.Count);
|
|
Assert.AreEqual(
|
|
1,
|
|
cliRunner.TaskPool.Count(t => t.State == CliTaskState.Completed),
|
|
"Exactly one fast task should be completed before timeout handling.");
|
|
|
|
cliRunner.CancelUndoneTasksAsTimedOut();
|
|
cliRunner.RefreshTaskStates();
|
|
|
|
var doneTask = cliRunner.TaskPool.Single(t => t.State == CliTaskState.Completed);
|
|
var timedOutTask = cliRunner.TaskPool.Single(t => t.State == CliTaskState.TimedOut);
|
|
|
|
Assert.IsTrue(doneTask.UseResult);
|
|
Assert.IsFalse(timedOutTask.UseResult);
|
|
|
|
var completed = doneTask.Task as Task<JsonDataFromPoseidon>;
|
|
|
|
Assert.IsNotNull(completed);
|
|
Assert.AreEqual(TaskStatus.RanToCompletion, completed.Status);
|
|
Assert.IsNotNull(completed.Result);
|
|
}
|
|
|
|
[TestMethod]
|
|
public async Task AreTasksDone_ShouldReturnTrue_AfterTimeoutCancellation()
|
|
{
|
|
string exePath = GetCmdSleepTestPath();
|
|
EnsureExeExists(exePath);
|
|
|
|
var cliRunner = new CliRunner(false);
|
|
|
|
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=5000");
|
|
|
|
await Task.Delay(150);
|
|
|
|
Assert.IsFalse(
|
|
cliRunner.AreTasksDone(),
|
|
"Task should still be running before timeout cancellation.");
|
|
|
|
cliRunner.CancelUndoneTasksAsTimedOut();
|
|
cliRunner.RefreshTaskStates();
|
|
|
|
Assert.IsTrue(
|
|
cliRunner.AreTasksDone(),
|
|
"After timed out tasks are marked, runner should report no running tasks.");
|
|
}
|
|
|
|
[TestMethod]
|
|
public async Task TimedOutTask_ShouldNotHaveUseResult()
|
|
{
|
|
string exePath = GetCmdSleepTestPath();
|
|
EnsureExeExists(exePath);
|
|
|
|
var cliRunner = new CliRunner(false);
|
|
|
|
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(exePath, "sleep=5000");
|
|
|
|
await Task.Delay(150);
|
|
|
|
cliRunner.CancelUndoneTasksAsTimedOut();
|
|
cliRunner.RefreshTaskStates();
|
|
|
|
var taskInfo = cliRunner.TaskPool.Single();
|
|
|
|
Assert.AreEqual(CliTaskState.TimedOut, taskInfo.State);
|
|
Assert.IsFalse(taskInfo.UseResult);
|
|
}
|
|
|
|
[TestMethod]
|
|
public async Task MultipleSlowTasks_ShouldAllBeMarkedTimedOut()
|
|
{
|
|
string exePath = GetCmdSleepTestPath();
|
|
EnsureExeExists(exePath);
|
|
|
|
var cliRunner = new CliRunner(false);
|
|
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(
|
|
exePath,
|
|
"sleep=5000");
|
|
}
|
|
|
|
await Task.Delay(200);
|
|
|
|
cliRunner.CancelUndoneTasksAsTimedOut();
|
|
cliRunner.RefreshTaskStates();
|
|
|
|
Assert.AreEqual(5, cliRunner.TaskPool.Count);
|
|
Assert.AreEqual(5, cliRunner.TaskPool.Count(t => t.State == CliTaskState.TimedOut));
|
|
Assert.AreEqual(0, cliRunner.TaskPool.Count(t => t.UseResult));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void FastTask_WithInvalidJson_ShouldFinishButNotProduceUsefulResult()
|
|
{
|
|
string exePath = GetCmdSleepTestPath();
|
|
EnsureExeExists(exePath);
|
|
|
|
var cliRunner = new CliRunner(false);
|
|
|
|
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(
|
|
exePath,
|
|
"sleep=50 invalidjson=true");
|
|
|
|
try
|
|
{
|
|
cliRunner.WaitAll();
|
|
}
|
|
catch
|
|
{
|
|
// Let assertions inspect states.
|
|
}
|
|
|
|
cliRunner.RefreshTaskStates();
|
|
|
|
Assert.AreEqual(1, cliRunner.TaskPool.Count);
|
|
|
|
var taskInfo = cliRunner.TaskPool.Single();
|
|
|
|
Assert.AreEqual(CliTaskState.Completed, taskInfo.State);
|
|
|
|
var task = taskInfo.Task as Task<JsonDataFromPoseidon>;
|
|
|
|
Assert.IsNotNull(task);
|
|
Assert.AreEqual(TaskStatus.RanToCompletion, task.Status);
|
|
|
|
// Depending on TryJsonStringDeserialize fallback,
|
|
// result may be null or an empty/default object.
|
|
if (task.Result != null)
|
|
{
|
|
Assert.IsTrue(
|
|
string.IsNullOrEmpty(task.Result.DeviceId),
|
|
"Invalid JSON should not produce a valid DeviceId.");
|
|
}
|
|
}
|
|
}
|
|
} |