├── src
├── HealthCheck.Nancy
│ ├── packages.config
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── HealthCheck.Nancy.nuspec
│ ├── HealthCheckModule.cs
│ └── HealthCheck.Nancy.csproj
├── HealthCheck.Redis
│ ├── packages.config
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Metrics
│ │ ├── RedisVersion.cs
│ │ ├── RedisMemoryUsage.cs
│ │ ├── RedisUptime.cs
│ │ └── RedisMaxMemory.cs
│ ├── HealthCheck.Redis.nuspec
│ ├── Checkers
│ │ ├── RedisIsAvailable.cs
│ │ └── RedisHasFreeMemory.cs
│ └── HealthCheck.Redis.csproj
├── HealthCheck.Core
│ ├── IMetric.cs
│ ├── IChecker.cs
│ ├── CheckResult.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Helpers
│ │ └── TaskExtensions.cs
│ ├── HealthCheckResult.cs
│ ├── HealthCheck.Core.nuspec
│ ├── CheckerBase.cs
│ ├── HealthCheck.Core.csproj
│ └── HealthCheck.cs
├── Tests
│ ├── HealthCheck.Core.Tests
│ │ ├── packages.config
│ │ ├── Properties
│ │ │ └── AssemblyInfo.cs
│ │ ├── CheckerBaseTests.cs
│ │ ├── HealthCheck.Core.Tests.csproj
│ │ └── HealthCheckTests.cs
│ ├── HealthCheck.Redis.Tests
│ │ ├── packages.config
│ │ ├── Properties
│ │ │ └── AssemblyInfo.cs
│ │ ├── Checkers
│ │ │ ├── RedisIsAvailableTests.cs
│ │ │ └── RedisHasFreeMemoryTests.cs
│ │ └── HealthCheck.Redis.Tests.csproj
│ ├── HealthCheck.Windows.Tests
│ │ ├── packages.config
│ │ ├── Properties
│ │ │ └── AssemblyInfo.cs
│ │ ├── Checkers
│ │ │ ├── CpuUsageIsOkTests.cs
│ │ │ └── SystemDriveHasFreeSpaceTests.cs
│ │ └── HealthCheck.Windows.Tests.csproj
│ └── HealthCheck.Nancy.Tests
│ │ ├── packages.config
│ │ ├── NancyTestingExtensions.cs
│ │ ├── Properties
│ │ └── AssemblyInfo.cs
│ │ ├── HealthCheck.Nancy.Tests.csproj
│ │ └── HealthCheckModuleTests.cs
├── SharedAssemblyInfo.cs
├── HealthCheck.Windows
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Metrics
│ │ ├── AvailableSystemDriveSpace.cs
│ │ └── CpuUsage.cs
│ ├── HealthCheck.Windows.nuspec
│ ├── Checkers
│ │ ├── CpuUsageIsOk.cs
│ │ └── SystemDriveHasFreeSpace.cs
│ └── HealthCheck.Windows.csproj
└── HealthCheck.sln
├── LICENSE
├── .gitattributes
├── .gitignore
└── README.md
/src/HealthCheck.Nancy/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/HealthCheck.Redis/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/HealthCheck.Core/IMetric.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace HealthCheck.Core
4 | {
5 | public interface IMetric
6 | {
7 | Task Read();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/HealthCheck.Core/IChecker.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace HealthCheck.Core
4 | {
5 | public interface IChecker
6 | {
7 | string Name { get; }
8 | Task Check();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Core.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Redis.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Windows.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/HealthCheck.Core/CheckResult.cs:
--------------------------------------------------------------------------------
1 | namespace HealthCheck.Core
2 | {
3 | public class CheckResult
4 | {
5 | public string Checker { get; set; }
6 | public bool Passed { get; set; }
7 | public string Output { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/SharedAssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 |
3 | [assembly: AssemblyCompany("Anders Fjeldstad")]
4 | [assembly: AssemblyProduct("Hihaj.HealthCheck")]
5 | [assembly: AssemblyCopyright("Copyright © Anders Fjeldstad 2015")]
6 | [assembly: AssemblyTrademark("")]
7 | [assembly: AssemblyVersion("0.0.0.0")]
8 | [assembly: AssemblyFileVersion("0.0.0.0")]
--------------------------------------------------------------------------------
/src/HealthCheck.Core/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | [assembly: AssemblyTitle("HealthCheck.Core")]
5 | [assembly: AssemblyDescription("")]
6 | [assembly: AssemblyConfiguration("")]
7 | [assembly: AssemblyCulture("")]
8 | [assembly: ComVisible(false)]
9 | [assembly: Guid("e8fdafbe-1b56-413b-ab6e-10d3b086fa29")]
10 |
--------------------------------------------------------------------------------
/src/HealthCheck.Nancy/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | [assembly: AssemblyTitle("HealthCheck.Nancy")]
5 | [assembly: AssemblyDescription("")]
6 | [assembly: AssemblyConfiguration("")]
7 | [assembly: AssemblyCulture("")]
8 | [assembly: ComVisible(false)]
9 | [assembly: Guid("e5b8d5ed-f312-498f-b963-1b0760fa80df")]
10 |
--------------------------------------------------------------------------------
/src/HealthCheck.Redis/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | [assembly: AssemblyTitle("HealthCheck.Redis")]
5 | [assembly: AssemblyDescription("")]
6 | [assembly: AssemblyConfiguration("")]
7 | [assembly: AssemblyCulture("")]
8 | [assembly: ComVisible(false)]
9 | [assembly: Guid("fe7f9cdb-9f43-4984-9ed7-3ff1f1c810f0")]
10 |
--------------------------------------------------------------------------------
/src/HealthCheck.Windows/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | [assembly: AssemblyTitle("HealthCheck.Windows")]
5 | [assembly: AssemblyDescription("")]
6 | [assembly: AssemblyConfiguration("")]
7 | [assembly: AssemblyCulture("")]
8 | [assembly: ComVisible(false)]
9 | [assembly: Guid("c451395c-20f9-4d8f-af98-9953050c2204")]
10 |
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Nancy.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Nancy.Tests/NancyTestingExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Nancy.Testing;
7 | using Newtonsoft.Json.Linq;
8 |
9 | namespace HealthCheck.Nancy.Tests
10 | {
11 | public static class NancyTestingExtensions
12 | {
13 | public static dynamic AsJson(this BrowserResponseBodyWrapper bodyWrapper)
14 | {
15 | return JObject.Parse(bodyWrapper.AsString());
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/HealthCheck.Core/Helpers/TaskExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 |
4 | namespace HealthCheck.Core.Helpers
5 | {
6 | public static class TaskExtensions
7 | {
8 | public static async Task TimeoutAfter(this Task task, TimeSpan timeout)
9 | {
10 | if (task == await Task.WhenAny(task, Task.Delay(timeout)).ConfigureAwait(false))
11 | {
12 | return await task.ConfigureAwait(false);
13 | }
14 | throw new TimeoutException();
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/HealthCheck.Core/HealthCheckResult.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 |
4 | namespace HealthCheck.Core
5 | {
6 | public class HealthCheckResult
7 | {
8 | private readonly CheckResult[] _results;
9 | private readonly bool _passed;
10 |
11 | public CheckResult[] Results { get { return _results; } }
12 | public bool Passed { get { return _passed; } }
13 | public string Status { get { return _passed ? "success" : "failure"; } }
14 |
15 | public HealthCheckResult(IEnumerable results)
16 | {
17 | _results = results.OrderBy(x => x.Checker).ToArray();
18 | _passed = _results.All(x => x.Passed);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/HealthCheck.Core/HealthCheck.Core.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Hihaj.HealthCheck
5 | $version$
6 | Anders Fjeldstad
7 | Anders Fjeldstad
8 | https://raw.githubusercontent.com/Hihaj/HealthCheck/master/LICENSE
9 | https://github.com/Hihaj/HealthCheck
10 | false
11 | Flexible asynchronous healthcheck for apps.
12 |
13 | Anders Fjeldstad 2015
14 | async healthcheck
15 |
16 |
--------------------------------------------------------------------------------
/src/HealthCheck.Redis/Metrics/RedisVersion.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using HealthCheck.Core;
5 | using StackExchange.Redis;
6 |
7 | namespace HealthCheck.Redis.Metrics
8 | {
9 | public interface IRedisVersion : IMetric
10 | {
11 | }
12 |
13 | public class RedisVersion : IRedisVersion
14 | {
15 | private readonly Func _redisServer;
16 |
17 | public RedisVersion(Func redisServer)
18 | {
19 | _redisServer = redisServer;
20 | }
21 |
22 | public async Task Read()
23 | {
24 | var info = (await _redisServer().InfoAsync("Server").ConfigureAwait(false)).First();
25 | return info.First(x => x.Key.Equals("redis_version")).Value;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/HealthCheck.Redis/Metrics/RedisMemoryUsage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using HealthCheck.Core;
5 | using StackExchange.Redis;
6 |
7 | namespace HealthCheck.Redis.Metrics
8 | {
9 | public interface IRedisMemoryUsage : IMetric
10 | {
11 | }
12 |
13 | public class RedisMemoryUsage : IRedisMemoryUsage
14 | {
15 | private readonly Func _redisServer;
16 |
17 | public RedisMemoryUsage(Func redisServer)
18 | {
19 | _redisServer = redisServer;
20 | }
21 |
22 | public async Task Read()
23 | {
24 | var info = (await _redisServer().InfoAsync("Memory").ConfigureAwait(false)).First();
25 | return long.Parse(info.First(x => x.Key.Equals("used_memory")).Value);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/HealthCheck.Windows/Metrics/AvailableSystemDriveSpace.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using HealthCheck.Core;
6 |
7 | namespace HealthCheck.Windows.Metrics
8 | {
9 | public interface IAvailableSystemDriveSpace : IMetric
10 | {
11 | }
12 |
13 | public class AvailableSystemDriveSpace : IAvailableSystemDriveSpace
14 | {
15 | public Task Read()
16 | {
17 | var systemDriveName = Path.GetPathRoot(Environment.GetFolderPath(Environment.SpecialFolder.System));
18 | return Task.FromResult(
19 | DriveInfo.GetDrives()
20 | .Single(x => x.IsReady && x.Name.Equals(systemDriveName, StringComparison.OrdinalIgnoreCase))
21 | .AvailableFreeSpace);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/HealthCheck.Redis/Metrics/RedisUptime.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using HealthCheck.Core;
5 | using StackExchange.Redis;
6 |
7 | namespace HealthCheck.Redis.Metrics
8 | {
9 | public interface IRedisUptime : IMetric
10 | {
11 | }
12 |
13 | public class RedisUptime : IRedisUptime
14 | {
15 | private readonly Func _redisServer;
16 |
17 | public RedisUptime(Func redisServer)
18 | {
19 | _redisServer = redisServer;
20 | }
21 |
22 | public async Task Read()
23 | {
24 | var info = (await _redisServer().InfoAsync("Server").ConfigureAwait(false)).First();
25 | return TimeSpan.FromSeconds(int.Parse(info.First(x => x.Key.Equals("uptime_in_seconds")).Value));
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/HealthCheck.Windows/HealthCheck.Windows.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Hihaj.HealthCheck.Windows
5 | $version$
6 | Anders Fjeldstad
7 | Anders Fjeldstad
8 | https://raw.githubusercontent.com/Hihaj/HealthCheck/master/LICENSE
9 | https://github.com/Hihaj/HealthCheck
10 | false
11 | Windows OS-specific checkers and metrics for Hihaj.HealthCheck.
12 |
13 | Anders Fjeldstad 2015
14 | async windows os healthcheck
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/HealthCheck.Redis/HealthCheck.Redis.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Hihaj.HealthCheck.Redis
5 | $version$
6 | Anders Fjeldstad
7 | Anders Fjeldstad
8 | https://raw.githubusercontent.com/Hihaj/HealthCheck/master/LICENSE
9 | https://github.com/Hihaj/HealthCheck
10 | false
11 | Redis checkers and metrics for Hihaj.HealthCheck.
12 |
13 | Anders Fjeldstad 2015
14 | redis async healthcheck
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/HealthCheck.Nancy/HealthCheck.Nancy.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Hihaj.HealthCheck.Nancy
5 | $version$
6 | Anders Fjeldstad
7 | Anders Fjeldstad
8 | https://raw.githubusercontent.com/Hihaj/HealthCheck/master/LICENSE
9 | https://github.com/Hihaj/HealthCheck
10 | false
11 | Nancy module for exposing a health check endpoint backed by Hihaj.HealthCheck.
12 |
13 | Anders Fjeldstad 2015
14 | nancy async healthcheck
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Anders Fjeldstad
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/src/HealthCheck.Redis/Metrics/RedisMaxMemory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using HealthCheck.Core;
7 | using StackExchange.Redis;
8 |
9 | namespace HealthCheck.Redis.Metrics
10 | {
11 | public interface IRedisMaxMemory : IMetric
12 | {
13 | }
14 |
15 | public class RedisMaxMemory : IRedisMaxMemory
16 | {
17 | private readonly Func _redisServer;
18 |
19 | public RedisMaxMemory(Func redisServer)
20 | {
21 | _redisServer = redisServer;
22 | }
23 |
24 | public async Task Read()
25 | {
26 | string maxMemory = (await _redisServer().ConfigGetAsync("maxmemory").ConfigureAwait(false))
27 | .Select(x => x.Value)
28 | .FirstOrDefault();
29 | if (string.IsNullOrEmpty(maxMemory))
30 | {
31 | return null;
32 | }
33 | long maxMemoryBytes;
34 | return long.TryParse(maxMemory, out maxMemoryBytes) ?
35 | maxMemoryBytes :
36 | (long?)null;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/HealthCheck.Redis/Checkers/RedisIsAvailable.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using HealthCheck.Core;
4 | using HealthCheck.Redis.Metrics;
5 |
6 | namespace HealthCheck.Redis.Checkers
7 | {
8 | public class RedisIsAvailable : CheckerBase
9 | {
10 | private readonly IRedisVersion _redisVersion;
11 | private readonly IRedisUptime _redisUptime;
12 |
13 | public override string Name
14 | {
15 | get { return "Redis is available"; }
16 | }
17 |
18 | public RedisIsAvailable(
19 | IRedisVersion redisVersion,
20 | IRedisUptime redisUptime)
21 | {
22 | _redisVersion = redisVersion;
23 | _redisUptime = redisUptime;
24 | }
25 |
26 | protected override async Task CheckCore()
27 | {
28 | var redisVersion = await _redisVersion.Read().ConfigureAwait(false);
29 | var redisUptime = await _redisUptime.Read().ConfigureAwait(false);
30 | return CreateResult(
31 | true,
32 | string.Format("Version {0}, uptime {1:%d} days {1:%h} hours {1:%m} minutes.", redisVersion, redisUptime));
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/src/HealthCheck.Core/CheckerBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using HealthCheck.Core.Helpers;
4 |
5 | namespace HealthCheck.Core
6 | {
7 | public abstract class CheckerBase : IChecker
8 | {
9 | private TimeSpan? _timeout = TimeSpan.FromSeconds(5);
10 |
11 | public abstract string Name { get; }
12 | public TimeSpan? Timeout { get { return _timeout; } set { _timeout = value; } }
13 |
14 | protected CheckResult CreateResult(bool passed, string output)
15 | {
16 | return new CheckResult
17 | {
18 | Checker = Name,
19 | Passed = passed,
20 | Output = output
21 | };
22 | }
23 |
24 | public async Task Check()
25 | {
26 | try
27 | {
28 | if (Timeout.HasValue && Timeout.Value > TimeSpan.Zero)
29 | {
30 | return await CheckCore().TimeoutAfter(Timeout.Value).ConfigureAwait(false);
31 | }
32 | return await CheckCore().ConfigureAwait(false);
33 | }
34 | catch (Exception ex)
35 | {
36 | return CreateResult(false, ex.Message);
37 | }
38 | }
39 |
40 | protected abstract Task CheckCore();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/HealthCheck.Windows/Checkers/CpuUsageIsOk.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using HealthCheck.Core;
4 | using HealthCheck.Windows.Metrics;
5 |
6 | namespace HealthCheck.Windows.Checkers
7 | {
8 | public class CpuUsageIsOk : CheckerBase
9 | {
10 | private readonly ICpuUsage _cpuUsage;
11 | private readonly Options _options;
12 |
13 | public override string Name
14 | {
15 | get { return "CPU usage is OK"; }
16 | }
17 |
18 | public CpuUsageIsOk(
19 | ICpuUsage cpuUsage,
20 | Options options = null)
21 | {
22 | _cpuUsage = cpuUsage;
23 | _options = options ?? new Options();
24 | }
25 |
26 | protected override async Task CheckCore()
27 | {
28 | var currentCpuUsage = await _cpuUsage.Read().ConfigureAwait(false);
29 | return CreateResult(
30 | currentCpuUsage < _options.CpuUsageWarningThresholdInPercent,
31 | string.Format("Currently using {0:F1} % of total processor time.", currentCpuUsage));
32 | }
33 |
34 | public class Options
35 | {
36 | public float CpuUsageWarningThresholdInPercent { get; set; }
37 |
38 | public Options()
39 | {
40 | CpuUsageWarningThresholdInPercent = 90;
41 | }
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/src/HealthCheck.Windows/Metrics/CpuUsage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Threading.Tasks;
4 | using System.Timers;
5 | using HealthCheck.Core;
6 |
7 | namespace HealthCheck.Windows.Metrics
8 | {
9 | public interface ICpuUsage : IMetric
10 | {
11 | }
12 |
13 | public class CpuUsage : ICpuUsage, IDisposable
14 | {
15 | private static readonly object Token = new object();
16 | private readonly PerformanceCounter _performanceCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
17 | private readonly Timer _timer = new Timer();
18 | private float _lastCpuUsageValue;
19 |
20 | public CpuUsage()
21 | {
22 | _performanceCounter.NextValue();
23 | _timer.AutoReset = true;
24 | _timer.Interval = TimeSpan.FromSeconds(10).TotalMilliseconds;
25 | _timer.Elapsed += (sender, args) =>
26 | {
27 | lock (Token)
28 | {
29 | _lastCpuUsageValue = _performanceCounter.NextValue();
30 | }
31 | };
32 | _timer.Start();
33 | }
34 |
35 | public Task Read()
36 | {
37 | lock (Token)
38 | {
39 | return Task.FromResult(_lastCpuUsageValue);
40 | }
41 | }
42 |
43 | public void Dispose()
44 | {
45 | _timer.Stop();
46 | _timer.Dispose();
47 | }
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Core.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("HealthCheck.Core.Tests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("HealthCheck.Core.Tests")]
13 | [assembly: AssemblyCopyright("Copyright © 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("4ab25e02-146b-44ce-bccc-fa3ca8a099b2")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Nancy.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("HealthCheck.Nancy.Tests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("HealthCheck.Nancy.Tests")]
13 | [assembly: AssemblyCopyright("Copyright © 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("635cc6c2-5bab-4c40-bd6c-534bf0cc057d")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Redis.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("HealthCheck.Redis.Tests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("HealthCheck.Redis.Tests")]
13 | [assembly: AssemblyCopyright("Copyright © 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("5ab28921-7785-4ffc-ad6d-dce7c004b85f")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Windows.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("HealthCheck.Windows.Tests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("HealthCheck.Windows.Tests")]
13 | [assembly: AssemblyCopyright("Copyright © 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("823b7ef3-082b-4d22-a0b6-5470400e23b1")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/HealthCheck.Windows/Checkers/SystemDriveHasFreeSpace.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using HealthCheck.Core;
4 | using HealthCheck.Windows.Metrics;
5 |
6 | namespace HealthCheck.Windows.Checkers
7 | {
8 | public class SystemDriveHasFreeSpace : CheckerBase
9 | {
10 | private readonly IAvailableSystemDriveSpace _availableSystemDriveSpace;
11 | private readonly Options _options;
12 |
13 | public override string Name
14 | {
15 | get { return "System drive has free space"; }
16 | }
17 |
18 | public SystemDriveHasFreeSpace(IAvailableSystemDriveSpace availableSystemDriveSpace, Options options = null)
19 | {
20 | _availableSystemDriveSpace = availableSystemDriveSpace;
21 | _options = options ?? new Options();
22 | }
23 |
24 | protected override async Task CheckCore()
25 | {
26 | var freeBytes = await _availableSystemDriveSpace.Read().ConfigureAwait(false);
27 | return CreateResult(
28 | freeBytes >= _options.SystemDriveAvailableFreeSpaceWarningThresholdInBytes,
29 | string.Format("{0:F1} GB available.", freeBytes / (double)(1024 * 1024 * 1024)));
30 | }
31 |
32 | public class Options
33 | {
34 | public long SystemDriveAvailableFreeSpaceWarningThresholdInBytes { get; set; }
35 |
36 | public Options()
37 | {
38 | SystemDriveAvailableFreeSpaceWarningThresholdInBytes = 5L * 1024L * 1024L * 1024L; // 5 GB
39 | }
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Core.Tests/CheckerBaseTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using NUnit.Framework;
7 |
8 | namespace HealthCheck.Core.Tests
9 | {
10 | [TestFixture]
11 | public class CheckerBaseTests
12 | {
13 | [Test]
14 | public async Task CheckFailsOnTimeout()
15 | {
16 | // Arrange
17 | var delay = TimeSpan.FromSeconds(3);
18 | var checker = new DummyChecker(async () =>
19 | {
20 | await Task.Delay(delay);
21 | return new CheckResult { Passed = true };
22 | });
23 | checker.Timeout = TimeSpan.FromSeconds(delay.TotalSeconds / 2);
24 |
25 | // Act
26 | var result = await checker.Check();
27 |
28 | // Assert
29 | Assert.That(result.Passed, Is.False);
30 | Assert.That(result.Output, Is.EqualTo(new TimeoutException().Message));
31 | }
32 |
33 | public class DummyChecker : CheckerBase
34 | {
35 | private readonly Func> _check;
36 |
37 | public override string Name
38 | {
39 | get { return "Dummy checker"; }
40 | }
41 |
42 | public DummyChecker(Func> check)
43 | {
44 | _check = check;
45 | }
46 |
47 | protected override async Task CheckCore()
48 | {
49 | return await _check().ConfigureAwait(false);
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/HealthCheck.Nancy/HealthCheckModule.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using HealthCheck.Core;
7 | using Nancy;
8 | using Nancy.Security;
9 |
10 | namespace HealthCheck.Nancy
11 | {
12 | public class HealthCheckModule : NancyModule
13 | {
14 | public const string DefaultRoute = "/healthcheck";
15 |
16 | public HealthCheckModule(IEnumerable checkers, HealthCheckOptions options = null)
17 | {
18 | if (options == null)
19 | {
20 | options = new HealthCheckOptions();
21 | }
22 | if (options.RequireHttps)
23 | {
24 | this.RequiresHttps(redirect: false);
25 | }
26 |
27 | Get[options.Route, true] = async (_, ct) =>
28 | {
29 | if (options.AuthorizationCallback != null && !await options.AuthorizationCallback(Context))
30 | {
31 | return HttpStatusCode.Unauthorized;
32 | }
33 | return Response.AsJson(await (new Core.HealthCheck(checkers).Run()));
34 | };
35 | }
36 | }
37 |
38 | public class HealthCheckOptions
39 | {
40 | public string Route { get; set; }
41 | public bool RequireHttps { get; set; }
42 | public Func> AuthorizationCallback { get; set; }
43 |
44 | public HealthCheckOptions()
45 | {
46 | Route = "/healthcheck";
47 | RequireHttps = true;
48 | AuthorizationCallback = null;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Redis.Tests/Checkers/RedisIsAvailableTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using HealthCheck.Redis.Checkers;
7 | using HealthCheck.Redis.Metrics;
8 | using Moq;
9 | using NUnit.Framework;
10 |
11 | namespace HealthCheck.Redis.Tests.Checkers
12 | {
13 | [TestFixture]
14 | public class RedisIsAvailableTests
15 | {
16 | [Test]
17 | public async Task CheckFailsWhenRedisVersionThrows()
18 | {
19 | // Arrange
20 | var redisVersionMock = new Mock();
21 | var exception = new Exception("error message");
22 | redisVersionMock.Setup(x => x.Read()).ThrowsAsync(exception);
23 | var redisUptimeMock = new Mock();
24 | redisUptimeMock.Setup(x => x.Read()).ReturnsAsync(TimeSpan.FromDays(1));
25 | var check = new RedisIsAvailable(redisVersionMock.Object, redisUptimeMock.Object);
26 |
27 | // Act
28 | var result = await check.Check();
29 |
30 | // Assert
31 | Assert.That(result.Passed, Is.False);
32 | Assert.That(result.Output, Is.EqualTo(exception.Message));
33 | }
34 |
35 | [Test]
36 | public async Task CheckFailsWhenRedisUptimeThrows()
37 | {
38 | // Arrange
39 | var redisVersionMock = new Mock();
40 | redisVersionMock.Setup(x => x.Read()).ReturnsAsync("x");
41 | var redisUptimeMock = new Mock();
42 | var exception = new Exception("error message");
43 | redisUptimeMock.Setup(x => x.Read()).ThrowsAsync(exception);
44 | var check = new RedisIsAvailable(redisVersionMock.Object, redisUptimeMock.Object);
45 |
46 | // Act
47 | var result = await check.Check();
48 |
49 | // Assert
50 | Assert.That(result.Passed, Is.False);
51 | Assert.That(result.Output, Is.EqualTo(exception.Message));
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Windows.Tests/Checkers/CpuUsageIsOkTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using HealthCheck.Windows.Checkers;
7 | using HealthCheck.Windows.Metrics;
8 | using Moq;
9 | using NUnit.Framework;
10 |
11 | namespace HealthCheck.Windows.Tests.Checkers
12 | {
13 | [TestFixture]
14 | public class CpuUsageIsOkTests
15 | {
16 | [Test]
17 | public async Task CheckPassesWhenCpuUsageIsBelowThreshold()
18 | {
19 | // Arrange
20 | var options = new CpuUsageIsOk.Options();
21 | var cpuUsageMock = new Mock();
22 | cpuUsageMock.Setup(x => x.Read()).ReturnsAsync(options.CpuUsageWarningThresholdInPercent - 1);
23 | var check = new CpuUsageIsOk(cpuUsageMock.Object);
24 |
25 | // Act
26 | var result = await check.Check();
27 |
28 | // Assert
29 | Assert.That(result.Passed, Is.True);
30 | }
31 |
32 | [Test]
33 | public async Task CheckFailsWhenCpuUsageIsAboveThreshold()
34 | {
35 | // Arrange
36 | var options = new CpuUsageIsOk.Options();
37 | var cpuUsageMock = new Mock();
38 | cpuUsageMock.Setup(x => x.Read()).ReturnsAsync(options.CpuUsageWarningThresholdInPercent + 1);
39 | var check = new CpuUsageIsOk(cpuUsageMock.Object);
40 |
41 | // Act
42 | var result = await check.Check();
43 |
44 | // Assert
45 | Assert.That(result.Passed, Is.False);
46 | }
47 |
48 | [Test]
49 | public async Task CheckFailsWhenCpuUsageThrows()
50 | {
51 | // Arrange
52 | var exception = new Exception("error message");
53 | var cpuUsageMock = new Mock();
54 | cpuUsageMock.Setup(x => x.Read()).ThrowsAsync(exception);
55 | var check = new CpuUsageIsOk(cpuUsageMock.Object);
56 |
57 | // Act
58 | var result = await check.Check();
59 |
60 | // Assert
61 | Assert.That(result.Passed, Is.False);
62 | Assert.That(result.Output, Is.EqualTo(exception.Message));
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/HealthCheck.Redis/Checkers/RedisHasFreeMemory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using HealthCheck.Core;
4 | using HealthCheck.Redis.Metrics;
5 |
6 | namespace HealthCheck.Redis.Checkers
7 | {
8 | public class RedisHasFreeMemory : CheckerBase
9 | {
10 | private readonly IRedisMemoryUsage _redisMemoryUsage;
11 | private readonly IRedisMaxMemory _redisMaxMemory;
12 | private readonly Options _options;
13 |
14 | public override string Name
15 | {
16 | get { return "Redis has free memory"; }
17 | }
18 |
19 | public RedisHasFreeMemory(
20 | IRedisMemoryUsage redisMemoryUsage,
21 | IRedisMaxMemory redisMaxMemory,
22 | Options options = null)
23 | {
24 | _redisMemoryUsage = redisMemoryUsage;
25 | _redisMaxMemory = redisMaxMemory;
26 | _options = options ?? new Options();
27 | }
28 |
29 | protected override async Task CheckCore()
30 | {
31 | var maxBytes = await _redisMaxMemory.Read().ConfigureAwait(false);
32 | var usedBytes = await _redisMemoryUsage.Read().ConfigureAwait(false);
33 | if (!maxBytes.HasValue || maxBytes.Value == 0)
34 | {
35 | return CreateResult(
36 | true,
37 | string.Format(
38 | "Currently using {0:F1} MB, no hard upper limit configured.",
39 | usedBytes / (double)(1024 * 1024)));
40 | }
41 | var usage = usedBytes / (double)maxBytes;
42 | var freeMegabytes = (maxBytes - usedBytes) / (double)(1024 * 1024);
43 | return CreateResult(
44 | maxBytes - usedBytes > _options.RedisFreeMemoryWarningThresholdInBytes,
45 | string.Format(
46 | "{0:P0} of the reserved memory is used ({1:F1} MB free).",
47 | usage,
48 | freeMegabytes));
49 | }
50 |
51 | public class Options
52 | {
53 | public long RedisFreeMemoryWarningThresholdInBytes { get; set; }
54 |
55 | public Options()
56 | {
57 | RedisFreeMemoryWarningThresholdInBytes = 50L * 1024L * 1024L; // 50 MB
58 | }
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Windows.Tests/Checkers/SystemDriveHasFreeSpaceTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using HealthCheck.Windows.Checkers;
7 | using HealthCheck.Windows.Metrics;
8 | using Moq;
9 | using NUnit.Framework;
10 |
11 | namespace HealthCheck.Windows.Tests.Checkers
12 | {
13 | [TestFixture]
14 | public class SystemDriveHasFreeSpaceTests
15 | {
16 | [Test]
17 | public async Task CheckPassesWhenFreeSpaceIsAboveThreshold()
18 | {
19 | // Arrange
20 | var options = new SystemDriveHasFreeSpace.Options();
21 | var driveSpaceMock = new Mock();
22 | driveSpaceMock.Setup(x => x.Read()).ReturnsAsync(options.SystemDriveAvailableFreeSpaceWarningThresholdInBytes + 1);
23 | var check = new SystemDriveHasFreeSpace(driveSpaceMock.Object);
24 |
25 | // Act
26 | var result = await check.Check();
27 |
28 | // Assert
29 | Assert.That(result.Passed, Is.True);
30 | }
31 |
32 | [Test]
33 | public async Task CheckFailsWhenFreeSpaceIsBelowThreshold()
34 | {
35 | // Arrange
36 | var options = new SystemDriveHasFreeSpace.Options();
37 | var driveSpaceMock = new Mock();
38 | driveSpaceMock.Setup(x => x.Read()).ReturnsAsync(options.SystemDriveAvailableFreeSpaceWarningThresholdInBytes - 1);
39 | var check = new SystemDriveHasFreeSpace(driveSpaceMock.Object);
40 |
41 | // Act
42 | var result = await check.Check();
43 |
44 | // Assert
45 | Assert.That(result.Passed, Is.False);
46 | }
47 |
48 | [Test]
49 | public async Task CheckFailsWhenFreeSpaceThrows()
50 | {
51 | // Arrange
52 | var exception = new Exception("error message");
53 | var driveSpaceMock = new Mock();
54 | driveSpaceMock.Setup(x => x.Read()).ThrowsAsync(exception);
55 | var check = new SystemDriveHasFreeSpace(driveSpaceMock.Object);
56 |
57 | // Act
58 | var result = await check.Check();
59 |
60 | // Assert
61 | Assert.That(result.Passed, Is.False);
62 | Assert.That(result.Output, Is.EqualTo(exception.Message));
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/src/HealthCheck.Core/HealthCheck.Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {7052554B-0005-47E4-B3C3-318D41261E72}
8 | Library
9 | Properties
10 | HealthCheck.Core
11 | HealthCheck.Core
12 | v4.5.1
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | Properties\SharedAssemblyInfo.cs
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
58 |
--------------------------------------------------------------------------------
/src/HealthCheck.Core/HealthCheck.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace HealthCheck.Core
7 | {
8 | public class HealthCheck
9 | {
10 | private readonly IEnumerable _checkers;
11 |
12 | public HealthCheck(IEnumerable checkers)
13 | {
14 | _checkers = checkers;
15 | }
16 |
17 | public async Task Run()
18 | {
19 | try
20 | {
21 | if (_checkers == null)
22 | {
23 | return new HealthCheckResult(Enumerable.Empty());
24 | }
25 | // Run all checks in parallel (if possible). Catch exceptions for each
26 | // checker individually.
27 | var checkResults = _checkers
28 | .AsParallel()
29 | .Select(async x =>
30 | {
31 | try
32 | {
33 | return await x.Check().ConfigureAwait(false);
34 | }
35 | catch (Exception ex)
36 | {
37 | return new CheckResult
38 | {
39 | Checker = x.Name,
40 | Passed = false,
41 | Output = ex.Message
42 | };
43 | }
44 | })
45 | .ToArray();
46 | await Task.WhenAll(checkResults).ConfigureAwait(false);
47 | return new HealthCheckResult(checkResults.Select(x => x.Result));
48 | }
49 | catch (AggregateException ex)
50 | {
51 | return new HealthCheckResult(ex.Flatten().InnerExceptions.Select(innerEx => new CheckResult
52 | {
53 | Checker = innerEx.TargetSite != null && !string.IsNullOrEmpty(innerEx.TargetSite.Name) ?
54 | innerEx.TargetSite.Name :
55 | "HealthCheck",
56 | Passed = false,
57 | Output = innerEx.Message
58 | }));
59 | }
60 | catch (Exception ex)
61 | {
62 | // Never let Run throw. Instead, returned a failed HealthCheckResult.
63 | return new HealthCheckResult(new[]
64 | {
65 | new CheckResult
66 | {
67 | Checker = "HealthCheck",
68 | Passed = false,
69 | Output = ex.Message
70 | }
71 | });
72 | }
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/HealthCheck.Windows/HealthCheck.Windows.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {5A6CF0A0-AFBC-460D-BA51-D5898175983B}
8 | Library
9 | Properties
10 | HealthCheck.Windows
11 | HealthCheck.Windows
12 | v4.5.1
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | Properties\SharedAssemblyInfo.cs
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | {7052554b-0005-47e4-b3c3-318d41261e72}
49 | HealthCheck.Core
50 |
51 |
52 |
53 |
60 |
--------------------------------------------------------------------------------
/src/HealthCheck.Nancy/HealthCheck.Nancy.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {971A62B5-6E57-408C-9D2B-A2EA1F9BADFD}
8 | Library
9 | Properties
10 | HealthCheck.Nancy
11 | HealthCheck.Nancy
12 | v4.5.1
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 | ..\packages\Nancy.1.1\lib\net40\Nancy.dll
35 |
36 |
37 |
38 |
39 |
40 |
41 | Properties\SharedAssemblyInfo.cs
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | {7052554b-0005-47e4-b3c3-318d41261e72}
52 | HealthCheck.Core
53 |
54 |
55 |
56 |
63 |
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Core.Tests/HealthCheck.Core.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {02AF9FC9-D118-4628-B468-3D77D5DAC257}
8 | Library
9 | Properties
10 | HealthCheck.Core.Tests
11 | HealthCheck.Core.Tests
12 | v4.5.1
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 | ..\..\packages\Moq.4.2.1502.0911\lib\net40\Moq.dll
35 |
36 |
37 | ..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | {7052554b-0005-47e4-b3c3-318d41261e72}
58 | HealthCheck.Core
59 |
60 |
61 |
62 |
69 |
--------------------------------------------------------------------------------
/src/HealthCheck.Redis/HealthCheck.Redis.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {677553A9-E456-4C94-9777-F8E2030EEE83}
8 | Library
9 | Properties
10 | HealthCheck.Redis
11 | HealthCheck.Redis
12 | v4.5.1
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 | ..\packages\StackExchange.Redis.1.0.414\lib\net45\StackExchange.Redis.dll
35 |
36 |
37 |
38 |
39 |
40 |
41 | Properties\SharedAssemblyInfo.cs
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | {7052554b-0005-47e4-b3c3-318d41261e72}
57 | HealthCheck.Core
58 |
59 |
60 |
61 |
62 |
69 |
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Redis.Tests/HealthCheck.Redis.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {87678CED-1200-4B5D-8CC5-B8CAC3FF4229}
8 | Library
9 | Properties
10 | HealthCheck.Redis.Tests
11 | HealthCheck.Redis.Tests
12 | v4.5.1
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 | ..\..\packages\Moq.4.2.1502.0911\lib\net40\Moq.dll
35 |
36 |
37 | ..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | {7052554b-0005-47e4-b3c3-318d41261e72}
58 | HealthCheck.Core
59 |
60 |
61 | {677553a9-e456-4c94-9777-f8e2030eee83}
62 | HealthCheck.Redis
63 |
64 |
65 |
66 |
73 |
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Windows.Tests/HealthCheck.Windows.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {81F62453-AB66-4D41-8516-6B4465F49334}
8 | Library
9 | Properties
10 | HealthCheck.Windows.Tests
11 | HealthCheck.Windows.Tests
12 | v4.5.1
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 | ..\..\packages\Moq.4.2.1502.0911\lib\net40\Moq.dll
35 |
36 |
37 | ..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | {7052554b-0005-47e4-b3c3-318d41261e72}
58 | HealthCheck.Core
59 |
60 |
61 | {5a6cf0a0-afbc-460d-ba51-d5898175983b}
62 | HealthCheck.Windows
63 |
64 |
65 |
66 |
73 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studo 2015 cache/options directory
26 | .vs/
27 |
28 | # MSTest test Results
29 | [Tt]est[Rr]esult*/
30 | [Bb]uild[Ll]og.*
31 |
32 | # NUNIT
33 | *.VisualState.xml
34 | TestResult.xml
35 |
36 | # Build Results of an ATL Project
37 | [Dd]ebugPS/
38 | [Rr]eleasePS/
39 | dlldata.c
40 |
41 | *_i.c
42 | *_p.c
43 | *_i.h
44 | *.ilk
45 | *.meta
46 | *.obj
47 | *.pch
48 | *.pdb
49 | *.pgc
50 | *.pgd
51 | *.rsp
52 | *.sbr
53 | *.tlb
54 | *.tli
55 | *.tlh
56 | *.tmp
57 | *.tmp_proj
58 | *.log
59 | *.vspscc
60 | *.vssscc
61 | .builds
62 | *.pidb
63 | *.svclog
64 | *.scc
65 |
66 | # Chutzpah Test files
67 | _Chutzpah*
68 |
69 | # Visual C++ cache files
70 | ipch/
71 | *.aps
72 | *.ncb
73 | *.opensdf
74 | *.sdf
75 | *.cachefile
76 |
77 | # Visual Studio profiler
78 | *.psess
79 | *.vsp
80 | *.vspx
81 |
82 | # TFS 2012 Local Workspace
83 | $tf/
84 |
85 | # Guidance Automation Toolkit
86 | *.gpState
87 |
88 | # ReSharper is a .NET coding add-in
89 | _ReSharper*/
90 | *.[Rr]e[Ss]harper
91 | *.DotSettings.user
92 |
93 | # JustCode is a .NET coding addin-in
94 | .JustCode
95 |
96 | # TeamCity is a build add-in
97 | _TeamCity*
98 |
99 | # DotCover is a Code Coverage Tool
100 | *.dotCover
101 |
102 | # NCrunch
103 | _NCrunch_*
104 | .*crunch*.local.xml
105 |
106 | # MightyMoose
107 | *.mm.*
108 | AutoTest.Net/
109 |
110 | # Web workbench (sass)
111 | .sass-cache/
112 |
113 | # Installshield output folder
114 | [Ee]xpress/
115 |
116 | # DocProject is a documentation generator add-in
117 | DocProject/buildhelp/
118 | DocProject/Help/*.HxT
119 | DocProject/Help/*.HxC
120 | DocProject/Help/*.hhc
121 | DocProject/Help/*.hhk
122 | DocProject/Help/*.hhp
123 | DocProject/Help/Html2
124 | DocProject/Help/html
125 |
126 | # Click-Once directory
127 | publish/
128 |
129 | # Publish Web Output
130 | *.[Pp]ublish.xml
131 | *.azurePubxml
132 | # TODO: Comment the next line if you want to checkin your web deploy settings
133 | # but database connection strings (with potential passwords) will be unencrypted
134 | *.pubxml
135 | *.publishproj
136 |
137 | # NuGet Packages
138 | *.nupkg
139 | # The packages folder can be ignored because of Package Restore
140 | **/packages/*
141 | # except build/, which is used as an MSBuild target.
142 | !**/packages/build/
143 | # Uncomment if necessary however generally it will be regenerated when needed
144 | #!**/packages/repositories.config
145 |
146 | # Windows Azure Build Output
147 | csx/
148 | *.build.csdef
149 |
150 | # Windows Store app package directory
151 | AppPackages/
152 |
153 | # Others
154 | *.[Cc]ache
155 | ClientBin/
156 | [Ss]tyle[Cc]op.*
157 | ~$*
158 | *~
159 | *.dbmdl
160 | *.dbproj.schemaview
161 | *.pfx
162 | *.publishsettings
163 | node_modules/
164 | bower_components/
165 |
166 | # RIA/Silverlight projects
167 | Generated_Code/
168 |
169 | # Backup & report files from converting an old project file
170 | # to a newer Visual Studio version. Backup files are not needed,
171 | # because we have git ;-)
172 | _UpgradeReport_Files/
173 | Backup*/
174 | UpgradeLog*.XML
175 | UpgradeLog*.htm
176 |
177 | # SQL Server files
178 | *.mdf
179 | *.ldf
180 |
181 | # Business Intelligence projects
182 | *.rdl.data
183 | *.bim.layout
184 | *.bim_*.settings
185 |
186 | # Microsoft Fakes
187 | FakesAssemblies/
188 |
189 | # Node.js Tools for Visual Studio
190 | .ntvs_analysis.dat
191 |
192 | # Visual Studio 6 build log
193 | *.plg
194 |
195 | # Visual Studio 6 workspace options file
196 | *.opt
197 |
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Nancy.Tests/HealthCheck.Nancy.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {F5C18CB0-A863-4DA7-A99F-1E4AE3B717F2}
8 | Library
9 | Properties
10 | HealthCheck.Nancy.Tests
11 | HealthCheck.Nancy.Tests
12 | v4.5.1
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 | ..\..\packages\CsQuery.1.3.3\lib\net40\CsQuery.dll
35 |
36 |
37 | ..\..\packages\Moq.4.2.1502.0911\lib\net40\Moq.dll
38 |
39 |
40 | False
41 | ..\..\packages\Nancy.1.1\lib\net40\Nancy.dll
42 |
43 |
44 | ..\..\packages\Nancy.Testing.1.1\lib\net40\Nancy.Testing.dll
45 |
46 |
47 | ..\..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll
48 |
49 |
50 | ..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | {7052554b-0005-47e4-b3c3-318d41261e72}
71 | HealthCheck.Core
72 |
73 |
74 | {971a62b5-6e57-408c-9d2b-a2ea1f9badfd}
75 | HealthCheck.Nancy
76 |
77 |
78 |
79 |
86 |
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Redis.Tests/Checkers/RedisHasFreeMemoryTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using HealthCheck.Redis.Checkers;
7 | using HealthCheck.Redis.Metrics;
8 | using Moq;
9 | using NUnit.Framework;
10 |
11 | namespace HealthCheck.Redis.Tests.Checkers
12 | {
13 | [TestFixture]
14 | public class RedisHasFreeMemoryTests
15 | {
16 | [Test]
17 | public async Task CheckPassesWhenFreeMemoryIsAboveThreshold()
18 | {
19 | // Arrange
20 | var options = new RedisHasFreeMemory.Options
21 | {
22 | RedisFreeMemoryWarningThresholdInBytes = 1024
23 | };
24 | long maxMemory = options.RedisFreeMemoryWarningThresholdInBytes * 10;
25 | long usedMemory = maxMemory - options.RedisFreeMemoryWarningThresholdInBytes - 1;
26 | var redisMemoryUsageMock = new Mock();
27 | redisMemoryUsageMock
28 | .Setup(x => x.Read())
29 | .ReturnsAsync(usedMemory);
30 | var redisMaxMemoryMock = new Mock();
31 | redisMaxMemoryMock
32 | .Setup(x => x.Read())
33 | .ReturnsAsync(maxMemory);
34 | var check = new RedisHasFreeMemory(redisMemoryUsageMock.Object, redisMaxMemoryMock.Object, options);
35 |
36 | // Act
37 | var result = await check.Check();
38 |
39 | // Assert
40 | Assert.That(result.Passed, Is.True);
41 | }
42 |
43 | [Test]
44 | public async Task CheckFailsWhenFreeMemoryIsBelowThreshold()
45 | {
46 | // Arrange
47 | var options = new RedisHasFreeMemory.Options
48 | {
49 | RedisFreeMemoryWarningThresholdInBytes = 1024
50 | };
51 | long maxMemory = options.RedisFreeMemoryWarningThresholdInBytes * 10;
52 | long usedMemory = maxMemory - options.RedisFreeMemoryWarningThresholdInBytes + 1;
53 | var redisMemoryUsageMock = new Mock();
54 | redisMemoryUsageMock
55 | .Setup(x => x.Read())
56 | .ReturnsAsync(usedMemory);
57 | var redisMaxMemoryMock = new Mock();
58 | redisMaxMemoryMock
59 | .Setup(x => x.Read())
60 | .ReturnsAsync(maxMemory);
61 | var check = new RedisHasFreeMemory(redisMemoryUsageMock.Object, redisMaxMemoryMock.Object, options);
62 |
63 | // Act
64 | var result = await check.Check();
65 |
66 | // Assert
67 | Assert.That(result.Passed, Is.False);
68 | }
69 |
70 | [Test]
71 | public async Task CheckFailsWhenRedisMemoryUsageThrows()
72 | {
73 | // Arrange
74 | var redisMemoryUsageMock = new Mock();
75 | var exception = new Exception("error message");
76 | redisMemoryUsageMock.Setup(x => x.Read()).ThrowsAsync(exception);
77 | var redisMaxMemoryMock = new Mock();
78 | var check = new RedisHasFreeMemory(redisMemoryUsageMock.Object, redisMaxMemoryMock.Object, new RedisHasFreeMemory.Options());
79 |
80 | // Act
81 | var result = await check.Check();
82 |
83 | // Assert
84 | Assert.That(result.Passed, Is.False);
85 | Assert.That(result.Output, Is.EqualTo(exception.Message));
86 | }
87 |
88 | [Test]
89 | public async Task CheckFailsWhenRedisMaxMemoryThrows()
90 | {
91 | // Arrange
92 | var redisMemoryUsageMock = new Mock();
93 | var exception = new Exception("error message");
94 | var redisMaxMemoryMock = new Mock();
95 | redisMaxMemoryMock.Setup(x => x.Read()).ThrowsAsync(exception);
96 | var check = new RedisHasFreeMemory(redisMemoryUsageMock.Object, redisMaxMemoryMock.Object, new RedisHasFreeMemory.Options());
97 |
98 | // Act
99 | var result = await check.Check();
100 |
101 | // Assert
102 | Assert.That(result.Passed, Is.False);
103 | Assert.That(result.Output, Is.EqualTo(exception.Message));
104 | }
105 |
106 | [Test]
107 | public async Task CheckPassesWhenThereIsNoUpperLimitOnMemoryUsage()
108 | {
109 | // Arrange
110 | var redisMaxMemoryMock = new Mock();
111 | redisMaxMemoryMock.Setup(x => x.Read()).ReturnsAsync(null);
112 | var redisMemoryUsageMock = new Mock();
113 | redisMemoryUsageMock.Setup(x => x.Read()).ReturnsAsync(1024);
114 | var check = new RedisHasFreeMemory(redisMemoryUsageMock.Object, redisMaxMemoryMock.Object, new RedisHasFreeMemory.Options());
115 |
116 | // Act
117 | var result = await check.Check();
118 |
119 | // Assert
120 | Assert.That(result.Passed, Is.True);
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/HealthCheck.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.31101.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HealthCheck.Core", "HealthCheck.Core\HealthCheck.Core.csproj", "{7052554B-0005-47E4-B3C3-318D41261E72}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HealthCheck.Redis", "HealthCheck.Redis\HealthCheck.Redis.csproj", "{677553A9-E456-4C94-9777-F8E2030EEE83}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{EBE0C6CC-E4DF-4657-B291-570F25B042E5}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HealthCheck.Nancy", "HealthCheck.Nancy\HealthCheck.Nancy.csproj", "{971A62B5-6E57-408C-9D2B-A2EA1F9BADFD}"
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HealthCheck.Windows", "HealthCheck.Windows\HealthCheck.Windows.csproj", "{5A6CF0A0-AFBC-460D-BA51-D5898175983B}"
15 | EndProject
16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FD23FB63-8010-40AC-B752-D7BD3BBD8D8F}"
17 | ProjectSection(SolutionItems) = preProject
18 | HealthCheck.Core\HealthCheck.Core.nuspec = HealthCheck.Core\HealthCheck.Core.nuspec
19 | HealthCheck.Nancy\HealthCheck.Nancy.nuspec = HealthCheck.Nancy\HealthCheck.Nancy.nuspec
20 | HealthCheck.Redis\HealthCheck.Redis.nuspec = HealthCheck.Redis\HealthCheck.Redis.nuspec
21 | HealthCheck.Windows\HealthCheck.Windows.nuspec = HealthCheck.Windows\HealthCheck.Windows.nuspec
22 | SharedAssemblyInfo.cs = SharedAssemblyInfo.cs
23 | EndProjectSection
24 | EndProject
25 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HealthCheck.Core.Tests", "Tests\HealthCheck.Core.Tests\HealthCheck.Core.Tests.csproj", "{02AF9FC9-D118-4628-B468-3D77D5DAC257}"
26 | EndProject
27 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HealthCheck.Windows.Tests", "Tests\HealthCheck.Windows.Tests\HealthCheck.Windows.Tests.csproj", "{81F62453-AB66-4D41-8516-6B4465F49334}"
28 | EndProject
29 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HealthCheck.Redis.Tests", "Tests\HealthCheck.Redis.Tests\HealthCheck.Redis.Tests.csproj", "{87678CED-1200-4B5D-8CC5-B8CAC3FF4229}"
30 | EndProject
31 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HealthCheck.Nancy.Tests", "Tests\HealthCheck.Nancy.Tests\HealthCheck.Nancy.Tests.csproj", "{F5C18CB0-A863-4DA7-A99F-1E4AE3B717F2}"
32 | EndProject
33 | Global
34 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
35 | Debug|Any CPU = Debug|Any CPU
36 | Release|Any CPU = Release|Any CPU
37 | EndGlobalSection
38 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
39 | {7052554B-0005-47E4-B3C3-318D41261E72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
40 | {7052554B-0005-47E4-B3C3-318D41261E72}.Debug|Any CPU.Build.0 = Debug|Any CPU
41 | {7052554B-0005-47E4-B3C3-318D41261E72}.Release|Any CPU.ActiveCfg = Release|Any CPU
42 | {7052554B-0005-47E4-B3C3-318D41261E72}.Release|Any CPU.Build.0 = Release|Any CPU
43 | {677553A9-E456-4C94-9777-F8E2030EEE83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
44 | {677553A9-E456-4C94-9777-F8E2030EEE83}.Debug|Any CPU.Build.0 = Debug|Any CPU
45 | {677553A9-E456-4C94-9777-F8E2030EEE83}.Release|Any CPU.ActiveCfg = Release|Any CPU
46 | {677553A9-E456-4C94-9777-F8E2030EEE83}.Release|Any CPU.Build.0 = Release|Any CPU
47 | {971A62B5-6E57-408C-9D2B-A2EA1F9BADFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
48 | {971A62B5-6E57-408C-9D2B-A2EA1F9BADFD}.Debug|Any CPU.Build.0 = Debug|Any CPU
49 | {971A62B5-6E57-408C-9D2B-A2EA1F9BADFD}.Release|Any CPU.ActiveCfg = Release|Any CPU
50 | {971A62B5-6E57-408C-9D2B-A2EA1F9BADFD}.Release|Any CPU.Build.0 = Release|Any CPU
51 | {5A6CF0A0-AFBC-460D-BA51-D5898175983B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
52 | {5A6CF0A0-AFBC-460D-BA51-D5898175983B}.Debug|Any CPU.Build.0 = Debug|Any CPU
53 | {5A6CF0A0-AFBC-460D-BA51-D5898175983B}.Release|Any CPU.ActiveCfg = Release|Any CPU
54 | {5A6CF0A0-AFBC-460D-BA51-D5898175983B}.Release|Any CPU.Build.0 = Release|Any CPU
55 | {02AF9FC9-D118-4628-B468-3D77D5DAC257}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
56 | {02AF9FC9-D118-4628-B468-3D77D5DAC257}.Debug|Any CPU.Build.0 = Debug|Any CPU
57 | {02AF9FC9-D118-4628-B468-3D77D5DAC257}.Release|Any CPU.ActiveCfg = Release|Any CPU
58 | {02AF9FC9-D118-4628-B468-3D77D5DAC257}.Release|Any CPU.Build.0 = Release|Any CPU
59 | {81F62453-AB66-4D41-8516-6B4465F49334}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
60 | {81F62453-AB66-4D41-8516-6B4465F49334}.Debug|Any CPU.Build.0 = Debug|Any CPU
61 | {81F62453-AB66-4D41-8516-6B4465F49334}.Release|Any CPU.ActiveCfg = Release|Any CPU
62 | {81F62453-AB66-4D41-8516-6B4465F49334}.Release|Any CPU.Build.0 = Release|Any CPU
63 | {87678CED-1200-4B5D-8CC5-B8CAC3FF4229}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
64 | {87678CED-1200-4B5D-8CC5-B8CAC3FF4229}.Debug|Any CPU.Build.0 = Debug|Any CPU
65 | {87678CED-1200-4B5D-8CC5-B8CAC3FF4229}.Release|Any CPU.ActiveCfg = Release|Any CPU
66 | {87678CED-1200-4B5D-8CC5-B8CAC3FF4229}.Release|Any CPU.Build.0 = Release|Any CPU
67 | {F5C18CB0-A863-4DA7-A99F-1E4AE3B717F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
68 | {F5C18CB0-A863-4DA7-A99F-1E4AE3B717F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
69 | {F5C18CB0-A863-4DA7-A99F-1E4AE3B717F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
70 | {F5C18CB0-A863-4DA7-A99F-1E4AE3B717F2}.Release|Any CPU.Build.0 = Release|Any CPU
71 | EndGlobalSection
72 | GlobalSection(SolutionProperties) = preSolution
73 | HideSolutionNode = FALSE
74 | EndGlobalSection
75 | GlobalSection(NestedProjects) = preSolution
76 | {02AF9FC9-D118-4628-B468-3D77D5DAC257} = {EBE0C6CC-E4DF-4657-B291-570F25B042E5}
77 | {81F62453-AB66-4D41-8516-6B4465F49334} = {EBE0C6CC-E4DF-4657-B291-570F25B042E5}
78 | {87678CED-1200-4B5D-8CC5-B8CAC3FF4229} = {EBE0C6CC-E4DF-4657-B291-570F25B042E5}
79 | {F5C18CB0-A863-4DA7-A99F-1E4AE3B717F2} = {EBE0C6CC-E4DF-4657-B291-570F25B042E5}
80 | EndGlobalSection
81 | EndGlobal
82 |
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Nancy.Tests/HealthCheckModuleTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using HealthCheck.Core;
7 | using Moq;
8 | using Nancy;
9 | using Nancy.Testing;
10 | using Newtonsoft.Json;
11 | using NUnit.Framework;
12 |
13 | namespace HealthCheck.Nancy.Tests
14 | {
15 | [TestFixture]
16 | public class HealthCheckModuleTests
17 | {
18 | [Test]
19 | public void UsesTheDesiredRoute()
20 | {
21 | // Arrange
22 | var options = new HealthCheckOptions
23 | {
24 | Route = "/my/custom/healthcheck"
25 | };
26 | var module = new HealthCheckModule(Enumerable.Empty(), options);
27 | var bootstrapper = new ConfigurableBootstrapper(with =>
28 | {
29 | with.Module(module);
30 | });
31 | var browser = new Browser(bootstrapper);
32 |
33 | // Act
34 | var response = browser.Get(options.Route, with =>
35 | {
36 | with.HttpsRequest();
37 | });
38 |
39 | // Assert
40 | Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
41 | }
42 |
43 | [Test]
44 | public void CanRequireHttps()
45 | {
46 | // Arrange
47 | var options = new HealthCheckOptions
48 | {
49 | RequireHttps = true
50 | };
51 | var module = new HealthCheckModule(Enumerable.Empty(), options);
52 | var bootstrapper = new ConfigurableBootstrapper(with =>
53 | {
54 | with.Module(module);
55 | });
56 | var browser = new Browser(bootstrapper);
57 |
58 | // Act
59 | var response = browser.Get("/healthcheck", with =>
60 | {
61 | with.HttpRequest();
62 | });
63 |
64 | // Assert
65 | Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.Forbidden));
66 | }
67 |
68 | [Test]
69 | public void DoesNotHaveToRequireHttps()
70 | {
71 | // Arrange
72 | var options = new HealthCheckOptions
73 | {
74 | RequireHttps = false
75 | };
76 | var module = new HealthCheckModule(Enumerable.Empty(), options);
77 | var bootstrapper = new ConfigurableBootstrapper(with =>
78 | {
79 | with.Module(module);
80 | });
81 | var browser = new Browser(bootstrapper);
82 |
83 | // Act
84 | var response = browser.Get("/healthcheck", with =>
85 | {
86 | with.HttpRequest();
87 | });
88 |
89 | // Assert
90 | Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
91 | }
92 |
93 | [Test]
94 | public void AllRequestsAuthorizedByDefault()
95 | {
96 | // Arrange
97 | var module = new HealthCheckModule(Enumerable.Empty());
98 | var bootstrapper = new ConfigurableBootstrapper(with =>
99 | {
100 | with.Module(module);
101 | });
102 | var browser = new Browser(bootstrapper);
103 |
104 | // Act
105 | var response = browser.Get("/healthcheck", with =>
106 | {
107 | with.HttpsRequest();
108 | });
109 |
110 | // Assert
111 | Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
112 | }
113 |
114 | [Test]
115 | public void BlocksUnauthorizedRequests()
116 | {
117 | // Arrange
118 | var options = new HealthCheckOptions
119 | {
120 | AuthorizationCallback = context => Task.FromResult(false)
121 | };
122 | var module = new HealthCheckModule(Enumerable.Empty(), options);
123 | var bootstrapper = new ConfigurableBootstrapper(with =>
124 | {
125 | with.Module(module);
126 | });
127 | var browser = new Browser(bootstrapper);
128 |
129 | // Act
130 | var response = browser.Get("/healthcheck", with =>
131 | {
132 | with.HttpsRequest();
133 | });
134 |
135 | // Assert
136 | Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.Unauthorized));
137 | }
138 |
139 | [Test]
140 | public void RunsAllCheckers()
141 | {
142 | // Arrange
143 | var checkerMocks = Enumerable
144 | .Range(1, 3)
145 | .Select(x =>
146 | {
147 | var mock = new Mock();
148 | mock.Setup(y => y.Check()).ReturnsAsync(new CheckResult());
149 | return mock;
150 | })
151 | .ToArray();
152 | var module = new HealthCheckModule(checkerMocks.Select(x => x.Object));
153 | var bootstrapper = new ConfigurableBootstrapper(with =>
154 | {
155 | with.Module(module);
156 | });
157 | var browser = new Browser(bootstrapper);
158 |
159 | // Act
160 | var response = browser.Get("/healthcheck", with =>
161 | {
162 | with.HttpsRequest();
163 | });
164 |
165 | // Assert
166 | Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
167 | foreach (var checkerMock in checkerMocks)
168 | {
169 | checkerMock.Verify(x => x.Check(), Times.Once);
170 | }
171 | }
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # HealthCheck - flexible, asynchronous health checks for your .NET apps
2 |
3 | [](https://ci.appveyor.com/project/Hihaj/healthcheck/branch/master)
4 | [](https://www.nuget.org/packages?q=hihaj.healthcheck)
5 |
6 | Heavily inspired by [Runscope/healthcheck](https://github.com/Runscope/healthcheck), HealthCheck provides a simple but flexible way to monitor application health, including OS resources, third-party service status etc.
7 |
8 |
9 | ## High-level overview
10 |
11 | A *health check* runs one or more independent *checks* that either pass or not depending on some specific *metric(s)*. The health check as a whole is successful if (and only if) all checks pass.
12 |
13 | A conceptual example could be to require that CPU usage is below 80% and Redis is available.
14 |
15 |
16 | ## Getting started
17 |
18 | HealthCheck can be used in any type of .NET application - just create an instance of `HealthCheck`, add some `IChecker` implementations and run it. A simple example that uses a built-in checker from the `Hihaj.HealthCheck.Windows` package:
19 |
20 | ```c#
21 | var healthCheck = new HealthCheck(new IChecker[]
22 | {
23 | new SystemDriveHasFreeSpace(new AvailableSystemDriveSpace())
24 | });
25 | var result = await healthCheck.Run();
26 |
27 | Console.WriteLine(result.Passed); // true/false
28 | Console.WriteLine(result.Status); // "success"/"failure"
29 | foreach (var checkResult in result.Results)
30 | {
31 | Console.WriteLine(checkResult.Checker); // E.g. "System drive has free space"
32 | Console.WriteLine(checkResult.Passed); // true/false
33 | Console.WriteLine(checkResult.Output); // E.g. "123.4 GB available"
34 | }
35 | ```
36 |
37 | ### Bonus: Nancy health check module
38 |
39 | If you're building a [Nancy](https://github.com/NancyFx) web app, things are even simpler. Just install the `Hihaj.HealthCheck.Nancy` package and add the `HealthCheckModule` to the `ConfigureApplicationContainer` method of your bootstrapper:
40 |
41 | ```c#
42 | container.RegisterMultiple(new[]
43 | {
44 | typeof(SystemDriveHasFreeSpace)
45 | });
46 | container.Register();
47 | ```
48 |
49 | This will expose the health check on the default url (`/healthcheck`), require https and use default options for all `IChecker` implementations that you specified.
50 |
51 | If you need more control, you can register non-default options:
52 |
53 | ```c#
54 | container.Register(new SystemDriveHasFreeSpace.Options
55 | {
56 | SystemDriveAvailableFreeSpaceWarningThresholdInBytes =
57 | 5L * 1024L * 1024L * 1024L; // 5 GB
58 | });
59 | container.RegisterMultiple(new[]
60 | {
61 | typeof(SystemDriveHasFreeSpace)
62 | });
63 | container.Register(new HealthCheckOptions
64 | {
65 | Route = "/healthcheck",
66 | RequireHttps = true,
67 | AuthorizationCallback = context => Task.FromResult(true)
68 | });
69 | container.Register();
70 | ```
71 |
72 | When issuing a GET request for the health check url (using the configured route or the default `/healthcheck` if none provided), you get back the complete result of the health check in JSON format. For example:
73 |
74 | ```json
75 | {
76 | "results": [
77 | {
78 | "checker": "CPU usage is OK",
79 | "passed": true,
80 | "output": "Currently using 4,2 % of total processor time."
81 | },
82 | {
83 | "checker": "Redis has free memory",
84 | "passed": true,
85 | "output": "1 % of the reserved memory is used (507,8 MB free)."
86 | },
87 | {
88 | "checker": "Redis is available",
89 | "passed": true,
90 | "output": "Version 2.8.19, uptime 1 days 12 hours 51 minutes."
91 | },
92 | {
93 | "checker": "System drive has free space",
94 | "passed": true,
95 | "output": "84,9 GB available."
96 | }
97 | ],
98 | "passed": true,
99 | "status": "success"
100 | }
101 | ```
102 |
103 | This endpoint can easily be monitored continously by a tool or service such as [Runscope](https://www.runscope.com/) (in fact, the JSON output is compatible with the one produced by [Runscope/healthcheck](https://github.com/Runscope/healthcheck)).
104 |
105 |
106 | ## Creating a custom `IChecker`
107 |
108 | Implement the `IChecker` interface to define custom checks:
109 |
110 | ```c#
111 | public interface IChecker
112 | {
113 | string Name { get; }
114 | Task Check();
115 | }
116 | ```
117 |
118 | The `CheckResult` returned by the `Check` method is very simple:
119 |
120 | ```c#
121 | public class CheckResult
122 | {
123 | public string Checker { get; set; } // Display name of the check
124 | public bool Passed { get; set; } // Whether it passed or not
125 | public string Output { get; set; } // Description of the outcome
126 | }
127 | ```
128 |
129 | You can of course implement your checks in any way you like, but to improve testability you could base the logic on readings from one or more _metrics_:
130 |
131 | ```c#
132 | public interface IMetric
133 | {
134 | Task Read();
135 | }
136 | ```
137 |
138 | A simple example:
139 |
140 | ```c#
141 | public interface ITemperature : IMetric
142 | {
143 | }
144 |
145 | public class Temperature : ITemperature
146 | {
147 | public async Task Read()
148 | {
149 | // Read the current temperature from some source,
150 | // preferably in an asynchronous manner.
151 | // ...
152 | }
153 | }
154 |
155 | public class TemperatureIsBelowFreezingPoint : IChecker
156 | {
157 | private readonly ITemperature _temperature;
158 |
159 | public string Name
160 | {
161 | get { return "Temperature is below freezing point"; }
162 | }
163 |
164 | public TemperatureIsBelowFreezingPoint(ITemperature temperature)
165 | {
166 | _temperature = temperature;
167 | }
168 |
169 | public async Task Check()
170 | {
171 | var temp = await _temperature.Read().ConfigureAwait(false);
172 | return new CheckResult
173 | {
174 | Checker = Name,
175 | Passed = temp <= 0,
176 | Output = string.Format("Current temperature is {0:F1} °C.", temp)
177 | };
178 | }
179 | }
180 | ```
181 |
182 |
183 | ## Built-in `IChecker`s
184 |
185 | ### Hihaj.HealthCheck.Windows
186 |
187 | - `CpuUsageIsOk` - passes as long as CPU usage is below a (configurable) threshold. _(Uses performance counters, which means the Windows user that is executing the health check (such as an app pool identity) needs to have the correct permissions.)_
188 | - `SystemDriveHasFreeSpace` - passes as long as the system drive has at least X bytes available (configurable).
189 |
190 | ### Hihaj.HealthCheck.Redis
191 |
192 | - `RedisIsAvailable` - self-explanatory.
193 | - `RedisHasFreeMemory` - passes as long as Redis has more than a (configurable) amount of free memory (or no upper limit).
194 |
195 | *Note:* This package depends on [StackExchange.Redis](https://github.com/StackExchange/StackExchange.Redis).
196 |
--------------------------------------------------------------------------------
/src/Tests/HealthCheck.Core.Tests/HealthCheckTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Moq;
7 | using NUnit.Framework;
8 |
9 | namespace HealthCheck.Core.Tests
10 | {
11 | [TestFixture]
12 | public class HealthCheckTests
13 | {
14 | [Test]
15 | public async Task Run_WhenNullCheckers_SuccessResult()
16 | {
17 | // Arrange
18 | var healthCheck = new HealthCheck(null);
19 |
20 | // Act
21 | var result = await healthCheck.Run();
22 |
23 | // Assert
24 | Assert.That(result.Passed, Is.True);
25 | Assert.That(result.Status, Is.EqualTo("success"));
26 | Assert.That(result.Results, Is.Empty);
27 | }
28 |
29 | [Test]
30 | public async Task Run_WhenNoCheckers_SuccessResult()
31 | {
32 | // Arrange
33 | var healthCheck = new HealthCheck(Enumerable.Empty());
34 |
35 | // Act
36 | var result = await healthCheck.Run();
37 |
38 | // Assert
39 | Assert.That(result.Passed, Is.True);
40 | Assert.That(result.Status, Is.EqualTo("success"));
41 | Assert.That(result.Results, Is.Empty);
42 | }
43 |
44 | [Test]
45 | public async Task Run_RunsAllCheckers()
46 | {
47 | // Arrange
48 | var checkerMocks = Enumerable
49 | .Range(1, 3)
50 | .Select(x =>
51 | {
52 | var mock = new Mock();
53 | mock.SetupGet(y => y.Name).Returns(x.ToString());
54 | mock.Setup(y => y.Check()).ReturnsAsync(new CheckResult());
55 | return mock;
56 | })
57 | .ToArray();
58 | var healthCheck = new HealthCheck(checkerMocks.Select(x => x.Object));
59 |
60 | // Act
61 | await healthCheck.Run();
62 |
63 | // Assert
64 | foreach (var checkerMock in checkerMocks)
65 | {
66 | checkerMock.Verify(x => x.Check(), Times.Once);
67 | }
68 | }
69 |
70 | [Test]
71 | public async Task Run_WhenCheckerThrows_FailureResult()
72 | {
73 | // Arrange
74 | var checkerMocks = Enumerable
75 | .Range(1, 3)
76 | .Select(x =>
77 | {
78 | var mock = new Mock();
79 | mock.SetupGet(y => y.Name).Returns(x.ToString());
80 | mock.Setup(y => y.Check()).ThrowsAsync(new Exception("error " + mock.Object.Name));
81 | return mock;
82 | })
83 | .ToArray();
84 | var healthCheck = new HealthCheck(checkerMocks.Select(x => x.Object));
85 |
86 | // Act
87 | var result = await healthCheck.Run();
88 |
89 | // Assert
90 | Assert.That(result.Passed, Is.False);
91 | Assert.That(result.Status, Is.EqualTo("failure"));
92 | Assert.That(result.Results.Length, Is.EqualTo(checkerMocks.Length));
93 | foreach (var checkerMock in checkerMocks)
94 | {
95 | var checkResult = result.Results.Single(x => x.Checker == checkerMock.Object.Name);
96 | Assert.That(checkResult.Checker, Is.EqualTo(checkerMock.Object.Name));
97 | Assert.That(checkResult.Passed, Is.False);
98 | Assert.That(checkResult.Output, Is.EqualTo("error " + checkerMock.Object.Name));
99 | }
100 | }
101 |
102 | [Test]
103 | public async Task Run_WhenAtLeastOneCheckerFails_FailureResult()
104 | {
105 | // Arrange
106 | var checkerMocks = Enumerable
107 | .Range(1, 3)
108 | .Select(x =>
109 | {
110 | var mock = new Mock();
111 | mock.SetupGet(y => y.Name).Returns(x.ToString());
112 | mock.Setup(y => y.Check()).ReturnsAsync(new CheckResult { Passed = true });
113 | return mock;
114 | })
115 | .ToArray();
116 | var exception = new Exception("error message");
117 | checkerMocks[1].Setup(x => x.Check()).ThrowsAsync(exception);
118 | var healthCheck = new HealthCheck(checkerMocks.Select(x => x.Object));
119 |
120 | // Act
121 | var result = await healthCheck.Run();
122 |
123 | // Assert
124 | Assert.That(result.Passed, Is.False);
125 | Assert.That(result.Status, Is.EqualTo("failure"));
126 | Assert.That(result.Results.Length, Is.EqualTo(checkerMocks.Length));
127 | Assert.That(result.Results.Count(x => x.Passed), Is.EqualTo(checkerMocks.Length - 1));
128 | }
129 |
130 | [Test]
131 | public async Task Run_WhenAllCheckersPass_SuccessResult()
132 | {
133 | // Arrange
134 | var checkerMocks = Enumerable
135 | .Range(1, 3)
136 | .Select(x =>
137 | {
138 | var mock = new Mock();
139 | mock.SetupGet(y => y.Name).Returns(x.ToString());
140 | mock.Setup(y => y.Check()).ReturnsAsync(new CheckResult { Passed = true });
141 | return mock;
142 | })
143 | .ToArray();
144 | var healthCheck = new HealthCheck(checkerMocks.Select(x => x.Object));
145 |
146 | // Act
147 | var result = await healthCheck.Run();
148 |
149 | // Assert
150 | Assert.That(result.Passed, Is.True);
151 | Assert.That(result.Status, Is.EqualTo("success"));
152 | Assert.That(result.Results.Length, Is.EqualTo(checkerMocks.Length));
153 | Assert.That(result.Results.Count(x => x.Passed), Is.EqualTo(checkerMocks.Length));
154 | }
155 |
156 | [Test]
157 | public async Task Run_WhenSomethingOutsideOfTheCheckersThrows_FailureResult()
158 | {
159 | // Arrange
160 | var checkersMock = new Mock>();
161 | var exception = new Exception("surprise");
162 | checkersMock.Setup(x => x.GetEnumerator()).Throws(exception);
163 | var healthCheck = new HealthCheck(checkersMock.Object);
164 |
165 | // Act
166 | var result = await healthCheck.Run();
167 |
168 | // Assert
169 | Assert.That(result.Passed, Is.False);
170 | Assert.That(result.Status, Is.EqualTo("failure"));
171 | Assert.That(result.Results, Is.Not.Null);
172 | Assert.That(result.Results.Single().Checker, Is.EqualTo("HealthCheck"));
173 | Assert.That(result.Results.Single().Passed, Is.False);
174 | Assert.That(result.Results.Single().Output, Is.EqualTo(exception.Message));
175 | }
176 | }
177 | }
178 |
--------------------------------------------------------------------------------