diff --git a/.assets/api.png b/.assets/api.png
index bedabcbc2..729ebfd46 100644
Binary files a/.assets/api.png and b/.assets/api.png differ
diff --git a/.assets/core.png b/.assets/core.png
index f4932e1cd..c1d2e5008 100644
Binary files a/.assets/core.png and b/.assets/core.png differ
diff --git a/.github/workflows/docker-push.yml b/.github/workflows/docker-push.yml
index 5583b2471..dc580f9be 100644
--- a/.github/workflows/docker-push.yml
+++ b/.github/workflows/docker-push.yml
@@ -87,6 +87,9 @@ jobs:
uses: docker/build-push-action@v5
with:
push: true
+ build-args: |
+ VERSION=${{ env.VERSION }}
+ SHA=${{ github.sha }}
labels: ${{ steps.meta.outputs.labels }}
tags: |
${{ env.BASE_TAG }}:${{ env.VERSION }}
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 11b7d2e2d..9f9708e36 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -1,26 +1,27 @@
-{
- // Use IntelliSense to learn about possible attributes.
- // Hover to view descriptions of existing attributes.
- // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
- "version": "0.2.0",
- "configurations": [
- {
- "name": "Launch API",
- "type": "coreclr",
- "request": "launch",
- "preLaunchTask": "build",
- "program": "${workspaceFolder}/src/HappyCode.NetCoreBoilerplate.Api/bin/Debug/netcoreapp3.1/HappyCode.NetCoreBoilerplate.Api.dll",
- "args": [],
- "cwd": "${workspaceFolder}/src/HappyCode.NetCoreBoilerplate.Api",
- "stopAtEntry": false,
- "serverReadyAction": {
- "action": "openExternally",
- "pattern": "^\\s*Now listening on:\\s+(https?://\\S+)",
- },
- "env": {
- "ASPNETCORE_ENVIRONMENT": "Development",
- "ASPNETCORE_URLS": "http://*:5000",
- }
- }
- ]
-}
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Debug API",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ "program": "${workspaceFolder}/src/HappyCode.NetCoreBoilerplate.Api/bin/Debug/net8.0/HappyCode.NetCoreBoilerplate.Api.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}/src/HappyCode.NetCoreBoilerplate.Api",
+ "stopAtEntry": false,
+ "serverReadyAction": {
+ "action": "openExternally",
+ "pattern": "\\bNow listening on:\\s+(https?://\\S+)",
+ "uriFormat": "%s/swagger"
+ },
+ "env": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "ASPNETCORE_URLS": "http://localhost:5000",
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index fb2c872e1..a19d84a07 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -7,7 +7,9 @@
"type": "process",
"args": [
"build",
- "${workspaceFolder}/src/HappyCode.NetCoreBoilerplate.Api/HappyCode.NetCoreBoilerplate.Api.csproj"
+ "${workspaceFolder}/src/HappyCode.NetCoreBoilerplate.Api/HappyCode.NetCoreBoilerplate.Api.csproj",
+ "-c",
+ "Debug",
],
"problemMatcher": "$msCompile"
}
diff --git a/Directory.Build.props b/Directory.Build.props
index 9f4186974..10d365a7e 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -6,7 +6,7 @@
Łukasz Kurzyniec
- Copyright © happy+code Łukasz Kurzyniec 2022
+ Copyright © happy+code Łukasz Kurzyniec 2024
2.0.0
diff --git a/README.md b/README.md
index 0acc64347..a15d3593f 100644
--- a/README.md
+++ b/README.md
@@ -116,6 +116,7 @@ After successful start of the solution in any of above option, check useful endp
* swagger -
* health check -
+* version -
### Standalone
@@ -183,6 +184,10 @@ Generally it is totally up to you! But in case you do not have any plan, You can
* Configurations
* `Serilog` configuration place - [SerilogConfigurator.cs](src/HappyCode.NetCoreBoilerplate.Api/Infrastructure/Configurations/SerilogConfigurator.cs)
* `Swagger` registration place - [SwaggerRegistration.cs](src/HappyCode.NetCoreBoilerplate.Api/Infrastructure/Registrations/SwaggerRegistration.cs)
+ * Feature flag documentation filter - [FeatureFlagSwaggerDocumentFilter.cs](src/HappyCode.NetCoreBoilerplate.Api/Infrastructure/Filters/FeatureFlagSwaggerDocumentFilter.cs)
+ * Security requirement operation filter - [SecurityRequirementSwaggerOperationFilter.cs](src/HappyCode.NetCoreBoilerplate.Api/Infrastructure/Filters/SecurityRequirementSwaggerOperationFilter.cs)
+* Logging
+ * Custom enricher to have version properties in logs - [VersionEnricher.cs](src/HappyCode.NetCoreBoilerplate.Api/Infrastructure/Logging/VersionEnricher.cs)
* Simple exemplary API controllers - [EmployeesController.cs](src/HappyCode.NetCoreBoilerplate.Api/Controllers/EmployeesController.cs), [CarsController.cs](src/HappyCode.NetCoreBoilerplate.Api/Controllers/CarsController.cs), [PingsController.cs](src/HappyCode.NetCoreBoilerplate.Api/Controllers/PingsController.cs)
* Example of BackgroundService - [PingWebsiteBackgroundService.cs](src/HappyCode.NetCoreBoilerplate.Api/BackgroundServices/PingWebsiteBackgroundService.cs)
@@ -199,6 +204,8 @@ Generally it is totally up to you! But in case you do not have any plan, You can
* DbContexts
* MySQL DbContext - [EmployeesContext.cs](src/HappyCode.NetCoreBoilerplate.Core/EmployeesContext.cs)
* MsSQL DbContext - [CarsContext.cs](src/HappyCode.NetCoreBoilerplate.Core/CarsContext.cs)
+* Providers
+ * Version provider - [VersionProvider.cs](src/HappyCode.NetCoreBoilerplate.Core/Providers/VersionProvider.cs)
* Core registrations - [CoreRegistrations.cs](src/HappyCode.NetCoreBoilerplate.Core/Registrations/CoreRegistrations.cs)
* Exemplary MySQL repository - [EmployeeRepository.cs](src/HappyCode.NetCoreBoilerplate.Core/Repositories/EmployeeRepository.cs)
* Exemplary MsSQL service - [CarService.cs](src/HappyCode.NetCoreBoilerplate.Core/Services/CarService.cs)
@@ -224,7 +231,8 @@ Generally it is totally up to you! But in case you do not have any plan, You can
* Fixture with TestServer - [TestServerClientFixture.cs](test/HappyCode.NetCoreBoilerplate.Api.IntegrationTests/Infrastructure/TestServerClientFixture.cs)
* TestStartup with InMemory databases - [TestStartup.cs](test/HappyCode.NetCoreBoilerplate.Api.IntegrationTests/Infrastructure/TestStartup.cs)
* Simple data feeders - [EmployeeContextDataFeeder.cs](test/HappyCode.NetCoreBoilerplate.Api.IntegrationTests/Infrastructure/DataFeeders/EmployeeContextDataFeeder.cs), [CarsContextDataFeeder.cs](test/HappyCode.NetCoreBoilerplate.Api.IntegrationTests/Infrastructure/DataFeeders/CarsContextDataFeeder.cs)
-* Exemplary tests - [EmployeesTests.cs](test/HappyCode.NetCoreBoilerplate.Api.IntegrationTests/EmployeesTests.cs), [CarsTests.cs](test/HappyCode.NetCoreBoilerplate.Api.IntegrationTests/CarsTests.cs)
+ * Fakes - [FakePingService.cs](test/HappyCode.NetCoreBoilerplate.Api.IntegrationTests/Infrastructure/Fakes/FakePingService.cs)
+* Exemplary tests - [EmployeesTests.cs](test/HappyCode.NetCoreBoilerplate.Api.IntegrationTests/EmployeesTests.cs), [CarsTests.cs](test/HappyCode.NetCoreBoilerplate.Api.IntegrationTests/CarsTests.cs), [PingsTests.cs](test/HappyCode.NetCoreBoilerplate.Api.IntegrationTests/PingsTests.cs)
![HappyCode.NetCoreBoilerplate.Api.IntegrationTests](.assets/itests.png "HappyCode.NetCoreBoilerplate.Api.IntegrationTests")
@@ -232,13 +240,18 @@ Generally it is totally up to you! But in case you do not have any plan, You can
[HappyCode.NetCoreBoilerplate.Api.UnitTests](test/HappyCode.NetCoreBoilerplate.Api.UnitTests)
-* Exemplary tests - [EmployeesControllerTests.cs](test/HappyCode.NetCoreBoilerplate.Api.UnitTests/Controllers/EmployeesControllerTests.cs)
-* Unit tests of `ApiKeyAuthorizationFilter.cs` - [ApiKeyAuthorizationFilterTests.cs](test/HappyCode.NetCoreBoilerplate.Api.UnitTests/Infrastructure/Filters/ApiKeyAuthorizationFilterTests.cs)
+* Exemplary tests - [EmployeesControllerTests.cs](test/HappyCode.NetCoreBoilerplate.Api.UnitTests/Controllers/EmployeesControllerTests.cs), [CarsControllerTests.cs](test/HappyCode.NetCoreBoilerplate.Api.UnitTests/Controllers/CarsControllerTests.cs), [PingsControllerTests.cs](test/HappyCode.NetCoreBoilerplate.Api.UnitTests/Controllers/PingsControllerTests.cs)
+* API Infrastructure Unit tests
+ * [ApiKeyAuthorizationFilterTests.cs](test/HappyCode.NetCoreBoilerplate.Api.UnitTests/Infrastructure/Filters/ApiKeyAuthorizationFilterTests.cs)
+ * [ValidateModelStateFilterTests.cs](test/HappyCode.NetCoreBoilerplate.Api.UnitTests/Infrastructure/Filters/ValidateModelStateFilterTests.cs)
+ * [VersionEnricherTests.cs](test/HappyCode.NetCoreBoilerplate.Api.UnitTests/Infrastructure/Logging/VersionEnricherTests.cs)
[HappyCode.NetCoreBoilerplate.Core.UnitTests](test/HappyCode.NetCoreBoilerplate.Core.UnitTests)
* Extension methods to mock `DbSet` faster - [EnumerableExtensions.cs](test/HappyCode.NetCoreBoilerplate.Core.UnitTests/Extensions/EnumerableExtensions.cs)
* Exemplary tests - [EmployeeRepositoryTests.cs](test/HappyCode.NetCoreBoilerplate.Core.UnitTests/Repositories/EmployeeRepositoryTests.cs), [CarServiceTests.cs](test/HappyCode.NetCoreBoilerplate.Core.UnitTests/Services/CarServiceTests.cs)
+* Providers tests
+ * [VersionProviderTests.cs](test/HappyCode.NetCoreBoilerplate.Core.UnitTests/Providers/VersionProviderTests.cs) with [HappyCode.NetCoreBoilerplate.Core.UnitTests.runsettings](test/HappyCode.NetCoreBoilerplate.Core.UnitTests/HappyCode.NetCoreBoilerplate.Core.UnitTests.runsettings)
![HappyCode.NetCoreBoilerplate.Core.UnitTests](.assets/utests.png "HappyCode.NetCoreBoilerplate.Core.UnitTests")
diff --git a/dockerfile b/dockerfile
index 4b895c3e9..0afcf8f44 100644
--- a/dockerfile
+++ b/dockerfile
@@ -1,3 +1,6 @@
+ARG VERSION=2.0.0
+ARG SHA=none
+
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER $APP_UID
WORKDIR /app
@@ -45,6 +48,9 @@ COPY --from=publish /app .
ENV DOTNET_NOLOGO=true
ENV DOTNET_CLI_TELEMETRY_OPTOUT=true
+ENV HC_SHA=${SHA}
+ENV HC_VERSION=${VERSION}
+
HEALTHCHECK --interval=5m --timeout=3s --start-period=10s --retries=1 \
CMD curl --fail http://localhost:8080/healthz/live || exit 1
diff --git a/src/HappyCode.NetCoreBoilerplate.Api/Infrastructure/Configurations/SerilogConfigurator.cs b/src/HappyCode.NetCoreBoilerplate.Api/Infrastructure/Configurations/SerilogConfigurator.cs
index 4841757bf..3cee3f35e 100644
--- a/src/HappyCode.NetCoreBoilerplate.Api/Infrastructure/Configurations/SerilogConfigurator.cs
+++ b/src/HappyCode.NetCoreBoilerplate.Api/Infrastructure/Configurations/SerilogConfigurator.cs
@@ -1,3 +1,4 @@
+using HappyCode.NetCoreBoilerplate.Api.Infrastructure.Logging;
using Microsoft.Extensions.Configuration;
using Serilog;
using Serilog.Core;
@@ -11,6 +12,7 @@ public static Logger CreateLogger()
var configuration = LoadAppConfiguration();
return new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
+ .Enrich.With(new VersionEnricher(new ()))
.CreateLogger();
}
diff --git a/src/HappyCode.NetCoreBoilerplate.Api/Infrastructure/Logging/VersionEnricher.cs b/src/HappyCode.NetCoreBoilerplate.Api/Infrastructure/Logging/VersionEnricher.cs
new file mode 100644
index 000000000..c6577909a
--- /dev/null
+++ b/src/HappyCode.NetCoreBoilerplate.Api/Infrastructure/Logging/VersionEnricher.cs
@@ -0,0 +1,23 @@
+using HappyCode.NetCoreBoilerplate.Core.Providers;
+using Serilog.Core;
+using Serilog.Events;
+
+namespace HappyCode.NetCoreBoilerplate.Api.Infrastructure.Logging;
+
+public class VersionEnricher : ILogEventEnricher
+{
+ private readonly VersionProvider _versionProvider;
+
+ public VersionEnricher(VersionProvider versionProvider)
+ {
+ _versionProvider = versionProvider;
+ }
+
+ public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
+ {
+ foreach (var item in _versionProvider.VersionEntries)
+ {
+ logEvent.AddPropertyIfAbsent(new LogEventProperty(item.Key, new ScalarValue(item.Value)));
+ }
+ }
+}
diff --git a/src/HappyCode.NetCoreBoilerplate.Api/Properties/launchSettings.json b/src/HappyCode.NetCoreBoilerplate.Api/Properties/launchSettings.json
index 113d07f1e..013ad0082 100644
--- a/src/HappyCode.NetCoreBoilerplate.Api/Properties/launchSettings.json
+++ b/src/HappyCode.NetCoreBoilerplate.Api/Properties/launchSettings.json
@@ -6,8 +6,10 @@
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_URLS": "http://localhost:5000",
- "ASPNETCORE_ENVIRONMENT": "Development"
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "HC_SHA": "2a6ba3cac8416214cfa84eb1f9092f130427479f",
+ "HC_VERSION": "2.0.0"
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/HappyCode.NetCoreBoilerplate.Api/Startup.cs b/src/HappyCode.NetCoreBoilerplate.Api/Startup.cs
index f3a679ab2..7b042d044 100644
--- a/src/HappyCode.NetCoreBoilerplate.Api/Startup.cs
+++ b/src/HappyCode.NetCoreBoilerplate.Api/Startup.cs
@@ -5,12 +5,14 @@
using HappyCode.NetCoreBoilerplate.Api.Infrastructure.Registrations;
using HappyCode.NetCoreBoilerplate.BooksModule;
using HappyCode.NetCoreBoilerplate.Core;
+using HappyCode.NetCoreBoilerplate.Core.Providers;
using HappyCode.NetCoreBoilerplate.Core.Registrations;
using HappyCode.NetCoreBoilerplate.Core.Settings;
using HealthChecks.UI.Client;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
@@ -91,6 +93,9 @@ public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env)
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse,
}).ShortCircuit();
+ endpoints.MapGet("/version", (VersionProvider provider) => provider.VersionEntries)
+ .ExcludeFromDescription();
+
endpoints.MapControllers();
endpoints.MapBooksModule();
});
diff --git a/src/HappyCode.NetCoreBoilerplate.Core/Providers/VersionProvider.cs b/src/HappyCode.NetCoreBoilerplate.Core/Providers/VersionProvider.cs
new file mode 100644
index 000000000..01edd0532
--- /dev/null
+++ b/src/HappyCode.NetCoreBoilerplate.Core/Providers/VersionProvider.cs
@@ -0,0 +1,24 @@
+using System.Collections;
+using System.Linq;
+
+namespace HappyCode.NetCoreBoilerplate.Core.Providers;
+
+public class VersionProvider
+{
+ private const string PREFIX = "HC_";
+
+ private readonly Lazy> _versionEntries = new(GetVersionEntries);
+
+ private static Dictionary GetVersionEntries()
+ {
+ var variables = Environment.GetEnvironmentVariables()
+ .Cast()
+ .Where(x => x.Key.ToString().StartsWith(PREFIX))
+ .ToDictionary(
+ x => x.Key.ToString().Remove(0, PREFIX.Length),
+ y => y.Value.ToString());
+ return variables;
+ }
+
+ public Dictionary VersionEntries => _versionEntries.Value;
+}
diff --git a/src/HappyCode.NetCoreBoilerplate.Core/Registrations/CoreRegistrations.cs b/src/HappyCode.NetCoreBoilerplate.Core/Registrations/CoreRegistrations.cs
index 8090327a4..7566d3eb9 100644
--- a/src/HappyCode.NetCoreBoilerplate.Core/Registrations/CoreRegistrations.cs
+++ b/src/HappyCode.NetCoreBoilerplate.Core/Registrations/CoreRegistrations.cs
@@ -1,3 +1,4 @@
+using HappyCode.NetCoreBoilerplate.Core.Providers;
using HappyCode.NetCoreBoilerplate.Core.Repositories;
using HappyCode.NetCoreBoilerplate.Core.Services;
using Microsoft.Extensions.DependencyInjection;
@@ -10,6 +11,7 @@ public static IServiceCollection AddCoreComponents(this IServiceCollection servi
{
services.AddTransient();
services.AddScoped();
+ services.AddSingleton();
return services;
}
diff --git a/test/HappyCode.NetCoreBoilerplate.Api.UnitTests/HappyCode.NetCoreBoilerplate.Api.UnitTests.csproj b/test/HappyCode.NetCoreBoilerplate.Api.UnitTests/HappyCode.NetCoreBoilerplate.Api.UnitTests.csproj
index 494d46fa2..bb37c6d69 100644
--- a/test/HappyCode.NetCoreBoilerplate.Api.UnitTests/HappyCode.NetCoreBoilerplate.Api.UnitTests.csproj
+++ b/test/HappyCode.NetCoreBoilerplate.Api.UnitTests/HappyCode.NetCoreBoilerplate.Api.UnitTests.csproj
@@ -1,4 +1,8 @@
+
+ $(MSBuildProjectDirectory)\HappyCode.NetCoreBoilerplate.Api.UnitTests.runsettings
+
+
diff --git a/test/HappyCode.NetCoreBoilerplate.Api.UnitTests/HappyCode.NetCoreBoilerplate.Api.UnitTests.runsettings b/test/HappyCode.NetCoreBoilerplate.Api.UnitTests/HappyCode.NetCoreBoilerplate.Api.UnitTests.runsettings
new file mode 100644
index 000000000..3f297f311
--- /dev/null
+++ b/test/HappyCode.NetCoreBoilerplate.Api.UnitTests/HappyCode.NetCoreBoilerplate.Api.UnitTests.runsettings
@@ -0,0 +1,10 @@
+
+
+
+
+ TEST_VALUE
+ 36b90293
+ 9.9.9
+
+
+
diff --git a/test/HappyCode.NetCoreBoilerplate.Api.UnitTests/Infrastructure/Logging/VersionEnricherTests.cs b/test/HappyCode.NetCoreBoilerplate.Api.UnitTests/Infrastructure/Logging/VersionEnricherTests.cs
new file mode 100644
index 000000000..ecf1fc0b1
--- /dev/null
+++ b/test/HappyCode.NetCoreBoilerplate.Api.UnitTests/Infrastructure/Logging/VersionEnricherTests.cs
@@ -0,0 +1,38 @@
+using System;
+using FluentAssertions;
+using HappyCode.NetCoreBoilerplate.Api.Infrastructure.Logging;
+using HappyCode.NetCoreBoilerplate.Core.Providers;
+using Serilog.Events;
+using Xunit;
+
+namespace HappyCode.NetCoreBoilerplate.Api.UnitTests.Infrastructure.Logging;
+
+public class VersionEnricherTests
+{
+ private readonly VersionEnricher _sut;
+
+ public VersionEnricherTests()
+ {
+ _sut = new VersionEnricher(new VersionProvider());
+ }
+
+ [Fact]
+ public void Properties_should_be_available()
+ {
+ // Arrange
+ var logEvent = GetEmptyLogEvent();
+
+ // Act
+ _sut.Enrich(logEvent, null);
+
+ // Assert
+ logEvent.Properties["SHA"].ToString().Should().Contain("36b90293");
+ logEvent.Properties["VERSION"].ToString().Should().Contain("9.9.9");
+ }
+
+ private static LogEvent GetEmptyLogEvent()
+ {
+ return new LogEvent(DateTimeOffset.UtcNow, LogEventLevel.Verbose, null,
+ new MessageTemplate(Guid.NewGuid().ToString(), []), []);
+ }
+}
diff --git a/test/HappyCode.NetCoreBoilerplate.Core.UnitTests/HappyCode.NetCoreBoilerplate.Core.UnitTests.csproj b/test/HappyCode.NetCoreBoilerplate.Core.UnitTests/HappyCode.NetCoreBoilerplate.Core.UnitTests.csproj
index 8e26e805e..c32eb0b3b 100644
--- a/test/HappyCode.NetCoreBoilerplate.Core.UnitTests/HappyCode.NetCoreBoilerplate.Core.UnitTests.csproj
+++ b/test/HappyCode.NetCoreBoilerplate.Core.UnitTests/HappyCode.NetCoreBoilerplate.Core.UnitTests.csproj
@@ -1,4 +1,8 @@
+
+ $(MSBuildProjectDirectory)\HappyCode.NetCoreBoilerplate.Core.UnitTests.runsettings
+
+
diff --git a/test/HappyCode.NetCoreBoilerplate.Core.UnitTests/HappyCode.NetCoreBoilerplate.Core.UnitTests.runsettings b/test/HappyCode.NetCoreBoilerplate.Core.UnitTests/HappyCode.NetCoreBoilerplate.Core.UnitTests.runsettings
new file mode 100644
index 000000000..3f297f311
--- /dev/null
+++ b/test/HappyCode.NetCoreBoilerplate.Core.UnitTests/HappyCode.NetCoreBoilerplate.Core.UnitTests.runsettings
@@ -0,0 +1,10 @@
+
+
+
+
+ TEST_VALUE
+ 36b90293
+ 9.9.9
+
+
+
diff --git a/test/HappyCode.NetCoreBoilerplate.Core.UnitTests/Providers/VersionProviderTests.cs b/test/HappyCode.NetCoreBoilerplate.Core.UnitTests/Providers/VersionProviderTests.cs
new file mode 100644
index 000000000..a973aee4f
--- /dev/null
+++ b/test/HappyCode.NetCoreBoilerplate.Core.UnitTests/Providers/VersionProviderTests.cs
@@ -0,0 +1,27 @@
+using FluentAssertions;
+using HappyCode.NetCoreBoilerplate.Core.Providers;
+using Xunit;
+
+namespace HappyCode.NetCoreBoilerplate.Core.UnitTests.Providers;
+
+public class VersionProviderTests
+{
+ private readonly VersionProvider _provider;
+
+ public VersionProviderTests()
+ {
+ _provider = new VersionProvider();
+ }
+
+ [Fact]
+ public void Provided_should_returns_expected_values()
+ {
+ // act
+ var result = _provider.VersionEntries;
+
+ // assert
+ result.Should().NotContainKeys("TEST_ENV", "HC_SHA", "HC_VERSION");
+ result.Should().ContainKeys("SHA", "VERSION");
+ result.Should().HaveCount(2);
+ }
+}