ResourceDep[] getManyResources <T>(T[] steps)
        {
            if (steps.Length == 0)
            {
                return(Array.Empty <ResourceDep>());
            }

            var result = new HashSet <ResourceDep>();

            TestStepExtensions.GetObjectSettings <IResource, T, ResourceDep>(steps, true, FilterProps, result);
            result.RemoveWhere(dep => dep.Behavior == ResourceOpenBehavior.Ignore);
            return(result.ToArray());
        }
Exemple #2
0
        /// <summary>
        /// Checks all validation rules on this object (<see cref="Rules"/>) and throws an AggregateException on errors.
        /// </summary>
        /// <param name="ignoreDisabledProperties">If true, ignores <see cref="Rules"/> related to properties that are disabled or hidden as a result of <see cref="EnabledIfAttribute"/> or <see cref="Enabled{T}"/>.</param>
        /// <exception cref="AggregateException">Thrown when any <see cref="Rules"/> on this object are invalid. This exception contains an ArgumentException for each invalid setting.</exception>
        protected void ThrowOnValidationError(bool ignoreDisabledProperties)
        {
            var propertyNames = new HashSet <string>();

            TestStepExtensions.GetObjectSettings(this, ignoreDisabledProperties,
                                                 (object o, IMemberData pi) => pi.Name, propertyNames);
            foreach (ValidationRule rule in Rules)
            {
                if (!rule.IsValid() && propertyNames.Contains(rule.PropertyName))
                {
                    throw new Exception($"The Property [{rule.PropertyName}] is invalid. Details: {rule.ErrorMessage}");
                }
            }
        }
        /// <summary>
        /// Finds all IResource properties on a list of references. The references can be any class derived from ITapPlugin, such as ITestStep or IResource.
        /// If a reference supplied in the <paramref name="references"/> list is a IResource itself it will be added to the resulting list.
        /// </summary>
        internal List <ResourceNode> GetAllResources(object[] references, out bool errorDetected)
        {
            errorDetected = false;

            ResourceDep[] stepResources = getManyResources(references);
            var           resourceDeps  = new List <ResourceDep>(stepResources);

            foreach (var reference in references)
            {
                if (reference is IResource res)
                {
                    resourceDeps.Add(new ResourceDep(res));
                }
            }
            List <ResourceNode> tree = GetResourceTree(resourceDeps);

            ExpandTree(tree);

            // Check that no resources have direct references to itself.
            foreach (var scc in tree.Where(x => x.StrongDependencies.Any(dep => dep == x.Resource)))
            {
                foreach (var dep in scc.StrongDependencies)
                {
                    if (dep == scc.Resource)
                    {
                        errorDetected = true;
                        Log.Error("Resource is referencing itself: {0}", scc.Resource);
                        break;
                    }
                }
            }

            // Figure out if all resources has their resource properties set
            foreach (var leaf in tree)
            {
                if (leaf.StrongDependencies.Any(s => s is null))
                {
                    errorDetected = true;
                    Log.Error($"Resource setting not set on resource {leaf.Resource}. Please configure or disable the resource.");
                }
            }

            if (errorDetected) // If any resources has resource properties which is not set, let's return early, because FindStronglyConntectedComponents method below will throw a confusing error in this case.
            {
                return(tree);
            }

            // Figure out if there are circular references, and list the circular references in an exception each.
            var sccs = FindStronglyConnectedComponents(tree);

            if (sccs.Count > 0)
            {
                errorDetected = true;

                foreach (var scc in sccs)
                {
                    Log.Error(string.Format("Circular references between resources: {0}", string.Join(",", scc.Select(res => res.Name))));
                }
            }

            //Add users of resources
            foreach (var r in references)
            {
                TestStepExtensions.GetObjectSettings <IResource, object, ResourceNode>(r, true, (res, prop) =>
                {
                    var nodes = tree.Where(n => n.Resource == res);
                    if (nodes.Count() > 1)
                    {
                        // Normally we would expect that the tree only contains one node representing each resource.
                        // In case of null resources however, we want one node per property, such that ILockManager.BeforeOpen()
                        // has a chance to set each property to a different resource instance.
                        if (res != null)
                        {
                            throw new Exception($"Duplicate entry for Resource '{res.Name}' in tree.");
                        }
                        nodes = nodes.Where(n => n.Depender == prop);
                    }
                    var nodeRepresentingResource = nodes.FirstOrDefault();
                    if (nodeRepresentingResource != null)
                    {
                        nodeRepresentingResource.References.Add(new ResourceReference(r, prop));
                    }
                    return(nodeRepresentingResource);
                }, new HashSet <ResourceNode>());
            }
            return(tree);
        }
Exemple #4
0
        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);
        }