596 lines
24 KiB
C#
596 lines
24 KiB
C#
/*-------------------------------------------------------------------------
|
|
// UNCLASSIFIED
|
|
/*-------------------------------------------------------------------------
|
|
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
|
|
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
|
|
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
|
|
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
|
|
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
|
|
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
|
|
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
|
|
COMPANY.
|
|
|
|
THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
|
|
GOVERNMENT.
|
|
|
|
UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
|
|
-------------------------------------------------------------------------*/
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Text.RegularExpressions;
|
|
using System.Xml;
|
|
using MeasurementManagerLib;
|
|
using NationalInstruments.TestStand.Interop.API;
|
|
using NLog;
|
|
using NLog.Targets;
|
|
using NLog.Targets.Wrappers;
|
|
using Raytheon.Common;
|
|
using Raytheon.Common.PdelWriter;
|
|
using Raytheon.Common.PdelWriter.Utilities;
|
|
using Raytheon.Instruments;
|
|
|
|
namespace ProgramLib
|
|
{
|
|
/// <summary>
|
|
/// Class for interfacing with any third party test executive such as Test Stand
|
|
/// DO NOT implement IDisposable interface for this class. If there are unmanaged resources that need to be freed,
|
|
/// do it in the destructor.
|
|
/// </summary>
|
|
internal partial class Program
|
|
{
|
|
#region PrivateMemberVariables
|
|
// the one and only program
|
|
internal static Program _program = null;
|
|
|
|
internal static object _terminateTestSyncObj = new object();
|
|
internal static bool _terminateTestInitiated = false;
|
|
|
|
private List<BasicThread> _threadList = new List<BasicThread>();
|
|
|
|
private IInstrumentManager _instrumentManager;
|
|
|
|
internal static ILogger _logger;
|
|
|
|
private object _fatalFailureExceptionFromSupportThreadSyncObj = new object();
|
|
internal static Exception _fatalFailureExceptionFromSupportThread;
|
|
|
|
private MalMeasurementLibManager _malMeasurementLibManager;
|
|
|
|
#endregion
|
|
|
|
internal IInstrumentManager InstrumentManager
|
|
{
|
|
get { return _instrumentManager; }
|
|
set { _instrumentManager = value; }
|
|
}
|
|
internal bool IsThereHardware { get; private set; }
|
|
internal bool IsAppControlled { get; private set; }
|
|
internal bool CableSelfTestHasRun { get; set; }
|
|
internal static SequenceContext TestStandSeqContext { get; private set; }
|
|
internal UutInfo UutInfo { get; private set; }
|
|
internal TestInfo TestInfo { get; private set; }
|
|
internal EventManager EventManager { get; private set; }
|
|
internal FileAndFolderManager FileAndFolderManager { get; private set; }
|
|
internal IConfigurationFile ProgramGeneralConfig { get; private set; }
|
|
internal IConfigurationFile ProgramSpecificConfig { get; private set; }
|
|
internal TestStation TestStation { get; private set; }
|
|
internal EthernetSocketManager EthernetSocketManager { get; private set; }
|
|
internal PdelInformation PdelData { get; private set; }
|
|
internal TestResultList PcodeTestResultList { get; private set; }
|
|
|
|
internal MalMeasurementLibManager MalMeasurementLibManager
|
|
{
|
|
get
|
|
{
|
|
if (_malMeasurementLibManager == null)
|
|
throw new MalMeasurementManagerNullReferenceException(typeof(MalMeasurementLibManager));
|
|
|
|
return _malMeasurementLibManager;
|
|
}
|
|
|
|
private set
|
|
{
|
|
_malMeasurementLibManager = value;
|
|
}
|
|
}
|
|
|
|
internal List<string> PowerModulesToBePowered { get; set; }
|
|
|
|
/// <summary>
|
|
/// Create an instance of this class. Only one instance is allowed
|
|
/// </summary>
|
|
/// <param name="partNumber">The UUT part number</param>
|
|
/// <param name="serialNumber">The UUT serial number</param>
|
|
/// <param name="isThereHardware">false for simulation</param>
|
|
/// <returns></returns>
|
|
internal static Program Instance(string partNumber = "", string serialNumber = "", string testType = "", string testName = "", bool isThereHardware = true, string configSubFolderName = "Default", object testStandSeqContext = null)
|
|
{
|
|
if (testStandSeqContext != null)
|
|
{
|
|
TestStandSeqContext = testStandSeqContext as SequenceContext;
|
|
}
|
|
|
|
if (_logger == null)
|
|
{
|
|
// this line is for when this is called from third-party test executive such as TestStand. Without this, NLOG library won't be able to find the NLog.config file
|
|
NLog.LogManager.Setup().LoadConfigurationFromFile(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "NLog.config"));
|
|
|
|
_logger = LogManager.GetCurrentClassLogger();
|
|
}
|
|
|
|
if (_program == null)
|
|
{
|
|
_program = new Program(partNumber, serialNumber, testType, testName, isThereHardware, configSubFolderName);
|
|
_program.Initialize();
|
|
}
|
|
|
|
return _program;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The private constructor
|
|
/// </summary>
|
|
/// <param name="partNumber">the UUT part number</param>
|
|
/// <param name="serialNumber">the UUT serial number</param>
|
|
/// <param name="isThereHardware">false for simulation</param>
|
|
private Program(string partNumber, string serialNumber, string testType, string testName, bool isThereHardware, string configSubFolderName)
|
|
{
|
|
try
|
|
{
|
|
PdelData = new PdelInformation();
|
|
PcodeTestResultList = new TestResultList();
|
|
IsThereHardware = isThereHardware;
|
|
|
|
CableSelfTestHasRun = false;
|
|
|
|
_terminateTestInitiated = false;
|
|
|
|
_fatalFailureExceptionFromSupportThread = null;
|
|
|
|
string testOperator = Util.GetWindowsUserFullName(Environment.UserDomainName, Environment.UserName);
|
|
|
|
DateTime assemblyBuildDateTime = File.GetLastWriteTime(GetType().Assembly.Location);
|
|
string assemblyBuildDateTimeStr = assemblyBuildDateTime.ToString("MM/dd/yyyy");
|
|
|
|
Version appVersion = GetType().Assembly.GetName().Version;
|
|
string softwareBuildInfo = $"{assemblyBuildDateTimeStr} - Version " + appVersion.Major.ToString() + "." + appVersion.Minor.ToString();
|
|
|
|
if (String.IsNullOrEmpty(testOperator))
|
|
testOperator = Environment.UserName;
|
|
|
|
if (TestStandSeqContext != null)
|
|
{
|
|
partNumber = TestStandSeqContext.FileGlobals.GetValString("UUT.PartNumber", PropertyOptions.PropOption_CaseInsensitive);
|
|
serialNumber = TestStandSeqContext.FileGlobals.GetValString("UUT.SerialNumber", PropertyOptions.PropOption_CaseInsensitive);
|
|
|
|
testType = TestStandSeqContext.FileGlobals.GetValString("UUT.AdditionalData.TEST_CATEGORY", PropertyOptions.PropOption_CaseInsensitive);
|
|
|
|
if (String.Equals(testType, "engineering", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
testType = "en";
|
|
}
|
|
else
|
|
testType = "at";
|
|
|
|
testName = TestStandSeqContext.FileGlobals.GetValString("UUT.AdditionalData.TEST_NAME", PropertyOptions.PropOption_CaseInsensitive);
|
|
|
|
if (!String.IsNullOrEmpty(testOperator))
|
|
TestStandSeqContext.FileGlobals.SetValString("UUT.AdditionalData.TEST_OPERATOR", PropertyOptions.PropOption_CaseInsensitive, testOperator);
|
|
else
|
|
testOperator = TestStandSeqContext.FileGlobals.GetValString("UUT.AdditionalData.TEST_OPERATOR", PropertyOptions.PropOption_CaseInsensitive);
|
|
|
|
string dateTimeStr = TestStandSeqContext.Root.Locals.GetValString("StartDate.ShortText", PropertyOptions.PropOption_CaseInsensitive);
|
|
dateTimeStr += " " + TestStandSeqContext.Root.Locals.GetValString("StartTime.Text", PropertyOptions.PropOption_CaseInsensitive);
|
|
TestInfo = new TestInfo(testType, testName, testOperator, DateTime.Parse(dateTimeStr));
|
|
|
|
TestStandSeqContext.FileGlobals.SetValString("UUT.AdditionalData.MTS_Software_Build", PropertyOptions.PropOption_CaseInsensitive, softwareBuildInfo);
|
|
}
|
|
else
|
|
{
|
|
// make sure PN/SN are valid (TS may not pass in the PN)
|
|
if (String.IsNullOrEmpty(partNumber))
|
|
{
|
|
partNumber = "DefaultPN";
|
|
}
|
|
|
|
if (String.IsNullOrEmpty(serialNumber))
|
|
{
|
|
serialNumber = "DefaultSN";
|
|
}
|
|
|
|
if (String.Equals(testType, "en", StringComparison.OrdinalIgnoreCase) || String.Equals(testType, "at", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
TestInfo = new TestInfo(testType, testName, testOperator, DateTime.Now);
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("Argument testType is invalid. Must be either 'en' or 'at'");
|
|
}
|
|
|
|
if (String.IsNullOrEmpty(testName))
|
|
{
|
|
throw new Exception("Argument testName is invalid. Please provide name of test");
|
|
}
|
|
}
|
|
|
|
PdelData.TestOperator = testOperator;
|
|
PdelData.TestSoftwareIdentification = softwareBuildInfo;
|
|
PdelData.UutIdentification = partNumber;
|
|
PdelData.UutSerialNumber = serialNumber;
|
|
PdelData.TestStartTime = TestInfo.TestStartDateTime;
|
|
PdelData.TestCategory = TestCategory.ENGINEERING_TEST;
|
|
if (TestInfo.TestType == "at")
|
|
{
|
|
PdelData.TestCategory = TestCategory.ACCEPTANCE_TEST;
|
|
}
|
|
|
|
string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
|
ProgramGeneralConfig = new ConfigurationFile(Path.Combine(assemblyFolder, GeneralConstants.ConfigFolderName, GeneralConstants.ProgramGeneralConfigFilename));
|
|
|
|
PowerModulesToBePowered = new List<string>();
|
|
EventManager = new EventManager();
|
|
IConfigurationFile programSpecificConfig;
|
|
FileAndFolderManager = new FileAndFolderManager(ProgramGeneralConfig, out programSpecificConfig, isThereHardware, configSubFolderName);
|
|
ProgramSpecificConfig = programSpecificConfig;
|
|
|
|
StartLogDashBoard();
|
|
|
|
CheckForControlledSoftware();
|
|
|
|
Target target = LogManager.Configuration.FindTargetByName("RunFile");
|
|
|
|
if (target != null)
|
|
{
|
|
FileTarget fileTarget = null;
|
|
WrapperTargetBase wrapperTarget = target as WrapperTargetBase;
|
|
|
|
if (wrapperTarget == null)
|
|
{
|
|
fileTarget = target as FileTarget;
|
|
}
|
|
else
|
|
{
|
|
fileTarget = wrapperTarget.WrappedTarget as FileTarget;
|
|
}
|
|
|
|
// re-direct NLOG log to specific folder
|
|
fileTarget.FileName = FileAndFolderManager.GetFile(FileAndFolderManager.Files.NLOG_TEMP);
|
|
LogManager.ReconfigExistingLoggers();
|
|
}
|
|
|
|
UutInfo = new UutInfo(partNumber, serialNumber);
|
|
|
|
var configFolder = Path.Combine(FileAndFolderManager.GetFolder(FileAndFolderManager.Folders.CONFIG), ProgramGeneralConfig.ReadValue(ProgramGeneralConfigIni.GENERAL.ToString(), ProgramGeneralConfigIni.INSTRUMENT_CONFIG_FOLDER_NAME.ToString()));
|
|
_instrumentManager = new GeneralInstrumentManager(assemblyFolder, configFolder, IsThereHardware);
|
|
_instrumentManager.Initialize();
|
|
|
|
_malMeasurementLibManager = new MalMeasurementLibManager(_instrumentManager);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finalizer
|
|
/// </summary>
|
|
~Program()
|
|
{
|
|
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() ...");
|
|
|
|
if (TestStandSeqContext == null)
|
|
{
|
|
// signal to all running threads to exit
|
|
EventManager[EventManager.Events.GLOBAL_QUIT].Set();
|
|
|
|
if (IsUutPwrOn)
|
|
{
|
|
BasicAction action = new UutPowerOffAction();
|
|
action.Run();
|
|
}
|
|
|
|
// needs to kill all the support threads since they could be accessing GUI
|
|
foreach (BasicThread thread in _threadList)
|
|
{
|
|
thread.Quit();
|
|
thread.WaitForExit();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Perform initializations
|
|
/// </summary>
|
|
internal void Initialize()
|
|
{
|
|
UutInfo.Initialize();
|
|
|
|
EthernetSocketManager = new EthernetSocketManager();
|
|
|
|
TestStation = new TestStation();
|
|
TestStation.PerformCableChecks();
|
|
|
|
FileAndFolderManager.ConstructTestFolder(UutInfo, TestInfo);
|
|
|
|
RecordTestRunStartInfoToFile();
|
|
|
|
if (TestStandSeqContext != null)
|
|
{
|
|
string testStandReportPath = Path.Combine(FileAndFolderManager.GetFolder(FileAndFolderManager.Folders.DATA_TEST), ProgramGeneralConfig.ReadValue(ProgramGeneralConfigIni.GENERAL.ToString(), ProgramGeneralConfigIni.TESTSTAND_FOLDER_NAME.ToString()));
|
|
|
|
if (!Directory.Exists(testStandReportPath))
|
|
Directory.CreateDirectory(testStandReportPath);
|
|
|
|
string testStandVarName = ProgramGeneralConfig.ReadValue(ProgramGeneralConfigIni.GENERAL.ToString(), ProgramGeneralConfigIni.DESTINATION_TEST_REPORT_PATH_VAR_NAME.ToString());
|
|
TestStandSeqContext.Main.FileGlobals.SetValString(testStandVarName, PropertyOptions.PropOption_CaseInsensitive, testStandReportPath);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check if we are running controlled software
|
|
/// </summary>
|
|
internal void CheckForControlledSoftware()
|
|
{
|
|
try
|
|
{
|
|
string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
|
IsAppControlled = false;
|
|
|
|
string drive = FileAndFolderManager.GetFolder(FileAndFolderManager.Folders.DATA).Substring(0, 2);
|
|
|
|
string appControlledPath = Path.Combine(drive, ProgramSpecificConfig.ReadValue(ProgramSpecificConfigIni.GENERAL.ToString(), ProgramSpecificConfigIni.APP_RELEASE_CONTROLLED_FOLDER.ToString()));
|
|
|
|
if (Regex.IsMatch(assemblyFolder, @"^" + Regex.Escape(appControlledPath), RegexOptions.IgnoreCase))
|
|
{
|
|
IsAppControlled = true;
|
|
|
|
if (TestStandSeqContext != null)
|
|
{
|
|
string testStandSeqFilePath = TestStandSeqContext.Sequence.SequenceFile.Path;
|
|
|
|
if (!Regex.IsMatch(testStandSeqFilePath, @"^" + Regex.Escape(appControlledPath), RegexOptions.IgnoreCase))
|
|
{
|
|
if (IsThereHardware)
|
|
_logger.Warn($"Uncontrolled TestStand sequence execution is detected. {testStandSeqFilePath} is not running out of {appControlledPath}.");
|
|
IsAppControlled = false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (IsThereHardware)
|
|
_logger.Warn($"Uncontrolled software execution is detected. {Assembly.GetExecutingAssembly().Location} is not running out of {appControlledPath}.");
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Start LogDashboard application
|
|
/// </summary>
|
|
internal void StartLogDashBoard()
|
|
{
|
|
try
|
|
{
|
|
string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
|
|
|
string drive = FileAndFolderManager.GetFolder(FileAndFolderManager.Folders.DATA).Substring(0, 2);
|
|
|
|
string logDashboardAppPath = Path.Combine(drive, ProgramSpecificConfig.ReadValue(ProgramSpecificConfigIni.GENERAL.ToString(), ProgramSpecificConfigIni.LOG_DASHBOARD_APP_PATH.ToString()));
|
|
string logDashboardProcessName = Path.GetFileNameWithoutExtension(logDashboardAppPath);
|
|
|
|
if (!Path.IsPathRooted(logDashboardAppPath))
|
|
logDashboardAppPath = Path.Combine(assemblyFolder, logDashboardAppPath);
|
|
|
|
if (!String.IsNullOrEmpty(logDashboardAppPath) && !String.IsNullOrEmpty(logDashboardProcessName))
|
|
{
|
|
if (File.Exists(logDashboardAppPath))
|
|
{
|
|
Process[] procArray = Process.GetProcessesByName(logDashboardProcessName);
|
|
|
|
if (procArray.Length == 0)
|
|
{
|
|
Process.Start(logDashboardAppPath);
|
|
|
|
int maxRetries = 5;
|
|
int retriev = 0;
|
|
do
|
|
{
|
|
System.Threading.Thread.Sleep(1000);
|
|
procArray = Process.GetProcessesByName(logDashboardProcessName);
|
|
} while (retriev++ < maxRetries && procArray.Length == 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Perform post test activities
|
|
/// </summary>
|
|
internal void PerformPostTestActivities()
|
|
{
|
|
try
|
|
{
|
|
MoveNlogToTestFolder();
|
|
RecordTestRunEndInfoToFile();
|
|
CreatePdelFile();
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create PDEL file if there are PDEL results
|
|
/// </summary>
|
|
internal void CreatePdelFile()
|
|
{
|
|
if (PcodeTestResultList.List.Count > 0)
|
|
{
|
|
PdelWriter pdelWriter = new PdelWriter();
|
|
string pdelReportPath = Path.Combine(FileAndFolderManager.GetFolder(FileAndFolderManager.Folders.DATA_TEST), ProgramGeneralConfig.ReadValue(ProgramGeneralConfigIni.GENERAL.ToString(), ProgramGeneralConfigIni.PDEL_FOLDER_NAME.ToString()));
|
|
pdelWriter.CreatePdelFile(PcodeTestResultList.List, PdelData, pdelReportPath);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Move NLog to test folder
|
|
/// </summary>
|
|
private void MoveNlogToTestFolder()
|
|
{
|
|
if (FileAndFolderManager != null)
|
|
{
|
|
string nlogFilePath = FileAndFolderManager.GetFile(FileAndFolderManager.Files.NLOG_TEMP);
|
|
// move nlog log to test folder
|
|
if (File.Exists(nlogFilePath))
|
|
{
|
|
string destPath = String.Empty;
|
|
|
|
int numTries = 1;
|
|
while (numTries++ <= 2)
|
|
{
|
|
try
|
|
{
|
|
destPath = Path.Combine(FileAndFolderManager.GetFolder(FileAndFolderManager.Folders.DATA_TEST), ProgramGeneralConfig.ReadValue(ProgramGeneralConfigIni.GENERAL.ToString(), ProgramGeneralConfigIni.NLOG_FOLDER_NAME.ToString()));
|
|
}
|
|
catch (Exception)
|
|
{
|
|
FileAndFolderManager.ConstructTestFolder(UutInfo, TestInfo);
|
|
|
|
if (TestStandSeqContext != null)
|
|
{
|
|
string testStandReportPath = Path.Combine(FileAndFolderManager.GetFolder(FileAndFolderManager.Folders.DATA_TEST), ProgramGeneralConfig.ReadValue(ProgramGeneralConfigIni.GENERAL.ToString(), ProgramGeneralConfigIni.TESTSTAND_FOLDER_NAME.ToString()));
|
|
|
|
if (!Directory.Exists(testStandReportPath))
|
|
Directory.CreateDirectory(testStandReportPath);
|
|
|
|
string testStandVarName = ProgramGeneralConfig.ReadValue(ProgramGeneralConfigIni.GENERAL.ToString(), ProgramGeneralConfigIni.DESTINATION_TEST_REPORT_PATH_VAR_NAME.ToString());
|
|
TestStandSeqContext.Main.FileGlobals.SetValString(testStandVarName, PropertyOptions.PropOption_CaseInsensitive, testStandReportPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!Directory.Exists(destPath))
|
|
{
|
|
Directory.CreateDirectory(destPath);
|
|
}
|
|
|
|
if (Directory.Exists(destPath))
|
|
{
|
|
string destFilePath = Path.Combine(destPath, Path.GetFileName(nlogFilePath));
|
|
File.Move(nlogFilePath, destFilePath);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Record general information about start of test run to file
|
|
/// </summary>
|
|
private void RecordTestRunStartInfoToFile()
|
|
{
|
|
XmlDocumentWrapper doc = new XmlDocumentWrapper(FileAndFolderManager.GetFile(FileAndFolderManager.Files.TEST_RUN_LOG));
|
|
XmlNodeList nodeList = doc.GetNodes(TestRunConfigXml.TestRunPath);
|
|
|
|
int maxNumTestRunRecordsToKeep = 50;
|
|
for (int i = maxNumTestRunRecordsToKeep - 1; i < nodeList.Count; i++)
|
|
{
|
|
doc.RemoveNode(nodeList[i]);
|
|
}
|
|
|
|
Dictionary<string, string> attributesDict = new Dictionary<string, string>();
|
|
attributesDict[TestRunConfigXml.TestRunPathAttributeName] = FileAndFolderManager.GetFolder(FileAndFolderManager.Folders.DATA_TEST);
|
|
attributesDict[TestRunConfigXml.TestRunTestNameAttributeName] = TestInfo.TestName;
|
|
attributesDict[TestRunConfigXml.TestRunTesterAttributeName] = TestInfo.TestOperator;
|
|
attributesDict[TestRunConfigXml.TestRunStartDateAttributeName] = TestInfo.TestStartDateTime.ToString("MM/dd/yyyy");
|
|
attributesDict[TestRunConfigXml.TestRunStartTimeAttributeName] = TestInfo.TestStartDateTime.ToString("HH:mm:ss");
|
|
doc.AddNode(TestRunConfigXml.TestRunPath, attributesDict, null, XmlDocumentWrapper.AddNodePosition.First);
|
|
|
|
doc.SaveToFile();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Record general information about end of test run to file
|
|
/// </summary>
|
|
private void RecordTestRunEndInfoToFile()
|
|
{
|
|
XmlDocumentWrapper doc = new XmlDocumentWrapper(FileAndFolderManager.GetFile(FileAndFolderManager.Files.TEST_RUN_LOG));
|
|
XmlNodeList nodeList = doc.GetNodes(TestRunConfigXml.TestRunPath);
|
|
|
|
int maxNumTestRunRecordsToKeep = 50;
|
|
for (int i = maxNumTestRunRecordsToKeep - 1; i < nodeList.Count; i++)
|
|
{
|
|
doc.RemoveNode(nodeList[i]);
|
|
}
|
|
|
|
XmlNode node = doc.GetNode(TestRunConfigXml.TestRunPath);
|
|
|
|
if (node != null)
|
|
{
|
|
XmlAttribute attr = node.Attributes["path"];
|
|
|
|
if (attr != null)
|
|
{
|
|
if (String.Equals(attr.Value, FileAndFolderManager.GetFolder(FileAndFolderManager.Folders.DATA_TEST), StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
Dictionary<string, string> attributesDict = new Dictionary<string, string>();
|
|
attributesDict[TestRunConfigXml.TestRunEndDateAttributeName] = DateTime.Now.ToString("MM/dd/yyyy");
|
|
attributesDict[TestRunConfigXml.TestRunEndTimeAttributeName] = DateTime.Now.ToString("HH:mm:ss");
|
|
doc.ChangeNode(node, attributesDict);
|
|
}
|
|
}
|
|
}
|
|
|
|
doc.SaveToFile();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Kill GUI thread
|
|
/// </summary>
|
|
internal void KillGuiThread()
|
|
{
|
|
try
|
|
{
|
|
// Because the GuiManager class starts a STA thread to manage WPF GUIs
|
|
// the Program destructor doesn't get called if we don't shut down the STA thread first
|
|
// so we explicitly call Dispose here to shutdown the thread. This is a special case.
|
|
// All other classes call Dispose() in their Destructor
|
|
_program.GuiManager?.Dispose();
|
|
}
|
|
catch (MalMeasurementManagerNullReferenceException) { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Kill support threads
|
|
/// </summary>
|
|
internal void KillSupportThreads()
|
|
{
|
|
foreach (BasicThread thread in _threadList)
|
|
{
|
|
thread.Quit();
|
|
thread.WaitForExit();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Save error message originated from other threads
|
|
/// </summary>
|
|
/// <param name=""></param>
|
|
/// <returns></returns>
|
|
internal void SetFatalFailureExceptionFromSupportThread(Exception fatalFailureException)
|
|
{
|
|
lock (_fatalFailureExceptionFromSupportThreadSyncObj)
|
|
{
|
|
if (_fatalFailureExceptionFromSupportThread == null)
|
|
{
|
|
_fatalFailureExceptionFromSupportThread = fatalFailureException;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|