From f9477118d67305644786ace5a451da4a00286373 Mon Sep 17 00:00:00 2001 From: Maciej Zieniuk Date: Wed, 23 Oct 2024 14:15:10 +0100 Subject: [PATCH] PM-10600: UTs coverage --- .../AzureQueuePushNotificationService.cs | 8 +-- .../Utilities/ServiceCollectionExtensions.cs | 6 +- .../AutoFixture/QueueClientFixture.cs | 35 +++++++++ .../AzureQueuePushNotificationServiceTests.cs | 71 ++++++++++++++----- 4 files changed, 95 insertions(+), 25 deletions(-) create mode 100644 test/Core.Test/AutoFixture/QueueClientFixture.cs diff --git a/src/Core/Services/Implementations/AzureQueuePushNotificationService.cs b/src/Core/Services/Implementations/AzureQueuePushNotificationService.cs index 44cb56d806..9b45d49187 100644 --- a/src/Core/Services/Implementations/AzureQueuePushNotificationService.cs +++ b/src/Core/Services/Implementations/AzureQueuePushNotificationService.cs @@ -5,26 +5,24 @@ using Bit.Core.Context; using Bit.Core.Enums; using Bit.Core.Models; using Bit.Core.NotificationCenter.Entities; -using Bit.Core.Settings; using Bit.Core.Tools.Entities; using Bit.Core.Utilities; using Bit.Core.Vault.Entities; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; namespace Bit.Core.Services; public class AzureQueuePushNotificationService : IPushNotificationService { private readonly QueueClient _queueClient; - private readonly GlobalSettings _globalSettings; private readonly IHttpContextAccessor _httpContextAccessor; public AzureQueuePushNotificationService( - GlobalSettings globalSettings, + [FromKeyedServices("notifications")] QueueClient queueClient, IHttpContextAccessor httpContextAccessor) { - _queueClient = new QueueClient(globalSettings.Notifications.ConnectionString, "notifications"); - _globalSettings = globalSettings; + _queueClient = queueClient; _httpContextAccessor = httpContextAccessor; } diff --git a/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs b/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs index b0a2c42ead..79eafc6102 100644 --- a/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs +++ b/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs @@ -3,6 +3,7 @@ using System.Reflection; using System.Security.Claims; using System.Security.Cryptography.X509Certificates; using AspNetCoreRateLimit; +using Azure.Storage.Queues; using Bit.Core.AdminConsole.Models.Business.Tokenables; using Bit.Core.AdminConsole.OrganizationFeatures.Policies; using Bit.Core.AdminConsole.Services; @@ -287,7 +288,10 @@ public static class ServiceCollectionExtensions services.AddKeyedSingleton("implementation"); if (CoreHelpers.SettingHasValue(globalSettings.Notifications?.ConnectionString)) { - services.AddKeyedSingleton("implementation"); + services.AddKeyedSingleton("notifications", + (_, _) => new QueueClient(globalSettings.Notifications.ConnectionString, "notifications")); + services.AddKeyedSingleton( + "implementation"); } } else diff --git a/test/Core.Test/AutoFixture/QueueClientFixture.cs b/test/Core.Test/AutoFixture/QueueClientFixture.cs new file mode 100644 index 0000000000..1b5a82595c --- /dev/null +++ b/test/Core.Test/AutoFixture/QueueClientFixture.cs @@ -0,0 +1,35 @@ +#nullable enable +using AutoFixture; +using AutoFixture.Kernel; +using Azure.Storage.Queues; +using Bit.Test.Common.AutoFixture.Attributes; +using NSubstitute; + +namespace Bit.Core.Test.AutoFixture; + +public class QueueClientBuilder : ISpecimenBuilder +{ + public object Create(object request, ISpecimenContext context) + { + var type = request as Type; + if (type == typeof(QueueClient)) + { + return Substitute.For(); + } + + return new NoSpecimen(); + } +} + +public class QueueClientCustomizeAttribute : BitCustomizeAttribute +{ + public override ICustomization GetCustomization() => new QueueClientFixture(); +} + +public class QueueClientFixture : ICustomization +{ + public void Customize(IFixture fixture) + { + fixture.Customizations.Add(new QueueClientBuilder()); + } +} diff --git a/test/Core.Test/Services/AzureQueuePushNotificationServiceTests.cs b/test/Core.Test/Services/AzureQueuePushNotificationServiceTests.cs index 7f9cb750aa..375e9d6883 100644 --- a/test/Core.Test/Services/AzureQueuePushNotificationServiceTests.cs +++ b/test/Core.Test/Services/AzureQueuePushNotificationServiceTests.cs @@ -1,34 +1,67 @@ -using Bit.Core.Services; -using Bit.Core.Settings; +#nullable enable +using System.Text.Json; +using Azure.Storage.Queues; +using Bit.Core.Context; +using Bit.Core.Enums; +using Bit.Core.Models; +using Bit.Core.NotificationCenter.Entities; +using Bit.Core.Services; +using Bit.Core.Test.AutoFixture; +using Bit.Core.Test.AutoFixture.CurrentContextFixtures; +using Bit.Core.Test.NotificationCenter.AutoFixture; +using Bit.Test.Common.AutoFixture; +using Bit.Test.Common.AutoFixture.Attributes; using Microsoft.AspNetCore.Http; using NSubstitute; using Xunit; namespace Bit.Core.Test.Services; +[QueueClientCustomize] +[SutProviderCustomize] public class AzureQueuePushNotificationServiceTests { - private readonly AzureQueuePushNotificationService _sut; - - private readonly GlobalSettings _globalSettings; - private readonly IHttpContextAccessor _httpContextAccessor; - - public AzureQueuePushNotificationServiceTests() + [Theory] + [BitAutoData] + [NotificationCustomize] + [CurrentContextCustomize] + public async void PushSyncNotificationAsync_Notification_Sent( + SutProvider sutProvider, Notification notification, Guid deviceIdentifier, + ICurrentContext currentContext) { - _globalSettings = new GlobalSettings(); - _httpContextAccessor = Substitute.For(); + currentContext.DeviceIdentifier.Returns(deviceIdentifier.ToString()); + sutProvider.GetDependency().HttpContext!.RequestServices + .GetService(Arg.Any()).Returns(currentContext); - _sut = new AzureQueuePushNotificationService( - _globalSettings, - _httpContextAccessor - ); + await sutProvider.Sut.PushSyncNotificationAsync(notification); + + await sutProvider.GetDependency().Received(1) + .SendMessageAsync(Arg.Is(message => + MatchMessage(PushType.SyncNotification, message, new SyncNotificationEquals(notification), + deviceIdentifier.ToString()))); } - // Remove this test when we add actual tests. It only proves that - // we've properly constructed the system under test. - [Fact(Skip = "Needs additional work")] - public void ServiceExists() + private static bool MatchMessage(PushType pushType, string message, IEquatable expectedPayloadEquatable, + string contextId) { - Assert.NotNull(_sut); + var pushNotificationData = + JsonSerializer.Deserialize>(message); + return pushNotificationData != null && + pushNotificationData.Type == pushType && + expectedPayloadEquatable.Equals(pushNotificationData.Payload) && + pushNotificationData.ContextId == contextId; + } + + private class SyncNotificationEquals(Notification notification) : IEquatable + { + public bool Equals(SyncNotificationPushNotification? other) + { + return other != null && + other.Id == notification.Id && + other.UserId == notification.UserId && + other.OrganizationId == notification.OrganizationId && + other.ClientType == notification.ClientType && + other.RevisionDate == notification.RevisionDate; + } } }