Skip to content

Commit

Permalink
PM-10600: UT coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
mzieniukbw committed Oct 22, 2024
1 parent e0d46d2 commit ab370a3
Show file tree
Hide file tree
Showing 2 changed files with 223 additions and 26 deletions.
76 changes: 76 additions & 0 deletions test/Core.Test/Models/Api/Request/PushSendRequestModelTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#nullable enable
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums;
using Bit.Core.Models.Api;
using Xunit;

namespace Bit.Core.Test.Models.Api.Request;

public class PushSendRequestModelTests
{
[Theory]
[InlineData(null, null)]
[InlineData(null, "")]
[InlineData(null, " ")]
[InlineData("", null)]
[InlineData(" ", null)]
[InlineData("", "")]
[InlineData(" ", " ")]
public void Validate_UserIdOrganizationIdNullOrEmpty_Invalid(string? userId, string? organizationId)
{
var model = new PushSendRequestModel
{
UserId = userId,
OrganizationId = organizationId,
Type = PushType.SyncCiphers,
Payload = "test"
};

var results = Validate(model);

Assert.Single(results);
Assert.Contains(results, result => result.ErrorMessage == "UserId or OrganizationId is required.");
}

[Fact]
public void Validate_RequiredPayloadFieldNotProvided_Invalid()
{
var model = new PushSendRequestModel
{
UserId = Guid.NewGuid().ToString(),
OrganizationId = Guid.NewGuid().ToString(),
Type = PushType.SyncCiphers
};

var results = Validate(model);

Assert.Single(results);
Assert.Contains(results, result => result.ErrorMessage == "The Payload field is required.");
}

[Fact]
public void Validate_AllFieldsPresent_Valid()
{
var model = new PushSendRequestModel
{
UserId = Guid.NewGuid().ToString(),
OrganizationId = Guid.NewGuid().ToString(),
Type = PushType.SyncCiphers,
Payload = "test payload",
Identifier = Guid.NewGuid().ToString(),
ClientType = ClientType.All,
DeviceId = Guid.NewGuid().ToString()
};

var results = Validate(model);

Assert.Empty(results);
}

private static List<ValidationResult> Validate(PushSendRequestModel model)
{
var results = new List<ValidationResult>();
Validator.TryValidateObject(model, new ValidationContext(model), results);
return results;
}
}
Original file line number Diff line number Diff line change
@@ -1,42 +1,163 @@
using Bit.Core.NotificationHub;
using System.Text.Json;
using Bit.Core.Enums;
using Bit.Core.Models;
using Bit.Core.Models.Data;
using Bit.Core.NotificationCenter.Entities;
using Bit.Core.NotificationHub;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Bit.Core.Test.NotificationCenter.AutoFixture;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;

namespace Bit.Core.Test.NotificationHub;

[SutProviderCustomize]
public class NotificationHubPushNotificationServiceTests
{
private readonly NotificationHubPushNotificationService _sut;
[Theory]
[BitAutoData]
[NotificationCustomize]
public async void PushSyncNotificationAsync_Global_NotSent(
SutProvider<NotificationHubPushNotificationService> sutProvider, Notification notification)
{
await sutProvider.Sut.PushSyncNotificationAsync(notification);

await sutProvider.GetDependency<INotificationHubPool>()
.Received(0)
.AllClients
.Received(0)
.SendTemplateNotificationAsync(Arg.Any<IDictionary<string, string>>(), Arg.Any<string>());
await sutProvider.GetDependency<IInstallationDeviceRepository>()
.Received(0)
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
}

[Theory]
[BitAutoData(false)]
[BitAutoData(true)]
[NotificationCustomize(false)]
public async void PushSyncNotificationAsync_UserIdProvidedClientTypeAll_SentToUser(
bool organizationIdNull, SutProvider<NotificationHubPushNotificationService> sutProvider,
Notification notification)
{
if (organizationIdNull)
{
notification.OrganizationId = null;
}

notification.ClientType = ClientType.All;
var expectedSyncNotification = ToSyncNotificationPushNotification(notification);

await sutProvider.Sut.PushSyncNotificationAsync(notification);

await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotification, expectedSyncNotification,
$"(template:payload_userId:{notification.UserId})");
await sutProvider.GetDependency<IInstallationDeviceRepository>()
.Received(0)
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
}

