/// <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); }
/// <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)); } }