1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 using System.Text;
7 using System.Collections.Concurrent;
8 using System.Diagnostics;
9 using System.Threading;
10 
11 namespace DPStressHarness
12 {
13     public class RecordedExceptions
14     {
15         // Reference wrapper around an integer which is used in order to make updating a little easier & more efficient
16         public class ExceptionCount
17         {
18             public int Count = 0;
19         }
20 
21         private ConcurrentDictionary<string, ConcurrentDictionary<string, ExceptionCount>> _exceptions = new ConcurrentDictionary<string, ConcurrentDictionary<string, ExceptionCount>>();
22 
23         /// <summary>
24         /// Records an exception and returns true if the threshold is exceeded for that exception
25         /// </summary>
Record(string testName, Exception ex)26         public bool Record(string testName, Exception ex)
27         {
28             // Converting from exception to string can be expensive so only do it once and cache the string
29             string exceptionString = ex.ToString();
30             TraceException(testName, exceptionString);
31 
32             // Get the exceptions for the current test case
33             ConcurrentDictionary<string, ExceptionCount> exceptionsForTest = _exceptions.GetOrAdd(testName, _ => new ConcurrentDictionary<string, ExceptionCount>());
34 
35             // Get the count for the current exception
36             ExceptionCount exCount = exceptionsForTest.GetOrAdd(exceptionString, _ => new ExceptionCount());
37 
38             // Increment the count
39             Interlocked.Increment(ref exCount.Count);
40 
41             // If the count is over the threshold, return true
42             return TestMetrics.ExceptionThreshold.HasValue && (exCount.Count > TestMetrics.ExceptionThreshold);
43         }
44 
TraceException(string testName, string exceptionString)45         private void TraceException(string testName, string exceptionString)
46         {
47             StringBuilder status = new StringBuilder();
48             status.AppendLine("========================================================================");
49             status.AppendLine("Exception Report");
50             status.AppendLine("========================================================================");
51 
52             status.AppendLine(string.Format("Test: {0}", testName));
53             status.AppendLine(exceptionString);
54 
55             status.AppendLine("========================================================================");
56             status.AppendLine("End of Exception Report");
57             status.AppendLine("========================================================================");
58             Trace.WriteLine(status.ToString());
59         }
60 
TraceAllExceptions()61         public void TraceAllExceptions()
62         {
63             StringBuilder status = new StringBuilder();
64             status.AppendLine("========================================================================");
65             status.AppendLine("All Exceptions Report");
66             status.AppendLine("========================================================================");
67 
68             foreach (string testName in _exceptions.Keys)
69             {
70                 ConcurrentDictionary<string, ExceptionCount> exceptionsForTest = _exceptions[testName];
71 
72                 status.AppendLine(string.Format("Test: {0}", testName));
73                 foreach (var exceptionString in exceptionsForTest.Keys)
74                 {
75                     status.AppendLine(string.Format("Count: {0}", exceptionsForTest[exceptionString].Count));
76                     status.AppendLine(string.Format("Exception: {0}", exceptionString));
77                     status.AppendLine();
78                 }
79 
80                 status.AppendLine();
81                 status.AppendLine();
82             }
83 
84             status.AppendLine("========================================================================");
85             status.AppendLine("End of All Exceptions Report");
86             status.AppendLine("========================================================================");
87             Trace.WriteLine(status.ToString());
88         }
89 
GetExceptionsCount()90         public int GetExceptionsCount()
91         {
92             int count = 0;
93 
94             foreach (string testName in _exceptions.Keys)
95             {
96                 ConcurrentDictionary<string, ExceptionCount> exceptionsForTest = _exceptions[testName];
97 
98                 foreach (var exceptionString in exceptionsForTest.Keys)
99                 {
100                     count += exceptionsForTest[exceptionString].Count;
101                 }
102             }
103 
104             return count;
105         }
106     }
107 }
108