tbf/TBFTests/Rig/RegisterReaders/PoseidonCmdStartStop/CliRunnerTest.cs
Michal Buzik 2fd2697e3b Fix lost 3.9.2204.0 versioning and improve Poseidon CLI diagnostics
- restore the Morrisville release version metadata
- add end-to-end logs for CLI execution, reader state, parsed results,
  and UI updates
- prevent completed Poseidon reads from being started repeatedly in a cycle
- use a fixed CLI directory and reliable working directory
2026-08-28 12:44:42 +02:00

462 lines
18 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.IsFalse(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.IsFalse(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);
bool 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 SerialPortData_NewDefaults_ShouldUsePoseidonMthTimeout10()
{
SerialPortData serialPort = new SerialPortData(
"COM3",
"HalCli.exe",
SerialPortData.MeterProduct.Poseidon);
string args = serialPort.DefaultArgSettings(SerialPortData.EMeterArg.AllParams);
Assert.AreEqual(
"-p COM3 -m 74 --hat mth --timeout 10 --operation readall",
args);
}
[TestMethod]
public void SerialPortData_HarryHat_ShouldUseHarry()
{
SerialPortData serialPort = new SerialPortData(
"COM3",
"HalCli.exe",
SerialPortData.MeterProduct.Poseidon,
SerialPortData.HatType.Harry,
30);
string args = serialPort.DefaultArgSettings(SerialPortData.EMeterArg.DeviceId);
Assert.AreEqual(
"-p COM3 -m 74 --hat harry --timeout 30 --operation read --parameter DeviceId",
args);
}
[TestMethod]
public void SerialPortData_OldConstructor_ShouldKeepOldMeterType()
{
SerialPortData serialPort = new SerialPortData("COM3", "HalCli.exe", 74);
string args = serialPort.DefaultArgSettings(SerialPortData.EMeterArg.AllParams);
Assert.AreEqual(
"-p COM3 -m 74 --hat mth --timeout 10 --operation readall",
args);
}
[TestMethod]
public void SerialPortData_NewMeterTypes_ShouldGenerateCorrectMeterNames()
{
var testCases = new[]
{
new { Meter = SerialPortData.MeterProduct.Poseidon, Expected = "74" },
new { Meter = SerialPortData.MeterProduct.Ally, Expected = "ally" },
new { Meter = SerialPortData.MeterProduct.IperlPlus, Expected = "iperlplus" },
new { Meter = SerialPortData.MeterProduct.IperlLegacy, Expected = "iperllegacy" }
};
foreach (var testCase in testCases)
{
SerialPortData serialPort = new SerialPortData(
"COM3",
"HalCli.exe",
testCase.Meter);
string args = serialPort.DefaultArgSettings(SerialPortData.EMeterArg.AllParams);
StringAssert.Contains(args, $"-m {testCase.Expected}");
}
}
[TestMethod]
public void SerialPortData_ReadMacros_ShouldGenerateCorrectOperations()
{
SerialPortData serialPort = new SerialPortData(
"COM3",
"HalCliDemo.exe",
SerialPortData.MeterProduct.Poseidon);
serialPort.Macro = "readmacro1";
Assert.AreEqual(
"-p COM3 -m 74 --hat mth --timeout 10 --operation readmacro1",
serialPort.DefaultArgSettings(SerialPortData.EMeterArg.ReadMacro1));
serialPort.Macro = "readmacro2";
Assert.AreEqual(
"-p COM3 -m 74 --hat mth --timeout 10 --operation readmacro2",
serialPort.DefaultArgSettings(SerialPortData.EMeterArg.ReadMacro2));
serialPort.Macro = "readmacro3";
Assert.AreEqual(
"-p COM3 -m 74 --hat mth --timeout 10 --operation readmacro3",
serialPort.DefaultArgSettings(SerialPortData.EMeterArg.ReadMacro3));
serialPort.Macro = "xxx";
Assert.AreEqual(
"-p COM3 -m 74 --hat mth --timeout 10 --operation xxx",
serialPort.DefaultArgSettings(SerialPortData.EMeterArg.AllParams));
}
[TestMethod]
public void SerialPortData_CliPath_ShouldAlwaysUseFixedCliDirectory()
{
SerialPortData serialPort = new SerialPortData(
"COM3",
@"D:\obsolete\HatCliDemo.exe",
SerialPortData.MeterProduct.Poseidon);
Assert.AreEqual(
@"C:\TBF\Cli\HatCliDemo.exe",
serialPort.SerialPortCmdClientPath);
}
[TestMethod]
public void RunMultipleTimesTestProgram_CheckParalelWork()
{
SerialPortData serialPort = new SerialPortData(
"COM3",
"cmdSleepTest.exe",
SerialPortData.MeterProduct.Poseidon,
SerialPortData.HatType.Mth,
10);
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: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: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 (CliTaskInfo taskInfo in cliRunner.TaskPool)
{
Assert.IsNotNull(taskInfo);
Assert.IsNotNull(taskInfo.Task);
if (taskInfo.UseResult)
{
var task = taskInfo.Task as Task<JsonDataFromPoseidon>;
Assert.IsNotNull(task, "Expected Task<JsonDataFromPoseidon>.");
JsonDataFromPoseidon jsonDataFromPoseidon = task.Result;
Console.WriteLine($"Result: {jsonDataFromPoseidon?.DeviceId}");
Assert.IsNotNull(jsonDataFromPoseidon);
}
else
{
Assert.Fail(
$"Task did not complete successfully. State={taskInfo.State}, Status={taskInfo.Task.Status}");
}
}
Assert.IsTrue((cliRunner.TaskPool.Count * oneEndTime.Ticks) > delta.Ticks);
}
[TestMethod]
public async Task RunMultipleTimesTestProgram_CheckParalelWorkCumulative()
{
SerialPortData serialPort = new SerialPortData(
"COM3",
"cmdSleepTest.exe",
SerialPortData.MeterProduct.Poseidon,
SerialPortData.HatType.Mth,
10);
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: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);
}
}
Task[] allTasks = cliRunnerList
.SelectMany(r => r.TaskPool)
.Where(ti => ti != null && ti.Task != null)
.Select(ti => ti.Task)
.ToArray();
await Task.WhenAll(allTasks);
DateTime endTime = DateTime.Now;
Console.WriteLine($"End Time Loop: {endTime: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 (CliTaskInfo taskInfo in cliRunnerList[iCliRunner].TaskPool)
{
Assert.IsNotNull(taskInfo);
Assert.IsNotNull(taskInfo.Task);
if (taskInfo.UseResult)
{
var task = taskInfo.Task as Task<JsonDataFromPoseidon>;
Assert.IsNotNull(task, "Expected Task<JsonDataFromPoseidon>.");
JsonDataFromPoseidon jsonDataFromPoseidon = task.Result;
results += $" ID: {jsonDataFromPoseidon?.DeviceId}";
Assert.IsNotNull(jsonDataFromPoseidon);
}
else
{
Assert.Fail(
$"Task did not complete successfully. Runner={iCliRunner}, State={taskInfo.State}, Status={taskInfo.Task.Status}");
}
}
Console.WriteLine(results);
}
Assert.IsTrue((cliRunnerList.Count * oneEndTime.Ticks) > delta.Ticks);
}
[TestMethod]
public void TryJsonStringDeserialize_ReadMacro1_Test()
{
string allOutput = @"{
""DeviceId"": ""1000000176"",
""MeterState"": ""MB012501A177"",
""CalibrationFactor"": ""3250"",
""Reading_Units"": ""0"",
""Reading_Totalizer"": 0,
""Reading_FlowRate"": 0,
""Reading_FlowDirection"": 0,
""Reading_Digits"": 0,
""Reading_Shift"": 0,
""Reading_Resolution"": 0,
""OpticalDataMode"": ""199"",
""MeterSize"": ""3"",
""ManufactureDate"": ""2026/04/20 00:56:00"",
""ProductType"": ""74"",
""ProductTypeVersion"": ""B1.0.29"",
""CliVersion"": ""2.0.0.0"",
""ReadingComplete"": true,
""NfcTagDetected"": true
}";
CliRunner cliRunner = new CliRunner(false);
string json = cliRunner.ExtractJson(allOutput);
bool ok = cliRunner.TryJsonStringDeserialize<JsonDataFromPoseidon>(json, out var dto);
Assert.IsTrue(ok);
Assert.IsNotNull(dto);
Assert.AreEqual("1000000176", dto.DeviceId);
Assert.AreEqual("MB012501A177", dto.MeterState);
Assert.AreEqual("3250", dto.CalibrationFactor);
Assert.AreEqual("199", dto.OpticalDataMode);
Assert.AreEqual("3", dto.MeterSize);
Assert.AreEqual("74", dto.ProductType);
Assert.AreEqual("2.0.0.0", dto.CliVersion);
Assert.IsTrue(dto.ReadingComplete);
Assert.IsTrue(dto.NfcTagDetected);
}
[TestMethod]
public void TryJsonStringDeserialize_ReadMacro2_Test()
{
string allOutput = @"{
""DeviceId"": ""1000000176"",
""Reading_Units"": ""0"",
""Reading_Totalizer"": 0,
""Reading_FlowRate"": 0,
""Reading_FlowDirection"": 0,
""Reading_Digits"": 0,
""Reading_Shift"": 0,
""Reading_Resolution"": 0,
""ProductType"": ""74"",
""ProductTypeVersion"": ""B1.0.29"",
""CliVersion"": ""2.0.0.0"",
""ReadingComplete"": true,
""NfcTagDetected"": true
}";
CliRunner cliRunner = new CliRunner(false);
string json = cliRunner.ExtractJson(allOutput);
bool ok = cliRunner.TryJsonStringDeserialize<JsonDataFromPoseidon>(json, out var dto);
Assert.IsTrue(ok);
Assert.IsNotNull(dto);
Assert.AreEqual("1000000176", dto.DeviceId);
Assert.AreEqual("0", dto.Reading_Units);
Assert.AreEqual("74", dto.ProductType);
Assert.AreEqual("B1.0.29", dto.ProductTypeVersion);
Assert.AreEqual("2.0.0.0", dto.CliVersion);
Assert.IsTrue(dto.ReadingComplete);
Assert.IsTrue(dto.NfcTagDetected);
}
[TestMethod]
public void TryJsonStringDeserialize_ReadMacro3_Test()
{
string allOutput = @"{
""DeviceId"": ""1000000176"",
""Reading_Units"": ""0"",
""Reading_Totalizer"": 0,
""Reading_FlowRate"": 0,
""Reading_FlowDirection"": 0,
""Reading_Digits"": 0,
""Reading_Shift"": 0,
""Reading_Resolution"": 0,
""CliVersion"": ""2.0.0.0"",
""ReadingComplete"": true,
""NfcTagDetected"": true
}";
CliRunner cliRunner = new CliRunner(false);
string json = cliRunner.ExtractJson(allOutput);
bool ok = cliRunner.TryJsonStringDeserialize<JsonDataFromPoseidon>(json, out var dto);
Assert.IsTrue(ok);
Assert.IsNotNull(dto);
Assert.AreEqual("1000000176", dto.DeviceId);
Assert.AreEqual("0", dto.Reading_Units);
Assert.AreEqual("2.0.0.0", dto.CliVersion);
Assert.IsTrue(dto.ReadingComplete);
Assert.IsTrue(dto.NfcTagDetected);
}
}
}