diff --git a/AspNetCore.Diagnostics.HealthChecks.sln b/AspNetCore.Diagnostics.HealthChecks.sln
index 114b388d59..ce1fe825b7 100644
--- a/AspNetCore.Diagnostics.HealthChecks.sln
+++ b/AspNetCore.Diagnostics.HealthChecks.sln
@@ -73,6 +73,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HealthChecks.Elasticsearch"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HealthChecks.EventStore", "src\HealthChecks.EventStore\HealthChecks.EventStore.csproj", "{39667845-526D-46ED-90F0-05ED6B8814F1}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HealthChecks.AzureKeyVault", "src\HealthChecks.AzureKeyVault\HealthChecks.AzureKeyVault.csproj", "{A6414860-EBAE-43E4-8109-DE745DA15C43}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "test\UnitTests\UnitTests.csproj", "{300A1B42-EA00-480A-AC43-007EBC7CE472}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -187,6 +191,14 @@ Global
{39667845-526D-46ED-90F0-05ED6B8814F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{39667845-526D-46ED-90F0-05ED6B8814F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{39667845-526D-46ED-90F0-05ED6B8814F1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A6414860-EBAE-43E4-8109-DE745DA15C43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A6414860-EBAE-43E4-8109-DE745DA15C43}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A6414860-EBAE-43E4-8109-DE745DA15C43}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A6414860-EBAE-43E4-8109-DE745DA15C43}.Release|Any CPU.Build.0 = Release|Any CPU
+ {300A1B42-EA00-480A-AC43-007EBC7CE472}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {300A1B42-EA00-480A-AC43-007EBC7CE472}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {300A1B42-EA00-480A-AC43-007EBC7CE472}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {300A1B42-EA00-480A-AC43-007EBC7CE472}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -219,6 +231,8 @@ Global
{6FB1E70A-2915-4810-BCA4-AF38010AF949} = {2A3FD988-2BB8-43CF-B3A2-B70E648259D4}
{8ACAEE4F-55EA-452F-A5EF-9D99EA9885F9} = {2A3FD988-2BB8-43CF-B3A2-B70E648259D4}
{39667845-526D-46ED-90F0-05ED6B8814F1} = {2A3FD988-2BB8-43CF-B3A2-B70E648259D4}
+ {A6414860-EBAE-43E4-8109-DE745DA15C43} = {2A3FD988-2BB8-43CF-B3A2-B70E648259D4}
+ {300A1B42-EA00-480A-AC43-007EBC7CE472} = {FF4414C2-8863-4ADA-8A1D-4B9F25C361FE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2B8C62A1-11B6-469F-874C-A02443256568}
diff --git a/README.md b/README.md
index b887991960..6acb297452 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,7 @@ HealthChecks packages include health checks for:
- System: Disk Storage, Private Memory, Virtual Memory
- Azure Service Bus: EventHub, Queue and Topics
- Azure Storage: Blob, Queue and Table
+- Azure Key Vault
- Azure DocumentDb
- Amazon DynamoDb
- Amazon S3
@@ -44,6 +45,7 @@ Install-Package AspNetCore.HealthChecks.Redis
Install-Package AspNetCore.HealthChecks.EventStore
Install-Package AspNetCore.HealthChecks.AzureStorage
Install-Package AspNetCore.HealthChecks.AzureServiceBus
+Install-Package AspNetCore.HealthChecks.AzureKeyVault
Install-Package AspNetCore.HealthChecks.MySql
Install-Package AspNetCore.HealthChecks.DocumentDb
Install-Package AspNetCore.HealthChecks.SqLite
diff --git a/build.ps1 b/build.ps1
index aa4ac3af0f..8bd405b6ea 100644
--- a/build.ps1
+++ b/build.ps1
@@ -38,13 +38,24 @@ echo "build: Build version suffix is $buildSuffix"
exec { & dotnet build AspNetCore.Diagnostics.HealthChecks.sln -c Release --version-suffix=$buildSuffix -v q /nologo }
+echo "Running unit tests"
+
+try {
+
+Push-Location -Path .\test\UnitTests
+ exec { & dotnet test}
+} finally {
+ Pop-Location
+}
+
+
if (-Not (Test-Path 'env:APPVEYOR')) {
exec { & docker-compose up -d }
}
echo "compose up done"
-echo "running tests"
+echo "Running functional tests"
try {
@@ -75,7 +86,8 @@ if ($suffix -eq "") {
exec { & dotnet pack .\src\HealthChecks.Oracle\HealthChecks.Oracle.csproj -c Release -o ..\..\artifacts --include-symbols --no-build }
exec { & dotnet pack .\src\HealthChecks.System\HealthChecks.System.csproj -c Release -o ..\..\artifacts --include-symbols --no-build }
exec { & dotnet pack .\src\HealthChecks.Network\HealthChecks.Network.csproj -c Release -o ..\..\artifacts --include-symbols --no-build }
- exec { & dotnet pack .\src\HealthChecks.Aws.S3\HealthChecks.Aws.S3.csproj -c Release -o ..\..\artifacts --include-symbols --no-build }
+ exec { & dotnet pack .\src\HealthChecks.Aws.S3\HealthChecks.Aws.S3.csproj -c Release -o ..\..\artifacts --include-symbols --no-build }
+ exec { & dotnet pack .\src\HealthChecks.HealthChecks.AzureKeyVault\HealthChecks.AzureKeyVault.csproj -c Release -o ..\..\artifacts --include-symbols --no-build }
exec { & dotnet pack .\src\HealthChecks.UI\HealthChecks.UI.csproj -c Release -o ..\..\artifacts --include-symbols --no-build }
exec { & dotnet pack .\src\HealthChecks.UI.Client\HealthChecks.UI.Client.csproj -c Release -o ..\..\artifacts --include-symbols --no-build }
exec { & dotnet pack .\src\HealthChecks.Publisher.ApplicationInsights\HealthChecks.Publisher.ApplicationInsights.csproj -c Release -o ..\..\artifacts --include-symbols --no-build }
@@ -102,7 +114,8 @@ else {
exec { & dotnet pack .\src\HealthChecks.Oracle\HealthChecks.Oracle.csproj -c Release -o ..\..\artifacts --include-symbols --no-build --version-suffix=$suffix }
exec { & dotnet pack .\src\HealthChecks.System\HealthChecks.System.csproj -c Release -o ..\..\artifacts --include-symbols --no-build --version-suffix=$suffix }
exec { & dotnet pack .\src\HealthChecks.Network\HealthChecks.Network.csproj -c Release -o ..\..\artifacts --include-symbols --no-build --version-suffix=$suffix }
- exec { & dotnet pack .\src\HealthChecks.Aws.S3\HealthChecks.Aws.S3.csproj -c Release -o ..\..\artifacts --include-symbols --no-build --version-suffix=$suffix }
+ exec { & dotnet pack .\src\HealthChecks.Aws.S3\HealthChecks.Aws.S3.csproj -c Release -o ..\..\artifacts --include-symbols --no-build --version-suffix=$suffix }
+ exec { & dotnet pack .\src\HealthChecks.AzureKeyVault\HealthChecks.AzureKeyVault.csproj -c Release -o ..\..\artifacts --include-symbols --no-build --version-suffix=$suffix }
exec { & dotnet pack .\src\HealthChecks.UI\HealthChecks.UI.csproj -c Release -o ..\..\artifacts --include-symbols --no-build --version-suffix=$suffix }
exec { & dotnet pack .\src\HealthChecks.UI.Client\HealthChecks.UI.Client.csproj -c Release -o ..\..\artifacts --include-symbols --no-build --version-suffix=$suffix }
exec { & dotnet pack .\src\HealthChecks.Publisher.ApplicationInsights\HealthChecks.Publisher.ApplicationInsights.csproj -c Release -o ..\..\artifacts --include-symbols --no-build --version-suffix=$suffix }
diff --git a/build/dependencies.props b/build/dependencies.props
index e1ae744727..42d225c45b 100644
--- a/build/dependencies.props
+++ b/build/dependencies.props
@@ -48,9 +48,13 @@
2.1.1
1.1.5
2.1.1
+ 2.1.1
2.7.2
2.1.3
3.3.29
+ 3.0.2
+ 4.4.1
+ 1.0.3
@@ -77,11 +81,12 @@
2.2.0
2.2.0
2.2.0
- 2.2.0
+ 2.2.1
2.2.4
2.2.2
2.2.0
2.2.0
2.2.0
+ 2.2.0
\ No newline at end of file
diff --git a/src/HealthChecks.AzureKeyVault/AzureKeyVaultHealthCheck.cs b/src/HealthChecks.AzureKeyVault/AzureKeyVaultHealthCheck.cs
new file mode 100644
index 0000000000..27d41545e0
--- /dev/null
+++ b/src/HealthChecks.AzureKeyVault/AzureKeyVaultHealthCheck.cs
@@ -0,0 +1,75 @@
+using Microsoft.Azure.KeyVault;
+using Microsoft.Azure.Services.AppAuthentication;
+using Microsoft.Extensions.Diagnostics.HealthChecks;
+using Microsoft.IdentityModel.Clients.ActiveDirectory;
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using static Microsoft.Azure.KeyVault.KeyVaultClient;
+
+namespace HealthChecks.AzureKeyVault
+{
+ public class AzureKeyVaultHealthCheck : IHealthCheck
+ {
+ private readonly AzureKeyVaultOptions _keyVaultOptions;
+
+ public AzureKeyVaultHealthCheck(AzureKeyVaultOptions keyVaultOptions)
+ {
+ if (!Uri.TryCreate(keyVaultOptions.KeyVaultUrlBase, UriKind.Absolute, out var _))
+ {
+ throw new ArgumentException("KeyVaultUrlBase must be a valid Uri");
+ }
+
+ _keyVaultOptions = keyVaultOptions;
+ }
+ public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
+ {
+ var currentSecret = string.Empty;
+
+ try
+ {
+ var client = GetClient(_keyVaultOptions);
+ foreach (var secretIdentifier in _keyVaultOptions.Secrets)
+ {
+ currentSecret = secretIdentifier;
+ await client.GetSecretAsync(_keyVaultOptions.KeyVaultUrlBase, secretIdentifier, cancellationToken);
+ }
+
+ return HealthCheckResult.Healthy();
+ }
+ catch (Exception ex)
+ {
+ var secretException = new Exception($"{currentSecret} secret error - {ex.Message}", ex);
+ return new HealthCheckResult(context.Registration.FailureStatus, exception: secretException);
+ }
+ }
+
+ private KeyVaultClient GetClient(AzureKeyVaultOptions options)
+ {
+ if (string.IsNullOrEmpty(options.ClientId))
+ {
+ var azureServiceTokenProvider = new AzureServiceTokenProvider();
+ return new KeyVaultClient(new AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
+ }
+ else
+ {
+ return new KeyVaultClient(GetToken);
+ }
+ }
+
+ public async Task GetToken(string authority, string resource, string scope)
+ {
+ var authContext = new AuthenticationContext(authority);
+ ClientCredential clientCred = new ClientCredential(_keyVaultOptions.ClientId, _keyVaultOptions.ClientSecret);
+ AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);
+
+ if (result == null)
+ throw new InvalidOperationException($"[{nameof(AzureKeyVaultHealthCheck)}] - Failed to obtain the JWT token");
+
+ return result.AccessToken;
+ }
+ }
+}
diff --git a/src/HealthChecks.AzureKeyVault/AzureKeyVaultMsiHealthCheck.cs b/src/HealthChecks.AzureKeyVault/AzureKeyVaultMsiHealthCheck.cs
new file mode 100644
index 0000000000..049bd74acc
--- /dev/null
+++ b/src/HealthChecks.AzureKeyVault/AzureKeyVaultMsiHealthCheck.cs
@@ -0,0 +1,51 @@
+using Microsoft.Azure.KeyVault;
+using Microsoft.Azure.Services.AppAuthentication;
+using Microsoft.Extensions.Diagnostics.HealthChecks;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using static Microsoft.Azure.KeyVault.KeyVaultClient;
+
+namespace HealthChecks.AzureKeyVault
+{
+ public class AzureKeyVaultMsiHealthCheck : IHealthCheck
+ {
+ private readonly AzureKeyVaultOptions _keyVaultOptions;
+
+ public AzureKeyVaultMsiHealthCheck(AzureKeyVaultOptions keyVaultOptions)
+ {
+ if (string.IsNullOrEmpty(keyVaultOptions.KeyVaultUrlBase))
+ {
+ throw new ArgumentNullException(nameof(keyVaultOptions.KeyVaultUrlBase));
+ }
+
+ _keyVaultOptions = keyVaultOptions;
+ }
+ public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
+ {
+ var currentSecret = string.Empty;
+
+ try
+ {
+ var azureServiceTokenProvider = new AzureServiceTokenProvider();
+
+ var client = new KeyVaultClient(new AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
+
+ foreach (var secretIdentifier in _keyVaultOptions.Secrets)
+ {
+ currentSecret = secretIdentifier;
+ await client.GetSecretAsync(_keyVaultOptions.KeyVaultUrlBase, secretIdentifier, cancellationToken);
+ }
+
+ return HealthCheckResult.Healthy();
+ }
+ catch (Exception ex)
+ {
+ var secretException = new Exception($"{currentSecret} secret error - {ex.Message}", ex);
+ return new HealthCheckResult(context.Registration.FailureStatus, exception: secretException);
+ }
+ }
+ }
+}
diff --git a/src/HealthChecks.AzureKeyVault/AzureKeyVaultOptions.cs b/src/HealthChecks.AzureKeyVault/AzureKeyVaultOptions.cs
new file mode 100644
index 0000000000..abcc4eaff0
--- /dev/null
+++ b/src/HealthChecks.AzureKeyVault/AzureKeyVaultOptions.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace HealthChecks.AzureKeyVault
+{
+ public class AzureKeyVaultOptions
+ {
+ internal List Secrets { get; } = new List();
+ internal string KeyVaultUrlBase { get; set; }
+ internal string ClientId { get; set; }
+ internal string ClientSecret { get; set; }
+
+
+ ///
+ /// Configures remote Azure Key Vault Url service
+ ///
+ ///
+ ///
+ public AzureKeyVaultOptions UseKeyVaultUrl(string keyVaultUrlBase)
+ {
+ KeyVaultUrlBase = keyVaultUrlBase;
+ return this;
+ }
+
+ ///
+ /// Azure key vault connection is performed using provided Client Id and Client Secret
+ ///
+ /// Azure Key Vault base url - https://[vaultname].vault.azure.net/
+ /// Registered application Id
+ /// Registered application secret
+ ///
+ public AzureKeyVaultOptions UseClientSecrets(string clientId, string clientSecret)
+ {
+ if(string.IsNullOrEmpty(clientId) || string.IsNullOrEmpty(clientSecret))
+ {
+ throw new ArgumentNullException("ClientId and ClientSecret parameters should not be empty");
+ }
+
+ ClientId = clientId;
+ ClientSecret = clientSecret;
+
+ return this;
+ }
+
+ ///
+ /// Add a Azure Key Vault secret to be checked
+ ///
+ ///
+ ///
+ public AzureKeyVaultOptions AddSecret(string secretIdentifier)
+ {
+ if(!Secrets.Contains(secretIdentifier))
+ {
+ Secrets.Add(secretIdentifier);
+ }
+
+ return this;
+ }
+ }
+}
diff --git a/src/HealthChecks.AzureKeyVault/DependencyInjection/AzureKeyVaultHealthChecksBuilderExtensions.cs b/src/HealthChecks.AzureKeyVault/DependencyInjection/AzureKeyVaultHealthChecksBuilderExtensions.cs
new file mode 100644
index 0000000000..77754d61f0
--- /dev/null
+++ b/src/HealthChecks.AzureKeyVault/DependencyInjection/AzureKeyVaultHealthChecksBuilderExtensions.cs
@@ -0,0 +1,37 @@
+using HealthChecks.AzureKeyVault;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Diagnostics.HealthChecks;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+ public static class AzureKeyVaultHealthChecksBuilderExtensions
+ {
+ ///
+ /// Add a health check for Azure Key Vault. Default behaviour is using Managed Service Identity, to use Client Secrets call UseClientSecrets in setup action
+ ///
+ /// The .
+ /// Setup action to configure Azure Key Vault options
+ /// The health check name. Optional. If null the type name 'azurekeyvault' will be used for the name.
+ ///
+ /// The that should be reported when the health check fails. Optional. If null then
+ /// the default status of will be reported.
+ ///
+ /// A list of tags that can be used to filter sets of health checks. Optional.
+ /// The .
+ public static IHealthChecksBuilder AddAzureKeyVault(this IHealthChecksBuilder builder, Action setup,
+ string name = default, HealthStatus? failureStatus = default, IEnumerable tags = default)
+ {
+ var options = new AzureKeyVaultOptions();
+ setup?.Invoke(options);
+
+ return builder.Add(new HealthCheckRegistration(
+ name ?? "azurekeyvault",
+ sp => new AzureKeyVaultHealthCheck(options),
+ failureStatus,
+ tags));
+ }
+ }
+}
diff --git a/src/HealthChecks.AzureKeyVault/HealthChecks.AzureKeyVault.csproj b/src/HealthChecks.AzureKeyVault/HealthChecks.AzureKeyVault.csproj
new file mode 100644
index 0000000000..225c4021b9
--- /dev/null
+++ b/src/HealthChecks.AzureKeyVault/HealthChecks.AzureKeyVault.csproj
@@ -0,0 +1,27 @@
+
+
+ $(NetStandardTargetVersion)
+ $(PackageLicenseUrl)
+ $(PackageProjectUrl)
+ HealthCheck;Azure Key Vault;Secrets
+ HealthChecks.AzureKeyVault is the health check package for Azure Key Vault secrets
+ $(HealthCheckKeyVault)
+ $(RepositoryUrl)
+ $(Company)
+ $(Authors)
+ latest
+ AspNetCore.HealthChecks.AzureKeyVault
+ $(PublishRepositoryUrl)
+ $(AllowedOutputExtensionsInPackageBuildOutputFolder)
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+
diff --git a/src/HealthChecks.AzureServiceBus/AzureEventHubHealthCheck.cs b/src/HealthChecks.AzureServiceBus/AzureEventHubHealthCheck.cs
index 29c569bd3f..988f5fde16 100644
--- a/src/HealthChecks.AzureServiceBus/AzureEventHubHealthCheck.cs
+++ b/src/HealthChecks.AzureServiceBus/AzureEventHubHealthCheck.cs
@@ -13,8 +13,18 @@ public class AzureEventHubHealthCheck
private readonly string _eventHubName;
public AzureEventHubHealthCheck(string connectionString, string eventHubName)
{
- _connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString));
- _eventHubName = eventHubName ?? throw new ArgumentNullException(nameof(eventHubName));
+ if (string.IsNullOrEmpty(connectionString))
+ {
+ throw new ArgumentNullException(nameof(connectionString));
+ }
+
+ if (string.IsNullOrEmpty(eventHubName))
+ {
+ throw new ArgumentNullException(nameof(eventHubName));
+ }
+
+ _connectionString = connectionString;
+ _eventHubName = eventHubName;
}
public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
diff --git a/src/HealthChecks.AzureServiceBus/AzureServiceBusQueueHealthCheck.cs b/src/HealthChecks.AzureServiceBus/AzureServiceBusQueueHealthCheck.cs
index aab5e040a3..4c47ee06c5 100644
--- a/src/HealthChecks.AzureServiceBus/AzureServiceBusQueueHealthCheck.cs
+++ b/src/HealthChecks.AzureServiceBus/AzureServiceBusQueueHealthCheck.cs
@@ -15,8 +15,11 @@ public class AzureServiceBusQueueHealthCheck
private readonly string _queueName;
public AzureServiceBusQueueHealthCheck(string connectionString, string queueName)
{
- _connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString));
- _queueName = queueName ?? throw new ArgumentNullException(nameof(queueName));
+ if (string.IsNullOrEmpty(connectionString)) throw new ArgumentNullException(nameof(connectionString));
+ if (string.IsNullOrEmpty(queueName)) throw new ArgumentNullException(nameof(queueName));
+
+ _connectionString = connectionString;
+ _queueName = queueName;
}
public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
diff --git a/src/HealthChecks.AzureServiceBus/AzureServiceBusTopicHealthCheck.cs b/src/HealthChecks.AzureServiceBus/AzureServiceBusTopicHealthCheck.cs
index b9bc1a87b8..9083af223d 100644
--- a/src/HealthChecks.AzureServiceBus/AzureServiceBusTopicHealthCheck.cs
+++ b/src/HealthChecks.AzureServiceBus/AzureServiceBusTopicHealthCheck.cs
@@ -15,8 +15,11 @@ public class AzureServiceBusTopicHealthCheck
private readonly string _topicName;
public AzureServiceBusTopicHealthCheck(string connectionString, string topicName)
{
- _connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString));
- _topicName = topicName ?? throw new ArgumentNullException(nameof(topicName));
+ if (string.IsNullOrEmpty(connectionString)) throw new ArgumentNullException(nameof(connectionString));
+ if (string.IsNullOrEmpty(topicName)) throw new ArgumentNullException(nameof(topicName));
+
+ _connectionString = connectionString;
+ _topicName = topicName;
}
public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
diff --git a/test/UnitTests/DependencyInjection/HealthChecks.AzureKeyVault/AzureKeyVaultUnitTests.cs b/test/UnitTests/DependencyInjection/HealthChecks.AzureKeyVault/AzureKeyVaultUnitTests.cs
new file mode 100644
index 0000000000..4095005b7d
--- /dev/null
+++ b/test/UnitTests/DependencyInjection/HealthChecks.AzureKeyVault/AzureKeyVaultUnitTests.cs
@@ -0,0 +1,97 @@
+using FluentAssertions;
+using HealthChecks.AzureKeyVault;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Diagnostics.HealthChecks;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Xunit;
+
+namespace UnitTests.HealthChecks.DependencyInjection.AzureKeyVault
+{
+ public class azure_keyvault_registration_should
+ {
+ [Fact]
+ public void add_health_check_when_properly_configured()
+ {
+ var services = new ServiceCollection();
+ services.AddHealthChecks()
+ .AddAzureKeyVault(setup =>
+ {
+ setup
+ .UseKeyVaultUrl("https://keyvault")
+ .AddSecret("supercret");
+ });
+
+ var serviceProvider = services.BuildServiceProvider();
+ var options = serviceProvider.GetService>();
+
+ var registration = options.Value.Registrations.First();
+ var check = registration.Factory(serviceProvider);
+
+ registration.Name.Should().Be("azurekeyvault");
+ check.GetType().Should().Be(typeof(AzureKeyVaultHealthCheck));
+
+ }
+
+ [Fact]
+ public void add_named_health_check_when_properly_configured()
+ {
+ var services = new ServiceCollection();
+ services.AddHealthChecks()
+ .AddAzureKeyVault(setup =>
+ {
+ setup
+ .UseKeyVaultUrl("https://keyvault")
+ .UseClientSecrets("client", "secret");
+
+ }, name: "keyvaultcheck");
+
+ var serviceProvider = services.BuildServiceProvider();
+ var options = serviceProvider.GetService>();
+
+ var registration = options.Value.Registrations.First();
+ var check = registration.Factory(serviceProvider);
+
+ registration.Name.Should().Be("keyvaultcheck");
+ check.GetType().Should().Be(typeof(AzureKeyVaultHealthCheck));
+ }
+
+ [Fact]
+ public void fail_when_invalidad_uri_provided_in_configuration()
+ {
+ var services = new ServiceCollection();
+ services.AddHealthChecks()
+ .AddAzureKeyVault(setup =>
+ {
+ setup
+ .UseKeyVaultUrl("invalid URI")
+ .AddSecret("mysecret");
+ });
+
+ var serviceProvider = services.BuildServiceProvider();
+ var options = serviceProvider.GetService>();
+
+ var registration = options.Value.Registrations.First();
+
+ Assert.Throws(() => registration.Factory(serviceProvider));
+ }
+
+ [Fact]
+ public void fail_when_no_health_check_configuration_provided()
+ {
+ var services = new ServiceCollection();
+ services.AddHealthChecks()
+ .AddAzureKeyVault(setup => { });
+
+ var serviceProvider = services.BuildServiceProvider();
+ var options = serviceProvider.GetService>();
+
+ var registration = options.Value.Registrations.First();
+
+ Assert.Throws(() => registration.Factory(serviceProvider));
+ }
+ }
+}
diff --git a/test/UnitTests/DependencyInjection/HeathChecks.AzureServiceBus/AzureEventHubUnitTests.cs b/test/UnitTests/DependencyInjection/HeathChecks.AzureServiceBus/AzureEventHubUnitTests.cs
new file mode 100644
index 0000000000..2445d00a71
--- /dev/null
+++ b/test/UnitTests/DependencyInjection/HeathChecks.AzureServiceBus/AzureEventHubUnitTests.cs
@@ -0,0 +1,66 @@
+using FluentAssertions;
+using HealthChecks.AzureServiceBus;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Diagnostics.HealthChecks;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Xunit;
+
+namespace UnitTests.HeathChecks.DependencyInjection.AzureServiceBus
+{
+ public class azure_event_hub_registration_should
+ {
+ [Fact]
+ public void add_health_check_when_properly_configured()
+ {
+ var services = new ServiceCollection();
+ services.AddHealthChecks()
+ .AddAzureEventHub("cnn", "hubName");
+
+ var serviceProvider = services.BuildServiceProvider();
+ var options = serviceProvider.GetService>();
+
+ var registration = options.Value.Registrations.First();
+ var check = registration.Factory(serviceProvider);
+
+ registration.Name.Should().Be("azureeventhub");
+ check.GetType().Should().Be(typeof(AzureEventHubHealthCheck));
+ }
+
+ [Fact]
+ public void add_named_health_check_when_properly_configured()
+ {
+ var services = new ServiceCollection();
+ services.AddHealthChecks()
+ .AddAzureEventHub("cnn", "hubName",
+ name: "azureeventhubcheck");
+
+ var serviceProvider = services.BuildServiceProvider();
+ var options = serviceProvider.GetService>();
+
+ var registration = options.Value.Registrations.First();
+ var check = registration.Factory(serviceProvider);
+
+ registration.Name.Should().Be("azureeventhubcheck");
+ check.GetType().Should().Be(typeof(AzureEventHubHealthCheck));
+ }
+
+ [Fact]
+ public void fail_when_no_health_check_configuration_provided()
+ {
+ var services = new ServiceCollection();
+ services.AddHealthChecks()
+ .AddAzureEventHub(string.Empty, string.Empty);
+
+ var serviceProvider = services.BuildServiceProvider();
+ var options = serviceProvider.GetService>();
+
+ var registration = options.Value.Registrations.First();
+
+ Assert.Throws(() => registration.Factory(serviceProvider));
+ }
+ }
+}
diff --git a/test/UnitTests/DependencyInjection/HeathChecks.AzureServiceBus/AzureServiceBusQueueUnitTests.cs b/test/UnitTests/DependencyInjection/HeathChecks.AzureServiceBus/AzureServiceBusQueueUnitTests.cs
new file mode 100644
index 0000000000..2ff631b98d
--- /dev/null
+++ b/test/UnitTests/DependencyInjection/HeathChecks.AzureServiceBus/AzureServiceBusQueueUnitTests.cs
@@ -0,0 +1,67 @@
+using FluentAssertions;
+using HealthChecks.AzureServiceBus;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Diagnostics.HealthChecks;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Xunit;
+
+namespace UnitTests.HeathChecks.DependencyInjection.AzureServiceBus
+{
+ public class azure_service_bus_queue_registration_should
+ {
+ [Fact]
+ public void add_health_check_when_properly_configured()
+ {
+ var services = new ServiceCollection();
+ services.AddHealthChecks()
+ .AddAzureServiceBusQueue("cnn", "queueName");
+
+ var serviceProvider = services.BuildServiceProvider();
+ var options = serviceProvider.GetService>();
+
+ var registration = options.Value.Registrations.First();
+ var check = registration.Factory(serviceProvider);
+
+ registration.Name.Should().Be("azurequeue");
+ check.GetType().Should().Be(typeof(AzureServiceBusQueueHealthCheck));
+
+ }
+
+ [Fact]
+ public void add_named_health_check_when_properly_configured()
+ {
+ var services = new ServiceCollection();
+ services.AddHealthChecks()
+ .AddAzureServiceBusQueue("cnn", "queueName",
+ name: "azureservicebusqueuecheck");
+
+ var serviceProvider = services.BuildServiceProvider();
+ var options = serviceProvider.GetService>();
+
+ var registration = options.Value.Registrations.First();
+ var check = registration.Factory(serviceProvider);
+
+ registration.Name.Should().Be("azureservicebusqueuecheck");
+ check.GetType().Should().Be(typeof(AzureServiceBusQueueHealthCheck));
+ }
+
+ [Fact]
+ public void fail_when_no_health_check_configuration_provided()
+ {
+ var services = new ServiceCollection();
+ services.AddHealthChecks()
+ .AddAzureServiceBusQueue(string.Empty, string.Empty);
+
+ var serviceProvider = services.BuildServiceProvider();
+ var options = serviceProvider.GetService>();
+
+ var registration = options.Value.Registrations.First();
+
+ Assert.Throws(() => registration.Factory(serviceProvider));
+ }
+ }
+}
diff --git a/test/UnitTests/DependencyInjection/HeathChecks.AzureServiceBus/AzureServiceBusTopicUnitTests.cs b/test/UnitTests/DependencyInjection/HeathChecks.AzureServiceBus/AzureServiceBusTopicUnitTests.cs
new file mode 100644
index 0000000000..d0246c800e
--- /dev/null
+++ b/test/UnitTests/DependencyInjection/HeathChecks.AzureServiceBus/AzureServiceBusTopicUnitTests.cs
@@ -0,0 +1,66 @@
+using FluentAssertions;
+using HealthChecks.AzureServiceBus;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Diagnostics.HealthChecks;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Xunit;
+
+namespace UnitTests.HeathChecks.DependencyInjection.AzureServiceBus
+{
+ public class azure_service_bus_topic_registration_should
+ {
+ [Fact]
+ public void add_health_check_when_properly_configured()
+ {
+ var services = new ServiceCollection();
+ services.AddHealthChecks()
+ .AddAzureServiceBusTopic("cnn", "topicName");
+
+ var serviceProvider = services.BuildServiceProvider();
+ var options = serviceProvider.GetService>();
+
+ var registration = options.Value.Registrations.First();
+ var check = registration.Factory(serviceProvider);
+
+ registration.Name.Should().Be("azuretopic");
+ check.GetType().Should().Be(typeof(AzureServiceBusTopicHealthCheck));
+ }
+
+ [Fact]
+ public void add_named_health_check_when_properly_configured()
+ {
+ var services = new ServiceCollection();
+ services.AddHealthChecks()
+ .AddAzureServiceBusTopic("cnn", "topic",
+ name: "azuretopiccheck");
+
+ var serviceProvider = services.BuildServiceProvider();
+ var options = serviceProvider.GetService>();
+
+ var registration = options.Value.Registrations.First();
+ var check = registration.Factory(serviceProvider);
+
+ registration.Name.Should().Be("azuretopiccheck");
+ check.GetType().Should().Be(typeof(AzureServiceBusTopicHealthCheck));
+ }
+
+ [Fact]
+ public void fail_when_no_health_check_configuration_provided()
+ {
+ var services = new ServiceCollection();
+ services.AddHealthChecks()
+ .AddAzureServiceBusTopic(string.Empty, string.Empty);
+
+ var serviceProvider = services.BuildServiceProvider();
+ var options = serviceProvider.GetService>();
+
+ var registration = options.Value.Registrations.First();
+
+ Assert.Throws(() => registration.Factory(serviceProvider));
+ }
+ }
+}
diff --git a/test/UnitTests/UnitTests.csproj b/test/UnitTests/UnitTests.csproj
new file mode 100644
index 0000000000..c5edd0d8ca
--- /dev/null
+++ b/test/UnitTests/UnitTests.csproj
@@ -0,0 +1,23 @@
+
+
+
+ $(NetCoreTargetVersion)
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+