diff ServerMonitor/Objects/Checks/Check.cs @ 16:7626b099aefd

More comments.
author Brad Greco <brad@bgreco.net>
date Tue, 30 Apr 2019 20:40:58 -0400
parents 052aa62cb42a
children 7645122aa7a9
line wrap: on
line diff
--- a/ServerMonitor/Objects/Checks/Check.cs	Mon Apr 22 21:11:27 2019 -0400
+++ b/ServerMonitor/Objects/Checks/Check.cs	Tue Apr 30 20:40:58 2019 -0400
@@ -8,11 +8,11 @@
 
 namespace ServerMonitorApp
 {
-    /*public enum CheckType
-    {
-        Command
-    }*/
-
+    /// <summary>The possible statuses of a check.</summary>
+    /// <remarks>
+    /// The integer values of the "completed" statuses (Success, Information,
+    /// Warning, Error) are in ascending order of severity.
+    /// </remarks>
     public enum CheckStatus
     {
         Success,
@@ -23,6 +23,7 @@
         Disabled,
     }
 
+    /// <summary>Base class for checks that run against a server and return a result status.</summary>
     public abstract class Check
     {
         private static Type[] _checkTypes;
@@ -37,60 +38,91 @@
             }
         }
 
+        /// <summary>The internal ID of the check.</summary>
         public int Id { get; set; }
 
+        /// <summary>The display name check.</summary>
         public string Name { get; set; }
 
-        /*public CheckType Type { get; set; }*/
-
+        /// <summary>The number of milliseconds the check must complete in before reporting failure.</summary>
         public int Timeout { get; set; }
 
+        /// <summary>Whether the check will be executed on a schedule.</summary>
         public bool Enabled { get; set; }
 
+        /// <summary>The schedule when the check will be executed.</summary>
         public Schedule Schedule { get; set; }
 
+        /// <summary>The date and time the check was last executed.</summary>
         public DateTime LastRunTime { get; set; }
 
+        /// <summary>The date and time the check was last executed on its schedule.</summary>
         public DateTime LastScheduledRunTime { get; set; }
 
+        /// <summary>The date and time the check is currently scheduled to execute next.</summary>
         public DateTime NextRunTime { get; set; }
 
+        /// <summary>The text output of the last execution of the check.</summary>
         public string LastMessage { get; set; }
 
+        /// <summary>The current status of the check.</summary>
         public CheckStatus Status { get; set; }
 
+        /// <summary>The status of the last check execution.</summary>
         public CheckStatus LastRunStatus { get; set; }
 
+        /// <summary>The severity level reported when the check execution fails.</summary>
         public CheckStatus FailStatus { get; set; }
 
+        /// <summary>The number of consecutive failed executions before the check begins reporting failure.</summary>
         public int MaxConsecutiveFailures { get; set; }
 
+        /// <summary>The current number of consecutive times the check has failed.</summary>
         [XmlIgnore]
         public int ConsecutiveFailures { get; set; }
 
+        /// <summary>The server the check belongs to.</summary>
         [XmlIgnore]
         public Server Server { get; set; }
 
+        /// <summary>Check constructor.</summary>
         public Check()
         {
+            // Set the default failure severity to Error.
             FailStatus = CheckStatus.Error;
         }
 
+        /// <summary>Displays the check name.</summary>
         public override string ToString()
         {
             return Name;
         }
 
+        /// <summary>Validates the check.</summary>
+        /// <param name="saving">
+        /// Whether the check is being saved.
+        /// Checks are validated before being saved and before being executed. This parameter allows
+        /// them to distinguish between these cases.
+        /// </param>
+        /// <returns>An empty string if the check is valid, or the reason the check is invalid.</returns>
         public virtual string Validate(bool saving = true)
         {
             string message = string.Empty;
+            // Allow blank names if the check is being executed before saving.
+            // This lets the user create a check and tinker with it without
+            // needing to type a name unless they want to save it.
             if (Name.IsNullOrEmpty() && saving)
                 message += "Name cannot be blank." + Environment.NewLine;
             return message;
         }
 
