Poseidon integration fix, ReadMe_BugFix.md actualisation
This commit is contained in:
parent
b8e54e1fc9
commit
0258e54b4e
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using MySql.Data.MySqlClient;
|
||||
using Common;
|
||||
using log4net;
|
||||
|
||||
namespace Results.Entities.helpers
|
||||
{
|
||||
@ -10,6 +11,8 @@ namespace Results.Entities.helpers
|
||||
/// </summary>
|
||||
public static class DatabaseMigrationHelper
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(DatabaseMigrationHelper));
|
||||
|
||||
public static void EnsureSchema(DBType dbType, string connectionString)
|
||||
{
|
||||
switch (dbType)
|
||||
@ -36,9 +39,31 @@ namespace Results.Entities.helpers
|
||||
// EnsureColumnMySql(conn, "WaterMeter", "Q3Channel", "INT NOT NULL DEFAULT 0");
|
||||
// EnsureColumnMySql(conn, "MeterTestRslt", "Q3Channel", "INT NOT NULL DEFAULT 0");
|
||||
|
||||
EnsureColumnMySql(conn, "MeterTestRslt", "FlipMode", "INT NULL");
|
||||
}
|
||||
}
|
||||
EnsureColumnMySql(conn, "MeterTestRslt", "PulsesPerKilogram", "DOUBLE NOT NULL DEFAULT 0");
|
||||
EnsureMeterTestResultMassColumnsMySql(conn);
|
||||
EnsureColumnMySql(conn, "MeterTestRslt", "FlipMode", "INT NULL");
|
||||
EnsureColumnMySql(conn, "MeterTestRslt", "ExtraDataPath", "VARCHAR(255) NULL");
|
||||
EnsureMeterTestResultExtraColumnsMySql(conn);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureMeterTestResultExtraColumnsMySql(MySqlConnection conn)
|
||||
{
|
||||
for (int index = 1; index <= 9; index++)
|
||||
EnsureColumnMySql(conn, "MeterTestRslt", "X" + index, "FLOAT NOT NULL DEFAULT 0");
|
||||
}
|
||||
|
||||
// These properties were added to the MeterTestRslt NHibernate mapping
|
||||
// after older customer databases had already been created. Keep them in
|
||||
// one migration group so a batch insert does not fail one column at a time.
|
||||
private static void EnsureMeterTestResultMassColumnsMySql(MySqlConnection conn)
|
||||
{
|
||||
EnsureColumnMySql(conn, "MeterTestRslt", "MassMeter", "DOUBLE NOT NULL DEFAULT 0");
|
||||
EnsureColumnMySql(conn, "MeterTestRslt", "MassRef", "DOUBLE NOT NULL DEFAULT 0");
|
||||
EnsureColumnMySql(conn, "MeterTestRslt", "ErrorMass", "DOUBLE NOT NULL DEFAULT 0");
|
||||
EnsureColumnMySql(conn, "MeterTestRslt", "PassedMass", "TINYINT(1) NOT NULL DEFAULT 0");
|
||||
EnsureColumnMySql(conn, "MeterTestRslt", "QuantityUnits", "VARCHAR(32) NULL");
|
||||
}
|
||||
|
||||
private static void EnsureColumnMySql(
|
||||
MySqlConnection conn,
|
||||
@ -74,7 +99,9 @@ namespace Results.Entities.helpers
|
||||
alter.Transaction = transaction;
|
||||
alter.CommandText = "ALTER TABLE `" + tableName + "` ADD COLUMN `" +
|
||||
columnName + "` " + columnDefinition;
|
||||
alter.ExecuteNonQuery();
|
||||
alter.ExecuteNonQuery();
|
||||
log.WarnFormat("Results DB migration: added {0}.{1} ({2}).",
|
||||
tableName, columnName, columnDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,9 +127,28 @@ namespace Results.Entities.helpers
|
||||
// EnsureColumnSQLite(conn, "WaterMeter", "Q3Channel", "INTEGER NOT NULL DEFAULT 0");
|
||||
// EnsureColumnSQLite(conn, "MeterTestRslt", "Q3Channel", "INTEGER NOT NULL DEFAULT 0");
|
||||
|
||||
EnsureColumnSQLite(conn, "MeterTestRslt", "FlipMode", "INTEGER NULL");
|
||||
}
|
||||
}
|
||||
EnsureColumnSQLite(conn, "MeterTestRslt", "PulsesPerKilogram", "REAL NOT NULL DEFAULT 0");
|
||||
EnsureMeterTestResultMassColumnsSQLite(conn);
|
||||
EnsureColumnSQLite(conn, "MeterTestRslt", "FlipMode", "INTEGER NULL");
|
||||
EnsureColumnSQLite(conn, "MeterTestRslt", "ExtraDataPath", "TEXT NULL");
|
||||
EnsureMeterTestResultExtraColumnsSQLite(conn);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureMeterTestResultExtraColumnsSQLite(System.Data.SQLite.SQLiteConnection conn)
|
||||
{
|
||||
for (int index = 1; index <= 9; index++)
|
||||
EnsureColumnSQLite(conn, "MeterTestRslt", "X" + index, "REAL NOT NULL DEFAULT 0");
|
||||
}
|
||||
|
||||
private static void EnsureMeterTestResultMassColumnsSQLite(System.Data.SQLite.SQLiteConnection conn)
|
||||
{
|
||||
EnsureColumnSQLite(conn, "MeterTestRslt", "MassMeter", "REAL NOT NULL DEFAULT 0");
|
||||
EnsureColumnSQLite(conn, "MeterTestRslt", "MassRef", "REAL NOT NULL DEFAULT 0");
|
||||
EnsureColumnSQLite(conn, "MeterTestRslt", "ErrorMass", "REAL NOT NULL DEFAULT 0");
|
||||
EnsureColumnSQLite(conn, "MeterTestRslt", "PassedMass", "INTEGER NOT NULL DEFAULT 0");
|
||||
EnsureColumnSQLite(conn, "MeterTestRslt", "QuantityUnits", "TEXT NULL");
|
||||
}
|
||||
|
||||
private static void EnsureColumnSQLite(
|
||||
System.Data.SQLite.SQLiteConnection conn,
|
||||
@ -136,7 +182,9 @@ namespace Results.Entities.helpers
|
||||
{
|
||||
alter.CommandText = "ALTER TABLE " + tableName + " ADD COLUMN " +
|
||||
columnName + " " + columnDefinition;
|
||||
alter.ExecuteNonQuery();
|
||||
alter.ExecuteNonQuery();
|
||||
log.WarnFormat("Results DB migration: added {0}.{1} ({2}).",
|
||||
tableName, columnName, columnDefinition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,3 +3,14 @@
|
||||
| Version | Source of change | Target Environment | Title | Description |
|
||||
|------------|----------------------|--------------------------------------------------------------|-----------------------------------------------------|------------------------------------|
|
||||
| 3.9.2149.0 | Michal databse error | HeatMeters, Heat meter sensors, Procedure Dilog, Tab Process | Excanged columns value 'Sensor' and 'Heat meter sensor' | Fix in code ProcedureDlg, row 1851 |
|
||||
| 3.9.2149.1 | Main TBF | General release | Version iteration | Assembly and file version increment. |
|
||||
| 3.9.2149.2 | Main TBF | Poseidon register reader | Poseidon pulse and timing handling | Added reference-pulse reading in `Run()` and improved Poseidon timing/task tracking. |
|
||||
| 3.9.2149.4 | Main TBF | Mass collection / Poseidon start-stop | Mass collection update | Refactored standing-start mass collection, extended Poseidon start/end data-entry configuration and improved dialog/task handling. |
|
||||
| 3.9.2200.1 | Main TBF | Test infrastructure | TBF test assembly access | Added `InternalsVisibleTo` support for `TBFTests`. |
|
||||
| 3.9.2201.1 | Main TBF | Poseidon CLI | Poseidon CLI configuration | Added macro descriptions, refined serial-port/CLI argument configuration and extended CLI test coverage. |
|
||||
| 3.9.2202.1 | Main TBF | Poseidon CLI | CLI release iteration | Assembly and file version increment for the Poseidon CLI workstream. |
|
||||
| 3.9.2203.1 | Main TBF | Poseidon CLI / smart-meter sequence | CLI test and configuration update | Updated CLI executable test setup, serial-port default responses and smart-meter component-name handling. |
|
||||
| 3.9.2204.1 | Morrisville | Morrisville / Poseidon CLI | Morrisville CLI diagnostics | Restored lost 2204 versioning, added detailed CLI command/response logging and used a fixed CLI directory for deployment. |
|
||||
| 3.9.2205.1 | Morrisville | Morrisville / Poseidon CLI / Results DB | Poseidon read diagnostics and results DB migration | Improved Poseidon CLI execution and diagnostics: fixed CLI working directory, exit code/stdout/stderr capture, JSON/NFC/reading validation and culture-independent decimal parsing. Added reader-cycle and fake-CLI coverage. Results DB now creates missing compatibility columns (`FlipMode`, `ExtraDataPath`, `X1`-`X9`) automatically for MySQL and SQLite. |
|
||||
| 3.9.2206.0 | Morrisville / Main TBF | Poseidon CLI / Results DB | Poseidon start/end rearm and simulation isolation | Re-armed a completed START reader once for END, preventing reused START values or skipped END CLI calls. Added CLI response, dialog prefill and confirmed-value diagnostics. Simulation always runs `C:\TBF\Cli\cmdSleepTest.exe` instead of the configured physical Hat CLI. Added customer-response, decimal separator, non-zero, dialog-transfer, reader-cycle and simulation-selection regression tests. Added compatibility migration for `PulsesPerKilogram`, `MassMeter`, `MassRef`, `ErrorMass`, `PassedMass` and `QuantityUnits`. |
|
||||
| 3.9.3143.0 | Ally port | Ally / Poseidon CLI / Results DB | Morrisville Poseidon fixes transferred | Ported the applicable Morrisville Poseidon read, simulation, logging, regression-test and results-schema migration fixes to the Ally source branch while retaining its compatible legacy reader configuration and non-blocking UI flow. |
|
||||
|
||||
@ -368,10 +368,16 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
{
|
||||
dlg.WMStartState[item] = poseidonReader.BeginWMState;
|
||||
dlg.WMStartStateStr[item] = poseidonReader.BeginWMState.ToString();
|
||||
log.InfoFormat("Poseidon dialog prefill: phase=Start, WM{0}, reader={1}, value={2}",
|
||||
item + 1, poseidonReader.Name, dlg.WMStartState[item]);
|
||||
}
|
||||
|
||||
if (currentOp == CurrentOp.ReadDatastream_EndStates)
|
||||
{
|
||||
dlg.WMEndState[item] = poseidonReader.EndWMState;
|
||||
log.InfoFormat("Poseidon dialog prefill: phase=End, WM{0}, reader={1}, value={2}",
|
||||
item + 1, poseidonReader.Name, dlg.WMEndState[item]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -426,31 +432,10 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (modelessDlg is TestStartEndForm && currentOp == CurrentOp.ReadDatastream_StartStates)
|
||||
else if (modelessDlg is TestStartEndForm)
|
||||
{
|
||||
/// Fixed start test - start
|
||||
TestStartEndForm dlg = (modelessDlg as TestStartEndForm);
|
||||
if (dlg != null)
|
||||
{
|
||||
for (int i = 0; i < dlg.WaterMetersCount; i++)
|
||||
{
|
||||
wmStartState[i] = dlg.WMStartState[i];
|
||||
wmStartStateStr[i] = dlg.WMStartStateStr[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (modelessDlg is TestStartEndForm && currentOp == CurrentOp.ReadDatastream_EndStates)
|
||||
{
|
||||
/// Fixed start test - end
|
||||
TestStartEndForm dlg = (modelessDlg as TestStartEndForm);
|
||||
if (dlg != null)
|
||||
{
|
||||
for (int i = 0; i < dlg.WaterMetersCount; i++)
|
||||
{
|
||||
wmEndState[i] = dlg.WMEndState[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
StoreAcceptedDialogValues((TestStartEndForm)modelessDlg);
|
||||
}
|
||||
resultSaved = true;
|
||||
modelessDlg = null;
|
||||
modelessDialogOpening = false;
|
||||
@ -459,6 +444,32 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
return Event.ModelessFormClosed; /// Form closed
|
||||
}
|
||||
|
||||
private void StoreAcceptedDialogValues(TestStartEndForm dlg)
|
||||
{
|
||||
if (dlg == null)
|
||||
return;
|
||||
|
||||
if (currentOp == CurrentOp.ReadDatastream_StartStates)
|
||||
{
|
||||
for (int i = 0; i < dlg.WaterMetersCount; i++)
|
||||
{
|
||||
wmStartState[i] = dlg.WMStartState[i];
|
||||
wmStartStateStr[i] = dlg.WMStartStateStr[i];
|
||||
log.InfoFormat("Poseidon dialog accepted: phase=Start, WM{0}, text='{1}', value={2}",
|
||||
i + 1, wmStartStateStr[i], wmStartState[i]);
|
||||
}
|
||||
}
|
||||
else if (currentOp == CurrentOp.ReadDatastream_EndStates)
|
||||
{
|
||||
for (int i = 0; i < dlg.WaterMetersCount; i++)
|
||||
{
|
||||
wmEndState[i] = dlg.WMEndState[i];
|
||||
log.InfoFormat("Poseidon dialog accepted: phase=End, WM{0}, value={1}",
|
||||
i + 1, wmEndState[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Stop this operation</summary>
|
||||
public void Stop()
|
||||
{
|
||||
|
||||
@ -147,6 +147,8 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
|
||||
private void SetUiBusy(bool busy, long deltaTime = -1)
|
||||
{
|
||||
log.DebugFormat("Poseidon UI: SetUiBusy busy={0}, deltaTime={1}, enabledTextBoxes={2}",
|
||||
busy, deltaTime, enabledTextBoxes.Count);
|
||||
// show wait cursor for form and children
|
||||
this.UseWaitCursor = busy;
|
||||
|
||||
@ -296,6 +298,8 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
BeginInvoke(new Action(() => UpdateValues(stratValue, enableEdit)));
|
||||
return;
|
||||
}
|
||||
log.DebugFormat("Poseidon UI: UpdateValues on UI thread startValue={0}, enableEdit={1}, deltaTime={2}",
|
||||
stratValue, enableEdit, deltaTime);
|
||||
|
||||
for (int i = 0; i < TextBoxesCount; i++)
|
||||
{
|
||||
@ -320,6 +324,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
if (enableEdit)
|
||||
{
|
||||
SetUiBusy(false, deltaTime);
|
||||
log.Debug("Poseidon UI: values applied and dialog released from Loading...");
|
||||
}
|
||||
// if you also need to enable/disable editing, do it here,
|
||||
// it's now safely on the UI thread.
|
||||
@ -348,6 +353,8 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
if (endTextBoxes[i].Visible && endTextBoxes[i].Enabled)
|
||||
{
|
||||
WMEndState[i] = Utils.ParseUDouble(endTextBoxes[i].Text);
|
||||
log.InfoFormat("Poseidon dialog OK: phase=End, WM{0}, enteredText='{1}', parsedValue={2}",
|
||||
i + 1, endTextBoxes[i].Text, WMEndState[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -359,6 +366,8 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
{
|
||||
WMStartStateStr[i] = startTextBoxes[i].Text;
|
||||
WMStartState[i] = Utils.ParseUDouble(startTextBoxes[i].Text);
|
||||
log.InfoFormat("Poseidon dialog OK: phase=Start, WM{0}, enteredText='{1}', parsedValue={2}",
|
||||
i + 1, startTextBoxes[i].Text, WMStartState[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +25,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
public class PoseidonReader : ComponentBase, IDevice, IRegReaderDatastream, ISessionDataMngmnt, IOperation, ICommonRegReader
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(PoseidonReader));
|
||||
// Simulation must never call the CLI configured for the physical Hat.
|
||||
internal const string SimulatedCliFileName = "cmdSleepTest.exe";
|
||||
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
|
||||
|
||||
readonly PoseidonCfg registerReaderCfg;
|
||||
@ -302,9 +304,17 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
registerReaderCfg.MeterType,
|
||||
SerialPortData.DefaultPoseidonMeterType);
|
||||
}
|
||||
serialPort = new SerialPortData(string.Format("COM{0}", registerReaderCfg.ComPortNr),
|
||||
registerReaderCfg.CliFileName,
|
||||
registerReaderCfg.MeterType);
|
||||
string cliFileName = GetCliFileNameForMode(DebugLevel, registerReaderCfg.CliFileName);
|
||||
serialPort = new SerialPortData(string.Format("COM{0}", registerReaderCfg.ComPortNr),
|
||||
cliFileName,
|
||||
registerReaderCfg.MeterType);
|
||||
|
||||
if (DebugLevel == DebugMode.Simulate)
|
||||
{
|
||||
log.WarnFormat(
|
||||
"{0}: simulation mode enabled; overriding configured CLI '{1}' with '{2}'.",
|
||||
Name, registerReaderCfg.CliFileName, serialPort.SerialPortCmdClientPath);
|
||||
}
|
||||
|
||||
|
||||
//TODO BUMI prepare serial port - for us do nothing
|
||||
@ -327,6 +337,13 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
}
|
||||
}
|
||||
|
||||
internal static string GetCliFileNameForMode(DebugMode debugMode, string configuredCliFileName)
|
||||
{
|
||||
return debugMode == DebugMode.Simulate
|
||||
? SimulatedCliFileName
|
||||
: configuredCliFileName;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
log.DebugFormat("{0}:Clear()", Name);
|
||||
@ -518,12 +535,14 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
}
|
||||
}
|
||||
|
||||
double volume;
|
||||
if (TryParseCliReading(data.Reading, out volume))
|
||||
double volumeLi;
|
||||
string dialogValueFailureReason;
|
||||
if (TryGetDialogValue(data, out volumeLi, out dialogValueFailureReason))
|
||||
{
|
||||
lastCliReadingParsed = true;
|
||||
lastCliReadSucceeded = true;
|
||||
double volumeLi = Units.ConvertFrom(Unit.USgal, volume);
|
||||
double volume;
|
||||
TryParseCliReading(data.Reading, out volume);
|
||||
|
||||
if (_isReadingStart)
|
||||
beginWMState = volumeLi;
|
||||
@ -533,7 +552,11 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
Name, _isReadingStart ? "Begin" : "End", data.DeviceId, data.Reading, volume, volumeLi, beginWMState, endWMState);
|
||||
}
|
||||
else
|
||||
lastCliReadFailureReason = "Reading could not be parsed: '" + data.Reading + "'.";
|
||||
{
|
||||
lastCliReadFailureReason = dialogValueFailureReason;
|
||||
log.ErrorFormat("{0}: cannot parse CLI reading '{1}' using invariant or current culture.",
|
||||
Name, data.Reading);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -554,6 +577,29 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
CultureInfo.InvariantCulture, out value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates a CLI response and converts its US-gallon reading to the
|
||||
/// litre value assigned to the START/END dialog.
|
||||
/// </summary>
|
||||
public static bool TryGetDialogValue(JsonDataFromPoseidon data, out double valueLitres,
|
||||
out string failureReason)
|
||||
{
|
||||
valueLitres = 0;
|
||||
if (!TryValidateCliReadResponse(data, out failureReason))
|
||||
return false;
|
||||
|
||||
double valueGallons;
|
||||
if (!TryParseCliReading(data.Reading, out valueGallons))
|
||||
{
|
||||
failureReason = "Reading could not be parsed: '" + data.Reading + "'.";
|
||||
return false;
|
||||
}
|
||||
|
||||
valueLitres = Units.ConvertFrom(Unit.USgal, valueGallons);
|
||||
failureReason = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool TryValidateCliReadResponse(JsonDataFromPoseidon data, out string failureReason)
|
||||
{
|
||||
if (data == null) { failureReason = "CLI returned no JSON data."; return false; }
|
||||
|
||||
@ -0,0 +1,54 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using TBF.Rig.RegisterReaders.PoseidonCmdStartStop;
|
||||
using CmdPoseidonReader = TBF.Rig.RegisterReaders.PoseidonCmdStartStop.PoseidonReader;
|
||||
|
||||
namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
/// <summary>
|
||||
/// Regression fixtures extracted from PT50 customer CliRunner responses.
|
||||
/// </summary>
|
||||
[TestClass]
|
||||
public class PoseidonCustomerCliResponseTest
|
||||
{
|
||||
// Independently calculated fixtures can differ by insignificant
|
||||
// IEEE-754 rounding during gallons-to-litres conversion.
|
||||
private const double DialogValueToleranceLitres = 0.0001;
|
||||
|
||||
private const string Com43InitialResponse =
|
||||
"{\"Reading\":\"002780.99\",\"DeviceId\":\"1000000219\",\"ProductType\":74,\"ReadingComplete\":true,\"NfcTagDetected\":true,\"CliVersion\":\"2.0.0.2\"}";
|
||||
private const string Com45InitialResponse =
|
||||
"{\"Reading\":\"002316.63\",\"DeviceId\":\"1000000279\",\"ProductType\":74,\"ReadingComplete\":true,\"NfcTagDetected\":true,\"CliVersion\":\"2.0.0.2\"}";
|
||||
private const string Com43LaterResponse =
|
||||
"{\"Reading\":\"002898.60\",\"DeviceId\":\"1000000219\",\"ProductType\":74,\"ReadingComplete\":true,\"NfcTagDetected\":true,\"CliVersion\":\"2.0.0.2\"}";
|
||||
private const string Com45LaterResponse =
|
||||
"{\"Reading\":\"002433.50\",\"DeviceId\":\"1000000279\",\"ProductType\":74,\"ReadingComplete\":true,\"NfcTagDetected\":true,\"CliVersion\":\"2.0.0.2\"}";
|
||||
|
||||
[TestMethod]
|
||||
public void CustomerCliResponses_AreDeserializedAndConvertedToDialogValues()
|
||||
{
|
||||
AssertDialogValue(Com43InitialResponse, "1000000219", "002780.99", 10527.1923171862);
|
||||
AssertDialogValue(Com45InitialResponse, "1000000279", "002316.63", 8769.39850116792);
|
||||
AssertDialogValue(Com43LaterResponse, "1000000219", "002898.60", 10972.3945971024);
|
||||
AssertDialogValue(Com45LaterResponse, "1000000279", "002433.50", 9211.799576364);
|
||||
}
|
||||
|
||||
private static void AssertDialogValue(string json, string expectedDeviceId,
|
||||
string expectedReading, double expectedLitres)
|
||||
{
|
||||
var cliRunner = new CliRunner(false);
|
||||
JsonDataFromPoseidon response;
|
||||
|
||||
Assert.IsTrue(cliRunner.TryJsonStringDeserialize(json, out response));
|
||||
Assert.IsNotNull(response);
|
||||
Assert.AreEqual(expectedDeviceId, response.DeviceId);
|
||||
Assert.AreEqual(expectedReading, response.Reading);
|
||||
|
||||
double dialogValue;
|
||||
string failureReason;
|
||||
Assert.IsTrue(CmdPoseidonReader.TryGetDialogValue(response, out dialogValue, out failureReason), failureReason);
|
||||
Assert.AreEqual(expectedLitres, dialogValue, DialogValueToleranceLitres,
|
||||
"The value assigned to the START/END dialog must come from the CLI response.");
|
||||
Assert.AreNotEqual(0d, dialogValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using TBF.Rig.DataEntry.PoseidonCmd;
|
||||
using TBF.Rig.RegisterReaders.PoseidonCmdStartStop;
|
||||
using CmdPoseidonReader = TBF.Rig.RegisterReaders.PoseidonCmdStartStop.PoseidonReader;
|
||||
|
||||
namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
[TestClass]
|
||||
public class PoseidonDialogTransferTest
|
||||
{
|
||||
private const string CustomerCliResponse =
|
||||
"{\"Reading\":\"002433.50\",\"DeviceId\":\"1000000279\",\"ProductType\":74,\"ReadingComplete\":true,\"NfcTagDetected\":true,\"CliVersion\":\"2.0.0.2\"}";
|
||||
|
||||
[TestMethod]
|
||||
public void CustomerCliValue_IsPrefilledConfirmedAndTransferred_ForStartAndEnd()
|
||||
{
|
||||
Exception failure = null;
|
||||
var staThread = new Thread(() =>
|
||||
{
|
||||
try { RunDialogTransferScenario(); }
|
||||
catch (Exception exception) { failure = exception; }
|
||||
});
|
||||
staThread.SetApartmentState(ApartmentState.STA);
|
||||
staThread.Start();
|
||||
staThread.Join(TimeSpan.FromSeconds(15));
|
||||
|
||||
Assert.IsFalse(staThread.IsAlive, "The Poseidon dialog test did not finish.");
|
||||
if (failure != null) throw failure;
|
||||
}
|
||||
|
||||
private static void RunDialogTransferScenario()
|
||||
{
|
||||
var cliRunner = new CliRunner(false);
|
||||
JsonDataFromPoseidon response;
|
||||
Assert.IsTrue(cliRunner.TryJsonStringDeserialize(CustomerCliResponse, out response));
|
||||
|
||||
double cliValueLitres;
|
||||
string failureReason;
|
||||
Assert.IsTrue(CmdPoseidonReader.TryGetDialogValue(response, out cliValueLitres, out failureReason), failureReason);
|
||||
VerifyStartDialogTransfer(cliValueLitres);
|
||||
VerifyEndDialogTransfer(cliValueLitres);
|
||||
}
|
||||
|
||||
private static void VerifyStartDialogTransfer(double expectedValue)
|
||||
{
|
||||
using (var dialog = new TestStartEndForm(1, null, new bool[1]))
|
||||
{
|
||||
dialog.CreateControl();
|
||||
dialog.WMStartState[0] = expectedValue;
|
||||
dialog.WMStartStateStr[0] = expectedValue.ToString();
|
||||
dialog.UpdateValues(true, true);
|
||||
Assert.AreEqual(dialog.WMStartStateStr[0], FindTextBox(dialog, "startTextBox1").Text);
|
||||
|
||||
ConfirmDialog(dialog);
|
||||
Assert.IsTrue(dialog.Completed);
|
||||
Assert.AreEqual(expectedValue, dialog.WMStartState[0], 0.0001);
|
||||
|
||||
var entryForm = CreateEntryFormForTransfer(EntryForm.CurrentOp.ReadDatastream_StartStates);
|
||||
TransferAcceptedDialogValues(entryForm, dialog);
|
||||
Assert.AreEqual(expectedValue, entryForm.WMStartState(0), 0.0001);
|
||||
}
|
||||
}
|
||||
|
||||
private static void VerifyEndDialogTransfer(double expectedValue)
|
||||
{
|
||||
using (var dialog = new TestStartEndForm(1, null, new[] { expectedValue.ToString() }, new bool[1], 0, 0, 0))
|
||||
{
|
||||
dialog.CreateControl();
|
||||
dialog.WMEndState[0] = expectedValue;
|
||||
dialog.UpdateValues(false, true);
|
||||
Assert.AreEqual(expectedValue.ToString(), FindTextBox(dialog, "endTextBox1").Text);
|
||||
|
||||
ConfirmDialog(dialog);
|
||||
Assert.IsTrue(dialog.Completed);
|
||||
Assert.AreEqual(expectedValue, dialog.WMEndState[0], 0.0001);
|
||||
|
||||
var entryForm = CreateEntryFormForTransfer(EntryForm.CurrentOp.ReadDatastream_EndStates);
|
||||
TransferAcceptedDialogValues(entryForm, dialog);
|
||||
Assert.AreEqual(expectedValue, entryForm.WMEndState(0), 0.0001);
|
||||
}
|
||||
}
|
||||
|
||||
private static TextBox FindTextBox(Control dialog, string name)
|
||||
{
|
||||
TextBox textBox = dialog.Controls.Find(name, true).OfType<TextBox>().FirstOrDefault();
|
||||
Assert.IsNotNull(textBox, "Expected dialog control was not found: " + name);
|
||||
return textBox;
|
||||
}
|
||||
|
||||
private static void ConfirmDialog(TestStartEndForm dialog)
|
||||
{
|
||||
MethodInfo okHandler = typeof(TestStartEndForm).GetMethod("okButton_Click",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
Assert.IsNotNull(okHandler);
|
||||
okHandler.Invoke(dialog, new object[] { dialog, EventArgs.Empty });
|
||||
}
|
||||
|
||||
private static EntryForm CreateEntryFormForTransfer(EntryForm.CurrentOp currentOp)
|
||||
{
|
||||
var entryForm = new EntryForm();
|
||||
SetPrivateField(entryForm, "currentOp", currentOp);
|
||||
SetPrivateField(entryForm, "wmStartState", new double[1]);
|
||||
SetPrivateField(entryForm, "wmStartStateStr", new string[1]);
|
||||
SetPrivateField(entryForm, "wmEndState", new double[1]);
|
||||
return entryForm;
|
||||
}
|
||||
|
||||
private static void TransferAcceptedDialogValues(EntryForm entryForm, TestStartEndForm dialog)
|
||||
{
|
||||
MethodInfo method = typeof(EntryForm).GetMethod("StoreAcceptedDialogValues",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
Assert.IsNotNull(method);
|
||||
method.Invoke(entryForm, new object[] { dialog });
|
||||
}
|
||||
|
||||
private static void SetPrivateField(object instance, string name, object value)
|
||||
{
|
||||
FieldInfo field = instance.GetType().GetField(name,
|
||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
Assert.IsNotNull(field, "Expected field was not found: " + name);
|
||||
field.SetValue(instance, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -82,6 +82,26 @@ namespace TBFTests.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void InputJson_NonZeroReading_WithDecimalCommaOrDot_IsParsedCorrectly()
|
||||
{
|
||||
foreach (string reading in new[] { "002433,50", "002433.50", "002898,60", "002898.60" })
|
||||
{
|
||||
double value;
|
||||
Assert.IsTrue(CmdPoseidonReader.TryParseCliReading(reading, out value));
|
||||
Assert.IsTrue(value > 0, "The non-zero CLI reading must remain non-zero: " + reading);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SimulationMode_AlwaysUsesCmdSleepTestInsteadOfConfiguredHatCli()
|
||||
{
|
||||
Assert.AreEqual("cmdSleepTest.exe", CmdPoseidonReader.GetCliFileNameForMode(
|
||||
Common.DebugMode.Simulate, "HatCliDemo.exe"));
|
||||
Assert.AreEqual("HatCliDemo.exe", CmdPoseidonReader.GetCliFileNameForMode(
|
||||
Common.DebugMode.Normal, "HatCliDemo.exe"));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CliReadResponse_RequiresNfcAndCompletedReading()
|
||||
{
|
||||
|
||||
@ -136,6 +136,8 @@
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\CliRunnerTimeoutUnitTest.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonReaderTest.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonReadCycleTest.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonCustomerCliResponseTest.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonDialogTransferTest.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonCmdStartStop\PoseidonSingleMeterIntegrationTest.cs" />
|
||||
<Compile Include="Rig\RegisterReaders\PoseidonReader\UniHeadTestCtrlTest.cs" />
|
||||
<Compile Include="Rig\Scales\MettlerToledo\ReadStableMassOpTest.cs" />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user