예제 #1
0
        /// <summary>
        /// Validate actual trace angainst expected trace.
        /// Call is comming from the parent step
        /// </summary>
        /// <param name="actualTrace">actual trace</param>
        /// <param name="startIndex">index to start searches from</param>
        /// <returns>true if traces match</returns>
        private static bool ValidateFirst(TraceGroup currentTrace, int startIndex)
        {
            currentTrace.startIndex = startIndex;
            for (int i = 0; i < currentTrace.Steps.Count; i++)
            {
                currentTrace.endIndexes[i] = -1;
            }

            bool match = false;

            if (!currentTrace.Optional)
            {
                match = TraceValidator.Validate(currentTrace, 0, startIndex, DateTime.MinValue, DateTime.MinValue);
            }
            else
            {
                TraceValidator.SetRestorePoint();
                match = TraceValidator.Validate(currentTrace, 0, startIndex, DateTime.MinValue, DateTime.MinValue);
                if (match)
                {
                    TraceValidator.Commit();
                }
                else
                {
                    TraceValidator.Rollback();

                    // try to skip this entire step, since it's optional
                    match = TraceValidator.ValidateNextSibling(currentTrace.parent, currentTrace.indexInParent, startIndex);
                }
            }

            return(match);
        }
예제 #2
0
        /// <summary>
        /// Flattens the expected trace hierarchy as much as possible
        /// Intended to simplify validation function and make expected
        /// trace more human-readable
        /// </summary>
        internal static void NormalizeExpectedTrace(TraceGroup currentTrace)
        {
            int index = 0;

            while (index < currentTrace.Steps.Count)
            {
                // overwrite if a placeholder
                if (currentTrace.Steps[index] is IPlaceholderTraceProvider)
                {
                    currentTrace.Steps[index] = ((IPlaceholderTraceProvider)currentTrace.Steps[index]).GetPlaceholderTrace();
                }

                TraceGroup childStep = currentTrace.Steps[index] as TraceGroup;
                if (childStep != null)
                {
                    TraceValidator.NormalizeExpectedTrace(childStep);

                    if (childStep.Steps.Count == 0)
                    {
                        currentTrace.Steps.RemoveAt(index);
                        // skip index++;
                        continue;
                    }

                    if (childStep.ordered == currentTrace.ordered &&
                        !childStep.Optional &&
                        !childStep.Async)
                    {
                        //flatten the child step
                        currentTrace.Steps.RemoveAt(index);
                        currentTrace.Steps.InsertRange(index, childStep.Steps);
                        // count n steps forward and skip index++;
                        index = childStep.Steps.Count;
                        continue;
                    }
                }

                index++;
            }

            if ((currentTrace.Steps.Count == 1) &&
                (currentTrace.Steps[0] is TraceGroup))
            {
                // merge current step with the only child step, and their properties
                TraceGroup child = (TraceGroup)currentTrace.Steps[0];

                currentTrace.ordered  = child.ordered;
                currentTrace.Async    = (currentTrace.Async || child.Async);
                currentTrace.Optional = (currentTrace.Optional || child.Optional);

                //flatten the child step
                currentTrace.Steps.Clear();
                currentTrace.Steps.AddRange(child.Steps);
            }
        }
예제 #3
0
 /// <summary>
 /// Validate actual trace angainst expected trace.
 /// This method signals parent step to continue validation
 /// with the next sibling of this step.
 /// Call is comming from the child step
 /// </summary>
 /// <param name="childIndex">index of child just executed</param>
 /// <param name="actualTrace">actual trace</param>
 /// <param name="endIndex">index of the step next to the last step validated by child</param>
 /// <returns>true if traces match</returns>
 private static bool ValidateNextSibling(TraceGroup currentTrace, int childIndex, int endIndex)
 {
     currentTrace.endIndexes[childIndex] = endIndex;
     if (currentTrace.ordered)
     {
         return(TraceValidator.Validate(currentTrace, childIndex + 1, endIndex, DateTime.MinValue, DateTime.MinValue));
     }
     else
     {
         return(TraceValidator.Validate(currentTrace, childIndex + 1, currentTrace.startIndex, DateTime.MinValue, DateTime.MinValue));
     }
 }
예제 #4
0
        // <summary>
        // Prepare datastructure for validation
        // </summary>
        // <param name="expectedTrace">expected trace</param>
        private static void PrepareActualTrace()
        {
            // remove ignorable traces
            var ignorableSteps =
                (from step in TraceValidator.s_actualTrace.Steps
                 where TraceValidator.s_expectedTrace.CanBeIgnored(step)
                 select step).ToList();

            foreach (IActualTraceStep step in ignorableSteps)
            {
                TraceValidator.s_actualTrace.Steps.Remove(step);
            }

            foreach (IActualTraceStep step in TraceValidator.s_actualTrace.Steps)
            {
                step.Validated = 0;
                TraceValidator.AddActualStepCount(step);
            }
        }