[Theory]
[BitAutoData(false, ClientType.Browser)]
[BitAutoData(false, ClientType.Desktop)]
[BitAutoData(false, ClientType.Web)]
[BitAutoData(false, ClientType.Mobile)]
[BitAutoData(true, ClientType.Browser)]
[BitAutoData(true, ClientType.Desktop)]
[BitAutoData(true, ClientType.Web)]
[BitAutoData(true, ClientType.Mobile)]
[NotificationCustomize(false)]
public async void PushSyncNotificationAsync_UserIdProvidedClientTypeNotAll_SentToUser(bool organizationIdNull,
ClientType clientType, SutProvider<NotificationHubPushNotificationService> sutProvider,
Notification notification)
{
if (organizationIdNull)
{
notification.OrganizationId = null;
}

notification.ClientType = clientType;
var expectedSyncNotification = ToSyncNotificationPushNotification(notification);

await sutProvider.Sut.PushSyncNotificationAsync(notification);

await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotification, expectedSyncNotification,
$"(template:payload_userId:{notification.UserId} && clientType:{clientType})");
await sutProvider.GetDependency<IInstallationDeviceRepository>()
.Received(0)
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
}

[Theory]
[BitAutoData]
[NotificationCustomize(false)]
public async void PushSyncNotificationAsync_UserIdNullOrganizationIdProvidedClientTypeAll_SentToOrganization(
SutProvider<NotificationHubPushNotificationService> sutProvider, Notification notification)
{
notification.UserId = null;
notification.ClientType = ClientType.All;
var expectedSyncNotification = ToSyncNotificationPushNotification(notification);

await sutProvider.Sut.PushSyncNotificationAsync(notification);

await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotification, expectedSyncNotification,
$"(template:payload && organizationId:{notification.OrganizationId})");
await sutProvider.GetDependency<IInstallationDeviceRepository>()
.Received(0)
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
}

[Theory]
[BitAutoData(ClientType.Browser)]
[BitAutoData(ClientType.Desktop)]
[BitAutoData(ClientType.Web)]
[BitAutoData(ClientType.Mobile)]
[NotificationCustomize(false)]
public async void PushSyncNotificationAsync_UserIdNullOrganizationIdProvidedClientTypeNotAll_SentToOrganization(
ClientType clientType, SutProvider<NotificationHubPushNotificationService> sutProvider,
Notification notification)
{
notification.UserId = null;
notification.ClientType = clientType;

var expectedSyncNotification = ToSyncNotificationPushNotification(notification);

await sutProvider.Sut.PushSyncNotificationAsync(notification);

await AssertSendTemplateNotificationAsync(sutProvider, PushType.SyncNotification, expectedSyncNotification,
$"(template:payload && organizationId:{notification.OrganizationId} && clientType:{clientType})");
await sutProvider.GetDependency<IInstallationDeviceRepository>()
.Received(0)
.UpsertAsync(Arg.Any<InstallationDeviceEntity>());
}

private readonly IInstallationDeviceRepository _installationDeviceRepository;
private readonly INotificationHubPool _notificationHubPool;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ILogger<NotificationsApiPushNotificationService> _logger;
private static SyncNotificationPushNotification ToSyncNotificationPushNotification(Notification notification) =>
new()
{
Id = notification.Id,
UserId = notification.UserId,
OrganizationId = notification.OrganizationId,
ClientType = notification.ClientType,
RevisionDate = notification.RevisionDate
};

public NotificationHubPushNotificationServiceTests()
private static async Task AssertSendTemplateNotificationAsync(
SutProvider<NotificationHubPushNotificationService> sutProvider, PushType type, object payload, string tag)
{
_installationDeviceRepository = Substitute.For<IInstallationDeviceRepository>();
_httpContextAccessor = Substitute.For<IHttpContextAccessor>();
_notificationHubPool = Substitute.For<INotificationHubPool>();
_logger = Substitute.For<ILogger<NotificationsApiPushNotificationService>>();

_sut = new NotificationHubPushNotificationService(
_installationDeviceRepository,
_notificationHubPool,
_httpContextAccessor,
_logger
);
await sutProvider.GetDependency<INotificationHubPool>()
.Received(1)
.AllClients
.Received(1)
.SendTemplateNotificationAsync(
Arg.Is<IDictionary<string, string>>(dictionary => MatchingSendPayload(dictionary, type, payload)),
tag);
}

// 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 MatchingSendPayload(IDictionary<string, string> dictionary, PushType type, object payload)
{
Assert.NotNull(_sut);
return dictionary.ContainsKey("type") && dictionary["type"].Equals(((byte)type).ToString()) &&
dictionary.ContainsKey("payload") && dictionary["payload"].Equals(JsonSerializer.Serialize(payload));
}
}

0 comments on commit ab370a3

Please sign in to comment.