/*-------------------------------------------------------------------------
// 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
{
///
/// 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.
///
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 _threadList = new List();
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 PowerModulesToBePowered { get; set; }
///
/// Create an instance of this class. Only one instance is allowed
///
/// The UUT part number
/// The UUT serial number
/// false for simulation
///
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;
}
///
/// The private constructor
///
/// the UUT part number
/// the UUT serial number
/// false for simulation
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();
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;
}
}
///
/// Finalizer
///
~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();
}
}
}
///
/// Perform initializations
///
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);
}
}
///
/// Check if we are running controlled software
///
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 { }
}
///
/// Start LogDashboard application
///
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 { }
}
///
/// Perform post test activities
///
internal void PerformPostTestActivities()
{
try
{
MoveNlogToTestFolder();
RecordTestRunEndInfoToFile();
CreatePdelFile();
}
catch (Exception) { }
}
///
/// Create PDEL file if there are PDEL results
///
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);
}
}
///
/// Move NLog to test folder
///
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);
}
}
}
}
///
/// Record general information about start of test run to file
///
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 attributesDict = new Dictionary();
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();
}
///
/// Record general information about end of test run to file
///
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 attributesDict = new Dictionary();
attributesDict[TestRunConfigXml.TestRunEndDateAttributeName] = DateTime.Now.ToString("MM/dd/yyyy");
attributesDict[TestRunConfigXml.TestRunEndTimeAttributeName] = DateTime.Now.ToString("HH:mm:ss");
doc.ChangeNode(node, attributesDict);
}
}
}
doc.SaveToFile();
}
///
/// Kill GUI thread
///
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) { }
}
///
/// Kill support threads
///
internal void KillSupportThreads()
{
foreach (BasicThread thread in _threadList)
{
thread.Quit();
thread.WaitForExit();
}
}
///
/// Save error message originated from other threads
///
///
///
internal void SetFatalFailureExceptionFromSupportThread(Exception fatalFailureException)
{
lock (_fatalFailureExceptionFromSupportThreadSyncObj)
{
if (_fatalFailureExceptionFromSupportThread == null)
{
_fatalFailureExceptionFromSupportThread = fatalFailureException;
}
}
}
}
}