tbf/TBFTests/Rig/RegisterReaders/PoseidonCmdStartStop/CliRunnerTest.cs
Michal Buzik c0385c0782 bugfix Parallel CLI Runner
Add parallel execution tests and improve cancellation handling in `CliRunner`

- Introduced new tests (`RunMultipleTimesTestProgram_CheckParalelWork` and `RunMultipleTimesTestProgram_CheckParalelWorkCumulative`) to verify parallel execution behavior.
- Enhanced `SendAsync` and `RunAndCaptureJsonAsync` methods in `CliRunner` with `CancellationToken` support for better task cancellation.
- Refactored process output handling for improved clarity and robustness.
- Added error handling during CLI logger initialization.
2025-10-27 11:38:43 +01:00

172 lines
8.7 KiB
C#

using System;
using System.Collections.Generic;
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 CliRunnerTest
{
[TestMethod]
public void ExtractJson_Test()
{
String allOutput = " {\n \"DeviceId\": \"1000000267\"\n}\n";
CliRunner cliRunner = new CliRunner(false);
string json = cliRunner.ExtractJson(allOutput);
Assert.IsTrue(!string.IsNullOrEmpty(json));
}
[TestMethod]
public void ExtractJson_Test2()
{
String allOutput = "{\n \"NfcTagDetected\": true,\n \"ProductType\": 74,\n \"ProductTypeVersion\": \"B1.0.13\",\n \"DeviceId\": \"1000000267\",\n \"Reading\": \"0003292.1\",\n \"Reading_Totalizer\": \"000329218\",\n \"Reading_Digits\": \"8\",\n \"Reading_Shift\": \"-1\",\n \"Reading_Resolution\": \"-2\",\n \"Reading_Units\": \"2\",\n \"Reading_FlowDirection\": \"3\",\n \"Reading_FlowRate\": \"0\",\n \"CalibrationFactor\": \"3197\",\n \"ReadingComplete\": true,\n \"MeterState\": \"0x02\",\n \"OpticalDataMode\": \"0x00\",\n \"SpreadSpectrumParameters\": \"Disabled: 0xTrue\",\n \"BuildInformation\": \"\"\n}\n";
CliRunner cliRunner = new CliRunner(false);
string json = cliRunner.ExtractJson(allOutput);
Assert.IsTrue(!string.IsNullOrEmpty(json));
}
[TestMethod]
public void TryJsonStringDeserialize_Test()
{
String allOutput = "{\n \"NfcTagDetected\": true,\n \"ProductType\": 74,\n \"ProductTypeVersion\": \"B1.0.13\",\n \"DeviceId\": \"1000000267\",\n \"Reading\": \"0003292.1\",\n \"Reading_Totalizer\": \"000329218\",\n \"Reading_Digits\": \"8\",\n \"Reading_Shift\": \"-1\",\n \"Reading_Resolution\": \"-2\",\n \"Reading_Units\": \"2\",\n \"Reading_FlowDirection\": \"3\",\n \"Reading_FlowRate\": \"0\",\n \"CalibrationFactor\": \"3197\",\n \"ReadingComplete\": true,\n \"MeterState\": \"0x02\",\n \"OpticalDataMode\": \"0x00\",\n \"SpreadSpectrumParameters\": \"Disabled: 0xTrue\",\n \"BuildInformation\": \"\"\n}\n";
CliRunner cliRunner = new CliRunner(false);
string json = cliRunner.ExtractJson(allOutput);
var ok = cliRunner.TryJsonStringDeserialize<JsonDataFromPoseidon>(json, out var dto);
Assert.IsTrue(ok, "Deserialization failed");
Assert.IsNotNull(dto);
Assert.AreEqual("1000000267", dto.DeviceId);
Assert.AreEqual("0003292.1", dto.Reading);
Assert.AreEqual("000329218", dto.Reading_Totalizer);
Assert.AreEqual(true, dto.NfcTagDetected);
Assert.AreEqual(74, dto.ProductType);
}
[TestMethod]
public void RunMultipleTimesTestProgram_CheckParalelWork()
{
SerialPortData serialPort = new SerialPortData("COM3","cmdSleepTest.exe",74);
// Check if the executable exists in current directory
if (!System.IO.File.Exists(serialPort.SerialPortCmdClientPath))
{
Assert.Inconclusive($"Test executable '{serialPort.SerialPortCmdClientPath}' not found. Please ensure cmdSleepTest.exe exists in the test directory.");
return;
}
CliRunner cliRunner = new CliRunner(false);
CliRunner cliRunnerOne = new CliRunner(false);
DateTime StartTime = DateTime.Now;
cliRunnerOne.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
cliRunnerOne.WaitAll();
TimeSpan OneEndTime = DateTime.Now - StartTime;
StartTime = DateTime.Now;
Console.WriteLine($"Start Time Loop: {StartTime.ToString("yyyy-MM-dd HH:mm:ss")}");
for (int i = 0; i < 20; i++)
{
cliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
}
cliRunner.WaitAll();
DateTime EndTime = DateTime.Now;
Console.WriteLine($"End Time Loop: {EndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
TimeSpan delta = EndTime - StartTime;
Console.WriteLine($"Delta Time One process {OneEndTime.Hours:D2}:{OneEndTime.Minutes:D2}:{OneEndTime.Seconds:D2}.{OneEndTime.Milliseconds:D3} " +
$"vs Loop: {delta.Hours:D2}:{delta.Minutes:D2}:{delta.Seconds:D2}.{delta.Milliseconds:D3}");
Console.WriteLine($"Total tasks: {cliRunner.TaskPool.Count}");
foreach (Task<JsonDataFromPoseidon> task in cliRunner.TaskPool)
{
if (task != null)
{
JsonDataFromPoseidon jsonDataFromPoseidon = task.Result;
Console.WriteLine($"Result: {jsonDataFromPoseidon.DeviceId}");
Assert.IsNotNull(jsonDataFromPoseidon);
}
}
// Check that the total time is greater than the sum of the individual times
Assert.IsTrue((cliRunner.TaskPool.Count*OneEndTime.Ticks) > delta.Ticks);
}
[TestMethod]
public async Task RunMultipleTimesTestProgram_CheckParalelWorkCumulative()
{
SerialPortData serialPort = new SerialPortData("COM3","cmdSleepTest.exe",74);
// Check if the executable exists in current directory
if (!System.IO.File.Exists(serialPort.SerialPortCmdClientPath))
{
Assert.Inconclusive($"Test executable '{serialPort.SerialPortCmdClientPath}' not found. Please ensure cmdSleepTest.exe exists in the test directory.");
return;
}
List<CliRunner> cliRunnerList = new List<CliRunner>();
for (int i = 0; i < 20; i++)
cliRunnerList.Add(new CliRunner(false));
CliRunner cliRunnerOne = new CliRunner(false);
DateTime StartTime = DateTime.Now;
cliRunnerOne.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
cliRunnerOne.WaitAll();
TimeSpan OneEndTime = DateTime.Now - StartTime;
StartTime = DateTime.Now;
Console.WriteLine($"Start Time Loop: {StartTime.ToString("yyyy-MM-dd HH:mm:ss")}");
for (int iCliRunner = 0; iCliRunner < cliRunnerList.Count; iCliRunner++)
{
cliRunnerList[iCliRunner].AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort,
SerialPortData.EMeterArg.AllParams);
for (int i = 0; i < 20; i++)
{
cliRunnerList[iCliRunner].AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort,
SerialPortData.EMeterArg.AllParams);
}
}
// Wait for ALL tasks from ALL runners
var allTasks = cliRunnerList.SelectMany(r => r.TaskPool).ToArray();
await Task.WhenAll(allTasks);
DateTime EndTime = DateTime.Now;
Console.WriteLine($"End Time Loop: {EndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
TimeSpan delta = EndTime - StartTime;
Console.WriteLine($"Delta Time One process {OneEndTime.Hours:D2}:{OneEndTime.Minutes:D2}:{OneEndTime.Seconds:D2}.{OneEndTime.Milliseconds:D3} " +
$"vs Loop: {delta.Hours:D2}:{delta.Minutes:D2}:{delta.Seconds:D2}.{delta.Milliseconds:D3}");
Console.WriteLine($"Total tasks: {cliRunnerList.Sum(runner => runner.TaskPool.Count)}");
for (int iCliRunner = 0; iCliRunner < cliRunnerList.Count; iCliRunner++)
{
string results = $"iCliRunner: {iCliRunner}";
foreach (Task<JsonDataFromPoseidon> task in cliRunnerList[iCliRunner].TaskPool)
{
if (task != null)
{
JsonDataFromPoseidon jsonDataFromPoseidon = task.Result;
results += ($" ID: {jsonDataFromPoseidon.DeviceId}");
Assert.IsNotNull(jsonDataFromPoseidon);
}
}
Console.WriteLine(results);
}
// Check that the total time is greater than the sum of the individual times
Assert.IsTrue((cliRunnerList.Count*OneEndTime.Ticks) > delta.Ticks);
}
}
}