예제 #5
0
        // <summary>
        // Remove traces we can ignore
        // </summary>
        private static void RemoveIgnorableSteps(TraceGroup trace)
        {
            var ignorableSteps =
                (from step in trace.Steps
                 where step is IActualTraceStep &&
                 TraceValidator.s_expectedTrace.CanBeIgnored((IActualTraceStep)step)
                 select step).ToList();

            foreach (WorkflowTraceStep step in ignorableSteps)
            {
                trace.Steps.Remove(step);
            }

            foreach (WorkflowTraceStep step in trace.Steps)
            {
                if (step is TraceGroup)
                {
                    TraceValidator.RemoveIgnorableSteps((TraceGroup)step);
                }
            }
        }
예제 #6
0
        /// <summary>
        /// Constructor
        /// </summary>
        public static void Validate(ActualTrace actualTrace, ExpectedTrace expectedTrace, bool traceTracking)
        {
            TraceValidator.s_actualTrace   = actualTrace;
            TraceValidator.s_expectedTrace = expectedTrace;

            TraceValidator.s_errorList  = new List <string>();
            TraceValidator.s_stepCounts = new Dictionary <string, StepCount>();

            TestTraceManager.OptionalLogTrace("[TraceValidator]Unfiltered expected trace:\n{0}", expectedTrace.ToString());
            TestTraceManager.OptionalLogTrace("[TraceValidator]Unfiltered actual trace:\n{0}", actualTrace.ToString());

            TraceValidator.NormalizeExpectedTrace(expectedTrace.Trace);
            TraceValidator.RemoveIgnorableSteps(expectedTrace.Trace);
            TraceValidator.PrepareExpectedTrace(expectedTrace.Trace, false, null, -1);

            TraceValidator.PrepareActualTrace();

            if (traceTracking)
            {
                //Log.TraceInternal("[TraceValidator]Filtered expected trace:\n{0}", expectedTrace.ToString());
                //Log.TraceInternal("[TraceValidator]Filtered actual trace:\n{0}", actualTrace.ToString());
                //Log.TraceInternal("[TraceValidator]Doing count validation...");
            }

            TraceValidator.CheckStepCounts();
            TraceValidator.CheckErrors();

            if (traceTracking)
            {
                //Log.TraceInternal("[TraceValidator]Validating...");
            }
            TraceValidator.ValidateFirst(expectedTrace.Trace, 0);
            TraceValidator.CheckErrors();

            if (traceTracking)
            {
                //Log.TraceInternal("[TraceValidator]ExpectedTrace: Validation complete.");
            }
        }
예제 #7
0
        // <summary>
        // Prepares composite steps for validation
        // </summary>
        // <param name="stepCounter">StepCounter object to count optional and required steps</param>
        // <param name="parentIsOptional">Indicates if parent step is optional</param>
        // <param name="parentStep">parent step object</param>
        // <param name="indexInParent">index of this step inside its parent</param>
        private static void PrepareExpectedTrace(TraceGroup traceStep, bool parentIsOptional, TraceGroup parentStep, int indexInParent)
        {
            // set parent step reference for this step
            traceStep.parent        = parentStep;
            traceStep.indexInParent = indexInParent;

            bool optional = parentIsOptional || traceStep.Optional;

            // set parent step reference for children steps
            for (int i = 0; i < traceStep.Steps.Count; i++)
            {
                WorkflowTraceStep childStep = traceStep.Steps[i];

                if (childStep is TraceGroup)
                {
                    TraceValidator.PrepareExpectedTrace((TraceGroup)childStep, optional, traceStep, i);
                }
                else if (childStep is IActualTraceStep)
                {
                    if (optional || childStep.Optional)
                    {
                        TraceValidator.AddExpectedOptStepCount((IActualTraceStep)childStep);
                    }
                    else
                    {
                        TraceValidator.AddExpectedReqStepCount((IActualTraceStep)childStep);
                    }
                }
            }

            // declare & init endIndexes[] array
            traceStep.endIndexes = new int[traceStep.Steps.Count];
            for (int i = 0; i < traceStep.Steps.Count; i++)
            {
                traceStep.endIndexes[i] = -1;
            }
        }
예제 #8
0
        public void Validate(ExpectedTrace expectedTrace, bool logTraces)
        {
            lock (_steps)
            {
                if (expectedTrace.SortBeforeVerification)
                {
                    // copy the expected trace, remove activity traces and verify workflow instnace traces
                    ExpectedTrace etrace = new ExpectedTrace(expectedTrace);
                    ActualTrace   atrace = new ActualTrace(this);
                    etrace.AddIgnoreTypes(typeof(ActivityTrace), typeof(UserTrace));
                    TraceValidator.Validate(atrace, etrace, logTraces);

                    // now verify the activity traces, after they have been ordered
                    expectedTrace.AddIgnoreTypes(typeof(WorkflowInstanceTrace));
                    expectedTrace.AddIgnoreTypes(typeof(UserTrace));
                    this.OrderTraces();
                    TraceValidator.Validate(this, expectedTrace);
                }
                else
                {
                    TraceValidator.Validate(this, expectedTrace, logTraces);
                }
            }
        }
예제 #9
0
 private static void AddExpectedOptStepCount(IActualTraceStep step)
 {
     TraceValidator.GetStepCount(step).expectedOptCount++;
 }
