/// <summary> /// This method removes all of the non-acitivity traces, and then orders the activity traces so they will match /// more closely the expected traces. This is required for complex parallel traces. /// </summary> public void OrderTraces() { List <ActivityTrace> traceSteps = new List <ActivityTrace>(); List <UserTrace> userTraces = new List <UserTrace>(); // Find the starting node lock (this.Steps) { foreach (IActualTraceStep ts in this.Steps) { if (ts is ActivityTrace) { traceSteps.Add(ts as ActivityTrace); } else if (ts is UserTrace) { userTraces.Add(ts as UserTrace); } else { //Log.TraceInternal("[ActualTrace]ParallelValidation removing trace " + ts.ToString()); } } } Dictionary <string, ATNode> sortedSteps = new Dictionary <string, ATNode>(); ATNode rootNode = null; this.Steps.Clear(); // do this until we have completely constructed the tree, in case traces get written out in // an order we arent expecting, loop until either we cant make any more changes, or until // all the traces have been ordered. bool changed; while (traceSteps.Count > 0) { changed = false; for (int x = 0; x < traceSteps.Count; x++) { ActivityTrace at = traceSteps[x]; ATNode parentnode; // If a new activity was scheduled if (at.IsScheduled) { // When activityID is null, this is the root activity. if (at.ActivityId == null) { rootNode = new ATNode() { trace = at, }; // add root node to the tree using its' activity id and instanceid (for when activities get // instantiated multiple times, like with parallelforeach sortedSteps[1 + ":" + 1] = rootNode; traceSteps.RemoveAt(x--); changed = true; } // otherwise, if parent has already been found, add this node else if (sortedSteps.TryGetValue(at.ActivityId + ":" + at.ActivityInstanceId, out parentnode)) { ATNode newnode = new ATNode() { trace = at, parent = parentnode }; // add the node to its parent. sortedSteps[at.ChildActivityId + ":" + at.ChildActivityInstanceId] = newnode; parentnode.children.Add(newnode); traceSteps.RemoveAt(x--); changed = true; } } else { if (sortedSteps.TryGetValue(at.ActivityId + ":" + at.ActivityInstanceId, out parentnode)) { ATNode node = new ATNode() { trace = at, parent = parentnode.parent }; // if root node, just add as the last child, if it ends up being out of order the // validation logic will correct it. if (parentnode.parent == null) { parentnode.children.Add(node); } else { // otherwise just setup parent parentnode.parent.children.Add(node); } traceSteps.RemoveAt(x--); changed = true; } } } if (rootNode == null) { // there is no root node, we cant construct without it //Log.TraceInternal("[ActualTrace]Parallel tracing couldnt find a root node, using the unordered traces."); return; } if (!changed) { // the tree is in a state that we cant reconstruct //Log.TraceInternal("[ActualTrace]Parallel tracing couldnt find the parent for a node, using the unordered traces"); return; } } foreach (UserTrace ut in userTraces) { (sortedSteps[ut.ActivityParent]).userTraces.Add(ut); } lock (this.Steps) { this.Steps.AddRange(rootNode.GetTraces()); } }