/// <summary> /// Execute the TestPlan as specified. /// </summary> /// <param name="resultListeners">ResultListeners for result outputs.</param> /// <param name="metaDataParameters">Optional metadata parameters.</param> /// <param name="stepsOverride">Sub-section of test plan to be executed. Note this might include child steps of disabled parent steps.</param> /// <param name="cancellationToken">Cancellation token to abort the testplan</param> /// <returns>TestPlanRun results, no StepResults.</returns> public Task <TestPlanRun> ExecuteAsync(IEnumerable <IResultListener> resultListeners, IEnumerable <ResultParameter> metaDataParameters, HashSet <ITestStep> stepsOverride, CancellationToken cancellationToken) { Task <TestPlanRun> result = Task.Run(() => { var sem = new SemaphoreSlim(0); TestPlanRun testPlanRun = null; TapThread.Start(() => { try { cancellationToken.Register(TapThread.Current.Abort); testPlanRun = Execute(resultListeners, metaDataParameters, stepsOverride); } finally { sem.Release(); } }, "Plan Thread"); sem.Wait(); return(testPlanRun); }); return(result); }
/// <summary> /// Execute the TestPlan as specified. Blocking. /// </summary> /// <param name="resultListeners">ResultListeners for result outputs.</param> /// <param name="metaDataParameters">Optional metadata parameters.</param> /// <param name="stepsOverride">Sub-section of test plan to be executed. Note this might include child steps of disabled parent steps.</param> /// <returns>TestPlanRun results, no StepResults.</returns> public TestPlanRun Execute(IEnumerable <IResultListener> resultListeners, IEnumerable <ResultParameter> metaDataParameters = null, HashSet <ITestStep> stepsOverride = null) { TestPlanRun run = null; TapThread.WithNewContext(() => run = this.DoExecute(resultListeners, metaDataParameters, stepsOverride)); return(run); }
/// <summary> /// Opens all resources referenced in this TestPlan (Instruments/DUTs/ResultListeners). /// This can be called before <see cref="TestPlan.Execute()"/> to manually control the opening/closing of the resources. /// </summary> public void Open(IEnumerable <IResultListener> listeners) { if (listeners == null) { throw new ArgumentNullException("listeners"); } if (PrintTestPlanRunSummary) { listeners = listeners.Concat(new IResultListener[] { summaryListener }); } if (currentExecutionState != null) { throw new InvalidOperationException("Open has already been called."); } if (IsRunning) { throw new InvalidOperationException("This TestPlan is already running."); } try { var allSteps = Utils.FlattenHeirarchy(Steps.Where(x => x.Enabled), step => step.GetEnabledChildSteps()).ToList(); Stopwatch timer = Stopwatch.StartNew(); currentExecutionState = new TestPlanRun(this, listeners.ToList(), DateTime.Now, Stopwatch.GetTimestamp(), true); OpenInternal(currentExecutionState, false, listeners.Cast <IResource>().ToList(), allSteps); try { currentExecutionState.ResourceManager.WaitUntilAllResourcesOpened(TapThread.Current.AbortToken); } catch { Log.Warning("Caught error while opening resources! See error message for details."); throw; } Log.Debug(timer, "TestPlan opened."); } catch { // If there is an error, reset the state to allow calling open again later // when the user has fixed the error. if (currentExecutionState != null) { currentExecutionState.ResourceManager.EndStep(this, TestPlanExecutionStage.Open); } if (monitors != null) { foreach (var item in monitors) { item.ExitTestPlanRun(currentExecutionState); } } currentExecutionState = null; throw; } }
/// <summary> /// Signals that an action is beginning. /// </summary> /// <param name="planRun">The planrun for the currently executing testplan.</param> /// <param name="item">The item affected by the current action. This can be either a testplan or a teststep.</param> /// <param name="stage">The stage that is beginning.</param> /// <param name="cancellationToken">Used to cancel the step early.</param> public void BeginStep(TestPlanRun planRun, ITestStepParent item, TestPlanExecutionStage stage, CancellationToken cancellationToken) { switch (stage) { case TestPlanExecutionStage.Execute: if (item is TestPlan testPlan) { var resources = ResourceManagerUtils.GetResourceNodes(StaticResources.Cast <object>().Concat(EnabledSteps)); // Proceed to open resources in case they have been changed or closed since last opening/executing the testplan. // In case any are null, we need to do this before the resource prompt to allow a ILockManager implementation to // set the resource first. if (resources.Any(r => r.Resource == null)) { beginOpenResoureces(resources, cancellationToken); } testPlan.StartResourcePromptAsync(planRun, resources.Select(res => res.Resource)); if (resources.Any(r => openTasks.ContainsKey(r.Resource) == false)) { beginOpenResoureces(resources, cancellationToken); } } break; case TestPlanExecutionStage.Open: if (item is TestPlan) { var resources = ResourceManagerUtils.GetResourceNodes(StaticResources.Cast <object>().Concat(EnabledSteps)); beginOpenResoureces(resources, cancellationToken); } break; case TestPlanExecutionStage.Run: case TestPlanExecutionStage.PrePlanRun: { bool openCompletedWithSuccess = openTasks.Values.All(x => x.Status == TaskStatus.RanToCompletion); if (!openCompletedWithSuccess) { // open did not complete or threw an exception. using (TimeoutOperation.Create(() => TestPlan.PrintWaitingMessage(Resources))) WaitUntilAllResourcesOpened(cancellationToken); } break; } case TestPlanExecutionStage.PostPlanRun: break; } }
public override void OnTestPlanRunCompleted(TestPlanRun planRun, Stream log) { foreach (IResultSink sink in currentSinks) { try { sink.OnTestPlanRunCompleted(planRun); } catch (Exception ex) { Log.Error($"{TypeData.GetTypeData(sink).Name} caused an error."); Log.Debug(ex); } } }
/// <summary> /// On test plan run completed the previously temporary file is moved to the location expanded by the macro path. /// </summary> /// <param name="planRun"></param> /// <param name="logStream"></param> public override void OnTestPlanRunCompleted(TestPlanRun planRun, Stream logStream) { if (logStream == null) { throw new ArgumentNullException("logStream"); } base.OnTestPlanRunCompleted(planRun, logStream); OnActivity(); string outpath = ""; FileStream fstr; lock (filereadlocker) { string realPath = FilePath.Expand(planRun); if (Path.GetDirectoryName(realPath) != "") { Directory.CreateDirectory(Path.GetDirectoryName(realPath)); } int fileid = 1; outpath = realPath; while (File.Exists(outpath)) { var extension = Path.GetExtension(realPath); outpath = Path.ChangeExtension(realPath, string.Format(".{0}", fileid++) + extension); } fstr = new FileStream(outpath, FileMode.Create); } if (useFilter()) { filterCopyStream(logStream, fstr); } else { logStream.CopyTo(fstr); } fstr.Close(); }
private void OpenInternal(TestPlanRun run, bool isOpen, List <IResource> resources, List <ITestStep> steps) { monitors = TestPlanRunMonitors.GetCurrent(); try { // Enter monitors foreach (var item in monitors) { item.EnterTestPlanRun(run); } } finally // We need to make sure OpenAllAsync is always called (even when CheckResources throws an exception). { // Otherwise we risk that e.g. ResourceManager.WaitUntilAllResourcesOpened() will hang forever. run.ResourceManager.EnabledSteps = steps; run.ResourceManager.StaticResources = resources; if (!isOpen) { run.ResourceManager.BeginStep(run, this, TestPlanExecutionStage.Open, TapThread.Current.AbortToken); } } }
/// <summary> /// Closes all resources referenced in this TestPlan (Instruments/DUTs/ResultListeners). /// This should be called if <see cref="TestPlan.Open()"/> was called earlier to manually close the resources again. /// </summary> public void Close() { if (IsRunning) { throw new InvalidOperationException("Cannot close TestPlan while it is running."); } if (currentExecutionState == null) { throw new InvalidOperationException("Call open first."); } Stopwatch timer = Stopwatch.StartNew(); currentExecutionState.ResourceManager.EndStep(this, TestPlanExecutionStage.Open); // If we locked the setup earlier, unlock it now that all recourses has been closed: foreach (var item in monitors) { item.ExitTestPlanRun(currentExecutionState); } currentExecutionState = null; Log.Debug(timer, "TestPlan closed."); }
bool runPrePlanRunMethods(IEnumerable <ITestStep> steps, TestPlanRun planRun) { Stopwatch preTimer = Stopwatch.StartNew(); // try to avoid calling Stopwatch.StartNew too often. TimeSpan elaps = preTimer.Elapsed; foreach (ITestStep step in steps) { if (step.Enabled == false) { continue; } bool runPre = true; if (step is TestStep s) { runPre = s.PrePostPlanRunUsed; } planRun.StepsWithPrePlanRun.Add(step); try { if (runPre) { planRun.AddTestStepStateUpdate(step.Id, null, StepState.PrePlanRun); try { step.PlanRun = planRun; planRun.ResourceManager.BeginStep(planRun, step, TestPlanExecutionStage.PrePlanRun, TapThread.Current.AbortToken); try { step.PrePlanRun(); } finally { planRun.ResourceManager.EndStep(step, TestPlanExecutionStage.PrePlanRun); step.PlanRun = null; } } finally { planRun.AddTestStepStateUpdate(step.Id, null, StepState.Idle); } } if (!runPrePlanRunMethods(step.ChildTestSteps, planRun)) { return(false); } } catch (Exception ex) { Log.Error(String.Format("PrePlanRun of '{0}' failed with message '{1}'.", step.Name, ex.Message)); Log.Debug(ex); Log.Error("Aborting TestPlan."); return(false); } finally { if (runPre) { var newelaps = preTimer.Elapsed; Log.Debug(newelaps - elaps, "{0} PrePlanRun completed.", step.GetStepPath()); elaps = newelaps; } } } return(true); }
private TestPlanRun DoExecute(IEnumerable <IResultListener> resultListeners, IEnumerable <ResultParameter> metaDataParameters, HashSet <ITestStep> stepsOverride) { if (resultListeners == null) { throw new ArgumentNullException("resultListeners"); } if (PrintTestPlanRunSummary && !resultListeners.Contains(summaryListener)) { resultListeners = resultListeners.Concat(new IResultListener[] { summaryListener }); } resultListeners = resultListeners.Where(r => r is IEnabledResource ? ((IEnabledResource)r).IsEnabled : true); IList <ITestStep> steps; if (stepsOverride == null) { steps = Steps; } else { // Remove steps that are already included via their parent steps. foreach (var step in stepsOverride) { if (step == null) { throw new ArgumentException("stepsOverride may not contain null", "stepsOverride"); } var p = step.GetParent <ITestStep>(); while (p != null) { if (stepsOverride.Contains(p)) { throw new ArgumentException("stepsOverride may not contain steps and their parents.", "stepsOverride"); } p = p.GetParent <ITestStep>(); } } steps = Utils.FlattenHeirarchy(Steps, step => step.ChildTestSteps).Where(stepsOverride.Contains).ToList(); } long initTimeStamp = Stopwatch.GetTimestamp(); var initTime = DateTime.Now; Log.Info("-----------------------------------------------------------------"); var fileStreamFile = FileSystemHelper.CreateTempFile(); var logStream = new HybridStream(fileStreamFile, 1024 * 1024); var planRunLog = new FileTraceListener(logStream) { IsRelative = true }; OpenTap.Log.AddListener(planRunLog); var allSteps = Utils.FlattenHeirarchy(steps, step => step.ChildTestSteps); var allEnabledSteps = Utils.FlattenHeirarchy(steps.Where(x => x.Enabled), step => step.GetEnabledChildSteps()); var enabledSinks = new HashSet <IResultSink>(); TestStepExtensions.GetObjectSettings <IResultSink, ITestStep, IResultSink>(allEnabledSteps, true, null, enabledSinks); if (enabledSinks.Count > 0) { var sinkListener = new ResultSinkListener(enabledSinks); resultListeners = resultListeners.Append(sinkListener); } Log.Info("Starting TestPlan '{0}' on {1}, {2} of {3} TestSteps enabled.", Name, initTime, allEnabledSteps.Count, allSteps.Count); // Reset step verdict. foreach (var step in allSteps) { if (step.Verdict != Verdict.NotSet) { step.Verdict = Verdict.NotSet; step.OnPropertyChanged("Verdict"); } } if (currentExecutionState != null) { // load result listeners that are _not_ used in the previous runs. // otherwise they wont get opened later. foreach (var rl in resultListeners) { if (!currentExecutionState.ResultListeners.Contains(rl)) { currentExecutionState.ResultListeners.Add(rl); } } } var currentListeners = currentExecutionState != null ? currentExecutionState.ResultListeners : resultListeners; TestPlanRun execStage; bool continuedExecutionState = false; if (currentExecutionState != null) { execStage = new TestPlanRun(currentExecutionState, initTime, initTimeStamp); continuedExecutionState = true; } else { execStage = new TestPlanRun(this, resultListeners.ToList(), initTime, initTimeStamp); execStage.Parameters.AddRange(PluginManager.GetPluginVersions(allEnabledSteps)); execStage.ResourceManager.ResourceOpened += r => { execStage.Parameters.AddRange(PluginManager.GetPluginVersions(new List <object> { r })); }; } if (metaDataParameters != null) { execStage.Parameters.AddRange(metaDataParameters); } var prevExecutingPlanRun = executingPlanRun.LocalValue; executingPlanRun.LocalValue = execStage; CurrentRun = execStage; failState runWentOk = failState.StartFail; // ReSharper disable once InconsistentNaming var preRun_Run_PostRunTimer = Stopwatch.StartNew(); try { execStage.FailedToStart = true; // Set it here in case OpenInternal throws an exception. Could happen if a step is missing an instrument OpenInternal(execStage, continuedExecutionState, currentListeners.Cast <IResource>().ToList(), allEnabledSteps); execStage.WaitForSerialization(); execStage.ResourceManager.BeginStep(execStage, this, TestPlanExecutionStage.Execute, TapThread.Current.AbortToken); if (continuedExecutionState) { // Since resources are not opened, getting metadata cannot be done in the wait for resources continuation // like shown in TestPlanRun. Instead we do it here. foreach (var res in execStage.ResourceManager.Resources) { execStage.Parameters.AddRange(ResultParameters.GetMetadataFromObject(res)); } } runWentOk = failState.ExecFail; //important if test plan is aborted and runWentOk is never returned. runWentOk = execTestPlan(execStage, steps); } catch (Exception e) { if (e is OperationCanceledException && execStage.MainThread.AbortToken.IsCancellationRequested) { Log.Warning(String.Format("TestPlan aborted. ({0})", e.Message)); execStage.UpgradeVerdict(Verdict.Aborted); } else if (e is ThreadAbortException) { // It seems this actually never happens. Log.Warning("TestPlan aborted."); execStage.UpgradeVerdict(Verdict.Aborted); //Avoid entering the finally clause. Thread.Sleep(500); } else if (e is System.ComponentModel.LicenseException) { Log.Error(e.Message); execStage.UpgradeVerdict(Verdict.Error); } else { Log.Warning("TestPlan aborted."); Log.Error(e.Message); Log.Debug(e); execStage.UpgradeVerdict(Verdict.Error); } } finally { execStage.FailedToStart = (runWentOk == failState.StartFail); try { finishTestPlanRun(execStage, preRun_Run_PostRunTimer, runWentOk, planRunLog, logStream); } catch (Exception ex) { Log.Error("Error while finishing TestPlan."); Log.Debug(ex); } OpenTap.Log.RemoveListener(planRunLog); planRunLog.Dispose(); logStream.Dispose(); File.Delete(fileStreamFile); // Clean all test steps StepRun, otherwise the next test plan execution will be stuck at TestStep.DoRun at steps that does not have a cleared StepRun. foreach (var step in allSteps) { step.StepRun = null; } executingPlanRun.LocalValue = prevExecutingPlanRun; CurrentRun = prevExecutingPlanRun; } return(execStage); }
/// <summary>Clears the memory.</summary> /// <param name="planRun"></param> public override void OnTestPlanRunStart(TestPlanRun planRun) { stepRuns = new Dictionary <Guid, TestStepRun>(); this.planRun = planRun; }
/// <summary> Cleans up after this instance </summary> public void OnTestPlanRunCompleted(TestPlanRun run) { ItemsInQueue.Dispose(); }
/// <summary> Initializes this instance. </summary> public void OnTestPlanRunStart(TestPlanRun run) { ItemsInQueue = new ManualResetEvent(false); }
void finishTestPlanRun(TestPlanRun run, Stopwatch testPlanTimer, failState runWentOk, TraceListener Logger, HybridStream logStream) { try { if (run != null) { if (runWentOk == failState.StartFail) { if (PrintTestPlanRunSummary) { summaryListener.OnTestPlanRunStart(run); // Call this to ensure that the correct planrun is being summarized } if (run.Verdict < Verdict.Aborted) { run.Verdict = Verdict.Error; } } for (int i = run.StepsWithPrePlanRun.Count - 1; i >= 0; i--) { Stopwatch postTimer = Stopwatch.StartNew(); String stepPath = string.Empty; try { ITestStep step = run.StepsWithPrePlanRun[i]; if ((step as TestStep)?.PrePostPlanRunUsed ?? true) { stepPath = step.GetStepPath(); run.AddTestStepStateUpdate(step.Id, null, StepState.PostPlanRun); try { run.ResourceManager.BeginStep(run, step, TestPlanExecutionStage.PostPlanRun, TapThread.Current.AbortToken); step.PlanRun = run; try { step.PostPlanRun(); } finally { run.ResourceManager.EndStep(step, TestPlanExecutionStage.PostPlanRun); step.PlanRun = null; } } finally { run.AddTestStepStateUpdate(step.Id, null, StepState.Idle); } Log.Debug(postTimer, "{0} PostPlanRun completed.", stepPath); } } catch (Exception ex) { Log.Warning("Error during post plan run of {0}.", stepPath); Log.Debug(ex); } } run.Duration = testPlanTimer.Elapsed; } if (run != null) { try { // The open resource threads might throw exceptions. If they do we must // Wait() for them to catch the exception. // If the run was aborted after the open resource threads were started but // before we wait for them (e.g. by an error in PrePlanRun), then we do it // here. run.ResourceManager.WaitUntilAllResourcesOpened(TapThread.Current.AbortToken); } catch (OperationCanceledException) { // Ignore this because this typically means that the wait was cancelled before. // Just to be sure also upgrade verdict to aborted. run.UpgradeVerdict(Verdict.Aborted); } catch (AggregateException e) { if (e.InnerExceptions.Count == 1) { Log.Error("Failed to open resource ({0})", e.GetInnerMostExceptionMessage()); Log.Debug(e); } else { Log.Error("Errors while opening resources:", e.GetInnerMostExceptionMessage()); foreach (Exception ie in e.InnerExceptions) { Log.Error(" {0}", ie.GetInnerMostExceptionMessage()); Log.Debug(ie); } } } if (PrintTestPlanRunSummary) { // wait for the summaryListener so the summary appears in the log file. run.WaitForResultListener(summaryListener); summaryListener.PrintSummary(); } OpenTap.Log.Flush(); Logger.Flush(); logStream.Flush(); run.AddTestPlanCompleted(logStream, runWentOk != failState.StartFail); run.ResourceManager.EndStep(this, TestPlanExecutionStage.Execute); if (!run.IsCompositeRun) { run.ResourceManager.EndStep(this, TestPlanExecutionStage.Open); } } } finally { if (monitors != null) { foreach (var item in monitors) { item.ExitTestPlanRun(run); } } } }
/// <summary> /// Calls the PromptForDutMetadata delegate for all referenced DUTs. /// </summary> internal void StartResourcePromptAsync(TestPlanRun planRun, IEnumerable <IResource> _resources) { var resources = _resources.Where(x => x != null).ToArray(); List <Type> componentSettingsWithMetaData = new List <Type>(); var componentSettings = PluginManager.GetPlugins <ComponentSettings>(); bool AnyMetaData = false; planRun.PromptWaitHandle.Reset(); try { foreach (var setting in componentSettings) { foreach (var member in setting.GetMembers()) { var attr = member.GetAttribute <MetaDataAttribute>(); if (attr != null && attr.PromptUser) { AnyMetaData = true; componentSettingsWithMetaData.Add(setting); } } } foreach (var resource in resources) { var type = TypeData.GetTypeData(resource); foreach (var __prop in type.GetMembers()) { IMemberData prop = __prop; var attr = prop.GetAttribute <MetaDataAttribute>(); if (attr != null && attr.PromptUser) { AnyMetaData = true; } } } } catch { // this is just a defensive catch to make sure that the waithandle is not left unset (and we risk waiting for it indefinitely) planRun.PromptWaitHandle.Set(); throw; } if (AnyMetaData && EngineSettings.Current.PromptForMetaData) { TapThread.Start(() => { try { List <object> objects = new List <object>(); objects.AddRange(componentSettingsWithMetaData.Select(ComponentSettings.GetCurrent)); objects.AddRange(resources); planRun.PromptedResources = resources; var obj = new MetadataPromptObject { Resources = objects }; UserInput.Request(obj, false); if (obj.Response == MetadataPromptObject.PromptResponse.Abort) { planRun.MainThread.Abort(); } } catch (Exception e) { Log.Debug(e); planRun.MainThread.Abort("Error occured while executing platform requests. Metadata prompt can be disabled from the Engine settings menu."); } finally { planRun.PromptWaitHandle.Set(); } }, name: "Request Metadata"); } else { planRun.PromptWaitHandle.Set(); } }
/// <summary> /// Signals that an action is beginning. /// </summary> /// <param name="planRun">The planrun for the currently executing testplan.</param> /// <param name="item">The item affected by the current action. This can be either a testplan or a teststep.</param> /// <param name="stage">The stage that is beginning.</param> /// <param name="cancellationToken">Used to cancel the step early.</param> public void BeginStep(TestPlanRun planRun, ITestStepParent item, TestPlanExecutionStage stage, CancellationToken cancellationToken) { switch (stage) { case TestPlanExecutionStage.Open: case TestPlanExecutionStage.Execute: { var resources = ResourceManagerUtils.GetResourceNodes(StaticResources); if (item is TestPlan plan && stage == TestPlanExecutionStage.Execute) { // Prompt for metadata for all resources, not only static ones. var testPlanResources = ResourceManagerUtils.GetResourceNodes(EnabledSteps); plan.StartResourcePromptAsync(planRun, resources.Concat(testPlanResources).Select(res => res.Resource)); } if (resources.All(r => r.Resource?.IsConnected ?? false)) { return; } // Call ILockManagers before checking for null try { lockManager.BeforeOpen(resources, cancellationToken); } finally { lock (resourceWithBeforeOpenCalled) { resourceWithBeforeOpenCalled.AddRange(resources); } } try { // Check null resources if (resources.Any(res => res.Resource == null)) { // Now check resources since we know one of them should have a null resource resources.ForEach(res => { if (res.StrongDependencies.Contains(null) || res.WeakDependencies.Contains(null)) { throw new Exception(String.Format("Resource property not set on resource {0}. Please configure resource.", res.Resource)); } }); } } finally { OpenResources(resources, cancellationToken); } break; } case TestPlanExecutionStage.Run: if (item is ITestStep step) { var resources = ResourceManagerUtils.GetResourceNodes(new List <object> { step }); if (resources.Any()) { // Call ILockManagers before checking for null try { lockManager.BeforeOpen(resources, cancellationToken); } finally { lock (resourceWithBeforeOpenCalled) { resourceWithBeforeOpenCalled.AddRange(resources); } } try { // Check null resources if (resources.Any(res => res.Resource == null)) { step.CheckResources(); // Now check resources since we know one of them should have a null resource resources.ForEach(res => { if (res.StrongDependencies.Contains(null) || res.WeakDependencies.Contains(null)) { throw new Exception(String.Format("Resource property not set on resource {0}. Please configure resource.", res.Resource)); } }); } } finally { lock (resourceLock) { resourceDependencies[step] = resources.Select(x => x.Resource).ToList(); foreach (ResourceNode n in resources) { if (n.Resource is IResource resource) { if (!resourceReferenceCount.ContainsKey(resource)) { resourceReferenceCount[resource] = 0; } resourceReferenceCount[resource] += 1; } } } OpenResources(resources, cancellationToken); } WaitHandle.WaitAny(new[] { planRun.PromptWaitHandle, planRun.MainThread.AbortToken.WaitHandle }); } } break; } }
failState execTestPlan(TestPlanRun execStage, IList <ITestStep> steps) { WaitHandle.WaitAny(new[] { execStage.PromptWaitHandle, TapThread.Current.AbortToken.WaitHandle }); bool resultListenerError = false; execStage.ScheduleInResultProcessingThread <IResultListener>(resultListener => { try { using (TimeoutOperation.Create(() => PrintWaitingMessage(new List <IResource>() { resultListener }))) execStage.ResourceManager.WaitUntilResourcesOpened(TapThread.Current.AbortToken, resultListener); try { // some resources might set metadata in the Open methods. // this information needs to be propagated to result listeners as well. // this returns quickly if its a lazy resource manager. using (TimeoutOperation.Create( () => PrintWaitingMessage(new List <IResource>() { resultListener }))) execStage.ResourceManager.WaitUntilAllResourcesOpened(TapThread.Current.AbortToken); } catch // this error will also be handled somewhere else. { } execStage.WaitForSerialization(); foreach (var res in execStage.PromptedResources) { execStage.Parameters.AddRange(ResultParameters.GetMetadataFromObject(res)); } resultListener.OnTestPlanRunStart(execStage); } catch (OperationCanceledException) when(execStage.MainThread.AbortToken.IsCancellationRequested) { // test plan thread was aborted, this is OK. } catch (Exception ex) { Log.Error("Error in OnTestPlanRunStart for '{0}': '{1}'", resultListener, ex.Message); Log.Debug(ex); resultListenerError = true; } }, true); if (resultListenerError) { return(failState.StartFail); } var sw = Stopwatch.StartNew(); try { execStage.StepsWithPrePlanRun.Clear(); if (!runPrePlanRunMethods(steps, execStage)) { return(failState.StartFail); } } catch (Exception e) { Log.Error(e.GetInnerMostExceptionMessage()); Log.Debug(e); return(failState.StartFail); } finally{ { Log.Debug(sw, "PrePlanRun Methods completed"); } } Stopwatch planRunOnlyTimer = Stopwatch.StartNew(); var runs = new List <TestStepRun>(); try { for (int i = 0; i < steps.Count; i++) { var step = steps[i]; if (step.Enabled == false) { continue; } var run = step.DoRun(execStage, execStage); if (!run.Skipped) { runs.Add(run); } run.CheckBreakCondition(); // note: The following is copied inside TestStep.cs if (run.SuggestedNextStep is Guid id) { int nextindex = steps.IndexWhen(x => x.Id == id); if (nextindex >= 0) { i = nextindex - 1; } // if skip to next step, dont add it to the wait queue. } } } catch (TestStepBreakException breakEx) { Log.Info("{0}", breakEx.Message); } finally { // Now wait for them to actually complete. They might defer internally. foreach (var run in runs) { run.WaitForCompletion(); execStage.UpgradeVerdict(run.Verdict); } } Log.Debug(planRunOnlyTimer, "Test step runs finished."); return(failState.Ok); }
/// <summary> /// Creates a new ResultProxy. Done for each test step run. /// </summary> /// <param name="stepRun">TestStepRun that this result proxy is proxy for.</param> /// <param name="planRun">TestPlanRun that this result proxy is proxy for.</param> public ResultSource(TestStepRun stepRun, TestPlanRun planRun) { this.stepRun = stepRun; this.planRun = planRun; }
/// <summary> Expands the text. Macros are harvested from the optional TestPlanRun or the test step.</summary> /// <param name="run">A place to find additional metadata for macro expansion.</param> /// <param name="date">If no date was found in the metadata, this date will be used. If date is not supplied, DateTime.Now will be used.</param> /// <param name="testPlanDir">If no TestPlanDir was found in the metata, this TestPlanDir will be used.</param> /// <param name="replacements">Overrides other macro parameters.</param> /// <returns>The expanded string.</returns> public string Expand(TestPlanRun run, DateTime?date, string testPlanDir, Dictionary <string, object> replacements) { ITestStepParent context = Context; IEnumerable <(string, object)> getMacro() { // note: macros are case-insensitive. if (testPlanDir != null) { yield return("TestPlanDir", testPlanDir); } if (date != null) { yield return("date", date); } if (replacements != null) { foreach (var elem in replacements) { yield return(elem.Key, elem.Value); } } if (run != null) { var runparams = run.Parameters.Concat(ResultParameters.GetMetadataFromObject(run)).Where(y => y.IsMetaData); foreach (var v in runparams) { var path = v.Value; yield return(v.Name, path); yield return(v.MacroName, path); } } ITestStepParent ctx = context; while (ctx != null) { var p = ResultParameters.GetMetadataFromObject(ctx); foreach (var v in p) { if (v.IsMetaData == false) { continue; } var path = v.Value; yield return(v.Name, path); yield return(v.MacroName, path); } ctx = ctx.Parent; } yield return("date", DateTime.Now); yield return("Verdict", Verdict.NotSet); var met = ResultParameters.GetComponentSettingsMetadataLazy(false); foreach (var ps in met) { foreach (var v in ps) { if (v.IsMetaData == false) { continue; } var path = v.Value; yield return(v.Name, path); yield return(v.MacroName, path); } } } return(ReplaceMacros(Text, getMacro().Select(x => (x.Item1, StringConvertProvider.GetString(x.Item2))))); }
/// <summary> Expands the text. Macros are harvested from the optional TestPlanRun or the test step.</summary> /// <param name="run">A place to find additional metadata for macro expansion.</param> /// <param name="date">If no date was found in the metadata, this date will be used. If date is not supplied, DateTime.Now will be used.</param> /// <param name="testPlanDir">If no TestPlanDir was found in the metata, this TestPlanDir will be used.</param> /// <returns>The expanded string.</returns> public string Expand(TestPlanRun run = null, DateTime?date = null, string testPlanDir = null) { return(Expand(run, date, testPlanDir, null)); }