+        /// <summary>Executes the check asynchronously.</summary>
+        /// <param name="token">A token for cancelling the execution.</param>
+        /// <param name="update">Whether the check status and last execution time should be updated when the check completes.</param>
+        /// <returns>The result of the check execution.</returns>
         public async Task<CheckResult> ExecuteAsync(CancellationToken token = default(CancellationToken), bool update = true)
         {
+            // Do nothing if the check has already been cancelled.
             if (token.IsCancellationRequested)
                 return null;
 
@@ -98,30 +130,35 @@
             DateTime startTime = DateTime.Now;
             try
             {
+                // Execute the check.
                 Task<CheckResult> checkTask = ExecuteCheckAsync(token);
                 try
                 {
+                    // Wait for the check to complete or timeout, whichever happens first.
                     if (await Task.WhenAny(checkTask, Task.Delay(Timeout, token)) == checkTask)
                     {
+                        // If the check completed before timing out, retrieve the result.
                         result = await checkTask;
                     }
                     else
                     {
+                        // If the check timed out before completing, report failure.
                         result = Fail("Timed out.");
                     }
                 }
                 catch (TaskCanceledException)
                 {
+                    // If the check was cancelled, do not return a result so it will not be logged.
                     return null;
                 }
             }
             catch (Exception e)
             {
+                // If the execution threw an exception, report the exception as a failure.
                 result = Fail(e.GetBaseException().Message);
             }
             result.StartTime = startTime;
             result.EndTime = DateTime.Now;
-            // If a check is executed from the CheckForm, we don't want to update the status or log the event.
             if (update)
             {
                 Status = result.CheckStatus;
@@ -132,21 +169,36 @@
             return result;
         }
 
+        /// <summary>Generates a successful check result.</summary>
+        /// <param name="message">The execution result message.</param>
+        /// <returns>A successful check result.</returns>
         public CheckResult Pass(string message)
         {
             return new CheckResult(this, CheckStatus.Success, message);
         }
 
+        /// <summary>Generates a failed check result.</summary>
+        /// <param name="message">The execution result message.</param>
+        /// <returns>A failed check result.</returns>
         public CheckResult Fail(string message)
         {
+            // The severity is controlled by the check's FailStatus setting.
             return new CheckResult(this, FailStatus, message);
         }
 
+        /// <summary>Generates a failed check result from an exception.</summary>
+        /// <param name="e">The exception that caused the failure.</param>
+        /// <returns>A failed check result.</returns>
         protected CheckResult Fail(Exception e)
         {
-            return new CheckResult(this, FailStatus, e.GetBaseException().Message);
+            return Fail(e.GetBaseException().Message);
         }
 
+        /// <summary>Generates a check result by comparing integer values for equality.</summary>
+        /// <param name="expectedValue">The expected result value.</param>
+        /// <param name="resultValue">The actual result value generated by the check execution.</param>
+        /// <param name="description">Description of what the integer represents to use in the check result message. Example: "Exit code".</param>
+        /// <returns>A successful check result if the values are equal, or a failed check result if they are unequal.</returns>
         protected CheckResult GetIntResult(int expectedValue, int resultValue, string description)
         {
             if (expectedValue == resultValue)
@@ -155,11 +207,21 @@
                 return Fail(string.Format("{0}: {1} (expected: {2})", description, resultValue, expectedValue));
         }
 
+        /// <summary>Generates a check result by comparing string values.</summary>
+        /// <param name="matchType">The comparison that will be used on the strings.</param>
+        /// <param name="expectedPattern">The expected pattern to test the result against.</param>
+        /// <param name="useRegex">Whether the expected pattern should be treated as a regular expression.</param>
+        /// <param name="resultValue">The actual result value generated by the check execution.</param>
+        /// <param name="description">Description of what the string represents to use in the check result message.</param>
+        /// <returns>A successful check result if the string comparison succeeds, or a failed check result if it fails.</returns>
         protected CheckResult GetStringResult(MatchType matchType, string expectedPattern, bool useRegex, string resultValue, string description)
         {
             bool match;
             if (useRegex)
             {
+                // If the match type is equals or not equals, modify the regex by
+                // adding beginning and ending anchors if not already present
+                // to prevent partial matches.
                 if (matchType.In(MatchType.Equals, MatchType.NotEquals))
                 {
                     if (!expectedPattern.StartsWith("^"))
@@ -167,11 +229,13 @@
                     if (!expectedPattern.EndsWith("$"))
                         expectedPattern += "$";
                 }
+                // Execute the regex.
                 Regex re = new Regex(expectedPattern, RegexOptions.Singleline);
                 match = re.IsMatch(resultValue);
             }
             else
             {
+                // Simple string comparisons.
                 if (matchType.In(MatchType.Equals, MatchType.NotEquals))
                 {
                     match = expectedPattern == resultValue;
@@ -182,9 +246,11 @@
                 }
                 else
                 {
+                    // If the match type is greater or less than, the values must be numeric.
                     if (decimal.TryParse(expectedPattern, out decimal expectedNumeric) &&
                         decimal.TryParse(resultValue, out decimal resultNumeric))
                     {
+                        // Compare the resulting decimals.
                         match = (matchType == MatchType.GreaterThan && resultNumeric > expectedNumeric) ||
                                 (matchType == MatchType.LessThan    && resultNumeric < expectedNumeric);
                     }
@@ -195,8 +261,11 @@
                 }
             }
 
+            // We have determined whether the result value matches the expected pattern.
+            // Generate a check result accordingly.
             if (matchType.In(MatchType.Equals, MatchType.Contains))
             {
+                // Equals, Contains: the strings are supposed to match.
                 if (match)
                     return Pass(string.Format("{0} {1} the pattern: {2}", description, matchType.ToString().ToLower(), expectedPattern));
                 else
@@ -204,6 +273,8 @@
             }
             else if (matchType.In(MatchType.NotEquals, MatchType.NotContains))
             {
+                // NotEquals, NotContains: the strings are not supposed to match.
+                // So, fail if they do match and pass if they do not.
                 if (match)
                     return Fail(string.Format("{0} {1} the pattern: {2} ({0}: {3})", description, matchType.ToString().ToLower().Replace("not", ""), expectedPattern, resultValue));
                 else
@@ -211,6 +282,7 @@
             }
             else
             {
+                // GreaterThan, LessThan
                 if (match)
                     return Pass(string.Format("{0} ({1}) is {2} {3}", description, resultValue, matchType.ToString().ToLower().Replace("than", " than"), expectedPattern));
                 else
@@ -218,6 +290,14 @@
             }
         }
 
+        /// <summary>Merges multiple execution results.</summary>
+        /// <param name="results">The results to merge.</param>
+        /// <returns>A single result containing the messages of all the input results, and a failure status if any of the input results failed.</returns>
+        /// <remarks>
+        /// Some checks may want to run several tests on the result of a remote command.
+        /// After collecting their results, they can use this method to combine them into
+        /// a single result that will be reported to the user.
+        /// </remarks>
         protected CheckResult MergeResults(params CheckResult[] results)
         {
             StringBuilder message = new StringBuilder();
@@ -226,13 +306,18 @@
             {
                 if (result == null)
                     continue;
+                // Report failure if any of the results has failed.
                 if (result.Failed)
                     failed = true;
+                // Merge the result messages.
                 message.AppendLine(result.Message);
             }
             return failed ? Fail(message.ToString().Trim()) : Pass(message.ToString().Trim());
         }
 
+        /// <summary>Executes the check asynchronously.</summary>
+        /// <param name="token">A token for cancelling the execution.</param>
+        /// <returns>The result of the check execution.</returns>
         protected abstract Task<CheckResult> ExecuteCheckAsync(CancellationToken token);
     }
 }
\ No newline at end of file