Major upgrade
This commit is contained in:
@@ -16,60 +16,88 @@ GOVERNMENT.
|
||||
UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
|
||||
-------------------------------------------------------------------------*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
using MeasurementManagerLib;
|
||||
using NationalInstruments.TestStand.Interop.API;
|
||||
using NLog;
|
||||
using Raytheon.Instruments;
|
||||
using NLog.Targets;
|
||||
using NLog.Targets.Wrappers;
|
||||
using Raytheon.Common;
|
||||
using MeasurementManagerLib;
|
||||
using Raytheon.Common.PdelWriter;
|
||||
using Raytheon.Common.PdelWriter.Utilities;
|
||||
using Raytheon.Instruments;
|
||||
|
||||
namespace ProgramLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Class for interfacing with any Test Executive such as third party test executive such as Test Stand
|
||||
/// 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>
|
||||
public partial class Program
|
||||
/// </summary>
|
||||
internal partial class Program
|
||||
{
|
||||
#region PrivateMemberVariables
|
||||
// the one and only program
|
||||
private static Program _program;
|
||||
internal static Program _program = null;
|
||||
|
||||
private object _terminateTestSyncObj = new object();
|
||||
private bool _terminateTestInitiated = false;
|
||||
|
||||
// simulation
|
||||
private readonly bool _isThereHardware;
|
||||
|
||||
// file management
|
||||
private string _partNumber;
|
||||
private string _serialNumber;
|
||||
internal static object _terminateTestSyncObj = new object();
|
||||
internal static bool _terminateTestInitiated = false;
|
||||
|
||||
private List<BasicThread> _threadList = new List<BasicThread>();
|
||||
|
||||
private IInstrumentManager _instrumentManager;
|
||||
|
||||
private ILogger _logger;
|
||||
internal static ILogger _logger;
|
||||
|
||||
private object _fatalErrorMsgFromSupportThreadSyncObj = new object();
|
||||
private string _fatalErrorMsgFromSupportThread;
|
||||
private object _fatalFailureExceptionFromSupportThreadSyncObj = new object();
|
||||
internal static Exception _fatalFailureExceptionFromSupportThread;
|
||||
|
||||
private MalMeasurementLibManager _malMeasurementLibManager;
|
||||
|
||||
#endregion
|
||||
|
||||
internal SequenceContext TestStandSeqContext { get; private set; }
|
||||
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 EventManager EventManager { get; private set; }
|
||||
internal FileAndFolderManager FileAndFolderManager { get; set; }
|
||||
internal IConfigurationFile ProgramConfig { get; private set; }
|
||||
internal MalMeasurementLibManager MalMeasurementLibManager { get; private set; }
|
||||
internal string TestMethodConfigFilePath { 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 bool SttoSuccess { get; 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
|
||||
@@ -78,100 +106,168 @@ namespace ProgramLib
|
||||
/// <param name="serialNumber">The UUT serial number</param>
|
||||
/// <param name="isThereHardware">false for simulation</param>
|
||||
/// <returns></returns>
|
||||
public static Program Instance(string partNumber = "", string serialNumber = "", bool isThereHardware = true, object testStandSeqContext = null)
|
||||
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, isThereHardware, testStandSeqContext);
|
||||
_program = new Program(partNumber, serialNumber, testType, testName, isThereHardware, configSubFolderName);
|
||||
_program.Initialize();
|
||||
}
|
||||
|
||||
return _program;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function is only meant to be called from third-party test executive such as TestStand.
|
||||
/// By settting this object to null, Garbage collection is initiated on this objects and any objects created by this object
|
||||
/// with the exception of static objects. Static objects needs to be explicitly killed by setting them to null
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static void KillInstance()
|
||||
{
|
||||
if (_program != null)
|
||||
{
|
||||
// signal to all running threads to exit
|
||||
_program.EventManager[EventManager.Events.GLOBAL_QUIT].Set();
|
||||
|
||||
UutPowerAction uutPowerAction = new UutPowerAction();
|
||||
uutPowerAction.UutPowerOff();
|
||||
|
||||
// needs to kill all the support threads since they could be accessing GUI
|
||||
_program.KillSupportThreads();
|
||||
|
||||
// Because the GuiManager class starts a STA thread to manage WPF GUIs
|
||||
// the 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.GetGuiManager()?.Dispose();
|
||||
|
||||
// this starts garbage collection on this object which then in turn start garbage collection
|
||||
// on all objects it created
|
||||
_program = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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, bool isThereHardware, object testStandSeqContext)
|
||||
private Program(string partNumber, string serialNumber, string testType, string testName, bool isThereHardware, string configSubFolderName)
|
||||
{
|
||||
// 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();
|
||||
|
||||
string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
ProgramConfig = new ConfigurationFile(Path.Combine(assemblyFolder, GeneralConstants.ProgramConfigFilename));
|
||||
|
||||
TestMethodConfigFilePath = Path.Combine(assemblyFolder, GeneralConstants.TestMethodConfigFolderName, GeneralConstants.TestMethodConfigFileName);
|
||||
|
||||
EventManager = new EventManager();
|
||||
FileAndFolderManager = new FileAndFolderManager(ProgramConfig);
|
||||
|
||||
if (testStandSeqContext != null)
|
||||
{
|
||||
TestStandSeqContext = testStandSeqContext as SequenceContext;
|
||||
}
|
||||
|
||||
// make sure PN/SN are valid (TS may not pass in the PN)
|
||||
if (partNumber == "" || partNumber == null)
|
||||
{
|
||||
partNumber = "DefaultPN";
|
||||
}
|
||||
|
||||
if (serialNumber == "" || serialNumber == null)
|
||||
{
|
||||
serialNumber = "DefaultSN";
|
||||
}
|
||||
|
||||
_partNumber = partNumber;
|
||||
_serialNumber = serialNumber;
|
||||
_isThereHardware = isThereHardware;
|
||||
|
||||
SttoSuccess = false;
|
||||
|
||||
// Initialze all other configuration that the program needs
|
||||
UutInfo = new UutInfo(_partNumber, _serialNumber);
|
||||
|
||||
try
|
||||
{
|
||||
var configFolder = Path.Combine(assemblyFolder, Raytheon.Common.Constants.InstrumentConfigFolder);
|
||||
_instrumentManager = new GeneralInstrumentManager(assemblyFolder, configFolder, _isThereHardware);
|
||||
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);
|
||||
_malMeasurementLibManager = new MalMeasurementLibManager(_instrumentManager);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
@@ -186,24 +282,292 @@ namespace ProgramLib
|
||||
{
|
||||
_logger?.Debug($"Entering {this.GetType().Name}::{System.Reflection.MethodBase.GetCurrentMethod().Name}() ...");
|
||||
|
||||
if (TestStandSeqContext != null)
|
||||
if (TestStandSeqContext == null)
|
||||
{
|
||||
// clear any setting that we have added for any steps in the Setup Group
|
||||
for (int i = 0; i < TestStandSeqContext.Sequence.GetNumSteps(StepGroups.StepGroup_Setup); i++)
|
||||
// signal to all running threads to exit
|
||||
EventManager[EventManager.Events.GLOBAL_QUIT].Set();
|
||||
|
||||
if (IsUutPwrOn)
|
||||
{
|
||||
TestStandSeqContext.Sequence.GetStep(i, StepGroups.StepGroup_Setup).PostExpression = "";
|
||||
BasicAction action = new UutPowerOffAction();
|
||||
action.Run();
|
||||
}
|
||||
|
||||
// clear any setting that we have added for any steps in the Main Group
|
||||
for (int i = 0; i < TestStandSeqContext.Sequence.GetNumSteps(StepGroups.StepGroup_Main); i++)
|
||||
// needs to kill all the support threads since they could be accessing GUI
|
||||
foreach (BasicThread thread in _threadList)
|
||||
{
|
||||
TestStandSeqContext.Sequence.GetStep(i, StepGroups.StepGroup_Main).PostExpression = "";
|
||||
TestStandSeqContext.Sequence.GetStep(i, StepGroups.StepGroup_Main).AdditionalResults.CustomResults.Clear();
|
||||
thread.Quit();
|
||||
thread.WaitForExit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void KillSupportThreads()
|
||||
/// <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)
|
||||
{
|
||||
@@ -212,82 +576,18 @@ namespace ProgramLib
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// All code module should not throw exception into teststand and let teststand handle the exception
|
||||
/// We give the teststand step a nice error message and tell teststand to go to cleanup
|
||||
/// If we are not calling into code from teststand, then we throw exception as usual
|
||||
/// Call this only from code executing on the main TestStand thread
|
||||
/// </summary>
|
||||
/// <param name="ex"></param>
|
||||
/// <returns></returns>
|
||||
private void TerminateTestOnMainThreadError(Exception ex)
|
||||
{
|
||||
if (TestStandSeqContext != null)
|
||||
{
|
||||
_logger.Error(ex.Message + "\n" + ex.StackTrace);
|
||||
|
||||
lock (_terminateTestSyncObj)
|
||||
{
|
||||
if (!_terminateTestInitiated)
|
||||
{
|
||||
// tells teststand there's a exception occurred and give it the error message
|
||||
TestStandSeqContext.Step.PostExpression = $"Step.Result.Error.Msg=\"{ex.Message} \", Step.Result.Error.Occurred=True";
|
||||
|
||||
TestStandSeqContext.Step.ResultStatus = "Error";
|
||||
|
||||
// tells TestStand to go to clean up
|
||||
TestStandSeqContext.StepGroup = StepGroups.StepGroup_Cleanup;
|
||||
TestStandSeqContext.NextStepIndex = 0;
|
||||
|
||||
_terminateTestInitiated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
throw ex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Support threads such as monitor threads need a way to stop the sequence if it encounters an error
|
||||
/// This function is meant to be called from FailureMonitorThread which monitors any error signaled by any
|
||||
/// support thread.
|
||||
/// </summary>
|
||||
/// <param name=""></param>
|
||||
/// <returns></returns>
|
||||
internal void TerminateTestOnSupportThreadError()
|
||||
{
|
||||
if (TestStandSeqContext != null)
|
||||
{
|
||||
lock (_terminateTestSyncObj)
|
||||
{
|
||||
if (!_terminateTestInitiated)
|
||||
{
|
||||
// tells teststand there's a exception occurred and give it the error message
|
||||
TestStandSeqContext.SequenceErrorMessage = _fatalErrorMsgFromSupportThread + " ";
|
||||
TestStandSeqContext.SequenceErrorOccurred = true;
|
||||
|
||||
// tells TestStand to go to clean up
|
||||
TestStandSeqContext.StepGroup = StepGroups.StepGroup_Cleanup;
|
||||
TestStandSeqContext.NextStepIndex = 0;
|
||||
|
||||
_terminateTestInitiated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save error message originated from other threads
|
||||
/// </summary>
|
||||
/// <param name=""></param>
|
||||
/// <returns></returns>
|
||||
internal void SetFatalErrorMsgFromSupportThread(string errorMsg)
|
||||
internal void SetFatalFailureExceptionFromSupportThread(Exception fatalFailureException)
|
||||
{
|
||||
lock(_fatalErrorMsgFromSupportThreadSyncObj)
|
||||
lock (_fatalFailureExceptionFromSupportThreadSyncObj)
|
||||
{
|
||||
if (String.IsNullOrEmpty(_fatalErrorMsgFromSupportThread))
|
||||
if (_fatalFailureExceptionFromSupportThread == null)
|
||||
{
|
||||
_fatalErrorMsgFromSupportThread = errorMsg;
|
||||
_fatalFailureExceptionFromSupportThread = fatalFailureException;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user