예제 #10
0
 private static void AddActualStepCount(IActualTraceStep step)
 {
     TraceValidator.GetStepCount(step).actualTraceCount++;
 }
예제 #11
0
        /// <summary>
        /// Validate actual trace angainst expected trace.
        /// This method validates next same level expected step
        /// </summary>
        /// <param name="curExpIndex">expected trace step index</param>
        /// <param name="actualTrace">actual trace</param>
        /// <param name="startIndex">index to start searches from</param>
        /// <param name="lastTime">time last step occured at</param>
        /// <param name="mustBeAfter">subsequent step must occur after time specified</param>
        /// <returns>true if traces match</returns>
        private static bool Validate(TraceGroup currentTrace, int curExpIndex, int startIndex, DateTime lastTime, DateTime mustBeAfter)
        {
            // is this a last step to check?
            if (curExpIndex >= currentTrace.Steps.Count)
            {
                bool match = false;

                if (null == currentTrace.parent)
                {
                    //Oracle.LogDebugInfo("End of step list. Verifying completeness");
                    return(TraceValidator.VerifyAllStepsValidated());
                }
                else
                {
                    //Oracle.LogDebugInfo("Check next parent step");
                    if (currentTrace.Async)
                    {
                        match = TraceValidator.ValidateNextSibling(currentTrace.parent, currentTrace.indexInParent, currentTrace.startIndex);
                    }
                    else
                    {
                        if (currentTrace.ordered)
                        {
                            match = TraceValidator.ValidateNextSibling(currentTrace.parent, currentTrace.indexInParent, currentTrace.startIndex);
                        }
                        else
                        {
                            match = TraceValidator.ValidateNextSibling(currentTrace.parent, currentTrace.indexInParent, TraceValidator.GetMaxEndIndex(currentTrace));
                        }
                    }
                }

                return(match);
            }

            WorkflowTraceStep step = currentTrace.Steps[curExpIndex];

            if (step is TraceGroup)
            {
                // check inner composite step
                return(TraceValidator.ValidateFirst((TraceGroup)step, startIndex));
            }
            else if (step is DelayTrace)
            {
                mustBeAfter = lastTime.Add(((DelayTrace)step).TimeSpan);

                return(TraceValidator.Validate(currentTrace, curExpIndex + 1, startIndex, lastTime, mustBeAfter));
            }
            else if (step is IActualTraceStep)
            {
                int[] entryIndexes = TraceValidator.FindAllEntries((IActualTraceStep)step, startIndex, mustBeAfter);
                bool  match        = false;

                if (entryIndexes.Length == 0)
                {
                    // step not found
                    if (!step.Optional)
                    {
                        string msg = String.Format("Step '{0}' is not found. Start index {1}", step, startIndex);
                        //Oracle.LogDebugInfo("Adding error: {0}", msg);
                        TraceValidator.s_errorList.Add(msg);
                    }
                }
                else if (entryIndexes.Length == 1 &&
                         !step.Optional)
                {
                    // this branch can be commented out
                    // it's an optimization for the most common case

                    // only one option
                    int index = entryIndexes[0];

                    TraceValidator.MarkAsFound(index, out lastTime);
                    currentTrace.endIndexes[curExpIndex] = index;

                    if (currentTrace.ordered && !step.Async)
                    {
                        match = TraceValidator.Validate(currentTrace, curExpIndex + 1, index + 1, lastTime, mustBeAfter);
                    }
                    else
                    {
                        match = TraceValidator.Validate(currentTrace, curExpIndex + 1, startIndex, lastTime, mustBeAfter);
                    }
                }
                else
                {
                    // many options. try each choice until succeed
                    foreach (int index in entryIndexes)
                    {
                        TraceValidator.SetRestorePoint();
                        //this.Dump("After SetRestorePoint");
                        TraceValidator.MarkAsFound(index, out lastTime);
                        currentTrace.endIndexes[curExpIndex] = index;
                        //this.Dump("After mark as found");

                        if (currentTrace.ordered && !step.Async)
                        {
                            match = TraceValidator.Validate(currentTrace, curExpIndex + 1, entryIndexes[0] + 1, lastTime, mustBeAfter);
                        }
                        else
                        {
                            match = TraceValidator.Validate(currentTrace, curExpIndex + 1, startIndex, lastTime, mustBeAfter);
                        }

                        //this.Dump("After searched subsequent steps");

                        if (match)
                        {
                            TraceValidator.Commit();
                            //this.Dump("After Commit");
                            break;
                        }
                        else
                        {
                            TraceValidator.Rollback();
                            //this.Dump("After Rollback1");
                        }
                    }
                }

                if (!match && step.Optional)
                {
                    //Oracle.LogDebugInfo("Skipping optional step");
                    match = TraceValidator.Validate(currentTrace, curExpIndex + 1, startIndex, lastTime, mustBeAfter);
                }

                return(match);
            }
            else
            {
                throw new Exception(String.Format(
                                        "Internal validation error. Unknown step type found {0}",
                                        step.GetType().Name));
            }
        }