diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8f4e3690d..88f183b57 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ Please ADD ALL Changes to the UNRELEASED SECTION and not a specific release
### Added
- BuildBot.GitHub - Increased code coverage to 100%
- [BuildBot.CloudFormation] Increase code coverage to 100%
+- Tests for BuildBot.Watchtower to increase code coverage to 100%
### Fixed
- Suppress known Scriban 6.2.0 vulnerabilities pending upgrade
### Changed
diff --git a/src/BuildBot.Watchtower.Tests/BuildBot.Watchtower.Tests.csproj b/src/BuildBot.Watchtower.Tests/BuildBot.Watchtower.Tests.csproj
new file mode 100644
index 000000000..a924016d5
--- /dev/null
+++ b/src/BuildBot.Watchtower.Tests/BuildBot.Watchtower.Tests.csproj
@@ -0,0 +1,72 @@
+
+
+ latest
+ AllEnabledByDefault
+ true
+ true
+ true
+ true
+ true
+ false
+ true
+ false
+ strict;flow-analysis
+ true
+ false
+ Size
+ disable
+ false
+ false
+ false
+ false
+ latest
+
+ true
+ high
+ all
+ enable
+ speed
+ Exe
+ false
+ net10.0
+ true
+ true
+ true
+
+ True
+ true
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BuildBot.Watchtower.Tests/DependencyInjectionTests.cs b/src/BuildBot.Watchtower.Tests/DependencyInjectionTests.cs
new file mode 100644
index 000000000..c3b2128d4
--- /dev/null
+++ b/src/BuildBot.Watchtower.Tests/DependencyInjectionTests.cs
@@ -0,0 +1,24 @@
+using BuildBot.Watchtower.Publishers;
+using FunFair.Test.Common;
+using Mediator;
+using Microsoft.Extensions.DependencyInjection;
+using Xunit;
+
+namespace BuildBot.Watchtower.Tests;
+
+public sealed class DependencyInjectionTests : DependencyInjectionTestsBase
+{
+ public DependencyInjectionTests(ITestOutputHelper output)
+ : base(output: output, dependencyInjectionRegistration: Configure) { }
+
+ private static IServiceCollection Configure(IServiceCollection services)
+ {
+ return services.AddMockedService().AddWatchtower();
+ }
+
+ [Fact]
+ public void WatchTowerPublishMessageNotificationHandlerMustBeRegistered()
+ {
+ this.RequireService();
+ }
+}
diff --git a/src/BuildBot.Watchtower.Tests/Models/WatchTowerPublishMessageTests.cs b/src/BuildBot.Watchtower.Tests/Models/WatchTowerPublishMessageTests.cs
new file mode 100644
index 000000000..905e5459d
--- /dev/null
+++ b/src/BuildBot.Watchtower.Tests/Models/WatchTowerPublishMessageTests.cs
@@ -0,0 +1,39 @@
+using BuildBot.ServiceModel.Watchtower;
+using BuildBot.Watchtower.Models;
+using FunFair.Test.Common;
+using Xunit;
+
+namespace BuildBot.Watchtower.Tests.Models;
+
+public sealed class WatchTowerPublishMessageTests : TestBase
+{
+ [Fact]
+ public void ModelPropertyMatchesConstructorArgument()
+ {
+ WatchTowerMessage model = new(Message: "Service deployed", Title: "Deployment");
+
+ WatchTowerPublishMessage notification = new(model);
+
+ Assert.Equal(expected: model, actual: notification.Model);
+ }
+
+ [Fact]
+ public void TwoNotificationsWithSameModelAreEqual()
+ {
+ WatchTowerMessage model = new(Message: "Service deployed", Title: "Deployment");
+
+ WatchTowerPublishMessage first = new(model);
+ WatchTowerPublishMessage second = new(model);
+
+ Assert.Equal(expected: first, actual: second);
+ }
+
+ [Fact]
+ public void TwoNotificationsWithDifferentModelsAreNotEqual()
+ {
+ WatchTowerPublishMessage first = new(new WatchTowerMessage(Message: "Service deployed", Title: "Deployment"));
+ WatchTowerPublishMessage second = new(new WatchTowerMessage(Message: "Service failed", Title: "Failure"));
+
+ Assert.NotEqual(expected: first, actual: second);
+ }
+}
diff --git a/src/BuildBot.Watchtower.Tests/Publishers/WatchTowerPublishMessageNotificationHandlerTests.cs b/src/BuildBot.Watchtower.Tests/Publishers/WatchTowerPublishMessageNotificationHandlerTests.cs
new file mode 100644
index 000000000..94e3925ae
--- /dev/null
+++ b/src/BuildBot.Watchtower.Tests/Publishers/WatchTowerPublishMessageNotificationHandlerTests.cs
@@ -0,0 +1,29 @@
+using System.Threading;
+using System.Threading.Tasks;
+using BuildBot.Discord.Models;
+using BuildBot.ServiceModel.Watchtower;
+using BuildBot.Watchtower.Models;
+using BuildBot.Watchtower.Publishers;
+using FunFair.Test.Common;
+using Mediator;
+using NSubstitute;
+using Xunit;
+
+namespace BuildBot.Watchtower.Tests.Publishers;
+
+public sealed class WatchTowerPublishMessageNotificationHandlerTests : TestBase
+{
+ [Fact]
+ public async Task HandlePublishesBotMessageViaMediatorAsync()
+ {
+ IMediator mediator = GetSubstitute();
+ WatchTowerPublishMessageNotificationHandler handler = new(mediator);
+
+ WatchTowerMessage model = new(Message: "Service deployed", Title: "Deployment");
+ WatchTowerPublishMessage notification = new(model);
+
+ await handler.Handle(notification: notification, cancellationToken: this.CancellationToken());
+
+ await mediator.Received(1).Publish(Arg.Any(), Arg.Any());
+ }
+}
diff --git a/src/BuildBot.Watchtower/WatchtowerSetup.cs b/src/BuildBot.Watchtower/WatchtowerSetup.cs
index 4dc5506e0..e44adaa5c 100644
--- a/src/BuildBot.Watchtower/WatchtowerSetup.cs
+++ b/src/BuildBot.Watchtower/WatchtowerSetup.cs
@@ -1,3 +1,4 @@
+using BuildBot.Watchtower.Publishers;
using Microsoft.Extensions.DependencyInjection;
namespace BuildBot.Watchtower;
@@ -6,6 +7,6 @@ public static class WatchtowerSetup
{
public static IServiceCollection AddWatchtower(this IServiceCollection services)
{
- return services;
+ return services.AddSingleton();
}
}
diff --git a/src/BuildBot.slnx b/src/BuildBot.slnx
index b2a33369a..6e8871f99 100644
--- a/src/BuildBot.slnx
+++ b/src/BuildBot.slnx
@@ -20,6 +20,7 @@
+